dydxprotocol / dydx-v3-python

Python client for dYdX (API v3)
Apache License 2.0
306 stars 176 forks source link

how to instantiate client for ledger wallets with no eth_private_key? #177

Closed normanlmfung closed 1 year ago

normanlmfung commented 1 year ago

hi there,

how to instantiate client for ledger wallets with no eth_private_key?

I am following example here:

I want to simply query account "Equity". client = Client( network_id=NETWORK_ID_MAINNET, host=API_HOST_MAINNET, default_ethereum_address=ETHEREUM_ADDRESS, eth_private_key=ETHEREUM_PRIVATE_KEY, <---- I dont have private key as it's ledger wallet, what to do?! (And I didnt use SAMPLE 1 to onboard the account. I done it via dydx website https://trade.dydx.exchange and there's no place from there where I can say export stark_public_key, stark_public_key_y_coordinate. Assuming this is what I need? I dont think "stark_private_key" can ever be exported?) web3=Web3(Web3.HTTPProvider(WEB_PROVIDER_URL)), ) stark_private_key = client.onboarding.derive_stark_key() client.stark_private_key = stark_private_key

account_response = client.private.get_account().data['account'] account_free_collateral_usd = float(account_response['freeCollateral']) account_equity_usd = float(account_response['equity'])

I checked client constructor: class Client(object): def init( self, host, api_timeout=None, default_ethereum_address=None, eth_private_key=None, eth_send_options=None, network_id=None, stark_private_key=None, stark_public_key=None, <---- This is what I need? stark_public_key_y_coordinate=None, <---- This is what I need? web3=None, web3_account=None, web3_provider=None, api_key_credentials=None, crypto_c_exports_path=None, )

Thanks in advance.

normanlmfung commented 1 year ago

I also tried https://docs.dydx.exchange/?python#derive-starkkey

client.onboarding.derive_stark_key(ethereum_address=ETHEREUM_ADDRESS,)

Error was: raise ValueError(response["error"]) ValueError: {'code': -32601, 'message': 'The method eth_signTypedData does not exist/is not available'}

I am guessing I can't just run derive_stark_key from some standalone python. I need to logon via https://trade.dydx.exchange, "Connect" to my wallet. Click approve from Ledger. Then from browser's Developer Console, somehow find the client object (How? I tried CTRL-SHIFT-F and search by "derive_stark_key", nothing. I searched "stark" also. But not sure how to go about get handle of "client" instance), then call "derive_stark_key" with it?

After digging around for awhile, I found this guy: https://www.reddit.com/r/dydxprotocol/comments/tn9hz9/derive_stark_key/

Basically, disconnect first. Then "Connect Wallet" again (With "Remember Me" enabled!). Then from Developer Tools (F12), under \ Local Storage \ https://trade.dydx.exchange, key = STARK_KEY_PAIRS, I found this object.

{ "walletAddress": "xxxxxx", "publicKey": "xxxxx", "publicKeyYCoordinate": "xxxxx", "privateKey": "xxxxx", <---- "legacySigning": false, "walletType": "METAMASK" }

I used that, client.stark_private_key = "... from Browser Developer Tools Local Storage ..." account_response = client.private.get_account().data['account']

Still getting error: File C:\ProgramData\Anaconda3\envs\py39\lib\site-packages\dydx3\dydx_client.py:147, in Client.private(self) 138 self._private = Private( 139 host=self.host, 140 network_id=self.network_id, (...) 144 api_key_credentials=self.api_key_credentials, 145 ) 146 else: --> 147 raise Exception( 148 'Private endpoints not supported ' + 149 'since api_key_credentials were not specified', 150 ) 151 return self._private

I dig further: https://blog.csdn.net/qq_27500493/article/details/120599965

You need to take two things from Local Storage!

a. \ Local Storage \ https://trade.dydx.exchange \ STARK_KEY_PAIRS

b. \ Local Storage \ https://trade.dydx.exchange \ API_KEY_PAIRS On client instantiation, pass as "api_key_credentials" (Note format from local storage different from constructor arg "api_key_credentials")

From \ Local Storage \ https://trade.dydx.exchange \ API_KEY_PAIRS , format is like this:

{

"0xWALLET_ADDRESS": {

"walletAddress": "0xWALLET_ADDRESS",

"secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",

"key": "xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",

"passphrase": "xxxxxxxxxxxxxxx",

"legacySigning": false,

"walletType": "METAMASK"

}

}

You need reformat to:

{

"walletAddress": "0xWALLET_ADDRESS",

"secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",

"key": "xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",

"passphrase": "xxxxxxxxxxxxxxx",

"legacySigning": false,

"walletType": "METAMASK"

}

What a waste of time. But this works. Hope it helps someone else.

normanlmfung commented 1 year ago

Solution in above