def test_order_expiration_boundary_case(self): order = SignableOrder( **dict( ORDER_PARAMS, expiration_epoch_seconds=iso_to_epoch_seconds( # Less than one second after the start of the hour. '2021-02-24T16:00:00.407Z', ), ), ) assert order.to_starkware().expiration_epoch_hours == 448553
"market": MARKET_ETH_USD, "side": ORDER_SIDE_BUY, "position_id": 12345, "human_size": '145.0005', "human_price": '350.00067', "limit_fee": '0.125', "client_id": ('This is an ID that the client came up with ' + 'to describe this order'), "expiration_epoch_seconds": iso_to_epoch_seconds('2020-09-17T04:15:55.028Z', ), } class TestOrder(): def test_sign_order(self): order = SignableOrder(**ORDER_PARAMS) signature = order.sign(MOCK_PRIVATE_KEY) assert signature == MOCK_SIGNATURE def test_verify_signature_odd_y(self): order = SignableOrder(**ORDER_PARAMS) assert order.verify_signature(MOCK_SIGNATURE, MOCK_PUBLIC_KEY) def test_verify_signature_even_y(self): order = SignableOrder(**ORDER_PARAMS)
def create_fast_withdrawal( self, position_id, credit_asset, credit_amount, debit_amount, to_address, lp_position_id, lp_stark_public_key, client_id=None, expiration=None, expiration_epoch_seconds=None, signature=None, ): ''' Post a fast withdrawal :param credit_asset: required :type credit_asset: str in list [ "USDC", "USDT", ] :param position_id: required :type position_id: str or int :param credit_amount: required :type credit_amount: str or int :param debit_amount: required :type debit_amount: str or int :param to_address: required :type to_address: str :param lp_position_id: required :type lp_position_id: str or int :param lp_stark_public_key: required :type lp_stark_public_key: str :param client_id: optional :type client_id: str :param expiration: optional :type expiration: ISO str :param expiration_epoch_seconds: optional :type expiration_epoch_seconds: int :param signature: optional :type signature: str :returns: Transfer :raises: DydxAPIError ''' client_id = client_id or random_client_id() if bool(expiration) == bool(expiration_epoch_seconds): raise ValueError( 'Exactly one of expiration and expiration_epoch_seconds must ' 'be specified', ) expiration = expiration or epoch_seconds_to_iso( expiration_epoch_seconds, ) expiration_epoch_seconds = (expiration_epoch_seconds or iso_to_epoch_seconds(expiration)) if not signature: if not self.stark_private_key: raise Exception('No signature provided and client was not' + 'initialized with stark_private_key') fact = get_transfer_erc20_fact( recipient=to_address, token_decimals=COLLATERAL_TOKEN_DECIMALS, human_amount=credit_amount, token_address=( TOKEN_CONTRACTS[COLLATERAL_ASSET][self.network_id]), salt=nonce_from_client_id(client_id), ) transfer_to_sign = SignableConditionalTransfer( network_id=self.network_id, sender_position_id=position_id, receiver_position_id=lp_position_id, receiver_public_key=lp_stark_public_key, fact_registry_address=FACT_REGISTRY_CONTRACT[self.network_id], fact=fact, human_amount=debit_amount, client_id=client_id, expiration_epoch_seconds=expiration_epoch_seconds, ) signature = transfer_to_sign.sign(self.stark_private_key) params = { 'creditAsset': credit_asset, 'creditAmount': credit_amount, 'debitAmount': debit_amount, # TODO: Signature verification should work regardless of case. 'toAddress': to_address.lower(), 'lpPositionId': lp_position_id, 'expiration': expiration, 'clientId': client_id, 'signature': signature, } return self._post('fast-withdrawals', params)
def create_withdrawal( self, position_id, amount, asset, to_address, client_id=None, expiration=None, expiration_epoch_seconds=None, signature=None, ): ''' Post a withdrawal :param position_id: required :type position_id: int or str :param amount: required :type amount: str :param asset: required :type asset: str in list [ "ETH", "LINK", "BTC", "USDC", "USDT", "USD", ] :param to_address: required :type to_address: str :param client_id: optional :type client_id: str :param expiration: optional :type expiration: ISO str :param expiration_epoch_seconds: optional :type expiration_epoch_seconds: int :param signature: optional :type signature: str :returns: Transfer :raises: DydxAPIError ''' client_id = client_id or random_client_id() if bool(expiration) == bool(expiration_epoch_seconds): raise ValueError( 'Exactly one of expiration and expiration_epoch_seconds must ' 'be specified', ) expiration = expiration or epoch_seconds_to_iso( expiration_epoch_seconds, ) expiration_epoch_seconds = (expiration_epoch_seconds or iso_to_epoch_seconds(expiration)) if not signature: if not self.stark_private_key: raise Exception('No signature provided and client was not' + 'initialized with stark_private_key') withdrawal_to_sign = SignableWithdrawal( network_id=self.network_id, position_id=position_id, client_id=client_id, human_amount=amount, expiration_epoch_seconds=expiration_epoch_seconds, ) signature = withdrawal_to_sign.sign(self.stark_private_key) params = { 'amount': amount, 'asset': asset, # TODO: Signature verification should work regardless of case. 'toAddress': to_address.lower(), 'expiration': expiration, 'clientId': client_id, 'signature': signature, } return self._post('withdrawals', params)
def create_order( self, position_id, market, side, order_type, post_only, size, price, limit_fee, time_in_force=None, cancel_id=None, trigger_price=None, trailing_percent=None, client_id=None, expiration=None, expiration_epoch_seconds=None, signature=None, ): ''' Post an order :param position_id: required :type position_id: str or int :param market: required :type market: str in list [ "BTC-USD", "ETH-USD", "LINK-USD", ] :param side: required :type side: str in list[ "BUY", "SELL", ], :param order_type: required :type order_type: str in list [ "LIMIT", "STOP", "TRAILING_STOP", "TAKE_PROFIT", ] :param post_only: required :type post_only: bool :param size: required :type size: str :param price: required :type price: str :param limit_fee: required :type limit_fee: str :param time_in_force: optional :type time_in_force: str in list [ "GTT", "FOK", "IOC", ] :param cancel_id: optional :type cancel_id: str :param trigger_price: optional :type trigger_price: Decimal :param trailing_percent: optional :type trailing_percent: Decimal :param client_id: optional :type client_id: str :param expiration: optional :type expiration: ISO str :param expiration_epoch_seconds: optional :type expiration_epoch_seconds: int :param signature: optional type signature: str :returns: Order :raises: DydxAPIError ''' client_id = client_id or random_client_id() if bool(expiration) == bool(expiration_epoch_seconds): raise ValueError( 'Exactly one of expiration and expiration_epoch_seconds must ' 'be specified', ) expiration = expiration or epoch_seconds_to_iso( expiration_epoch_seconds, ) expiration_epoch_seconds = (expiration_epoch_seconds or iso_to_epoch_seconds(expiration)) order_signature = signature if not order_signature: if not self.stark_private_key: raise Exception('No signature provided and client was not ' + 'initialized with stark_private_key') order_to_sign = SignableOrder( network_id=self.network_id, position_id=position_id, client_id=client_id, market=market, side=side, human_size=size, human_price=price, limit_fee=limit_fee, expiration_epoch_seconds=expiration_epoch_seconds, ) order_signature = order_to_sign.sign(self.stark_private_key) order = { 'market': market, 'side': side, 'type': order_type, 'timeInForce': time_in_force or TIME_IN_FORCE_GTT, 'size': size, 'price': price, 'limitFee': limit_fee, 'expiration': expiration, 'cancelId': cancel_id, 'triggerPrice': trigger_price, 'trailingPercent': trailing_percent, 'postOnly': post_only, 'clientId': client_id, 'signature': order_signature, } return self._post( 'orders', order, )
def create_withdrawal( self, position_id, amount, asset, to_address, expiration, client_id=None, signature=None, ): ''' Post a withdrawal :param position_id: required :type position_id: int or str :param amount: required :type amount: str :param asset: required :type asset: str in list [ "ETH", "LINK", "BTC", "USDC", "USDT", "USD", ] :param to_address: required :type to_address: str :param expiration: required :type expiration: ISO string :param client_id: optional :type client_id: str :param signature: optional :type signature: str :returns: Transfer :raises: DydxAPIError ''' client_id = client_id or random_client_id() withdrawal_signature = signature if not withdrawal_signature: if not self.stark_private_key: raise Exception( 'No signature provided and client was not' + 'initialized with stark_private_key' ) withdrawal_to_sign = SignableWithdrawal( position_id=position_id, client_id=client_id, human_amount=amount, expiration_epoch_seconds=iso_to_epoch_seconds(expiration), ) withdrawal_signature = withdrawal_to_sign.sign( self.stark_private_key, ) withdrawal = { 'amount': amount, 'asset': asset, # TODO: Signature verification should work regardless of case. 'toAddress': to_address.lower(), 'clientId': client_id, 'signature': withdrawal_signature, 'expiration': expiration, } return self._post( 'withdrawals', withdrawal, )