@sip-protocol/sdk 0.2.10 → 0.3.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/dist/browser.d.mts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +1334 -199
- package/dist/browser.mjs +19 -1
- package/dist/chunk-4IFOPYJF.mjs +11950 -0
- package/dist/chunk-4VJHI66K.mjs +12120 -0
- package/dist/chunk-5BAS4D44.mjs +10283 -0
- package/dist/chunk-6WOV2YNG.mjs +10179 -0
- package/dist/chunk-7IMRM7LN.mjs +12149 -0
- package/dist/chunk-DU7LQDD2.mjs +10148 -0
- package/dist/{chunk-AV37IZST.mjs → chunk-JNNXNTSS.mjs} +14 -0
- package/dist/chunk-KXN6IWL5.mjs +10736 -0
- package/dist/chunk-MR7HRCRS.mjs +10165 -0
- package/dist/chunk-NDGUWOOZ.mjs +10157 -0
- package/dist/chunk-O4Y2ZUDL.mjs +12721 -0
- package/dist/chunk-UPTISVCY.mjs +10304 -0
- package/dist/chunk-VITVG25F.mjs +982 -0
- package/dist/chunk-VXSHK7US.mjs +10158 -0
- package/dist/chunk-W3YXIQ7L.mjs +11950 -0
- package/dist/index-Ba7njCU3.d.ts +6925 -0
- package/dist/index-Co26-vbG.d.mts +6925 -0
- package/dist/{index-CAhjA4kh.d.mts → index-DqZoHYKI.d.mts} +362 -6
- package/dist/index-dTtK_DTl.d.ts +6762 -0
- package/dist/index-jnkYu-Z4.d.mts +6762 -0
- package/dist/{index-BFOKTz2z.d.ts → index-vB1N1mHd.d.ts} +362 -6
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1334 -199
- package/dist/index.mjs +19 -1
- package/dist/noir-BHQtFvRk.d.mts +467 -0
- package/dist/noir-BHQtFvRk.d.ts +467 -0
- package/package.json +14 -14
- package/src/index.ts +32 -0
- package/src/settlement/README.md +439 -0
- package/src/settlement/backends/direct-chain.ts +569 -0
- package/src/settlement/backends/index.ts +22 -0
- package/src/settlement/backends/near-intents.ts +480 -0
- package/src/settlement/backends/zcash-native.ts +516 -0
- package/src/settlement/index.ts +47 -0
- package/src/settlement/interface.ts +397 -0
- package/src/settlement/registry.ts +269 -0
- package/src/settlement/router.ts +383 -0
- package/LICENSE +0 -21
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NEAR Intents Settlement Backend
|
|
3
|
+
*
|
|
4
|
+
* Implements SettlementBackend interface for NEAR 1Click API.
|
|
5
|
+
* Wraps existing NEARIntentsAdapter functionality with standardized interface.
|
|
6
|
+
*
|
|
7
|
+
* @module settlement/backends/near-intents
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
SettlementBackend,
|
|
12
|
+
QuoteParams,
|
|
13
|
+
Quote,
|
|
14
|
+
SwapParams,
|
|
15
|
+
SwapResult,
|
|
16
|
+
SwapStatusResponse,
|
|
17
|
+
BackendCapabilities,
|
|
18
|
+
} from '../interface'
|
|
19
|
+
import { SwapStatus } from '../interface'
|
|
20
|
+
import {
|
|
21
|
+
NEARIntentsAdapter,
|
|
22
|
+
type NEARIntentsAdapterConfig,
|
|
23
|
+
type SwapRequest,
|
|
24
|
+
} from '../../adapters/near-intents'
|
|
25
|
+
import {
|
|
26
|
+
type ChainId,
|
|
27
|
+
type Asset,
|
|
28
|
+
PrivacyLevel,
|
|
29
|
+
OneClickSwapStatus,
|
|
30
|
+
} from '@sip-protocol/types'
|
|
31
|
+
import { ValidationError } from '../../errors'
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Map 1Click swap status to SIP SwapStatus
|
|
35
|
+
*/
|
|
36
|
+
function mapOneClickStatus(status: OneClickSwapStatus): SwapStatus {
|
|
37
|
+
switch (status) {
|
|
38
|
+
case OneClickSwapStatus.PENDING_DEPOSIT:
|
|
39
|
+
return SwapStatus.PENDING_DEPOSIT
|
|
40
|
+
case OneClickSwapStatus.PROCESSING:
|
|
41
|
+
return SwapStatus.IN_PROGRESS
|
|
42
|
+
case OneClickSwapStatus.SUCCESS:
|
|
43
|
+
return SwapStatus.SUCCESS
|
|
44
|
+
case OneClickSwapStatus.FAILED:
|
|
45
|
+
return SwapStatus.FAILED
|
|
46
|
+
case OneClickSwapStatus.INCOMPLETE_DEPOSIT:
|
|
47
|
+
return SwapStatus.FAILED
|
|
48
|
+
case OneClickSwapStatus.REFUNDED:
|
|
49
|
+
return SwapStatus.REFUNDED
|
|
50
|
+
default:
|
|
51
|
+
return SwapStatus.PENDING_DEPOSIT
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* NEAR Intents Settlement Backend
|
|
57
|
+
*
|
|
58
|
+
* Provides privacy-preserving cross-chain swaps via NEAR 1Click API.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const backend = new NEARIntentsBackend({
|
|
63
|
+
* jwtToken: process.env.NEAR_INTENTS_JWT,
|
|
64
|
+
* })
|
|
65
|
+
*
|
|
66
|
+
* // Get quote
|
|
67
|
+
* const quote = await backend.getQuote({
|
|
68
|
+
* fromChain: 'ethereum',
|
|
69
|
+
* toChain: 'solana',
|
|
70
|
+
* fromToken: 'USDC',
|
|
71
|
+
* toToken: 'SOL',
|
|
72
|
+
* amount: 1000000n, // 1 USDC
|
|
73
|
+
* privacyLevel: PrivacyLevel.SHIELDED,
|
|
74
|
+
* recipientMetaAddress: 'sip:solana:0x...:0x...',
|
|
75
|
+
* senderAddress: '0xYourEthAddress',
|
|
76
|
+
* })
|
|
77
|
+
*
|
|
78
|
+
* // Execute swap
|
|
79
|
+
* const result = await backend.executeSwap({
|
|
80
|
+
* quoteId: quote.quoteId,
|
|
81
|
+
* })
|
|
82
|
+
*
|
|
83
|
+
* // Check status
|
|
84
|
+
* const status = await backend.getStatus(result.swapId)
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export class NEARIntentsBackend implements SettlementBackend {
|
|
88
|
+
readonly name = 'near-intents' as const
|
|
89
|
+
readonly capabilities: BackendCapabilities
|
|
90
|
+
|
|
91
|
+
private adapter: NEARIntentsAdapter
|
|
92
|
+
private quoteCache: Map<string, QuoteParams>
|
|
93
|
+
|
|
94
|
+
constructor(config: NEARIntentsAdapterConfig = {}) {
|
|
95
|
+
this.adapter = new NEARIntentsAdapter(config)
|
|
96
|
+
this.quoteCache = new Map()
|
|
97
|
+
|
|
98
|
+
// Define backend capabilities
|
|
99
|
+
this.capabilities = {
|
|
100
|
+
supportedSourceChains: [
|
|
101
|
+
'near',
|
|
102
|
+
'ethereum',
|
|
103
|
+
'solana',
|
|
104
|
+
'polygon',
|
|
105
|
+
'arbitrum',
|
|
106
|
+
'optimism',
|
|
107
|
+
'base',
|
|
108
|
+
'bitcoin',
|
|
109
|
+
'zcash',
|
|
110
|
+
],
|
|
111
|
+
supportedDestinationChains: [
|
|
112
|
+
'near',
|
|
113
|
+
'ethereum',
|
|
114
|
+
'solana',
|
|
115
|
+
'polygon',
|
|
116
|
+
'arbitrum',
|
|
117
|
+
'optimism',
|
|
118
|
+
'base',
|
|
119
|
+
'bitcoin',
|
|
120
|
+
'zcash',
|
|
121
|
+
],
|
|
122
|
+
supportedPrivacyLevels: [
|
|
123
|
+
PrivacyLevel.TRANSPARENT,
|
|
124
|
+
PrivacyLevel.SHIELDED,
|
|
125
|
+
PrivacyLevel.COMPLIANT,
|
|
126
|
+
],
|
|
127
|
+
supportsCancellation: false,
|
|
128
|
+
supportsRefunds: true,
|
|
129
|
+
averageExecutionTime: 300, // 5 minutes
|
|
130
|
+
features: ['stealth-addresses', 'cross-chain', 'near-intents'],
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Get quote for a cross-chain swap
|
|
136
|
+
*/
|
|
137
|
+
async getQuote(params: QuoteParams): Promise<Quote> {
|
|
138
|
+
// Validate parameters
|
|
139
|
+
this.validateQuoteParams(params)
|
|
140
|
+
|
|
141
|
+
// Build swap request for adapter
|
|
142
|
+
const swapRequest: SwapRequest = {
|
|
143
|
+
requestId: this.generateRequestId(),
|
|
144
|
+
privacyLevel: params.privacyLevel,
|
|
145
|
+
inputAsset: {
|
|
146
|
+
chain: params.fromChain,
|
|
147
|
+
symbol: params.fromToken,
|
|
148
|
+
decimals: 0, // Will be inferred by adapter
|
|
149
|
+
} as Asset,
|
|
150
|
+
outputAsset: {
|
|
151
|
+
chain: params.toChain,
|
|
152
|
+
symbol: params.toToken,
|
|
153
|
+
decimals: 0, // Will be inferred by adapter
|
|
154
|
+
} as Asset,
|
|
155
|
+
inputAmount: params.amount,
|
|
156
|
+
minOutputAmount: params.slippageTolerance
|
|
157
|
+
? params.amount - (params.amount * BigInt(params.slippageTolerance) / BigInt(10000))
|
|
158
|
+
: undefined,
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Prepare swap with adapter
|
|
162
|
+
const prepared = await this.adapter.prepareSwap(
|
|
163
|
+
swapRequest,
|
|
164
|
+
params.recipientMetaAddress,
|
|
165
|
+
params.senderAddress
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
// Get quote from 1Click API
|
|
169
|
+
const oneClickQuote = await this.adapter.getQuote(prepared)
|
|
170
|
+
|
|
171
|
+
// Cache quote params for executeSwap
|
|
172
|
+
this.quoteCache.set(oneClickQuote.quoteId, params)
|
|
173
|
+
|
|
174
|
+
// Convert to standardized Quote format
|
|
175
|
+
const quote: Quote = {
|
|
176
|
+
quoteId: oneClickQuote.quoteId,
|
|
177
|
+
amountIn: oneClickQuote.amountIn,
|
|
178
|
+
amountOut: oneClickQuote.amountOut,
|
|
179
|
+
minAmountOut: oneClickQuote.amountOut, // 1Click doesn't provide separate minAmount
|
|
180
|
+
fees: {
|
|
181
|
+
networkFee: '0', // 1Click doesn't provide separate fee breakdown
|
|
182
|
+
protocolFee: '0',
|
|
183
|
+
totalFeeUSD: oneClickQuote.amountOutUsd,
|
|
184
|
+
},
|
|
185
|
+
depositAddress: oneClickQuote.depositAddress,
|
|
186
|
+
recipientAddress: prepared.stealthAddress?.address ?? params.senderAddress ?? '',
|
|
187
|
+
refundAddress: params.senderAddress,
|
|
188
|
+
expiresAt: new Date(oneClickQuote.deadline).getTime() / 1000,
|
|
189
|
+
estimatedTime: oneClickQuote.timeEstimate,
|
|
190
|
+
metadata: {
|
|
191
|
+
prepared,
|
|
192
|
+
oneClickQuote,
|
|
193
|
+
stealthAddress: prepared.stealthAddress,
|
|
194
|
+
ephemeralPublicKey: prepared.stealthAddress?.ephemeralPublicKey,
|
|
195
|
+
curve: prepared.curve,
|
|
196
|
+
},
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return quote
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Execute swap using a quote
|
|
204
|
+
*/
|
|
205
|
+
async executeSwap(params: SwapParams): Promise<SwapResult> {
|
|
206
|
+
// Validate parameters
|
|
207
|
+
if (!params.quoteId) {
|
|
208
|
+
throw new ValidationError('quoteId is required', 'quoteId')
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Retrieve cached quote params
|
|
212
|
+
const quoteParams = this.quoteCache.get(params.quoteId)
|
|
213
|
+
if (!quoteParams) {
|
|
214
|
+
throw new ValidationError(
|
|
215
|
+
'Quote not found. Please call getQuote() before executeSwap()',
|
|
216
|
+
'quoteId'
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Build swap request
|
|
221
|
+
const swapRequest: SwapRequest = {
|
|
222
|
+
requestId: this.generateRequestId(),
|
|
223
|
+
privacyLevel: quoteParams.privacyLevel,
|
|
224
|
+
inputAsset: {
|
|
225
|
+
chain: quoteParams.fromChain,
|
|
226
|
+
symbol: quoteParams.fromToken,
|
|
227
|
+
decimals: 0,
|
|
228
|
+
} as Asset,
|
|
229
|
+
outputAsset: {
|
|
230
|
+
chain: quoteParams.toChain,
|
|
231
|
+
symbol: quoteParams.toToken,
|
|
232
|
+
decimals: 0,
|
|
233
|
+
} as Asset,
|
|
234
|
+
inputAmount: quoteParams.amount,
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Execute swap via adapter
|
|
238
|
+
const adapterResult = await this.adapter.initiateSwap(
|
|
239
|
+
swapRequest,
|
|
240
|
+
quoteParams.recipientMetaAddress,
|
|
241
|
+
quoteParams.senderAddress
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
// If deposit tx provided, notify 1Click
|
|
245
|
+
if (params.depositTxHash) {
|
|
246
|
+
await this.adapter.notifyDeposit(
|
|
247
|
+
adapterResult.depositAddress,
|
|
248
|
+
params.depositTxHash,
|
|
249
|
+
params.nearAccount
|
|
250
|
+
)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Convert to standardized SwapResult format
|
|
254
|
+
const result: SwapResult = {
|
|
255
|
+
swapId: adapterResult.depositAddress, // Use deposit address as swap ID
|
|
256
|
+
status: mapOneClickStatus(adapterResult.status),
|
|
257
|
+
quoteId: params.quoteId,
|
|
258
|
+
depositAddress: adapterResult.depositAddress,
|
|
259
|
+
depositTxHash: params.depositTxHash,
|
|
260
|
+
settlementTxHash: adapterResult.settlementTxHash,
|
|
261
|
+
actualAmountOut: adapterResult.amountOut,
|
|
262
|
+
metadata: {
|
|
263
|
+
adapterResult,
|
|
264
|
+
stealthRecipient: adapterResult.stealthRecipient,
|
|
265
|
+
ephemeralPublicKey: adapterResult.ephemeralPublicKey,
|
|
266
|
+
},
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return result
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Get current swap status
|
|
274
|
+
*/
|
|
275
|
+
async getStatus(swapId: string): Promise<SwapStatusResponse> {
|
|
276
|
+
// swapId is the deposit address
|
|
277
|
+
const oneClickStatus = await this.adapter.getStatus(swapId)
|
|
278
|
+
|
|
279
|
+
// Convert to standardized format
|
|
280
|
+
const status: SwapStatusResponse = {
|
|
281
|
+
swapId,
|
|
282
|
+
status: mapOneClickStatus(oneClickStatus.status),
|
|
283
|
+
quoteId: '', // 1Click status doesn't include quoteId
|
|
284
|
+
depositAddress: swapId,
|
|
285
|
+
amountIn: oneClickStatus.amountIn ?? '0',
|
|
286
|
+
amountOut: oneClickStatus.amountOut ?? '0',
|
|
287
|
+
depositTxHash: oneClickStatus.depositTxHash,
|
|
288
|
+
settlementTxHash: oneClickStatus.settlementTxHash,
|
|
289
|
+
errorMessage: oneClickStatus.error,
|
|
290
|
+
updatedAt: Date.now() / 1000, // 1Click doesn't provide updatedAt
|
|
291
|
+
metadata: {
|
|
292
|
+
oneClickStatus,
|
|
293
|
+
},
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return status
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Wait for swap completion (optional)
|
|
301
|
+
*/
|
|
302
|
+
async waitForCompletion(
|
|
303
|
+
swapId: string,
|
|
304
|
+
options?: {
|
|
305
|
+
interval?: number
|
|
306
|
+
timeout?: number
|
|
307
|
+
onStatusChange?: (status: SwapStatusResponse) => void
|
|
308
|
+
}
|
|
309
|
+
): Promise<SwapStatusResponse> {
|
|
310
|
+
await this.adapter.waitForCompletion(swapId, {
|
|
311
|
+
interval: options?.interval,
|
|
312
|
+
timeout: options?.timeout,
|
|
313
|
+
onStatus: options?.onStatusChange
|
|
314
|
+
? (oneClickStatus) => {
|
|
315
|
+
const status: SwapStatusResponse = {
|
|
316
|
+
swapId,
|
|
317
|
+
status: mapOneClickStatus(oneClickStatus.status),
|
|
318
|
+
quoteId: '',
|
|
319
|
+
depositAddress: swapId,
|
|
320
|
+
amountIn: oneClickStatus.amountIn ?? '0',
|
|
321
|
+
amountOut: oneClickStatus.amountOut ?? '0',
|
|
322
|
+
depositTxHash: oneClickStatus.depositTxHash,
|
|
323
|
+
settlementTxHash: oneClickStatus.settlementTxHash,
|
|
324
|
+
errorMessage: oneClickStatus.error,
|
|
325
|
+
updatedAt: Date.now() / 1000,
|
|
326
|
+
metadata: { oneClickStatus },
|
|
327
|
+
}
|
|
328
|
+
options.onStatusChange?.(status)
|
|
329
|
+
}
|
|
330
|
+
: undefined,
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
return this.getStatus(swapId)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Get dry quote (preview without creating deposit address)
|
|
338
|
+
*/
|
|
339
|
+
async getDryQuote(params: QuoteParams): Promise<Quote> {
|
|
340
|
+
// Validate parameters
|
|
341
|
+
this.validateQuoteParams(params)
|
|
342
|
+
|
|
343
|
+
// Build swap request for adapter
|
|
344
|
+
const swapRequest: SwapRequest = {
|
|
345
|
+
requestId: this.generateRequestId(),
|
|
346
|
+
privacyLevel: params.privacyLevel,
|
|
347
|
+
inputAsset: {
|
|
348
|
+
chain: params.fromChain,
|
|
349
|
+
symbol: params.fromToken,
|
|
350
|
+
decimals: 0,
|
|
351
|
+
} as Asset,
|
|
352
|
+
outputAsset: {
|
|
353
|
+
chain: params.toChain,
|
|
354
|
+
symbol: params.toToken,
|
|
355
|
+
decimals: 0,
|
|
356
|
+
} as Asset,
|
|
357
|
+
inputAmount: params.amount,
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Prepare swap with adapter
|
|
361
|
+
const prepared = await this.adapter.prepareSwap(
|
|
362
|
+
swapRequest,
|
|
363
|
+
params.recipientMetaAddress,
|
|
364
|
+
params.senderAddress
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
// Get dry quote from 1Click API
|
|
368
|
+
const oneClickQuote = await this.adapter.getDryQuote(prepared)
|
|
369
|
+
|
|
370
|
+
// Convert to standardized Quote format
|
|
371
|
+
const quote: Quote = {
|
|
372
|
+
quoteId: oneClickQuote.quoteId,
|
|
373
|
+
amountIn: oneClickQuote.amountIn,
|
|
374
|
+
amountOut: oneClickQuote.amountOut,
|
|
375
|
+
minAmountOut: oneClickQuote.amountOut,
|
|
376
|
+
fees: {
|
|
377
|
+
networkFee: '0',
|
|
378
|
+
protocolFee: '0',
|
|
379
|
+
totalFeeUSD: oneClickQuote.amountOutUsd,
|
|
380
|
+
},
|
|
381
|
+
depositAddress: oneClickQuote.depositAddress,
|
|
382
|
+
recipientAddress: prepared.stealthAddress?.address ?? params.senderAddress ?? '',
|
|
383
|
+
refundAddress: params.senderAddress,
|
|
384
|
+
expiresAt: new Date(oneClickQuote.deadline).getTime() / 1000,
|
|
385
|
+
estimatedTime: oneClickQuote.timeEstimate,
|
|
386
|
+
metadata: {
|
|
387
|
+
prepared,
|
|
388
|
+
oneClickQuote,
|
|
389
|
+
stealthAddress: prepared.stealthAddress,
|
|
390
|
+
ephemeralPublicKey: prepared.stealthAddress?.ephemeralPublicKey,
|
|
391
|
+
curve: prepared.curve,
|
|
392
|
+
isDryQuote: true,
|
|
393
|
+
},
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return quote
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Notify backend of deposit transaction
|
|
401
|
+
*/
|
|
402
|
+
async notifyDeposit(
|
|
403
|
+
swapId: string,
|
|
404
|
+
txHash: string,
|
|
405
|
+
metadata?: Record<string, unknown>
|
|
406
|
+
): Promise<void> {
|
|
407
|
+
await this.adapter.notifyDeposit(
|
|
408
|
+
swapId, // swapId is deposit address
|
|
409
|
+
txHash,
|
|
410
|
+
metadata?.nearAccount as string | undefined
|
|
411
|
+
)
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// ─── Private Methods ──────────────────────────────────────────────────────────
|
|
415
|
+
|
|
416
|
+
private validateQuoteParams(params: QuoteParams): void {
|
|
417
|
+
if (!params.fromChain) {
|
|
418
|
+
throw new ValidationError('fromChain is required', 'fromChain')
|
|
419
|
+
}
|
|
420
|
+
if (!params.toChain) {
|
|
421
|
+
throw new ValidationError('toChain is required', 'toChain')
|
|
422
|
+
}
|
|
423
|
+
if (!params.fromToken) {
|
|
424
|
+
throw new ValidationError('fromToken is required', 'fromToken')
|
|
425
|
+
}
|
|
426
|
+
if (!params.toToken) {
|
|
427
|
+
throw new ValidationError('toToken is required', 'toToken')
|
|
428
|
+
}
|
|
429
|
+
if (!params.amount || params.amount <= BigInt(0)) {
|
|
430
|
+
throw new ValidationError('amount must be greater than 0', 'amount')
|
|
431
|
+
}
|
|
432
|
+
if (!params.privacyLevel) {
|
|
433
|
+
throw new ValidationError('privacyLevel is required', 'privacyLevel')
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Validate privacy level requirements
|
|
437
|
+
if (params.privacyLevel !== PrivacyLevel.TRANSPARENT && !params.recipientMetaAddress) {
|
|
438
|
+
throw new ValidationError(
|
|
439
|
+
'recipientMetaAddress is required for shielded/compliant privacy modes',
|
|
440
|
+
'recipientMetaAddress'
|
|
441
|
+
)
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (params.privacyLevel === PrivacyLevel.TRANSPARENT && !params.senderAddress) {
|
|
445
|
+
throw new ValidationError(
|
|
446
|
+
'senderAddress is required for transparent mode',
|
|
447
|
+
'senderAddress'
|
|
448
|
+
)
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Validate supported chains
|
|
452
|
+
if (!this.capabilities.supportedSourceChains.includes(params.fromChain)) {
|
|
453
|
+
throw new ValidationError(
|
|
454
|
+
`Source chain ${params.fromChain} is not supported`,
|
|
455
|
+
'fromChain',
|
|
456
|
+
{ supportedChains: this.capabilities.supportedSourceChains }
|
|
457
|
+
)
|
|
458
|
+
}
|
|
459
|
+
if (!this.capabilities.supportedDestinationChains.includes(params.toChain)) {
|
|
460
|
+
throw new ValidationError(
|
|
461
|
+
`Destination chain ${params.toChain} is not supported`,
|
|
462
|
+
'toChain',
|
|
463
|
+
{ supportedChains: this.capabilities.supportedDestinationChains }
|
|
464
|
+
)
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
private generateRequestId(): string {
|
|
469
|
+
return `req_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Create a new NEAR Intents settlement backend
|
|
475
|
+
*/
|
|
476
|
+
export function createNEARIntentsBackend(
|
|
477
|
+
config?: NEARIntentsAdapterConfig
|
|
478
|
+
): NEARIntentsBackend {
|
|
479
|
+
return new NEARIntentsBackend(config)
|
|
480
|
+
}
|