diff --git a/package.json b/package.json index 8271b72..87af89e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@reservoir0x/relay-protocol-sdk", - "version": "0.0.48", + "version": "0.0.49", "description": "Relay protocol SDK", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/index.ts b/src/index.ts index c969173..6029065 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,6 +17,7 @@ import { DecodedEthereumVmWithdrawal, DecodedSolanaVmWithdrawal, DecodedSuiVmWithdrawal, + DecodedHyperliquidVmWithdrawal, DepositoryWithdrawalMessage, DepositoryWithdrawalStatus, getDepositoryWithdrawalMessageId, @@ -85,6 +86,7 @@ export { DecodedEthereumVmWithdrawal, DecodedSolanaVmWithdrawal, DecodedSuiVmWithdrawal, + DecodedHyperliquidVmWithdrawal, DepositoryWithdrawalMessage, DepositoryWithdrawalStatus, getDepositoryWithdrawalMessageId, diff --git a/src/messages/v2.1/depository-withdrawal.ts b/src/messages/v2.1/depository-withdrawal.ts index fdee8fa..8392f12 100644 --- a/src/messages/v2.1/depository-withdrawal.ts +++ b/src/messages/v2.1/depository-withdrawal.ts @@ -142,12 +142,39 @@ export type DecodedBitcoinVmWithdrawal = { }; }; +export type DecodedHyperliquidVmWithdrawal = { + vmType: "hyperliquid-vm"; + withdrawal: { + txType: number; + parameters: + | { + type: "UsdSend"; + hyperliquidChain: string; + destination: string; + amount: string; + time: string; + } + | { + type: "SendAsset"; + hyperliquidChain: string; + destination: string; + sourceDex: string; + destinationDex: string; + token: string; + amount: string; + fromSubAccount: string; + nonce: string; + }; + }; +}; + type DecodedWithdrawal = | DecodedEthereumVmWithdrawal | DecodedSolanaVmWithdrawal | DecodedSuiVmWithdrawal | DecodedBitcoinVmWithdrawal - | DecodedTronVmWithdrawal; + | DecodedTronVmWithdrawal + | DecodedHyperliquidVmWithdrawal; export const encodeWithdrawal = ( decodedWithdrawal: DecodedWithdrawal @@ -247,6 +274,71 @@ export const encodeWithdrawal = ( return "0x" + decodedWithdrawal.withdrawal.psbt; } + case "hyperliquid-vm": { + const { txType, parameters } = decodedWithdrawal.withdrawal; + + let encodedParameters: string; + switch (parameters.type) { + case "UsdSend": { + encodedParameters = encodeAbiParameters( + parseAbiParameters([ + "(string hyperliquidChain, string destination, string amount, uint64 time)", + ]), + [ + { + hyperliquidChain: parameters.hyperliquidChain, + destination: parameters.destination, + amount: parameters.amount, + time: BigInt(parameters.time), + }, + ] + ); + + break; + } + + case "SendAsset": { + encodedParameters = encodeAbiParameters( + parseAbiParameters([ + "(string hyperliquidChain, string destination, string sourceDex, string destinationDex, string token, string amount, string fromSubAccount, uint64 nonce)", + ]), + [ + { + hyperliquidChain: parameters.hyperliquidChain, + destination: parameters.destination, + sourceDex: parameters.sourceDex, + destinationDex: parameters.destinationDex, + token: parameters.token, + amount: parameters.amount, + fromSubAccount: parameters.fromSubAccount, + nonce: BigInt(parameters.nonce), + }, + ] + ); + + break; + } + + default: { + throw new Error( + `Unsupported Hyperliquid transaction type ${ + (parameters as any).type + }` + ); + } + } + + return encodeAbiParameters( + parseAbiParameters(["(uint8 txType, bytes parameters)"]), + [ + { + txType, + parameters: encodedParameters as Hex, + }, + ] + ); + } + default: throw new Error("Unsupported vm type"); } @@ -366,6 +458,89 @@ export const decodeWithdrawal = ( }; } + case "hyperliquid-vm": { + const result = decodeAbiParameters( + parseAbiParameters(["(uint8 txType, bytes parameters)"]), + encodedWithdrawal as Hex + ); + + const { txType, parameters } = result[0]; + + switch (txType) { + case 0: { + // UsdSend + const paramResult = decodeAbiParameters( + parseAbiParameters([ + "(string hyperliquidChain, string destination, string amount, uint64 time)", + ]), + parameters + ); + + const { hyperliquidChain, destination, amount, time } = + paramResult[0]; + + return { + vmType: "hyperliquid-vm", + withdrawal: { + txType: Number(txType), + parameters: { + type: "UsdSend" as const, + hyperliquidChain, + destination, + amount, + time: time.toString(), + }, + }, + }; + } + + case 1: { + // SendAsset + const paramResult = decodeAbiParameters( + parseAbiParameters([ + "(string hyperliquidChain, string destination, string sourceDex, string destinationDex, string token, string amount, string fromSubAccount, uint64 nonce)", + ]), + parameters + ); + + const { + hyperliquidChain, + destination, + sourceDex, + destinationDex, + token, + amount, + fromSubAccount, + nonce, + } = paramResult[0]; + + return { + vmType: "hyperliquid-vm", + withdrawal: { + txType: Number(txType), + parameters: { + type: "SendAsset" as const, + hyperliquidChain, + destination, + sourceDex, + destinationDex, + token, + amount, + fromSubAccount, + nonce: nonce.toString(), + }, + }, + }; + } + + default: { + throw new Error( + `Unsupported Hyperliquid transaction type: ${txType}` + ); + } + } + } + default: throw new Error("Unsupported vm type"); } @@ -480,6 +655,68 @@ export const getDecodedWithdrawalId = ( return "0x" + sha256.create().update(encodedWithdrawal).hex(); } + case "hyperliquid-vm": { + const { parameters } = decodedWithdrawal.withdrawal; + + switch (parameters.type) { + case "UsdSend": { + return hashStruct({ + types: { + "HyperliquidTransaction:UsdSend": [ + { name: "hyperliquidChain", type: "string" }, + { name: "destination", type: "string" }, + { name: "amount", type: "string" }, + { name: "time", type: "uint64" }, + ], + }, + primaryType: "HyperliquidTransaction:UsdSend", + data: { + hyperliquidChain: parameters.hyperliquidChain, + destination: parameters.destination, + amount: parameters.amount, + time: parameters.time, + }, + }); + } + + case "SendAsset": { + return hashStruct({ + types: { + "HyperliquidTransaction:SendAsset": [ + { name: "hyperliquidChain", type: "string" }, + { name: "destination", type: "string" }, + { name: "sourceDex", type: "string" }, + { name: "destinationDex", type: "string" }, + { name: "token", type: "string" }, + { name: "amount", type: "string" }, + { name: "fromSubAccount", type: "string" }, + { name: "nonce", type: "uint64" }, + ], + }, + primaryType: "HyperliquidTransaction:SendAsset", + data: { + hyperliquidChain: parameters.hyperliquidChain, + destination: parameters.destination, + sourceDex: parameters.sourceDex, + destinationDex: parameters.destinationDex, + token: parameters.token, + amount: parameters.amount, + fromSubAccount: parameters.fromSubAccount, + nonce: parameters.nonce, + }, + }); + } + + default: { + throw new Error( + `Unsupported Hyperliquid transaction type ${ + (parameters as any).type + }` + ); + } + } + } + default: throw new Error("Unsupported vm type"); } @@ -514,5 +751,39 @@ export const getDecodedWithdrawalCurrency = ( case "sui-vm": { return decodedWithdrawal.withdrawal.coinType; } + + case "hyperliquid-vm": { + const { parameters } = decodedWithdrawal.withdrawal; + + switch (parameters.type) { + case "UsdSend": { + return getVmTypeNativeCurrency(decodedWithdrawal.vmType); + } + + case "SendAsset": { + const SPOT_USDC = "0x6d1e7cde53ba9467b783cb7c530ce054"; + + const tokenAddress = parameters.token.split(":")[1].toLowerCase(); + const tokenDex = parameters.sourceDex; + if (tokenDex === "" && tokenAddress !== SPOT_USDC) { + throw new Error("Only USDC is supported as a Perps token"); + } + + return tokenDex === "spot" + ? tokenAddress.toLowerCase() + : tokenDex === "" + ? getVmTypeNativeCurrency(decodedWithdrawal.vmType) + : tokenAddress.toLowerCase() + + Buffer.from(tokenDex, "ascii").toString("hex"); + } + + default: + throw new Error( + `Unsupported Hyperliquid transaction type ${ + (parameters as any).type + }` + ); + } + } } };