Skip to content

Commit 2519846

Browse files
authored
Integrate hyperliquid direct deposits (#878)
* wip: integrate hyperliquid direct deposits * refactor hyperliquid step logic * revert api change to dev * Improve hyperliquid logic * Fix backwards compatiility usdSend nonce handling * feat: changeset
1 parent b1dbfb7 commit 2519846

File tree

7 files changed

+96
-52
lines changed

7 files changed

+96
-52
lines changed

.changeset/five-sloths-wave.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@relayprotocol/relay-sdk': minor
3+
'@relayprotocol/relay-kit-ui': minor
4+
---
5+
6+
Integrate hyperliquid direct deposits

demo/pages/ui/swap.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import { adaptTronWallet } from '@relayprotocol/relay-tron-wallet-adapter'
3636
import Head from 'next/head'
3737
import { isTronWallet, TronWallet } from '@dynamic-labs/tron'
3838

39-
const WALLET_VM_TYPES = ['evm', 'bvm', 'svm', 'suivm', 'tvm'] as const
39+
const WALLET_VM_TYPES = ['evm', 'bvm', 'svm', 'suivm', 'tvm', 'hypevm'] as const
4040

4141
const SwapWidgetPage: NextPage = () => {
4242
useDynamicEvents('walletAdded', (newWallet) => {

packages/sdk/src/utils/executeSteps/index.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type {
66
import type { AxiosRequestConfig } from 'axios'
77
import { getClient, RelayClient } from '../../client.js'
88
import { LogLevel } from '../logger.js'
9-
import { prepareHyperliquidSignatureStep } from '../../utils/index.js'
9+
import { prepareHyperliquidSteps } from '../../utils/index.js'
1010
import {
1111
canBatchTransactions,
1212
prepareBatchTransaction
@@ -124,18 +124,10 @@ export async function executeSteps(
124124
}
125125
}
126126

127-
// Check if Hyperliquid and if so, rewrite steps to become a signature step
128-
if (
129-
chainId === 1337 &&
130-
json.steps[0] &&
131-
(json.steps[0].id as any) !== 'sign'
132-
) {
127+
// Check if Hyperliquid and if so, prepare the steps for Hyperliquid signing
128+
if (chainId === 1337) {
133129
const activeWalletChainId = await wallet?.getChainId()
134-
const signatureStep = prepareHyperliquidSignatureStep(
135-
json.steps,
136-
activeWalletChainId
137-
)
138-
json.steps = [signatureStep]
130+
json.steps = prepareHyperliquidSteps(json.steps, activeWalletChainId)
139131
}
140132

141133
// Update state on first call or recursion

packages/sdk/src/utils/executeSteps/signatureStep.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import type { AxiosRequestConfig } from 'axios'
99
import { LogLevel } from '../logger.js'
1010
import type { RelayClient } from '../../client.js'
1111
import type { SetStateData } from './index.js'
12-
import { sendUsd } from '../hyperliquid.js'
12+
import { postHyperliquidSignature } from '../hyperliquid.js'
1313

1414
/**
1515
* Handles the execution of a signature step item, including signing, posting, and validation.
@@ -57,6 +57,7 @@ export async function handleSignatureStepItem({
5757
breakdown: json?.breakdown,
5858
details: json?.details
5959
})
60+
6061
signature = await wallet.handleSignMessageStep(stepItem, step)
6162

6263
if (signature) {
@@ -67,8 +68,12 @@ export async function handleSignatureStepItem({
6768
}
6869
}
6970

70-
if (chain.id === 1337 && signature) {
71-
await sendUsd(client, signature, stepItem)
71+
if (
72+
chain.id === 1337 &&
73+
signature &&
74+
step?.id === ('hyperliquid-signature' as any)
75+
) {
76+
await postHyperliquidSignature(client, signature, stepItem)
7277
}
7378

7479
if (postData) {

packages/sdk/src/utils/hyperliquid.ts

Lines changed: 75 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@ import axios from 'axios'
44
import type { RelayClient } from '../client.js'
55
import { LogLevel } from './logger.js'
66

7-
export function prepareHyperliquidSignatureStep(
8-
steps: Execute['steps'],
7+
function prepareHyperliquidSignatureStep(
8+
step: Execute['steps'][0],
99
chainId: number
1010
) {
11-
const items = steps[0]?.items
12-
const amount = items[0]?.data?.action?.parameters?.amount
13-
const destination = items[0]?.data?.action?.parameters?.destination
11+
const stepItem = step?.items?.[0]
12+
const action = stepItem?.data?.action
13+
const eip712Types = stepItem?.data?.eip712Types
14+
const eip712PrimaryType = stepItem?.data?.eip712PrimaryType
15+
1416
const signatureStep = {
15-
id: 'sign' as any,
17+
id: 'hyperliquid-signature' as any,
1618
action: 'Confirm transaction in your wallet',
1719
description: `Sign a message to confirm the transaction`,
1820
kind: 'signature' as const,
@@ -29,44 +31,36 @@ export function prepareHyperliquidSignatureStep(
2931
verifyingContract: '0x0000000000000000000000000000000000000000'
3032
},
3133
types: {
32-
'HyperliquidTransaction:UsdSend': [
33-
{ name: 'hyperliquidChain', type: 'string' },
34-
{ name: 'destination', type: 'string' },
35-
{ name: 'amount', type: 'string' },
36-
{ name: 'time', type: 'uint64' }
37-
],
34+
...eip712Types,
3835
EIP712Domain: [
3936
{ name: 'name', type: 'string' },
4037
{ name: 'version', type: 'string' },
4138
{ name: 'chainId', type: 'uint256' },
4239
{ name: 'verifyingContract', type: 'address' }
4340
]
4441
},
45-
primaryType: 'HyperliquidTransaction:UsdSend',
42+
primaryType: eip712PrimaryType,
4643
value: {
47-
type: 'usdSend',
48-
signatureChainId: `0x${chainId.toString(16)}`,
49-
hyperliquidChain: 'Mainnet',
50-
destination: destination?.toLowerCase(),
51-
amount,
52-
time: new Date().getTime()
44+
...action.parameters,
45+
type: action.type,
46+
signatureChainId: `0x${chainId.toString(16)}`
5347
}
5448
}
5549
},
5650
check: {
57-
endpoint: `/intents/status?requestId=${steps[0]?.requestId}`,
51+
endpoint: `/intents/status?requestId=${step?.requestId}`,
5852
method: 'GET'
5953
}
6054
}
6155
],
62-
requestId: steps[0]?.requestId,
63-
depositAddress: steps[0]?.depositAddress
56+
requestId: step?.requestId,
57+
depositAddress: step?.depositAddress
6458
}
6559

6660
return signatureStep
6761
}
6862

69-
export async function sendUsd(
63+
export async function postHyperliquidSignature(
7064
client: RelayClient,
7165
signature: string,
7266
stepItem: Execute['steps'][0]['items'][0]
@@ -76,22 +70,18 @@ export async function sendUsd(
7670
LogLevel.Verbose
7771
)
7872
const { r, s, v } = parseSignature(signature as `0x${string}`)
79-
const currentTime = stepItem?.data?.sign?.value?.time ?? new Date().getTime()
73+
74+
const action = stepItem?.data?.sign?.value
75+
const nonce = action?.nonce ?? action?.time
76+
8077
const res = await axios.post('https://api.hyperliquid.xyz/exchange', {
8178
signature: {
8279
r,
8380
s,
8481
v: Number(v ?? 0n)
8582
},
86-
nonce: currentTime,
87-
action: {
88-
type: stepItem?.data?.sign?.value?.type,
89-
signatureChainId: `0x${stepItem?.data?.sign?.domain?.chainId?.toString(16)}`,
90-
hyperliquidChain: 'Mainnet',
91-
destination: stepItem?.data?.sign?.value?.destination?.toLowerCase(),
92-
amount: stepItem?.data?.sign?.value?.amount,
93-
time: currentTime
94-
}
83+
nonce,
84+
action
9585
})
9686
if (
9787
!res ||
@@ -107,3 +97,55 @@ export async function sendUsd(
10797
)
10898
return res.data
10999
}
100+
101+
function updateHyperliquidSignatureChainId(
102+
step: Execute['steps'][0],
103+
activeWalletChainId: number
104+
): Execute['steps'][0] {
105+
return {
106+
...step,
107+
items: step.items?.map((item) => ({
108+
...item,
109+
data: {
110+
...item.data,
111+
sign: {
112+
...item.data.sign,
113+
domain: {
114+
...item.data.sign.domain,
115+
chainId: activeWalletChainId
116+
}
117+
},
118+
...(item.data.post && {
119+
post: {
120+
...item.data.post,
121+
body: {
122+
...item.data.post.body,
123+
signatureChainId: activeWalletChainId
124+
}
125+
}
126+
})
127+
}
128+
}))
129+
}
130+
}
131+
132+
export function prepareHyperliquidSteps(
133+
steps: Execute['steps'],
134+
activeWalletChainId: number
135+
): Execute['steps'] {
136+
return steps.map((step) => {
137+
// Skip steps that have already been converted (id is set to 'sign' by prepareHyperliquidSignatureStep)
138+
if ((step.id as string) === 'hyperliquid-signature') {
139+
return step
140+
}
141+
// Update signature steps to use the active wallet chain ID
142+
if (step.kind === 'signature') {
143+
return updateHyperliquidSignatureChainId(step, activeWalletChainId)
144+
}
145+
// Convert transaction steps to Hyperliquid signature steps
146+
if (step.kind === 'transaction') {
147+
return prepareHyperliquidSignatureStep(step, activeWalletChainId)
148+
}
149+
return step
150+
})
151+
}

packages/sdk/src/utils/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ export {
1515
} from './simulateContract.js'
1616
export { safeStructuredClone } from './structuredClone.js'
1717
export { repeatUntilOk } from './repeatUntilOk.js'
18-
export { prepareHyperliquidSignatureStep } from './hyperliquid.js'
18+
export { prepareHyperliquidSteps } from './hyperliquid.js'
1919
export { isRelayApiUrl, getApiKeyHeader } from './apiKey.js'

packages/ui/src/components/widgets/SwapWidgetRenderer.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -523,8 +523,7 @@ const SwapWidgetRenderer: FC<SwapWidgetRendererProps> = ({
523523
toToken.decimals
524524
).toString(),
525525
referrer: relayClient?.source ?? undefined,
526-
useDepositAddress:
527-
!fromChainWalletVMSupported || fromToken?.chainId === 1337,
526+
useDepositAddress: !fromChainWalletVMSupported,
528527
refundTo: fromToken?.chainId === 1337 ? address : undefined,
529528
slippageTolerance: slippageTolerance,
530529
topupGas: gasTopUpEnabled && gasTopUpRequired,

0 commit comments

Comments
 (0)