@defuse-protocol/intents-sdk 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,214 +1,306 @@
1
1
  # @defuse-protocol/intents-sdk
2
2
 
3
- The Intents SDK for Near Intents provides a set of tools for interacting with various bridge implementations. It simplifies the process of transferring assets from Near Intents to different blockchains.
3
+ A comprehensive SDK for Near Intents protocol. This SDK provides tools for intent execution, deposits, withdrawals, and
4
+ interacting with various bridge implementations across multiple blockchains.
5
+
6
+ ## Table of Contents
7
+
8
+ - [Installation](#installation)
9
+ - [Features](#features)
10
+ - [Quick Start](#quick-start)
11
+ - [Core Functionalities](#core-functionalities)
12
+ - [Core Concepts](#core-concepts)
13
+ - [Intent Execution](#intent-execution)
14
+ - [Deposits](#deposits)
15
+ - [Withdrawals](#withdrawals)
16
+ - [Routes and Bridges](#routes-and-bridges)
17
+ - [Route Types](#route-types)
18
+ - [Fee Estimation](#fee-estimation)
19
+ - [Advanced Usage](#advanced-usage)
20
+ - [Custom RPC URLs](#custom-rpc-urls)
21
+ - [Other Intent Signers](#other-intent-signers)
22
+ - [Intent Publishing Hooks](#intent-publishing-hooks)
23
+ - [Batch Withdrawals](#batch-withdrawals)
24
+ - [Intent Management](#intent-management)
25
+ - [Configure Withdrawal Routes](#configure-withdrawal-routes)
26
+ - [Asset Information Parsing](#asset-information-parsing)
27
+ - [Waiting for Completion](#waiting-for-completion)
28
+ - [Error Handling](#error-handling)
29
+ - [Supported Networks](#supported-networks)
30
+ - [Development](#development)
4
31
 
5
- ## Features
6
-
7
- - Bridging from Near Intents:
8
- - Support for multiple bridge implementations (Hot, PoA)
9
- - Single and batch withdrawal operations
10
- - Automatic fee estimation
11
- - Built-in validation for withdrawal constraints:
12
- - PoA Bridge minimum withdrawal amounts
13
- - Hot Bridge Stellar trustline validation
14
- - Transfers within Near Intents
15
- - Transfers to NEAR blockchain
16
- - Transfers to Virtual Chains (e.g. Aurora)
17
-
18
-
19
-
20
- Note: Bridging to Near Intents is not supported yet.
21
-
22
32
  ## Installation
23
33
 
24
34
  ```bash
25
35
  npm install @defuse-protocol/intents-sdk --save-exact
26
36
  ```
27
37
 
38
+ ## Features
39
+
40
+ | Feature | Status | Description |
41
+ |------------------|:------:|------------------------------------------------------------------------|
42
+ | Intent Execution | ✅ | Sign, submit, and track intent execution on Near Intents |
43
+ | Deposits | ❌ | Deposit funds to Near Intents (use bridge interfaces directly) |
44
+ | Withdrawals | ✅ | Complete withdrawal functionality from Near Intents to external chains |
45
+
28
46
  ## Quick Start
29
47
 
48
+ ### Basic Setup
49
+
50
+ First, initialize the SDK with your referral code and intent signer:
51
+
30
52
  ```typescript
31
- import { IntentsSDK, createIntentSignerNearKeyPair } from '@defuse-protocol/intents-sdk';
32
- import { KeyPair } from 'near-api-js';
53
+ import {IntentsSDK, createIntentSignerNearKeyPair} from '@defuse-protocol/intents-sdk';
54
+ import {KeyPair} from 'near-api-js';
33
55
 
34
- // Initialize the SDK with required configuration
56
+ // Initialize the SDK
35
57
  const sdk = new IntentsSDK({
36
58
  referral: 'your-referral-code', // Only referral is required
59
+ intentSigner: createIntentSignerNearKeyPair({
60
+ keypair: KeyPair.fromString('your-private-key'),
61
+ accountId: 'your-account.near'
62
+ })
37
63
  });
64
+ ```
38
65
 
39
- // Set up intent signer (for NEAR)
40
- const keypair = KeyPair.fromString('your-private-key');
41
- const signer = createIntentSignerNearKeyPair({
42
- keypair: keypair,
43
- accountId: 'your-account.near'
44
- });
45
- sdk.setIntentSigner(signer);
66
+ ### Most Common Use Case: Withdrawals
67
+
68
+ For most users, the primary use case is withdrawing funds from Near Intents to external chains. Use the high-level
69
+ `processWithdrawal` method:
46
70
 
47
- // Method 1: Complete end-to-end withdrawal (orchestrated)
71
+ ```typescript
72
+ // Complete end-to-end withdrawal (recommended)
48
73
  const result = await sdk.processWithdrawal({
49
- withdrawalParams: {
50
- assetId: 'nep141:usdt.tether-token.near', // Asset identifier
51
- amount: 1000000n, // Amount in smallest unit
52
- destinationAddress: '0x742d35Cc6634C0532925a3b8D84B2021F90a51A3',
53
- feeInclusive: false, // Whether amount includes fees
54
- // routeConfig is optional - will be auto-detected from assetId
55
- }
74
+ withdrawalParams: {
75
+ assetId: 'nep141:usdt.tether-token.near', // USDT token on NEAR
76
+ amount: 1000000n, // 1 USDT (in smallest units - 6 decimals)
77
+ destinationAddress: '0x742d35Cc6634C0532925a3b8D84B2021F90a51A3', // Ethereum address
78
+ feeInclusive: false, // Amount excludes withdrawal fees
79
+ }
56
80
  });
57
81
 
58
82
  console.log('Intent hash:', result.intentHash);
59
- console.log('Destination tx:', result.destinationTx);
83
+ console.log('Destination transaction:', result.destinationTx);
84
+ ```
60
85
 
61
- // Method 2: Granular control with individual methods
62
- const feeEstimation = await sdk.estimateWithdrawalFee({
63
- withdrawalParams: {
64
- assetId: 'nep141:usdt.tether-token.near',
65
- amount: 1000000n,
66
- destinationAddress: '0x742d35Cc6634C0532925a3b8D84B2021F90a51A3',
67
- feeInclusive: false
68
- }
69
- });
86
+ ### Advanced Use Case: Custom Intents
70
87
 
71
- const { intentHash } = await sdk.signAndSendWithdrawalIntent({
72
- withdrawalParams: {
73
- assetId: 'nep141:usdt.tether-token.near',
74
- amount: 1000000n,
75
- destinationAddress: '0x742d35Cc6634C0532925a3b8D84B2021F90a51A3',
76
- feeInclusive: false
77
- },
78
- feeEstimation
79
- });
88
+ For advanced users who need custom intent logic beyond withdrawals, use the lower-level `signAndSendIntent` method:
80
89
 
81
- const intentTx = await sdk.waitForIntentSettlement({ intentHash });
82
- const destinationTx = await sdk.waitForWithdrawalCompletion({
83
- withdrawalParams: {
84
- assetId: 'nep141:usdt.tether-token.near',
85
- amount: 1000000n,
86
- destinationAddress: '0x742d35Cc6634C0532925a3b8D84B2021F90a51A3',
87
- feeInclusive: false
88
- },
89
- intentTx
90
+ ```typescript
91
+ // Custom intent execution (advanced)
92
+ const result = await sdk.signAndSendIntent({
93
+ intents: [
94
+ {
95
+ intent: "transfer", // Custom intent type
96
+ receiver_id: "recipient.near",
97
+ tokens: {"usdt.tether-token.near": "1000000"}, // 1 USDT
98
+ },
99
+ ],
90
100
  });
101
+
102
+ console.log('Intent hash:', result.intentHash);
91
103
  ```
92
104
 
93
- ## Core Concepts
105
+ > **💡 Tip**: Use `processWithdrawal` for withdrawals and `signAndSendIntent` for custom intent logic. The withdrawal
106
+ > method handles fee estimation, validation, and completion tracking automatically.
94
107
 
95
- ### Route and Bridge Enums
108
+ ## Core Functionalities
96
109
 
97
- The SDK uses two key concepts to organize withdrawal operations:
110
+ ### Core Concepts
98
111
 
99
- #### Routes
100
- Routes define the **path** a withdrawal takes - the specific mechanism and destination for transferring assets. Each route represents a different withdrawal flow:
112
+ #### Intent
101
113
 
102
- ```typescript
103
- import { RouteEnum } from '@defuse-protocol/intents-sdk';
114
+ TBD
104
115
 
105
- console.log(RouteEnum.HotBridge); // "hot_bridge" - Cross-chain via HOT protocol
106
- console.log(RouteEnum.PoaBridge); // "poa_bridge" - Cross-chain via PoA bridge
107
- console.log(RouteEnum.NearWithdrawal); // "near_withdrawal" - Direct to NEAR blockchain
108
- console.log(RouteEnum.VirtualChain); // "virtual_chain" - To Aurora Engine chains
109
- console.log(RouteEnum.InternalTransfer); // "internal_transfer" - Between protocol users
110
- ```
116
+ #### Intent Signers
111
117
 
112
- #### Bridge Names
113
- Bridge names identify the **underlying bridge infrastructure** that handles the cross-chain transfer. This determines which external protocol processes the withdrawal:
118
+ Intent signers are required to authenticate and sign both regular and withdrawal intents. The SDK supports
119
+ multiple signing methods:
114
120
 
115
- ```typescript
116
- import { BridgeNameEnum } from '@defuse-protocol/intents-sdk';
121
+ | Singing Standard | Methods | Description |
122
+ |------------------|:------------------------------------------------------------------:|----------------------------------------------------------|
123
+ | nep413 | `createIntentSignerNEP413()`<br/>`createIntentSignerNearKeyPair()` | Almost all NEAR wallets support this standard |
124
+ | erc191 | `createIntentSignerViem()` | Only Viem library supported, Ethers.js signer is coming |
125
+ | raw_ed25519 | ❌ | Available on the protocol level, but not included to SDK |
126
+ | webauthn | ❌ | Available on the protocol level, but not included to SDK |
127
+ | ton_connect | ❌ | Available on the protocol level, but not included to SDK |
117
128
 
118
- console.log(BridgeNameEnum.Hot); // "hot" - HOT Labs bridge infrastructure
119
- console.log(BridgeNameEnum.Poa); // "poa" - Proof-of-Authority bridge by Defuse Labs
120
- console.log(BridgeNameEnum.None); // null - No external bridge (NEAR-native or internal)
121
- ```
129
+ You must set an intent signer before processing withdrawals:
122
130
 
123
- **Key Difference**:
124
- - **Route** = "How and where" the withdrawal goes (the path)
125
- - **Bridge Name** = "Who operates" the underlying infrastructure (the bridge provider)
131
+ ```typescript
132
+ // Example: Set up a NEAR KeyPair signer
133
+ const signer = createIntentSignerNearKeyPair({
134
+ keypair: KeyPair.fromString('your-private-key'),
135
+ accountId: 'your-account.near'
136
+ });
137
+ sdk.setIntentSigner(signer);
138
+ ```
126
139
 
127
- For example, both `hot_bridge` and `poa_bridge` routes perform cross-chain transfers, but use different bridge infrastructures (`hot` vs `poa`) with different fee structures and supported networks.
140
+ See the [Intent Signers](#intent-signers-1) section below for detailed implementation examples.
128
141
 
129
- ### Asset Identifiers
142
+ #### Asset Identifiers
130
143
 
131
144
  The SDK uses standardized asset identifiers in the format:
145
+
132
146
  - `nep141:contract.near` - NEP-141 tokens
133
147
  - `nep245:contract.near:tokenId` - NEP-245 multi-tokens
134
148
 
135
- Asset Identifier uniquely determines the corresponding route and destination chain.
149
+ Asset Identifier uniquely determines the corresponding withdrawal route and destination chain.
136
150
 
137
151
  Examples:
152
+
138
153
  - `nep141:usdt.tether-token.near` - USDT on NEAR
139
154
  - `nep141:wrap.near` - Wrapped NEAR (native NEAR)
140
155
  - `nep245:v2_1.omni.hot.tg:137_qiStmoQJDQPTebaPjgx5VBxZv6L` - Polygon USDC through Hot
141
156
  - `nep141:base-0x833589fcd6edb6e08f4c7c32d4f71b54bda02913.omft.near` - Base USDC through PoA
142
157
 
143
- ### Intent Signers
158
+ ### Intent Execution
144
159
 
145
- Intent signers are required to authenticate and sign withdrawal operations. The SDK supports multiple signing methods:
160
+ The primary functionality of the SDK - execute custom intents on Near Intents:
146
161
 
147
- - **NEAR KeyPair Signer** - Use NEAR account private keys for signing
148
- - **NEP-413 Signer** - Custom message signing implementation
149
- - **EVM/Viem Signer** - Use Ethereum-compatible wallets and accounts
162
+ - **Sign Intents**: Create and sign intent payloads with various signer types
163
+ - **Submit Intents**: Publish intents to the Near Intents relayer network
164
+ - **Track Status**: Monitor intent settlement and execution status
165
+ - **Batch Intents**: Execute multiple intents in a single transaction
166
+ - **Custom Logic**: Support for any intent type supported by the protocol
150
167
 
151
- You must set an intent signer before processing withdrawals:
168
+ ```typescript
169
+ // Generic intent execution
170
+ const {intentHash} = await sdk.signAndSendIntent({
171
+ intents: [/* array of intent primitives */],
172
+ onBeforePublishIntent: async (data) => {
173
+ console.log('About to publish intent:', data.intentHash);
174
+ }
175
+ });
176
+
177
+ // Monitor settlement
178
+ const intentTx = await sdk.waitForIntentSettlement({intentHash});
179
+ ```
180
+
181
+ ### Deposits
182
+
183
+ Deposit funds into Near Intents *(Coming Soon)*.
184
+
185
+ > **Note**: Deposit functionality is not yet implemented in this SDK. Currently, use bridge interfaces directly for
186
+ > deposit operations.
187
+
188
+ ### Withdrawals
189
+
190
+ Complete withdrawal functionality from Near Intents to external chains:
191
+
192
+ - **Cross-Chain Transfers**: Withdraw to 20+ supported blockchains
193
+ - **Multi-Bridge Support**: Hot Bridge, PoA Bridge
194
+ - **Batch Processing**: Process multiple withdrawals at a time
195
+ - **Fee Management**: Automatic fee estimation with quote support
196
+ - **Validation**: Built-in validation for withdrawal constraints
197
+ - **Status Tracking**: End-to-end monitoring from intent to destination
152
198
 
153
199
  ```typescript
154
- // Example: Set up a NEAR KeyPair signer
155
- const signer = createIntentSignerNearKeyPair({
156
- keypair: KeyPair.fromString('your-private-key'),
157
- accountId: 'your-account.near'
200
+ // Complete withdrawal process
201
+ const result = await sdk.processWithdrawal({
202
+ withdrawalParams: {
203
+ assetId: 'nep141:usdt.tether-token.near',
204
+ amount: 1000000n,
205
+ destinationAddress: '0x742d35Cc6634C0532925a3b8D84B2021F90a51A3',
206
+ feeInclusive: false
207
+ }
158
208
  });
159
- sdk.setIntentSigner(signer);
160
209
  ```
161
210
 
162
- See the [Intent Signers](#intent-signers-1) section below for detailed implementation examples.
211
+ #### Routes and Bridges
212
+
213
+ The SDK uses two key concepts to organize withdrawal operations:
214
+
215
+ ##### Routes
216
+
217
+ Routes define the **path** a withdrawal takes - the specific mechanism and destination for transferring assets. Each
218
+ route represents a different withdrawal flow:
219
+
220
+ ```typescript
221
+ import {RouteEnum} from '@defuse-protocol/intents-sdk';
222
+
223
+ console.log(RouteEnum.HotBridge); // "hot_bridge" - Cross-chain via HOT protocol
224
+ console.log(RouteEnum.PoaBridge); // "poa_bridge" - Cross-chain via PoA bridge
225
+ console.log(RouteEnum.NearWithdrawal); // "near_withdrawal" - Direct to NEAR blockchain
226
+ console.log(RouteEnum.VirtualChain); // "virtual_chain" - To Aurora Engine chains
227
+ console.log(RouteEnum.InternalTransfer); // "internal_transfer" - Between protocol users
228
+ ```
229
+
230
+ ##### Bridge Names
231
+
232
+ Bridge names identify the **underlying bridge infrastructure** that handles the cross-chain transfer. This determines
233
+ which external protocol processes the withdrawal:
234
+
235
+ ```typescript
236
+ import {BridgeNameEnum} from '@defuse-protocol/intents-sdk';
237
+
238
+ console.log(BridgeNameEnum.Hot); // "hot" - HOT Labs bridge infrastructure
239
+ console.log(BridgeNameEnum.Poa); // "poa" - Proof-of-Authority bridge by Defuse Labs
240
+ console.log(BridgeNameEnum.None); // null - No external bridge (NEAR-native or internal)
241
+ ```
163
242
 
164
- ## Route Types
243
+ **Key Difference**:
244
+
245
+ - **Route** = "How and where" the withdrawal goes (the path)
246
+ - **Bridge Name** = "Who operates" the underlying infrastructure (the bridge provider)
247
+
248
+ For example, both `hot_bridge` and `poa_bridge` routes perform cross-chain transfers, but use different bridge
249
+ infrastructures (`hot` vs `poa`) with different fee structures and supported networks.
250
+
251
+ #### Route Types
165
252
 
166
253
  The SDK automatically detects and supports multiple route types based on asset identifiers:
167
254
 
168
- ### Hot Bridge Route
255
+ ##### Hot Bridge Route
256
+
169
257
  - **Purpose**: Cross-chain transfers via HOT Labs infrastructure
170
258
  - **Supported Assets**: Multi-tokens (NEP-245) from Hot protocol (contract `v2_1.omni.hot.tg`)
171
259
  - **Use Case**: Cross-chain transfers for assets bridged through Hot protocol
172
260
  - **Route Type**: `hot_bridge`
173
261
 
174
- ### PoA Bridge Route
262
+ ##### PoA Bridge Route
263
+
175
264
  - **Purpose**: Proof-of-Authority bridge transfers operated by Defuse Labs
176
265
  - **Supported Assets**: Fungible tokens (NEP-141) ending with `.omft.near`
177
266
  - **Use Case**: Cross-chain transfers for assets bridged through PoA protocol
178
267
  - **Route Type**: `poa_bridge`
179
268
 
180
- ### Internal Transfer Route
269
+ ##### Internal Transfer Route
270
+
181
271
  - **Purpose**: Transfer between Near Intents users within the protocol
182
272
  - **Supported Assets**: All NEP-141 and NEP-245 tokens
183
273
  - **Use Case**: User A having funds in the protocol wants to transfer to User B
184
274
  - **Route Type**: `internal_transfer`
185
275
 
186
- ### Near Withdrawal Route
276
+ ##### Near Withdrawal Route
277
+
187
278
  - **Purpose**: Transfers within the NEAR blockchain
188
279
  - **Supported Assets**: NEP-141 tokens on NEAR, including native NEAR (wrap.near)
189
280
  - **Use Case**: Same-chain transfers on NEAR
190
281
  - **Route Type**: `near_withdrawal`
191
282
 
192
- ### Virtual Chain Route
283
+ ##### Virtual Chain Route
284
+
193
285
  - **Purpose**: Transfers to Aurora Engine-powered chains (aka Virtual chains)
194
286
  - **Supported Assets**: NEP-141 tokens with Aurora Engine integration
195
287
  - **Use Case**: Near Intents to Aurora ecosystem transfers
196
288
  - **Route Type**: `virtual_chain`
197
289
  - **Note**: Requires explicit `routeConfig` with `auroraEngineContractId`
198
290
 
199
- ### Fee Estimation
291
+ #### Fee Estimation
200
292
 
201
293
  The SDK now supports both single and batch fee estimation:
202
294
 
203
295
  ```typescript
204
296
  // Single withdrawal fee estimation
205
297
  const feeEstimation = await sdk.estimateWithdrawalFee({
206
- withdrawalParams: {
207
- assetId: 'nep141:usdt.tether-token.near',
208
- amount: 1000000n,
209
- destinationAddress: '0x742d35Cc6634C0532925a3b8D84B2021F90a51A3',
210
- feeInclusive: false
211
- }
298
+ withdrawalParams: {
299
+ assetId: 'nep141:usdt.tether-token.near',
300
+ amount: 1000000n,
301
+ destinationAddress: '0x742d35Cc6634C0532925a3b8D84B2021F90a51A3',
302
+ feeInclusive: false
303
+ }
212
304
  });
213
305
 
214
306
  console.log('Fee amount:', feeEstimation.amount);
@@ -216,61 +308,83 @@ console.log('Quote info:', feeEstimation.quote); // null if fee paid with withdr
216
308
 
217
309
  // Batch fee estimation
218
310
  const batchFees = await sdk.estimateWithdrawalFee({
219
- withdrawalParams: [
220
- {
221
- assetId: 'nep141:usdt.tether-token.near',
222
- amount: 1000000n,
223
- destinationAddress: '0x742d35Cc...',
224
- feeInclusive: false
225
- },
226
- {
227
- assetId: 'nep245:v2_1.omni.hot.tg:137_qiStmoQJDQPTebaPjgx5VBxZv6L',
228
- amount: 500000n,
229
- destinationAddress: '0x742d35Cc...',
230
- feeInclusive: false
231
- }
232
- ]
311
+ withdrawalParams: [
312
+ {
313
+ assetId: 'nep141:usdt.tether-token.near',
314
+ amount: 1000000n,
315
+ destinationAddress: '0x742d35Cc...',
316
+ feeInclusive: false
317
+ },
318
+ {
319
+ assetId: 'nep245:v2_1.omni.hot.tg:137_qiStmoQJDQPTebaPjgx5VBxZv6L',
320
+ amount: 500000n,
321
+ destinationAddress: '0x742d35Cc...',
322
+ feeInclusive: false
323
+ }
324
+ ]
233
325
  });
234
326
 
235
327
  console.log('Batch fees:', batchFees); // Array of FeeEstimation objects
236
328
  ```
237
329
 
238
- ### Intent Signers
330
+ ## Advanced Usage
331
+
332
+ ### Custom RPC URLs
333
+
334
+ Set NEAR and EVM chains RPC URLs in the constructor:
335
+
336
+ ```typescript
337
+ import {Chains} from '@defuse-protocol/intents-sdk'
338
+
339
+ const sdk = new IntentsSDK({
340
+ ...,
341
+ rpc: {
342
+ [Chains.Near]: ['https://rpc.mainnet.near.org'],
343
+ [Chains.Polygon]: ['https://polygon-rpc.com'],
344
+ [Chains.BNB]: ['https://bsc-dataseed.binance.org'],
345
+ }
346
+ });
347
+ ```
348
+
349
+ ### Other Intent Signers
239
350
 
240
351
  The SDK supports multiple intent signing methods using factory functions:
241
352
 
242
353
  #### NEAR KeyPair Signer
354
+
243
355
  ```typescript
244
- import { createIntentSignerNearKeyPair, IntentsSDK } from '@defuse-protocol/intents-sdk';
245
- import { KeyPair } from 'near-api-js';
356
+ import {createIntentSignerNearKeyPair, IntentsSDK} from '@defuse-protocol/intents-sdk';
357
+ import {KeyPair} from 'near-api-js';
246
358
 
247
359
  const keyPair = KeyPair.fromString('your-private-key');
248
360
  const signer = createIntentSignerNearKeyPair({
249
- keypair: keyPair,
250
- accountId: 'your-account.near'
361
+ keypair: keyPair,
362
+ accountId: 'your-account.near'
251
363
  });
252
364
  ```
253
365
 
254
366
  #### NEP-413 Signer
367
+
255
368
  ```typescript
256
- import { createIntentSignerNEP413 } from '@defuse-protocol/intents-sdk';
369
+ import {createIntentSignerNEP413} from '@defuse-protocol/intents-sdk';
257
370
 
258
371
  const signer = createIntentSignerNEP413({
259
- signMessage: async (nep413Payload, nep413Hash) => {
260
- // Implement your custom signing logic here
261
- return {
262
- publicKey: 'ed25519:YourPublicKey',
263
- signature: 'base64-encoded-signature'
264
- };
265
- },
266
- accountId: 'your-account.near'
372
+ signMessage: async (nep413Payload, nep413Hash) => {
373
+ // Implement your custom signing logic here
374
+ return {
375
+ publicKey: 'ed25519:YourPublicKey',
376
+ signature: 'base64-encoded-signature'
377
+ };
378
+ },
379
+ accountId: 'your-account.near'
267
380
  });
268
381
  ```
269
382
 
270
383
  #### EVM/Viem Signer
384
+
271
385
  ```typescript
272
- import { createIntentSignerViem } from '@defuse-protocol/intents-sdk';
273
- import { privateKeyToAccount } from 'viem/accounts';
386
+ import {createIntentSignerViem} from '@defuse-protocol/intents-sdk';
387
+ import {privateKeyToAccount} from 'viem/accounts';
274
388
 
275
389
  const account = privateKeyToAccount('0x...');
276
390
  const signer = createIntentSignerViem(account);
@@ -279,79 +393,63 @@ const signer = createIntentSignerViem(account);
279
393
  sdk.setIntentSigner(signer);
280
394
  ```
281
395
 
282
- ## Advanced Usage
283
-
284
- ### Custom RPC URLs
285
-
286
- Set NEAR and EVM chains RPC URLs in the constructor:
287
-
288
- ```typescript
289
- import { Chains } from '@defuse-protocol/intents-sdk'
290
-
291
- const sdk = new IntentsSDK({
292
- ...,
293
- rpc: {
294
- [Chains.Near]: ['https://rpc.mainnet.near.org'],
295
- [Chains.Polygon]: ['https://polygon-rpc.com'],
296
- [Chains.BNB]: ['https://bsc-dataseed.binance.org'],
297
- }
298
- });
299
- ```
300
-
301
396
  ### Intent Publishing Hooks
302
397
 
303
- Use the `onBeforePublishIntent` hook to intercept and process intent data before it's published to the relayer. This is useful for persistence, logging, analytics, or custom processing:
398
+ Use the `onBeforePublishIntent` hook to intercept and process intent data before it's published to the relayer. This is
399
+ useful for persistence, logging, analytics, or custom processing:
304
400
 
305
401
  ```typescript
306
- import { type OnBeforePublishIntentHook } from '@defuse-protocol/intents-sdk';
402
+ import {type OnBeforePublishIntentHook} from '@defuse-protocol/intents-sdk';
307
403
 
308
404
  // Define your hook function
309
405
  const onBeforePublishIntent: OnBeforePublishIntentHook = async (intentData) => {
310
- // Save to database for tracking
311
- await saveIntentToDatabase({
312
- hash: intentData.intentHash,
313
- payload: intentData.intentPayload,
314
- timestamp: new Date(),
315
- });
316
-
317
- // Send analytics
318
- analytics.track('intent_about_to_publish', {
319
- intentHash: intentData.intentHash,
320
- intentType: intentData.intentPayload.intents[0]?.intent,
321
- });
406
+ // Save to database for tracking
407
+ await saveIntentToDatabase({
408
+ hash: intentData.intentHash,
409
+ payload: intentData.intentPayload,
410
+ timestamp: new Date(),
411
+ });
412
+
413
+ // Send analytics
414
+ analytics.track('intent_about_to_publish', {
415
+ intentHash: intentData.intentHash,
416
+ intentType: intentData.intentPayload.intents[0]?.intent,
417
+ });
322
418
  };
323
419
 
324
420
  // Use the hook with the functional API
325
421
  const result = await sdk.processWithdrawal({
326
- withdrawalParams: { /* ... */ },
327
- intent: {
328
- onBeforePublishIntent, // Add the hook here
329
- }
422
+ withdrawalParams: { /* ... */},
423
+ intent: {
424
+ onBeforePublishIntent, // Add the hook here
425
+ }
330
426
  });
331
427
 
332
428
  // Or with granular control
333
- const { intentHash } = await sdk.signAndSendWithdrawalIntent({
334
- withdrawalParams: { /* ... */ },
335
- feeEstimation: fee,
336
- intent: {
337
- onBeforePublishIntent, // Add the hook here
338
- }
429
+ const {intentHash} = await sdk.signAndSendWithdrawalIntent({
430
+ withdrawalParams: { /* ... */},
431
+ feeEstimation: fee,
432
+ intent: {
433
+ onBeforePublishIntent, // Add the hook here
434
+ }
339
435
  });
340
436
 
341
437
  // Or with generic intent publishing
342
- const { intentHash } = await sdk.signAndSendIntent({
343
- intents: [/* ... */],
344
- onBeforePublishIntent, // Add the hook here
438
+ const {intentHash} = await sdk.signAndSendIntent({
439
+ intents: [/* ... */],
440
+ onBeforePublishIntent, // Add the hook here
345
441
  });
346
442
  ```
347
443
 
348
444
  **Hook Parameters:**
445
+
349
446
  - `intentHash` - The computed hash of the intent payload
350
447
  - `intentPayload` - The unsigned intent payload
351
448
  - `multiPayload` - The signed multi-payload containing signature and metadata
352
449
  - `relayParams` - Additional parameters passed to the relayer (quote hashes)
353
450
 
354
451
  **Important Notes:**
452
+
355
453
  - The hook is called synchronously before publishing the intent
356
454
  - If the hook throws an error, the withdrawal will fail
357
455
  - The hook can be async and return a Promise
@@ -362,24 +460,24 @@ Process multiple withdrawals in a single intent:
362
460
 
363
461
  ```typescript
364
462
  const withdrawalParams = [
365
- {
366
- assetId: 'nep141:usdt.tether-token.near',
367
- amount: 1000000n,
368
- destinationAddress: '0x742d35Cc...',
369
- feeInclusive: false
370
- },
371
- {
372
- assetId: 'nep245:v2_1.omni.hot.tg:137_qiStmoQJDQPTebaPjgx5VBxZv6L',
373
- amount: 100000n,
374
- destinationAddress: '0x742d35Cc...',
375
- feeInclusive: false
376
- }
463
+ {
464
+ assetId: 'nep141:usdt.tether-token.near',
465
+ amount: 1000000n,
466
+ destinationAddress: '0x742d35Cc...',
467
+ feeInclusive: false
468
+ },
469
+ {
470
+ assetId: 'nep245:v2_1.omni.hot.tg:137_qiStmoQJDQPTebaPjgx5VBxZv6L',
471
+ amount: 100000n,
472
+ destinationAddress: '0x742d35Cc...',
473
+ feeInclusive: false
474
+ }
377
475
  ]
378
476
 
379
477
  // Method 1: Complete end-to-end batch processing
380
478
  const batchResult = await sdk.processWithdrawal({
381
- withdrawalParams,
382
- // feeEstimation is optional - will be estimated automatically if not provided
479
+ withdrawalParams,
480
+ // feeEstimation is optional - will be estimated automatically if not provided
383
481
  });
384
482
 
385
483
  console.log('Batch intent hash:', batchResult.intentHash);
@@ -387,19 +485,19 @@ console.log('Destination transactions:', batchResult.destinationTx); // Array of
387
485
 
388
486
  // Method 2: Step-by-step batch processing for granular control
389
487
  const feeEstimation = await sdk.estimateWithdrawalFee({
390
- withdrawalParams
488
+ withdrawalParams
391
489
  });
392
490
 
393
- const { intentHash } = await sdk.signAndSendWithdrawalIntent({
394
- withdrawalParams,
395
- feeEstimation
491
+ const {intentHash} = await sdk.signAndSendWithdrawalIntent({
492
+ withdrawalParams,
493
+ feeEstimation
396
494
  });
397
495
 
398
- const intentTx = await sdk.waitForIntentSettlement({ intentHash });
496
+ const intentTx = await sdk.waitForIntentSettlement({intentHash});
399
497
 
400
498
  const destinationTxs = await sdk.waitForWithdrawalCompletion({
401
- withdrawalParams,
402
- intentTx
499
+ withdrawalParams,
500
+ intentTx
403
501
  });
404
502
 
405
503
  console.log('All destination transactions:', destinationTxs);
@@ -411,60 +509,62 @@ The SDK provides direct access to intent operations for advanced use cases:
411
509
 
412
510
  ```typescript
413
511
  // Generic intent signing and publishing
414
- const { intentHash } = await sdk.signAndSendIntent({
415
- intents: [/* array of intent primitives */],
416
- signer: customIntentSigner, // optional - uses SDK default if not provided
417
- onBeforePublishIntent: async (data) => {
418
- // Custom logic before publishing
419
- console.log('About to publish intent:', data.intentHash);
420
- }
512
+ const {intentHash} = await sdk.signAndSendIntent({
513
+ intents: [/* array of intent primitives */],
514
+ signer: customIntentSigner, // optional - uses SDK default if not provided
515
+ onBeforePublishIntent: async (data) => {
516
+ // Custom logic before publishing
517
+ console.log('About to publish intent:', data.intentHash);
518
+ }
421
519
  });
422
520
 
423
521
  // Wait for intent settlement
424
- const intentTx = await sdk.waitForIntentSettlement({
425
- intentHash
522
+ const intentTx = await sdk.waitForIntentSettlement({
523
+ intentHash
426
524
  });
427
525
 
428
526
  // or manual status check
429
527
 
430
528
  // Check intent status at any time
431
- const status = await sdk.getIntentStatus({
432
- intentHash: intentHash
529
+ const status = await sdk.getIntentStatus({
530
+ intentHash: intentHash
433
531
  });
434
532
 
435
533
  console.log('Intent status:', status.status); // "PENDING" | "TX_BROADCASTED" | "SETTLED" | "NOT_FOUND_OR_NOT_VALID"
436
534
 
437
535
  if (status.status === 'SETTLED') {
438
- console.log('Settlement transaction:', status.txHash);
536
+ console.log('Settlement transaction:', status.txHash);
439
537
  }
440
538
  ```
441
539
 
442
540
  **Intent Status Values:**
541
+
443
542
  - `PENDING` - Intent published but not yet processed
444
543
  - `TX_BROADCASTED` - Intent being processed, transaction broadcasted
445
544
  - `SETTLED` - Intent successfully completed
446
545
  - `NOT_FOUND_OR_NOT_VALID` - Intent not found or invalid, it isn't executed onchain
447
546
 
448
- ### Route Configuration Factory Functions
547
+ ### Configure Withdrawal Routes
449
548
 
450
- **Recommended**: Use factory functions to create route configurations. The SDK provides factory functions for type-safe and convenient route configuration creation:
549
+ **Recommended**: Use factory functions to create route configurations. The SDK provides factory functions for type-safe
550
+ and convenient route configuration creation:
451
551
 
452
552
  ```typescript
453
- import {
454
- createVirtualChainRoute,
455
- createNearWithdrawalRoute,
456
- createInternalTransferRoute
553
+ import {
554
+ createVirtualChainRoute,
555
+ createNearWithdrawalRoute,
556
+ createInternalTransferRoute
457
557
  } from '@defuse-protocol/intents-sdk';
458
558
 
459
559
  // Create virtual chain route configuration (recommended)
460
560
  const virtualChainRoute = createVirtualChainRoute(
461
- '0x4e45415f.c.aurora', // Aurora Engine contract ID
462
- null // Proxy token contract ID (optional)
561
+ '0x4e45415f.c.aurora', // Aurora Engine contract ID
562
+ null // Proxy token contract ID (optional)
463
563
  );
464
564
 
465
565
  // Create near withdrawal route with custom message
466
566
  const nearWithdrawalRoute = createNearWithdrawalRoute(
467
- 'Custom withdrawal message' // Optional message
567
+ 'Custom withdrawal message' // Optional message
468
568
  );
469
569
 
470
570
  // Create internal transfer route
@@ -472,13 +572,13 @@ const internalTransferRoute = createInternalTransferRoute();
472
572
 
473
573
  // Use the factory-created route configuration in withdrawal
474
574
  const result = await sdk.processWithdrawal({
475
- withdrawalParams: {
476
- assetId: 'nep141:a35923162c49cf95e6bf26623385eb431ad920d3.factory.bridge.near',
477
- amount: BigInt('1000000'),
478
- destinationAddress: '0x742d35Cc6634C0532925a3b8D84B2021F90a51A3',
479
- feeInclusive: false,
480
- routeConfig: virtualChainRoute // Recommended: Use factory function
481
- }
575
+ withdrawalParams: {
576
+ assetId: 'nep141:a35923162c49cf95e6bf26623385eb431ad920d3.factory.bridge.near',
577
+ amount: BigInt('1000000'),
578
+ destinationAddress: '0x742d35Cc6634C0532925a3b8D84B2021F90a51A3',
579
+ feeInclusive: false,
580
+ routeConfig: virtualChainRoute // Recommended: Use factory function
581
+ }
482
582
  });
483
583
  ```
484
584
 
@@ -488,13 +588,13 @@ Get detailed information about supported assets:
488
588
 
489
589
  ```typescript
490
590
  try {
491
- const assetInfo = sdk.parseAssetId('nep141:usdt.tether-token.near');
492
- console.log('Bridge name:', assetInfo.bridgeName);
493
- console.log('Blockchain:', assetInfo.blockchain);
494
- console.log('Contract ID:', assetInfo.contractId);
495
- console.log('Standard:', assetInfo.standard);
591
+ const assetInfo = sdk.parseAssetId('nep141:usdt.tether-token.near');
592
+ console.log('Bridge name:', assetInfo.bridgeName);
593
+ console.log('Blockchain:', assetInfo.blockchain);
594
+ console.log('Contract ID:', assetInfo.contractId);
595
+ console.log('Standard:', assetInfo.standard);
496
596
  } catch (error) {
497
- console.log('Asset not supported');
597
+ console.log('Asset not supported');
498
598
  }
499
599
  ```
500
600
 
@@ -505,12 +605,12 @@ Monitor withdrawal completion:
505
605
  ```typescript
506
606
  // Method 1: Using the orchestrated approach (automatic monitoring)
507
607
  const result = await sdk.processWithdrawal({
508
- withdrawalParams: {
509
- assetId: 'nep141:usdt.tether-token.near',
510
- amount: 1000000n,
511
- destinationAddress: '0x742d35Cc...',
512
- feeInclusive: false
513
- }
608
+ withdrawalParams: {
609
+ assetId: 'nep141:usdt.tether-token.near',
610
+ amount: 1000000n,
611
+ destinationAddress: '0x742d35Cc...',
612
+ feeInclusive: false
613
+ }
514
614
  });
515
615
 
516
616
  console.log('Intent settled:', result.intentTx.hash);
@@ -518,162 +618,169 @@ console.log('Withdrawal completed:', result.destinationTx);
518
618
 
519
619
  // Method 2: Step-by-step monitoring for granular control
520
620
  const feeEstimation = await sdk.estimateWithdrawalFee({
521
- withdrawalParams: {
522
- assetId: 'nep141:usdt.tether-token.near',
523
- amount: 1000000n,
524
- destinationAddress: '0x742d35Cc...',
525
- feeInclusive: false
526
- }
621
+ withdrawalParams: {
622
+ assetId: 'nep141:usdt.tether-token.near',
623
+ amount: 1000000n,
624
+ destinationAddress: '0x742d35Cc...',
625
+ feeInclusive: false
626
+ }
527
627
  });
528
628
 
529
- const { intentHash } = await sdk.signAndSendWithdrawalIntent({
530
- withdrawalParams: {
531
- assetId: 'nep141:usdt.tether-token.near',
532
- amount: 1000000n,
533
- destinationAddress: '0x742d35Cc...',
534
- feeInclusive: false
535
- },
536
- feeEstimation
629
+ const {intentHash} = await sdk.signAndSendWithdrawalIntent({
630
+ withdrawalParams: {
631
+ assetId: 'nep141:usdt.tether-token.near',
632
+ amount: 1000000n,
633
+ destinationAddress: '0x742d35Cc...',
634
+ feeInclusive: false
635
+ },
636
+ feeEstimation
537
637
  });
538
638
 
539
639
  // Monitor intent settlement
540
- const intentTx = await sdk.waitForIntentSettlement({ intentHash });
640
+ const intentTx = await sdk.waitForIntentSettlement({intentHash});
541
641
  console.log('Intent settled:', intentTx.hash);
542
642
 
543
643
  // Wait for withdrawal completion on destination chain
544
644
  const completionResult = await sdk.waitForWithdrawalCompletion({
545
- withdrawalParams: {
546
- assetId: 'nep141:usdt.tether-token.near',
547
- amount: 1000000n,
548
- destinationAddress: '0x742d35Cc...',
549
- feeInclusive: false
550
- },
551
- intentTx
645
+ withdrawalParams: {
646
+ assetId: 'nep141:usdt.tether-token.near',
647
+ amount: 1000000n,
648
+ destinationAddress: '0x742d35Cc...',
649
+ feeInclusive: false
650
+ },
651
+ intentTx
552
652
  });
553
653
 
554
654
  if ('hash' in completionResult) {
555
- console.log('Withdrawal completed with hash:', completionResult.hash);
655
+ console.log('Withdrawal completed with hash:', completionResult.hash);
556
656
  } else {
557
- console.log('Withdrawal completion not trackable for this bridge');
657
+ console.log('Withdrawal completion not trackable for this bridge');
558
658
  }
559
659
  ```
560
660
 
561
661
  ### Error Handling
562
662
 
563
663
  ```typescript
564
- import { FeeExceedsAmountError, MinWithdrawalAmountError } from '@defuse-protocol/intents-sdk';
664
+ import {FeeExceedsAmountError, MinWithdrawalAmountError} from '@defuse-protocol/intents-sdk';
565
665
 
566
666
  try {
567
- const result = await sdk.processWithdrawal({
568
- withdrawalParams: {
569
- assetId: 'nep141:usdt.tether-token.near',
570
- amount: BigInt('100'), // Very small amount
571
- destinationAddress: '0x742d35Cc...',
572
- feeInclusive: true // Fee must be less than amount
573
- }
574
- });
667
+ const result = await sdk.processWithdrawal({
668
+ withdrawalParams: {
669
+ assetId: 'nep141:usdt.tether-token.near',
670
+ amount: BigInt('100'), // Very small amount
671
+ destinationAddress: '0x742d35Cc...',
672
+ feeInclusive: true // Fee must be less than amount
673
+ }
674
+ });
575
675
  } catch (error) {
576
- if (error instanceof FeeExceedsAmountError) {
577
- console.log('Fee exceeds withdrawal amount');
578
- console.log('Required fee:', error.feeEstimation.amount);
579
- console.log('Withdrawal amount:', error.amount);
580
- } else if (error instanceof MinWithdrawalAmountError) {
581
- console.log('Amount below minimum withdrawal limit');
582
- console.log('Minimum required:', error.minAmount);
583
- console.log('Requested amount:', error.requestedAmount);
584
- console.log('Asset:', error.assetId);
585
- }
676
+ if (error instanceof FeeExceedsAmountError) {
677
+ console.log('Fee exceeds withdrawal amount');
678
+ console.log('Required fee:', error.feeEstimation.amount);
679
+ console.log('Withdrawal amount:', error.amount);
680
+ } else if (error instanceof MinWithdrawalAmountError) {
681
+ console.log('Amount below minimum withdrawal limit');
682
+ console.log('Minimum required:', error.minAmount);
683
+ console.log('Requested amount:', error.requestedAmount);
684
+ console.log('Asset:', error.assetId);
685
+ }
586
686
  }
587
687
 
588
688
  // Error handling with granular control
589
689
  try {
590
- const feeEstimation = await sdk.estimateWithdrawalFee({
591
- withdrawalParams: {
592
- assetId: 'nep141:usdt.tether-token.near',
593
- amount: 100n,
594
- destinationAddress: '0x742d35Cc...',
595
- feeInclusive: true
596
- }
597
- });
598
-
599
- // Continue with other operations...
690
+ const feeEstimation = await sdk.estimateWithdrawalFee({
691
+ withdrawalParams: {
692
+ assetId: 'nep141:usdt.tether-token.near',
693
+ amount: 100n,
694
+ destinationAddress: '0x742d35Cc...',
695
+ feeInclusive: true
696
+ }
697
+ });
698
+
699
+ // Continue with other operations...
600
700
  } catch (error) {
601
- // Handle specific errors at each step
602
- console.error('Fee estimation failed:', error);
701
+ // Handle specific errors at each step
702
+ console.error('Fee estimation failed:', error);
603
703
  }
604
704
  ```
605
705
 
606
706
  #### PoA Bridge Minimum Withdrawal Amount Validation
607
707
 
608
- PoA bridge has minimum withdrawal amount requirements that vary per token and blockchain. The SDK automatically validates this for all withdrawals.
708
+ PoA bridge has minimum withdrawal amount requirements that vary per token and blockchain. The SDK automatically
709
+ validates this for all withdrawals.
609
710
 
610
711
  ```typescript
611
712
  // Validation happens automatically during withdrawal processing:
612
713
  try {
613
- const result = await sdk.processWithdrawal({
614
- withdrawalParams: {
615
- assetId: 'nep141:zec.omft.near', // Zcash token
616
- amount: BigInt('50000000'), // 0.5 ZEC (in smallest units)
617
- destinationAddress: 'your-zcash-address',
618
- feeInclusive: false
619
- }
620
- });
714
+ const result = await sdk.processWithdrawal({
715
+ withdrawalParams: {
716
+ assetId: 'nep141:zec.omft.near', // Zcash token
717
+ amount: BigInt('50000000'), // 0.5 ZEC (in smallest units)
718
+ destinationAddress: 'your-zcash-address',
719
+ feeInclusive: false
720
+ }
721
+ });
621
722
  } catch (error) {
622
- if (error instanceof MinWithdrawalAmountError) {
623
- console.log(`Minimum withdrawal for ${error.assetId}: ${error.minAmount}`);
624
- console.log(`Requested amount: ${error.requestedAmount}`);
625
- // For Zcash: minimum is typically 1.0 ZEC (100000000 in smallest units)
626
- // Plus 0.2 ZEC fee, so user needs at least 1.2 ZEC to withdraw 1.0 ZEC
627
- }
723
+ if (error instanceof MinWithdrawalAmountError) {
724
+ console.log(`Minimum withdrawal for ${error.assetId}: ${error.minAmount}`);
725
+ console.log(`Requested amount: ${error.requestedAmount}`);
726
+ // For Zcash: minimum is typically 1.0 ZEC (100000000 in smallest units)
727
+ // Plus 0.2 ZEC fee, so user needs at least 1.2 ZEC to withdraw 1.0 ZEC
728
+ }
628
729
  }
629
730
  ```
630
731
 
631
- Note: Other routes (Near Withdrawal, Virtual Chain, Internal Transfer) don't have minimum withdrawal restrictions, so validation passes through for those routes.
732
+ Note: Other routes (Near Withdrawal, Virtual Chain, Internal Transfer) don't have minimum withdrawal restrictions, so
733
+ validation passes through for those routes.
632
734
 
633
735
  #### Hot Bridge Stellar Trustline Validation
634
736
 
635
- Hot Bridge validates that destination addresses have the required trustlines when withdrawing to Stellar blockchain. This prevents failed transactions due to missing trustlines.
737
+ Hot Bridge validates that destination addresses have the required trustlines when withdrawing to Stellar blockchain.
738
+ This prevents failed transactions due to missing trustlines.
636
739
 
637
740
  ```typescript
638
- import { TrustlineNotFoundError } from '@defuse-protocol/intents-sdk';
741
+ import {TrustlineNotFoundError} from '@defuse-protocol/intents-sdk';
639
742
 
640
743
  // Validation happens automatically during withdrawal processing:
641
744
  try {
642
- const result = await sdk.processWithdrawal({
643
- withdrawalParams: {
644
- assetId: 'nep245:v2_1.omni.hot.tg:stellar_1_USD_GBDMM6LG7YX7YGF6JFAEWX3KFUSBXGAEPZ2IHDLWH:1100', // Stellar USD token
645
- amount: BigInt('1000000'), // 1 USD (in smallest units)
646
- destinationAddress: 'GCKFBEIYTKP6RYVDYGMVVMJ6J6XKCRZL74JPWTFGD2NQNMPBQC2LGTVZ', // Stellar address
647
- feeInclusive: false
648
- }
649
- });
745
+ const result = await sdk.processWithdrawal({
746
+ withdrawalParams: {
747
+ assetId: 'nep245:v2_1.omni.hot.tg:stellar_1_USD_GBDMM6LG7YX7YGF6JFAEWX3KFUSBXGAEPZ2IHDLWH:1100', // Stellar USD token
748
+ amount: BigInt('1000000'), // 1 USD (in smallest units)
749
+ destinationAddress: 'GCKFBEIYTKP6RYVDYGMVVMJ6J6XKCRZL74JPWTFGD2NQNMPBQC2LGTVZ', // Stellar address
750
+ feeInclusive: false
751
+ }
752
+ });
650
753
  } catch (error) {
651
- if (error instanceof TrustlineNotFoundError) {
652
- console.log(`Trustline not found for token: ${error.assetId}`);
653
- console.log(`Destination address: ${error.destinationAddress}`);
654
- console.log('The destination address must have a trustline for this token before withdrawal');
655
- // User needs to create a trustline for the token on Stellar before withdrawing
656
- }
754
+ if (error instanceof TrustlineNotFoundError) {
755
+ console.log(`Trustline not found for token: ${error.assetId}`);
756
+ console.log(`Destination address: ${error.destinationAddress}`);
757
+ console.log('The destination address must have a trustline for this token before withdrawal');
758
+ // User needs to create a trustline for the token on Stellar before withdrawing
759
+ }
657
760
  }
658
761
  ```
659
762
 
660
763
  **What is a trustline?**
661
- On Stellar, accounts must explicitly create "trustlines" to hold non-native assets. Before receiving any token (except XLM), the destination address must:
764
+ On Stellar, accounts must explicitly create "trustlines" to hold non-native assets. Before receiving any token (except
765
+ XLM), the destination address must:
766
+
662
767
  1. Create a trustline for that specific token
663
768
  2. Have sufficient XLM balance to maintain the trustline
664
769
 
665
770
  **Why this validation matters:**
771
+
666
772
  - Prevents failed withdrawals due to missing trustlines
667
773
  - Saves gas fees and reduces user frustration
668
774
  - Provides clear error messages for troubleshooting
669
775
 
670
- Note: This validation only applies to Stellar destinations via Hot Bridge. Other blockchains and routes don't require trustline validation.
671
-
672
- TBD
776
+ Note: This validation only applies to Stellar destinations via Hot Bridge. Other blockchains and routes don't require
777
+ trustline validation.
673
778
 
674
779
  ## Supported Networks
675
780
 
676
- For a list of supported chains, see the [Chain Support page](https://docs.near-intents.org/near-intents/chain-address-support) in the Near Intents documentation.
781
+ For a list of supported chains, see
782
+ the [Chain Support page](https://docs.near-intents.org/near-intents/chain-address-support) in the Near Intents
783
+ documentation.
677
784
 
678
785
  ## Development
679
786