Example #1
0
 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
Example #2
0
    "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)
Example #3
0
    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)
Example #4
0
    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)
Example #5
0
    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,
        )
Example #6
0
    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,
        )