diff --git a/examples/basic_send_asset.py b/examples/basic_send_asset.py new file mode 100644 index 00000000..0afd66fb --- /dev/null +++ b/examples/basic_send_asset.py @@ -0,0 +1,24 @@ +import example_utils + +from hyperliquid.utils import constants + +SOURCE_DEX = "" +DESTINATION_DEX = "test" + + +def main(): + address, info, exchange = example_utils.setup(constants.TESTNET_API_URL, skip_ws=True) + + if exchange.account_address != exchange.wallet.address: + raise Exception("Agents do not have permission to perform internal transfers") + + # Transfer 1.23 USDC from SOURCE_DEX to the zero address on DESTINATION_DEX for demonstration purposes + # Note that the collateral token for SOURCE_DEX and DESTINATION_DEX must match + transfer_result = exchange.send_asset( + "0x0000000000000000000000000000000000000000", SOURCE_DEX, DESTINATION_DEX, "USDC", 1.23 + ) + print(transfer_result) + + +if __name__ == "__main__": + main() diff --git a/examples/basic_spot_to_builder_deployed_perp_dex.py b/examples/basic_spot_to_builder_deployed_perp_dex.py new file mode 100644 index 00000000..b6db82d2 --- /dev/null +++ b/examples/basic_spot_to_builder_deployed_perp_dex.py @@ -0,0 +1,22 @@ +import example_utils + +from hyperliquid.utils import constants + +DUMMY_DEX = "test" +COLLATERAL_TOKEN = "USDC" # nosec + + +def main(): + address, info, exchange = example_utils.setup(constants.TESTNET_API_URL, skip_ws=True) + + # Transfer 1.23 USDC from spot wallet to perp wallet + transfer_result = exchange.send_asset(address, "spot", DUMMY_DEX, COLLATERAL_TOKEN, 1.23) + print(transfer_result) + + # Transfer 1.23 collateral token from perp wallet back to spot wallet + transfer_result = exchange.send_asset(address, DUMMY_DEX, "spot", COLLATERAL_TOKEN, 1.23) + print(transfer_result) + + +if __name__ == "__main__": + main() diff --git a/examples/multi_sig_order.py b/examples/multi_sig_order.py index 7f839079..e974d1fb 100644 --- a/examples/multi_sig_order.py +++ b/examples/multi_sig_order.py @@ -36,9 +36,9 @@ def main(): exchange.base_url == constants.MAINNET_API_URL, None, timestamp, + exchange.expires_after, multi_sig_user, address, - exchange.expires_after, ) signatures.append(signature) diff --git a/examples/multi_sig_register_token.py b/examples/multi_sig_register_token.py index 9123b02f..f6b1ed9f 100644 --- a/examples/multi_sig_register_token.py +++ b/examples/multi_sig_register_token.py @@ -39,9 +39,9 @@ def main(): exchange.base_url == constants.MAINNET_API_URL, None, timestamp, + exchange.expires_after, multi_sig_user, address, - exchange.expires_after, ) signatures.append(signature) diff --git a/examples/perp_deploy.py b/examples/perp_deploy.py index 5d0d6ae5..c4fd8447 100644 --- a/examples/perp_deploy.py +++ b/examples/perp_deploy.py @@ -15,6 +15,10 @@ def main(): address, info, exchange = example_utils.setup(constants.TESTNET_API_URL, skip_ws=True) + # get perp deploy auction status which includes auction start and gas information + perp_deploy_auction_status = info.query_perp_deploy_auction_status() + print("perp deploy auction status:", perp_deploy_auction_status) + # Step 1: Registering a Perp Dex and Assets # # Takes part in the perp deploy auction and if successful, registers asset "TEST0". @@ -50,10 +54,12 @@ def main(): f"{DUMMY_DEX}:TEST0": "12.0", f"{DUMMY_DEX}:TEST1": "1.0", }, - { - f"{DUMMY_DEX}:TEST1": "3.0", - f"{DUMMY_DEX}:TEST0": "14.0", - }, + [ + { + f"{DUMMY_DEX}:TEST1": "3.0", + f"{DUMMY_DEX}:TEST0": "14.0", + } + ], ) print("set oracle result:", set_oracle_result) diff --git a/hyperliquid/exchange.py b/hyperliquid/exchange.py index d8954585..4888e523 100644 --- a/hyperliquid/exchange.py +++ b/hyperliquid/exchange.py @@ -26,7 +26,7 @@ sign_convert_to_multi_sig_user_action, sign_l1_action, sign_multi_sig_action, - sign_perp_dex_class_transfer_action, + sign_send_asset_action, sign_spot_transfer_action, sign_token_delegate_action, sign_usd_class_transfer_action, @@ -456,21 +456,25 @@ def usd_class_transfer(self, amount: float, to_perp: bool) -> Any: timestamp, ) - def perp_dex_class_transfer(self, dex: str, token: str, amount: float, to_perp: bool) -> Any: + def send_asset(self, destination: str, source_dex: str, destination_dex: str, token: str, amount: float) -> Any: + """ + For the default perp dex use the empty string "" as name. For spot use "spot". + Token must match the collateral token if transferring to or from a perp dex. + """ timestamp = get_timestamp_ms() str_amount = str(amount) - if self.vault_address: - str_amount += f" subaccount:{self.vault_address}" action = { - "type": "PerpDexClassTransfer", - "dex": dex, + "type": "sendAsset", + "destination": destination, + "sourceDex": source_dex, + "destinationDex": destination_dex, "token": token, "amount": str_amount, - "toPerp": to_perp, + "fromSubAccount": self.vault_address if self.vault_address else "", "nonce": timestamp, } - signature = sign_perp_dex_class_transfer_action(self.wallet, action, self.base_url == MAINNET_API_URL) + signature = sign_send_asset_action(self.wallet, action, self.base_url == MAINNET_API_URL) return self._post_action( action, signature, @@ -917,13 +921,11 @@ def perp_deploy_set_oracle( self, dex: str, oracle_pxs: Dict[str, str], - mark_pxs: Optional[Dict[str, str]], + all_mark_pxs: List[Dict[str, str]], ) -> Any: timestamp = get_timestamp_ms() oracle_pxs_wire = sorted(list(oracle_pxs.items())) - mark_pxs_wire = None - if mark_pxs is not None: - mark_pxs_wire = sorted(list(mark_pxs.items())) + mark_pxs_wire = [sorted(list(mark_pxs.items())) for mark_pxs in all_mark_pxs] action = { "type": "perpDeploy", "setOracle": { diff --git a/hyperliquid/info.py b/hyperliquid/info.py index 485779ab..cc831c93 100644 --- a/hyperliquid/info.py +++ b/hyperliquid/info.py @@ -598,6 +598,9 @@ def query_sub_accounts(self, user: str) -> Any: def query_user_to_multi_sig_signers(self, multi_sig_user: str) -> Any: return self.post("/info", {"type": "userToMultiSigSigners", "user": multi_sig_user}) + def query_perp_deploy_auction_status(self) -> Any: + return self.post("/info", {"type": "perpDeployAuctionStatus"}) + def _remap_coin_subscription(self, subscription: Subscription) -> None: if ( subscription["type"] == "l2Book" diff --git a/hyperliquid/utils/signing.py b/hyperliquid/utils/signing.py index bf2f2ab0..c0b3a0a3 100644 --- a/hyperliquid/utils/signing.py +++ b/hyperliquid/utils/signing.py @@ -104,12 +104,14 @@ {"name": "nonce", "type": "uint64"}, ] -PERP_DEX_CLASS_TRANSFER_SIGN_TYPES = [ +SEND_ASSET_SIGN_TYPES = [ {"name": "hyperliquidChain", "type": "string"}, - {"name": "dex", "type": "string"}, + {"name": "destination", "type": "string"}, + {"name": "sourceDex", "type": "string"}, + {"name": "destinationDex", "type": "string"}, {"name": "token", "type": "string"}, {"name": "amount", "type": "string"}, - {"name": "toPerp", "type": "bool"}, + {"name": "fromSubAccount", "type": "string"}, {"name": "nonce", "type": "uint64"}, ] @@ -350,12 +352,12 @@ def sign_usd_class_transfer_action(wallet, action, is_mainnet): ) -def sign_perp_dex_class_transfer_action(wallet, action, is_mainnet): +def sign_send_asset_action(wallet, action, is_mainnet): return sign_user_signed_action( wallet, action, - PERP_DEX_CLASS_TRANSFER_SIGN_TYPES, - "HyperliquidTransaction:PerpDexClassTransfer", + SEND_ASSET_SIGN_TYPES, + "HyperliquidTransaction:SendAsset", is_mainnet, ) diff --git a/pyproject.toml b/pyproject.toml index a1054ae8..34b944ed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "hyperliquid-python-sdk" -version = "0.15.0" +version = "0.16.0" description = "SDK for Hyperliquid API trading with Python." readme = "README.md" authors = ["Hyperliquid "]