def test_onboard_with_web3_default_account(self): # Generate private key. stark_private_key = generate_private_key_hex_unsafe() # Get public key. stark_public_key, stark_public_key_y_coordinate = ( private_key_to_public_key_pair_hex(stark_private_key)) # Connect to local Ethereum node. web3 = Web3() web3.eth.defaultAccount = web3.eth.accounts[1] # Create client WITHOUT any private keys. client = Client( host=HOST, network_id=NETWORK_ID, web3=web3, ) # Onboard the user. try: client.onboarding.create_user( stark_public_key=stark_public_key, stark_public_key_y_coordinate=stark_public_key_y_coordinate, ) # If the Ethereum address was already onboarded, ignore the error. except DydxApiError: pass # Register and then revoke a second API key. client.api_keys.create_api_key() client.private.get_api_keys() client.api_keys.delete_api_key( api_key=client.api_key_credentials['key'], )
def test_private_with_private_keys(self): # Generate STARK keys and Ethhereum account. stark_private_key = generate_private_key_hex_unsafe() eth_account = Web3(None).eth.account.create() # Get public key. stark_public_key, stark_public_key_y_coordinate = ( private_key_to_public_key_pair_hex(stark_private_key)) # Onboard the user. Client( host=HOST, network_id=NETWORK_ID, eth_private_key=eth_account.key, ).onboarding.create_user( stark_public_key=stark_public_key, stark_public_key_y_coordinate=stark_public_key_y_coordinate, ) # Create a second client WITHOUT eth_private_key. client = Client( host=HOST, network_id=NETWORK_ID, stark_private_key=stark_private_key, ) # Get the primary account. get_account_result = client.private.get_account( ethereum_address=eth_account.address, ) account = get_account_result['account'] # Initiate a regular (slow) withdrawal. # # Expect signature validation to pass, although the collateralization # check will fail. expected_error = ( 'Withdrawal would put account under collateralization minumum') expiration_epoch_seconds = time.time() + SEVEN_DAYS_S + 60 try: client.private.create_withdrawal( position_id=account['positionId'], amount='1', asset=constants.ASSET_USDC, to_address=eth_account.address, expiration_epoch_seconds=expiration_epoch_seconds, ) except DydxApiError as e: if expected_error not in str(e): raise
def test_onboard_with_web3_provider(self): # Generate private key. stark_private_key = generate_private_key_hex_unsafe() # Get public key. stark_public_key, stark_public_key_y_coordinate = ( private_key_to_public_key_pair_hex(stark_private_key)) # Get account address from local Ethereum node. ethereum_address = Web3().eth.accounts[0] # Create client WITHOUT any private keys. client = Client( host=HOST, network_id=NETWORK_ID, web3_provider=Web3.HTTPProvider('http://localhost:8545'), ) # Onboard the user. try: client.onboarding.create_user( ethereum_address=ethereum_address, stark_public_key=stark_public_key, stark_public_key_y_coordinate=stark_public_key_y_coordinate, ) # If the Ethereum address was already onboarded, ignore the error. except DydxApiError: pass # Register and then revoke a second API key. client.api_keys.create_api_key(ethereum_address=ethereum_address, ) client.private.get_api_keys() client.api_keys.delete_api_key( api_key=client.api_key_credentials['key'], ethereum_address=ethereum_address, )
def test_integration(self): source_private_key = os.environ.get('TEST_SOURCE_PRIVATE_KEY') if source_private_key is None: raise ValueError('TEST_SOURCE_PRIVATE_KEY must be set') web3_provider = os.environ.get('TEST_WEB3_PROVIDER_URL') if web3_provider is None: raise ValueError('TEST_WEB3_PROVIDER_URL must be set') # Create client that will be used to fund the new user. source_client = Client( host='', eth_private_key=source_private_key, web3_provider=web3_provider, ) # Create an Ethereum account and STARK keys for the new user. web3_account = Web3(None).eth.account.create() ethereum_address = web3_account.address eth_private_key = web3_account.key stark_private_key = generate_private_key_hex_unsafe() # Fund the new user with ETH and USDC. fund_eth_hash = source_client.eth.transfer_eth( to_address=ethereum_address, human_amount=0.001, ) fund_usdc_hash = source_client.eth.transfer_token( to_address=ethereum_address, human_amount=2, ) print('Waiting for funds...') source_client.eth.wait_for_tx(fund_eth_hash) source_client.eth.wait_for_tx(fund_usdc_hash) print('...done.') # Create client for the new user. client = Client( host=HOST, network_id=NETWORK_ID, stark_private_key=stark_private_key, eth_private_key=eth_private_key, web3_provider=web3_provider, ) # Onboard the user. res = client.onboarding.create_user() api_key_credentials = res['apiKey'] print('eth_private_key', eth_private_key) print('stark_private_key', stark_private_key) print('client.api_key_credentials', client.api_key_credentials) # Get the user. get_user_result = client.private.get_user() assert get_user_result['user'] == { 'ethereumAddress': ethereum_address.lower(), 'isRegistered': False, 'email': None, 'username': None, 'userData': {}, 'makerFeeRate': '0.0005', 'takerFeeRate': '0.0015', 'makerVolume30D': '0', 'takerVolume30D': '0', 'fees30D': '0', } # Get the registration signature. registration_result = client.private.get_registration() signature = registration_result['signature'] assert re.match('0x[0-9a-f]{130}$', signature) is not None, ( 'Invalid registration result: {}'.format(registration_result)) # Register the user on-chain. registration_tx_hash = client.eth.register_user(signature) print('Waiting for registration...') client.eth.wait_for_tx(registration_tx_hash) print('...done.') # Set the user's username. username = '******'.format(int(time.time())) client.private.update_user(username=username) # Create a second account under the same user. # # NOTE: Support for multiple accounts under the same user is limited. # The frontend does not currently support mutiple accounts per user. stark_private_key_2 = generate_private_key_hex_unsafe() stark_public_key_2, stark_public_key_y_coordinate_2 = ( private_key_to_public_key_pair_hex(stark_private_key_2)) client.private.create_account( stark_public_key=stark_public_key_2, stark_public_key_y_coordinate=stark_public_key_y_coordinate_2, ) # Get the primary account. get_account_result = client.private.get_account( ethereum_address=ethereum_address, ) account = get_account_result['account'] assert int(account['starkKey'], 16) == int(client.stark_public_key, 16) # Get all accounts. get_all_accounts_result = client.private.get_accounts() get_all_accounts_public_keys = [ a['starkKey'] for a in get_all_accounts_result['accounts'] ] assert int(client.stark_public_key, 16) in [int(k, 16) for k in get_all_accounts_public_keys] # TODO: Fix. # assert int(stark_public_key_2, 16) in [ # int(k, 16) for k in get_all_accounts_public_keys # ] # Get positions. get_positions_result = client.private.get_positions(market='BTC-USD') assert get_positions_result == {'positions': []} # Set allowance on the Starkware perpetual contract, for the deposit. approve_tx_hash = client.eth.set_token_max_allowance( client.eth.get_exchange_contract().address, ) print('Waiting for allowance...') client.eth.wait_for_tx(approve_tx_hash) print('...done.') # Send an on-chain deposit. deposit_tx_hash = client.eth.deposit_to_exchange( account['positionId'], 3, ) print('Waiting for deposit...') client.eth.wait_for_tx(deposit_tx_hash) print('...done.') # Wait for the deposit to be processed. print('Waiting for deposit to be processed on dYdX...') wait_for_condition( lambda: len(client.private.get_transfers()['transfers']) > 0, True, 60, ) print('...transfer was recorded, waiting for confirmation...') wait_for_condition( lambda: client.private.get_account()['account']['quoteBalance'], '2', 180, ) print('...done.') # Post an order. one_minute_from_now_iso = epoch_seconds_to_iso(time.time() + 60) create_order_result = client.private.create_order( position_id=account['positionId'], market=constants.MARKET_BTC_USD, side=constants.ORDER_SIDE_BUY, order_type=constants.ORDER_TYPE_LIMIT, post_only=False, size='10', price='1000', limit_fee='0.1', expiration=one_minute_from_now_iso, ) # Get the order. order_id = create_order_result['order']['id'] get_order_result = client.private.get_order_by_id(order_id) assert get_order_result['order']['market'] == constants.MARKET_BTC_USD # Cancel the order. client.private.cancel_order(order_id) # Cancel all orders. client.private.cancel_all_orders() # Get open orders. get_orders_result = client.private.get_orders( market=constants.MARKET_BTC_USD, status=constants.POSITION_STATUS_OPEN, ) assert get_orders_result == {'orders': []} # Get fills. client.private.get_fills(market=constants.MARKET_BTC_USD, ) # Initiate a regular (slow) withdrawal. expiration_epoch_seconds = time.time() + SEVEN_DAYS_S + 60 client.private.create_withdrawal( position_id=account['positionId'], amount='1', asset=constants.ASSET_USDC, to_address=ethereum_address, expiration_epoch_seconds=expiration_epoch_seconds, ) # Get deposits. deposits_result = client.private.get_transfers( transfer_type=constants.ACCOUNT_ACTION_DEPOSIT, ) assert len(deposits_result['transfers']) == 1 # Get withdrawals. withdrawals_result = client.private.get_transfers( transfer_type=constants.ACCOUNT_ACTION_WITHDRAWAL, ) assert len(withdrawals_result['transfers']) == 1 # Get funding payments. client.private.get_funding_payments(market=constants.MARKET_BTC_USD, ) # Register a new API key. create_api_key_result = client.api_keys.create_api_key() new_api_key_credentials = create_api_key_result['apiKey'] # Get all API keys. get_api_keys_result = client.private.get_api_keys() api_keys_public_keys = [ a['key'] for a in get_api_keys_result['apiKeys'] ] assert api_key_credentials['key'] in api_keys_public_keys # Delete an API key. client.api_keys.delete_api_key( api_key=new_api_key_credentials['key'], ethereum_address=ethereum_address, ) # Get all API keys after the deletion. get_api_keys_result_after = client.private.get_api_keys() assert len(get_api_keys_result_after['apiKeys']) == 1 # Initiate a fast withdrawal of USDC. expiration_epoch_seconds = time.time() + SEVEN_DAYS_S + 60 client.private.create_fast_withdrawal( position_id=account['positionId'], credit_asset='USDC', credit_amount='1', debit_amount='2', to_address=ethereum_address, lp_position_id=LP_POSITION_ID, lp_stark_public_key=LP_PUBLIC_KEY, client_id='mock-client-id', expiration_epoch_seconds=expiration_epoch_seconds, )
from web3 import Web3 # Ganache test address. ETHEREUM_ADDRESS = '0x22d491Bde2303f2f43325b2108D26f1eAbA1e32b' # Ganache node. WEB_PROVIDER_URL = 'http://localhost:8545' client = Client( network_id=NETWORK_ID_ROPSTEN, host=API_HOST_ROPSTEN, default_ethereum_address=ETHEREUM_ADDRESS, web3=Web3(Web3.HTTPProvider(WEB_PROVIDER_URL)), ) # Set STARK key. stark_private_key = client.onboarding.derive_stark_key() client.stark_private_key = stark_private_key public_x, public_y = private_key_to_public_key_pair_hex(stark_private_key) # Onboard the account. onboarding_response = client.onboarding.create_user( stark_public_key=public_x, stark_public_key_y_coordinate=public_y, ) print('onboarding_response', onboarding_response) # Query a private endpoint. accounts_response = client.private.get_accounts() print('accounts_response', accounts_response)