|
| 1 | +--- |
| 2 | +title: Withdraw |
| 3 | +--- |
| 4 | + |
| 5 | +The `withdraw` action enables Vincent Apps to bridge USDC from a Vincent User's HyperCore perp balance back to Arbitrum using the Hyperliquid bridge. |
| 6 | + |
| 7 | +## Prerequisites |
| 8 | + |
| 9 | +Before executing the `withdraw` action, the following conditions must be met: |
| 10 | + |
| 11 | +- **Perp Balance on HyperCore**: The Vincent User Agent Wallet must have sufficient USDC in their HyperCore perp balance to cover the withdrawal amount. |
| 12 | +- **Destination Address** (optional): You can specify a destination address on Arbitrum. If not provided, the withdrawal will be sent to the Vincent User's Agent Wallet address on Arbitrum. |
| 13 | + |
| 14 | +<Info> |
| 15 | + To learn more about executing Vincent Abilities, see the [Executing |
| 16 | + Abilities](/ability/explaining-abilities) guide. |
| 17 | +</Info> |
| 18 | + |
| 19 | +## Executing the `precheck` Function |
| 20 | + |
| 21 | +The `precheck` function validates some prerequisites for executing a withdrawal, without actually performing the operation. |
| 22 | + |
| 23 | +For the `withdraw` action, the `precheck` function will validate the following: |
| 24 | + |
| 25 | +- The Vincent User Agent Wallet has a HyperCore perp account. |
| 26 | +- The withdrawal amount is at least $1 USDC (due to the withdrawal fee required by Hyperliquid). |
| 27 | +- The Vincent User Agent Wallet has sufficient USDC in their HyperCore perp balance to cover the withdrawal amount. |
| 28 | + |
| 29 | +<Tabs> |
| 30 | + <Tab title="Parameters"> |
| 31 | + The `precheck` function requires the following parameters: |
| 32 | + |
| 33 | + ```typescript |
| 34 | + import { HyperliquidAction } from '@lit-protocol/vincent-ability-hyperliquid'; |
| 35 | + |
| 36 | + { |
| 37 | + /** |
| 38 | + * The action to perform (must be HyperliquidAction.WITHDRAW) |
| 39 | + */ |
| 40 | + action: HyperliquidAction.WITHDRAW; |
| 41 | + /** |
| 42 | + * Whether to use Hyperliquid testnet (optional, defaults to false) |
| 43 | + */ |
| 44 | + useTestnet?: boolean; |
| 45 | + /** |
| 46 | + * Withdraw parameters |
| 47 | + */ |
| 48 | + withdraw: { |
| 49 | + /** |
| 50 | + * The amount of USDC to withdraw in 6-decimal format. |
| 51 | + * Example: "5000000" = 5 USDC |
| 52 | + */ |
| 53 | + amount: string; |
| 54 | + /** |
| 55 | + * The destination address on Arbitrum (optional). |
| 56 | + * If not provided, defaults to the Vincent User's Agent Wallet address. |
| 57 | + */ |
| 58 | + destination?: string; |
| 59 | + }; |
| 60 | + } |
| 61 | + ``` |
| 62 | + |
| 63 | + </Tab> |
| 64 | + |
| 65 | + <Tab title="Implementation"> |
| 66 | + To execute `precheck`, you'll need to: |
| 67 | + |
| 68 | + - Create an instance of the `VincentAbilityClient` using the `getVincentAbilityClient` function (imported from `@lit-protocol/vincent-app-sdk/abilityClient`) |
| 69 | + - Pass in the Ability's `bundledVincentAbility` object (imported from `@lit-protocol/vincent-ability-hyperliquid`) |
| 70 | + - Pass in the `ethersSigner` you'll be using to sign the request to Lit with your Delegatee private key |
| 71 | + - Use the `VincentAbilityClient` instance to call the `precheck` function |
| 72 | + |
| 73 | + ```typescript |
| 74 | + import { getVincentAbilityClient } from '@lit-protocol/vincent-app-sdk/abilityClient'; |
| 75 | + import { bundledVincentAbility, HyperliquidAction } from '@lit-protocol/vincent-ability-hyperliquid'; |
| 76 | + import { ethers } from 'ethers'; |
| 77 | + |
| 78 | + // Your delegatee signer (one of the delegatee signers for the Vincent App) |
| 79 | + const delegateeSigner = new ethers.Wallet('YOUR_DELEGATEE_PRIVATE_KEY', provider); |
| 80 | + |
| 81 | + // Create ability client |
| 82 | + const hyperliquidAbilityClient = getVincentAbilityClient({ |
| 83 | + bundledVincentAbility, |
| 84 | + ethersSigner: delegateeSigner, |
| 85 | + }); |
| 86 | + |
| 87 | + // Run precheck |
| 88 | + const precheckResult = await hyperliquidAbilityClient.precheck( |
| 89 | + { |
| 90 | + action: HyperliquidAction.WITHDRAW, |
| 91 | + useTestnet: false, // Set to true for testnet |
| 92 | + withdraw: { |
| 93 | + amount: '5000000', // 5 USDC in 6-decimal format |
| 94 | + // destination is optional, defaults to Vincent User's Agent Wallet address |
| 95 | + }, |
| 96 | + }, |
| 97 | + { |
| 98 | + delegatorPkpEthAddress: '0x...', // The Vincent User's Vincent Wallet address |
| 99 | + }, |
| 100 | + ); |
| 101 | + |
| 102 | + if (precheckResult.success) { |
| 103 | + console.log('Withdraw precheck passed, ready to execute'); |
| 104 | + } else { |
| 105 | + // Handle different types of failures |
| 106 | + if (precheckResult.runtimeError) { |
| 107 | + console.error('Runtime error:', precheckResult.runtimeError); |
| 108 | + } |
| 109 | + if (precheckResult.schemaValidationError) { |
| 110 | + console.error('Schema validation error:', precheckResult.schemaValidationError); |
| 111 | + } |
| 112 | + if (precheckResult.result) { |
| 113 | + console.error('Withdraw precheck failed:', precheckResult.result.reason); |
| 114 | + } |
| 115 | + } |
| 116 | + ``` |
| 117 | + |
| 118 | + </Tab> |
| 119 | + |
| 120 | + <Tab title="Response"> |
| 121 | + ### Success |
| 122 | + |
| 123 | + A successful `precheck` response will contain: |
| 124 | + |
| 125 | + ```typescript |
| 126 | + { |
| 127 | + /** |
| 128 | + * The action that was prechecked |
| 129 | + */ |
| 130 | + action: 'withdraw'; |
| 131 | + } |
| 132 | + ``` |
| 133 | + |
| 134 | + ### Failure |
| 135 | + |
| 136 | + A failure `precheck` response will contain: |
| 137 | + |
| 138 | + ```typescript |
| 139 | + { |
| 140 | + /** |
| 141 | + * The action that was prechecked |
| 142 | + */ |
| 143 | + action: 'withdraw'; |
| 144 | + /** |
| 145 | + * The reason the precheck failed, such as insufficient perp balance |
| 146 | + */ |
| 147 | + reason: string; |
| 148 | + /** |
| 149 | + * The available USDC balance in the Vincent User's HyperCore perp account (optional) |
| 150 | + */ |
| 151 | + availableBalance?: string; |
| 152 | + /** |
| 153 | + * The required USDC balance in the Vincent User's HyperCore perp account to cover the withdrawal amount and withdrawal fee (optional) |
| 154 | + */ |
| 155 | + requiredBalance?: string; |
| 156 | + } |
| 157 | + ``` |
| 158 | + |
| 159 | + </Tab> |
| 160 | +</Tabs> |
| 161 | + |
| 162 | +## Executing the `execute` Function |
| 163 | + |
| 164 | +The `execute` function performs the actual withdrawal by initiating a bridge transfer from the Vincent User's HyperCore perp balance to Arbitrum. |
| 165 | + |
| 166 | +For the `withdraw` action, the `execute` function will: |
| 167 | + |
| 168 | +- Initiate a withdrawal of the specified amount of USDC from the Vincent User Agent Wallet's HyperCore perp balance to the specified destination address on Arbitrum (or the Agent Wallet address if no destination is provided). |
| 169 | +- Return the withdrawal result from Hyperliquid. |
| 170 | + |
| 171 | +<Tabs> |
| 172 | + <Tab title="Parameters"> |
| 173 | + The `execute` function requires the following parameters: |
| 174 | + |
| 175 | + ```typescript |
| 176 | + import { HyperliquidAction } from '@lit-protocol/vincent-ability-hyperliquid'; |
| 177 | + |
| 178 | + { |
| 179 | + /** |
| 180 | + * The action to perform (must be HyperliquidAction.WITHDRAW) |
| 181 | + */ |
| 182 | + action: HyperliquidAction.WITHDRAW; |
| 183 | + /** |
| 184 | + * Whether to use Hyperliquid testnet (optional, defaults to false) |
| 185 | + */ |
| 186 | + useTestnet?: boolean; |
| 187 | + /** |
| 188 | + * Withdraw parameters |
| 189 | + */ |
| 190 | + withdraw: { |
| 191 | + /** |
| 192 | + * The amount of USDC to withdraw in 6-decimal format. |
| 193 | + * Example: "5000000" = 5 USDC |
| 194 | + */ |
| 195 | + amount: string; |
| 196 | + /** |
| 197 | + * The destination address on Arbitrum (optional). |
| 198 | + * If not provided, defaults to the Vincent User's Agent Wallet address. |
| 199 | + */ |
| 200 | + destination?: string; |
| 201 | + }; |
| 202 | + } |
| 203 | + ``` |
| 204 | + |
| 205 | + </Tab> |
| 206 | + |
| 207 | + <Tab title="Implementation"> |
| 208 | + The `execute` function can be executed using the same `VincentAbilityClient` instance as used for the `precheck` function: |
| 209 | + |
| 210 | + ```typescript |
| 211 | + const executeResult = await hyperliquidAbilityClient.execute( |
| 212 | + { |
| 213 | + action: HyperliquidAction.WITHDRAW, |
| 214 | + useTestnet: false, // Set to true for testnet |
| 215 | + withdraw: { |
| 216 | + amount: '5000000', // 5 USDC in 6-decimal format |
| 217 | + destination: '0x...', // Optional: specify destination address on Arbitrum |
| 218 | + }, |
| 219 | + }, |
| 220 | + { |
| 221 | + delegatorPkpEthAddress: '0x...', // The Vincent User's Vincent Wallet address |
| 222 | + }, |
| 223 | + ); |
| 224 | + |
| 225 | + if (executeResult.success) { |
| 226 | + const { withdrawResult } = executeResult.result; |
| 227 | + console.log('Withdrawal initiated:', withdrawResult); |
| 228 | + } else { |
| 229 | + // Handle different types of failures |
| 230 | + if (executeResult.runtimeError) { |
| 231 | + console.error('Runtime error:', executeResult.runtimeError); |
| 232 | + } |
| 233 | + if (executeResult.schemaValidationError) { |
| 234 | + console.error('Schema validation error:', executeResult.schemaValidationError); |
| 235 | + } |
| 236 | + if (executeResult.result) { |
| 237 | + console.error('Withdraw execution failed:', executeResult.result.reason); |
| 238 | + } |
| 239 | + } |
| 240 | + ``` |
| 241 | + |
| 242 | + </Tab> |
| 243 | + |
| 244 | + <Tab title="Response"> |
| 245 | + **Success Response** |
| 246 | + |
| 247 | + A successful `execute` response will contain: |
| 248 | + |
| 249 | + ```typescript |
| 250 | + { |
| 251 | + /** |
| 252 | + * The action that was executed |
| 253 | + */ |
| 254 | + action: 'withdraw'; |
| 255 | + /** |
| 256 | + * The withdrawal result from Hyperliquid request as defined by the Hyperliquid SDK: @nktkas/hyperliquid |
| 257 | + * https://github.com/nktkas/hyperliquid/blob/2233ce942eb50ef8850073b387b9918d3a54a10b/src/api/exchange/_base/_schemas.ts#L49-L73 |
| 258 | + */ |
| 259 | + withdrawResult: SuccessResponse; |
| 260 | + } |
| 261 | + ``` |
| 262 | + |
| 263 | + **Failure Response** |
| 264 | + |
| 265 | + A failure `execute` response will contain: |
| 266 | + |
| 267 | + ```typescript |
| 268 | + { |
| 269 | + /** |
| 270 | + * The action that was executed |
| 271 | + */ |
| 272 | + action: 'withdraw'; |
| 273 | + /** |
| 274 | + * The reason the execution failed, such as insufficient perp balance |
| 275 | + */ |
| 276 | + reason: string; |
| 277 | + } |
| 278 | + ``` |
| 279 | + |
| 280 | + </Tab> |
| 281 | +</Tabs> |
| 282 | + |
| 283 | +## Important Considerations |
| 284 | + |
| 285 | +<AccordionGroup> |
| 286 | + <Accordion title="Withdrawal Processing Time" icon="clock"> |
| 287 | + After successfully executing a withdrawal, it takes some time for the funds to appear on Arbitrum. The withdrawal must be processed by Hyperliquid's bridge before the USDC becomes available on Arbitrum. |
| 288 | + </Accordion> |
| 289 | + |
| 290 | +<Accordion title="USDC Decimal Format" icon="hashtag"> |
| 291 | + USDC uses **6 decimals**. When specifying the withdrawal amount, use the 6-decimal format: |
| 292 | + |
| 293 | +- 5 USDC = `"5000000"` |
| 294 | +- 15 USDC = `"15000000"` |
| 295 | +- 100 USDC = `"100000000"` |
| 296 | + |
| 297 | +</Accordion> |
| 298 | + |
| 299 | +<Accordion title="Withdrawal Source" icon="wallet"> |
| 300 | + Withdrawals are always taken from the Vincent User's **HyperCore perp balance**. If you need to |
| 301 | + withdraw funds from the spot balance, you must first transfer them to the perp balance using the |
| 302 | + [Transfer to Perp](/ability/official-abilities/hyperliquid/transfer-to-perp) action. |
| 303 | +</Accordion> |
| 304 | + |
| 305 | +<Accordion title="Destination Address" icon="location-dot"> |
| 306 | + If you don't specify a `destination` address, the withdrawal will be sent to the Vincent User's |
| 307 | + Agent Wallet address on Arbitrum. You can optionally specify a different destination address if |
| 308 | + needed. |
| 309 | +</Accordion> |
| 310 | + |
| 311 | + <Accordion title="Verifying Withdrawal Success" icon="check"> |
| 312 | + After the withdrawal is initiated, you can verify the perp balance decreased by checking the clearinghouse state using a [Hyperliquid SDK](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api), or by using the [Hyperliquid API](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-a-users-perpetuals-account-summary). |
| 313 | + </Accordion> |
| 314 | +</AccordionGroup> |
| 315 | + |
| 316 | +## Reference Implementation |
| 317 | + |
| 318 | +For a complete working example showing the full withdrawal workflow including balance verification, see the [withdraw.spec.ts](https://github.com/LIT-Protocol/Vincent/blob/main/packages/apps/ability-hyperliquid/test/e2e/withdraw.spec.ts) end-to-end test in the `ability-hyperliquid` package. |
| 319 | + |
| 320 | +## Next Steps |
| 321 | + |
| 322 | +Explore the rest of the supported Hyperliquid actions: |
| 323 | + |
| 324 | +<CardGroup cols={3}> |
| 325 | + |
| 326 | +<Card title="Deposit" href="/ability/official-abilities/hyperliquid/deposit" icon="arrow-down" /> |
| 327 | + |
| 328 | +<Card |
| 329 | + title="Send Spot Asset" |
| 330 | + href="/ability/official-abilities/hyperliquid/send-spot-asset" |
| 331 | + icon="coins" |
| 332 | +/> |
| 333 | + |
| 334 | +<Card |
| 335 | + title="Send Perp USDC" |
| 336 | + href="/ability/official-abilities/hyperliquid/send-perp-usdc" |
| 337 | + icon="dollar-sign" |
| 338 | +/> |
| 339 | + |
| 340 | +<Card |
| 341 | + title="Transfer to Spot" |
| 342 | + href="/ability/official-abilities/hyperliquid/transfer-to-spot" |
| 343 | + icon="arrow-right" |
| 344 | +/> |
| 345 | + |
| 346 | +<Card |
| 347 | + title="Transfer to Perp" |
| 348 | + href="/ability/official-abilities/hyperliquid/transfer-to-perp" |
| 349 | + icon="arrow-left" |
| 350 | +/> |
| 351 | + |
| 352 | +<Card |
| 353 | + title="Spot Buy" |
| 354 | + href="/ability/official-abilities/hyperliquid/spot-buy" |
| 355 | + icon="shopping-cart" |
| 356 | +/> |
| 357 | + |
| 358 | +<Card title="Spot Sell" href="/ability/official-abilities/hyperliquid/spot-sell" icon="tag" /> |
| 359 | + |
| 360 | +<Card |
| 361 | + title="Perp Long" |
| 362 | + href="/ability/official-abilities/hyperliquid/perp-long" |
| 363 | + icon="arrow-up-right" |
| 364 | +/> |
| 365 | + |
| 366 | +<Card |
| 367 | + title="Perp Short" |
| 368 | + href="/ability/official-abilities/hyperliquid/perp-short" |
| 369 | + icon="arrow-down-right" |
| 370 | +/> |
| 371 | + |
| 372 | +<Card title="Cancel Order" href="/ability/official-abilities/hyperliquid/cancel-order" icon="ban" /> |
| 373 | + |
| 374 | +<Card |
| 375 | + title="Cancel All Orders" |
| 376 | + href="/ability/official-abilities/hyperliquid/cancel-all-orders-for-symbol" |
| 377 | + icon="trash" |
| 378 | +/> |
| 379 | + |
| 380 | +</CardGroup> |
0 commit comments