diff --git a/hyperliquid/exchange.py b/hyperliquid/exchange.py index f0c5d475..1edb76be 100644 --- a/hyperliquid/exchange.py +++ b/hyperliquid/exchange.py @@ -25,6 +25,8 @@ sign_approve_builder_fee, sign_l1_action, sign_spot_transfer_action, + sign_staking_delegation_action, + sign_staking_transfer_action, sign_usd_class_transfer_action, sign_usd_transfer_action, sign_withdraw_from_bridge_action, @@ -575,3 +577,35 @@ def multi_sig(self, multi_sig_user, inner_action, signatures, nonce, vault_addre signature, nonce, ) + + def staking_transfer(self, amount: float) -> Any: + timestamp = get_timestamp_ms() + action = { + "wei": str(amount), + "nonce": timestamp, + "type": "cDeposit", + } + is_mainnet = self.base_url == MAINNET_API_URL + signature = sign_staking_transfer_action(self.wallet, action, is_mainnet) + return self._post_action( + action, + signature, + timestamp, + ) + + def staking_delegation(self, validator: str, amount: float, is_undelegate: bool) -> Any: + timestamp = get_timestamp_ms() + action = { + "type": "tokenDelegate", + "validator": validator, + "wei": str(amount), + "isUndelegate": is_undelegate, + "nonce": timestamp, + } + is_mainnet = self.base_url == MAINNET_API_URL + signature = sign_staking_delegation_action(self.wallet, action, is_mainnet) + return self._post_action( + action, + signature, + timestamp, + ) diff --git a/hyperliquid/utils/signing.py b/hyperliquid/utils/signing.py index e3de7a44..5f26ee07 100644 --- a/hyperliquid/utils/signing.py +++ b/hyperliquid/utils/signing.py @@ -177,14 +177,14 @@ def sign_l1_action(wallet, action, active_pool, nonce, is_mainnet): return sign_inner(wallet, data) -def sign_user_signed_action(wallet, action, payload_types, primary_type, is_mainnet): - action["signatureChainId"] = "0x66eee" +def sign_user_signed_action(wallet, action, payload_types, primary_type, is_mainnet, signature_chain_id = "0x66eee", chainId = 421614): + action["signatureChainId"] = signature_chain_id action["hyperliquidChain"] = "Mainnet" if is_mainnet else "Testnet" data = { "domain": { "name": "HyperliquidSignTransaction", "version": "1", - "chainId": 421614, + "chainId": chainId, "verifyingContract": "0x0000000000000000000000000000000000000000", }, "types": { @@ -355,7 +355,59 @@ def sign_approve_builder_fee(wallet, action, is_mainnet): "HyperliquidTransaction:ApproveBuilderFee", is_mainnet, ) + +def sign_staking_transfer_action(wallet, action, is_mainnet): + """ + Action Message: + { + "type": "cDeposit", + "wei": <"100000000">, + "nonce": XXX, + "signatureChainId": "0x1", + } + "signatureChainId" and "hyperliquidChain" is populated by sign_user_signed_action + """ + return sign_user_signed_action( + wallet, + action, + [ + {"name": "hyperliquidChain", "type": "string"}, + {"name": "wei", "type": "uint64"}, + {"name": "nonce", "type": "uint64"}, + ], + "HyperliquidTransaction:CDeposit", + is_mainnet, + ) +def sign_staking_delegation_action(wallet, action, is_mainnet): + """ + Action Message: + { + "type": "tokenDelegate", + "validator": , + "wei": <"100000000">, + "isUndelegate": , + "nonce": <"XXX">, + "signatureChainId": "0x1", + } + + "signatureChainId" and "hyperliquidChain" is populated by sign_user_signed_action + """ + return sign_user_signed_action( + wallet, + action, + [ + {"name": "hyperliquidChain", "type": "string"}, + {"name": "validator", "type": "address"}, + {"name": "wei", "type": "uint64"}, + {"name": "isUndelegate", "type": "bool"}, + {"name": "nonce", "type": "uint64"}, + ], + "HyperliquidTransaction:TokenDelegate", + is_mainnet, + signatureChainId = "0x1", + chainId = 1 + ) def sign_inner(wallet, data): structured_data = encode_structured_data(data) diff --git a/tests/signing_test.py b/tests/signing_test.py index 4458290e..6e5c719f 100644 --- a/tests/signing_test.py +++ b/tests/signing_test.py @@ -13,6 +13,8 @@ sign_l1_action, sign_usd_transfer_action, sign_withdraw_from_bridge_action, + sign_staking_transfer_action, + sign_staking_delegation_action, ) from hyperliquid.utils.types import Cloid @@ -265,3 +267,31 @@ def test_schedule_cancel_action(): assert signature_testnet["r"] == "0x4e4f2dbd4107c69783e251b7e1057d9f2b9d11cee213441ccfa2be63516dc5bc" assert signature_testnet["s"] == "0x706c656b23428c8ba356d68db207e11139ede1670481a9e01ae2dfcdb0e1a678" assert signature_testnet["v"] == 27 + + +def test_sign_staking_transfer_action(): + wallet = eth_account.Account.from_key("0x0123456789012345678901234567890123456789012345678901234567890123") + message = { + "type": "cDeposit", + "wei": 100000000, + "nonce": 1687816341423, + } + signature = sign_staking_transfer_action(wallet, message, False) + assert signature["r"] == "0x9a8a8d278350f637a1066f14d66e9c42dc0a0f1d8a281b1ded2458628e244abd" + assert signature["s"] == "0x9a6b1a456c0794341a17ed9a7aca1527171229ef9b9b9fc5a817714fcb9afa6" + assert signature["v"] == 28 + + +def test_sign_staking_delegation_action(): + wallet = eth_account.Account.from_key("0x0123456789012345678901234567890123456789012345678901234567890123") + message = { + "type": "tokenDelegate", + "validator": "0x5e9ee1089755c3435139848e47e6635505d5a13a", + "wei": 100000000, + "isUndelegate": False, + "nonce": 1687816341423, + } + signature = sign_staking_delegation_action(wallet, message, False) + assert signature["r"] == "0xb8d14088d2efd302e451d0a4766eaf20d3fc234f0ba41fad078015fabe7f1442" + assert signature["s"] == "0x32529593b2cc6e9e00a01f25a4ad3628a50d2c3d40a88888a4e5f7dd184aa0b" + assert signature["v"] == 27