@sip-protocol/sdk 0.1.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/LICENSE +21 -0
- package/dist/index.d.mts +3640 -0
- package/dist/index.d.ts +3640 -0
- package/dist/index.js +5725 -0
- package/dist/index.mjs +5606 -0
- package/package.json +61 -0
- package/src/adapters/index.ts +19 -0
- package/src/adapters/near-intents.ts +475 -0
- package/src/adapters/oneclick-client.ts +367 -0
- package/src/commitment.ts +470 -0
- package/src/crypto.ts +93 -0
- package/src/errors.ts +471 -0
- package/src/index.ts +369 -0
- package/src/intent.ts +488 -0
- package/src/privacy.ts +382 -0
- package/src/proofs/index.ts +52 -0
- package/src/proofs/interface.ts +228 -0
- package/src/proofs/mock.ts +258 -0
- package/src/proofs/noir.ts +233 -0
- package/src/sip.ts +299 -0
- package/src/solver/index.ts +25 -0
- package/src/solver/mock-solver.ts +278 -0
- package/src/stealth.ts +414 -0
- package/src/validation.ts +401 -0
- package/src/wallet/base-adapter.ts +407 -0
- package/src/wallet/errors.ts +106 -0
- package/src/wallet/ethereum/adapter.ts +655 -0
- package/src/wallet/ethereum/index.ts +48 -0
- package/src/wallet/ethereum/mock.ts +505 -0
- package/src/wallet/ethereum/types.ts +364 -0
- package/src/wallet/index.ts +116 -0
- package/src/wallet/registry.ts +207 -0
- package/src/wallet/solana/adapter.ts +533 -0
- package/src/wallet/solana/index.ts +40 -0
- package/src/wallet/solana/mock.ts +522 -0
- package/src/wallet/solana/types.ts +253 -0
- package/src/zcash/index.ts +53 -0
- package/src/zcash/rpc-client.ts +623 -0
- package/src/zcash/shielded-service.ts +641 -0
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sip-protocol/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Core SDK for Shielded Intents Protocol - Privacy layer for cross-chain transactions",
|
|
5
|
+
"author": "SIP Protocol <hello@sip-protocol.org>",
|
|
6
|
+
"homepage": "https://sip-protocol.org",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/sip-protocol/sip-protocol.git",
|
|
10
|
+
"directory": "packages/sdk"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/sip-protocol/sip-protocol/issues"
|
|
14
|
+
},
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"module": "./dist/index.mjs",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.mjs",
|
|
22
|
+
"require": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"src"
|
|
28
|
+
],
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@noble/ciphers": "^2.0.1",
|
|
31
|
+
"@noble/curves": "^1.3.0",
|
|
32
|
+
"@noble/hashes": "^1.3.3",
|
|
33
|
+
"@sip-protocol/types": "0.1.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@vitest/coverage-v8": "1.6.1",
|
|
37
|
+
"tsup": "^8.0.0",
|
|
38
|
+
"typescript": "^5.3.0",
|
|
39
|
+
"vitest": "^1.1.0"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"sip",
|
|
43
|
+
"privacy",
|
|
44
|
+
"intents",
|
|
45
|
+
"cross-chain",
|
|
46
|
+
"stealth-addresses",
|
|
47
|
+
"zcash"
|
|
48
|
+
],
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
52
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
53
|
+
"lint": "eslint src/",
|
|
54
|
+
"typecheck": "tsc --noEmit",
|
|
55
|
+
"clean": "rm -rf dist",
|
|
56
|
+
"test": "vitest",
|
|
57
|
+
"test:coverage": "vitest run --coverage",
|
|
58
|
+
"bench": "vitest bench --config vitest.bench.config.ts",
|
|
59
|
+
"bench:json": "vitest bench --config vitest.bench.config.ts --outputJson benchmarks/results.json"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Network Adapters for SIP Protocol
|
|
3
|
+
*
|
|
4
|
+
* Provides integration with external networks and services.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// NEAR Intents (1Click API)
|
|
8
|
+
export { OneClickClient } from './oneclick-client'
|
|
9
|
+
export {
|
|
10
|
+
NEARIntentsAdapter,
|
|
11
|
+
createNEARIntentsAdapter,
|
|
12
|
+
} from './near-intents'
|
|
13
|
+
|
|
14
|
+
export type {
|
|
15
|
+
SwapRequest,
|
|
16
|
+
PreparedSwap,
|
|
17
|
+
SwapResult,
|
|
18
|
+
NEARIntentsAdapterConfig,
|
|
19
|
+
} from './near-intents'
|
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NEAR Intents Adapter for SIP Protocol
|
|
3
|
+
*
|
|
4
|
+
* Bridges SIP SDK with NEAR 1Click API, providing privacy-preserving
|
|
5
|
+
* cross-chain swaps using stealth addresses.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
type StealthMetaAddress,
|
|
10
|
+
type OneClickQuoteRequest,
|
|
11
|
+
type OneClickQuoteResponse,
|
|
12
|
+
type OneClickStatusResponse,
|
|
13
|
+
type DefuseAssetId,
|
|
14
|
+
type ChainType,
|
|
15
|
+
type ChainId,
|
|
16
|
+
type HexString,
|
|
17
|
+
type Asset,
|
|
18
|
+
PrivacyLevel,
|
|
19
|
+
OneClickSwapType,
|
|
20
|
+
OneClickSwapStatus,
|
|
21
|
+
} from '@sip-protocol/types'
|
|
22
|
+
import { OneClickClient } from './oneclick-client'
|
|
23
|
+
import { generateStealthAddress, decodeStealthMetaAddress } from '../stealth'
|
|
24
|
+
import { ValidationError } from '../errors'
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Swap request parameters (simplified interface for adapter)
|
|
28
|
+
*/
|
|
29
|
+
export interface SwapRequest {
|
|
30
|
+
/** Unique request ID */
|
|
31
|
+
requestId: string
|
|
32
|
+
/** Privacy level for the swap */
|
|
33
|
+
privacyLevel: PrivacyLevel
|
|
34
|
+
/** Input asset */
|
|
35
|
+
inputAsset: Asset
|
|
36
|
+
/** Input amount in smallest units */
|
|
37
|
+
inputAmount: bigint
|
|
38
|
+
/** Output asset */
|
|
39
|
+
outputAsset: Asset
|
|
40
|
+
/** Minimum output amount */
|
|
41
|
+
minOutputAmount?: bigint
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Result of preparing a swap with SIP privacy
|
|
46
|
+
*/
|
|
47
|
+
export interface PreparedSwap {
|
|
48
|
+
/** Original swap request */
|
|
49
|
+
request: SwapRequest
|
|
50
|
+
/** 1Click quote request */
|
|
51
|
+
quoteRequest: OneClickQuoteRequest
|
|
52
|
+
/** Generated stealth address (for shielded/compliant modes) */
|
|
53
|
+
stealthAddress?: {
|
|
54
|
+
address: HexString
|
|
55
|
+
ephemeralPublicKey: HexString
|
|
56
|
+
viewTag: number
|
|
57
|
+
}
|
|
58
|
+
/** Shared secret for stealth address derivation (keep private!) */
|
|
59
|
+
sharedSecret?: HexString
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Result of executing a swap
|
|
64
|
+
*/
|
|
65
|
+
export interface SwapResult {
|
|
66
|
+
/** Request ID */
|
|
67
|
+
requestId: string
|
|
68
|
+
/** 1Click quote ID */
|
|
69
|
+
quoteId: string
|
|
70
|
+
/** Deposit address for input tokens */
|
|
71
|
+
depositAddress: string
|
|
72
|
+
/** Expected input amount */
|
|
73
|
+
amountIn: string
|
|
74
|
+
/** Expected output amount */
|
|
75
|
+
amountOut: string
|
|
76
|
+
/** Current status */
|
|
77
|
+
status: OneClickSwapStatus
|
|
78
|
+
/** Deposit transaction hash (after deposit) */
|
|
79
|
+
depositTxHash?: string
|
|
80
|
+
/** Settlement transaction hash (after success) */
|
|
81
|
+
settlementTxHash?: string
|
|
82
|
+
/** Stealth address for recipient (if privacy mode) */
|
|
83
|
+
stealthRecipient?: string
|
|
84
|
+
/** Ephemeral public key (for recipient to derive stealth key) */
|
|
85
|
+
ephemeralPublicKey?: string
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Configuration for NEAR Intents adapter
|
|
90
|
+
*/
|
|
91
|
+
export interface NEARIntentsAdapterConfig {
|
|
92
|
+
/** OneClickClient instance or config */
|
|
93
|
+
client?: OneClickClient
|
|
94
|
+
/** Base URL for 1Click API */
|
|
95
|
+
baseUrl?: string
|
|
96
|
+
/** JWT token for authentication */
|
|
97
|
+
jwtToken?: string
|
|
98
|
+
/** Default slippage tolerance in basis points (100 = 1%) */
|
|
99
|
+
defaultSlippage?: number
|
|
100
|
+
/** Default deadline offset in seconds */
|
|
101
|
+
defaultDeadlineOffset?: number
|
|
102
|
+
/** Custom asset mappings (merged with defaults) */
|
|
103
|
+
assetMappings?: Record<string, DefuseAssetId>
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Default asset mapping from SIP format to Defuse asset identifier
|
|
108
|
+
*/
|
|
109
|
+
const DEFAULT_ASSET_MAPPINGS: Record<string, DefuseAssetId> = {
|
|
110
|
+
// NEAR assets
|
|
111
|
+
'near:NEAR': 'near:mainnet:native',
|
|
112
|
+
'near:wNEAR': 'near:mainnet:wrap.near',
|
|
113
|
+
|
|
114
|
+
// Ethereum assets
|
|
115
|
+
'ethereum:ETH': 'eth:1:native',
|
|
116
|
+
'ethereum:USDC': 'eth:1:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
117
|
+
'ethereum:USDT': 'eth:1:0xdac17f958d2ee523a2206206994597c13d831ec7',
|
|
118
|
+
|
|
119
|
+
// Solana assets
|
|
120
|
+
'solana:SOL': 'sol:mainnet:native',
|
|
121
|
+
|
|
122
|
+
// Zcash assets
|
|
123
|
+
'zcash:ZEC': 'zcash:mainnet:native',
|
|
124
|
+
|
|
125
|
+
// Arbitrum assets
|
|
126
|
+
'arbitrum:ETH': 'arb:42161:native',
|
|
127
|
+
|
|
128
|
+
// Base assets
|
|
129
|
+
'base:ETH': 'base:8453:native',
|
|
130
|
+
|
|
131
|
+
// Polygon assets
|
|
132
|
+
'polygon:MATIC': 'polygon:137:native',
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Chain ID to ChainType mapping
|
|
137
|
+
*/
|
|
138
|
+
const CHAIN_TYPE_MAP: Record<ChainId, ChainType> = {
|
|
139
|
+
near: 'near',
|
|
140
|
+
ethereum: 'eth',
|
|
141
|
+
solana: 'sol',
|
|
142
|
+
zcash: 'zcash',
|
|
143
|
+
polygon: 'polygon',
|
|
144
|
+
arbitrum: 'arb',
|
|
145
|
+
optimism: 'optimism',
|
|
146
|
+
base: 'base',
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* NEAR Intents Adapter
|
|
151
|
+
*
|
|
152
|
+
* Provides privacy-preserving cross-chain swaps via NEAR 1Click API.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const adapter = new NEARIntentsAdapter({
|
|
157
|
+
* jwtToken: process.env.NEAR_INTENTS_JWT,
|
|
158
|
+
* })
|
|
159
|
+
*
|
|
160
|
+
* // Or with custom asset mappings (e.g., testnet)
|
|
161
|
+
* const testnetAdapter = new NEARIntentsAdapter({
|
|
162
|
+
* jwtToken: process.env.NEAR_INTENTS_JWT,
|
|
163
|
+
* assetMappings: {
|
|
164
|
+
* 'near:testUSDC': 'near:testnet:usdc.test',
|
|
165
|
+
* },
|
|
166
|
+
* })
|
|
167
|
+
*
|
|
168
|
+
* // Prepare a swap with stealth recipient
|
|
169
|
+
* const prepared = await adapter.prepareSwap(intent, recipientMetaAddress)
|
|
170
|
+
*
|
|
171
|
+
* // Get quote
|
|
172
|
+
* const quote = await adapter.getQuote(prepared)
|
|
173
|
+
*
|
|
174
|
+
* // Execute (after depositing to depositAddress)
|
|
175
|
+
* const result = await adapter.trackSwap(quote.depositAddress)
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
export class NEARIntentsAdapter {
|
|
179
|
+
private readonly client: OneClickClient
|
|
180
|
+
private readonly defaultSlippage: number
|
|
181
|
+
private readonly defaultDeadlineOffset: number
|
|
182
|
+
private readonly assetMappings: Record<string, DefuseAssetId>
|
|
183
|
+
|
|
184
|
+
constructor(config: NEARIntentsAdapterConfig = {}) {
|
|
185
|
+
this.client = config.client ?? new OneClickClient({
|
|
186
|
+
baseUrl: config.baseUrl,
|
|
187
|
+
jwtToken: config.jwtToken,
|
|
188
|
+
})
|
|
189
|
+
this.defaultSlippage = config.defaultSlippage ?? 100 // 1%
|
|
190
|
+
this.defaultDeadlineOffset = config.defaultDeadlineOffset ?? 3600 // 1 hour
|
|
191
|
+
this.assetMappings = {
|
|
192
|
+
...DEFAULT_ASSET_MAPPINGS,
|
|
193
|
+
...config.assetMappings,
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Get the underlying OneClick client
|
|
199
|
+
*/
|
|
200
|
+
getClient(): OneClickClient {
|
|
201
|
+
return this.client
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Prepare a swap request
|
|
206
|
+
*
|
|
207
|
+
* For shielded/compliant modes, generates a stealth address for the recipient.
|
|
208
|
+
*
|
|
209
|
+
* @param request - Swap request parameters
|
|
210
|
+
* @param recipientMetaAddress - Recipient's stealth meta-address (for privacy modes)
|
|
211
|
+
* @param senderAddress - Sender's address for refunds
|
|
212
|
+
* @returns Prepared swap with quote request
|
|
213
|
+
*/
|
|
214
|
+
async prepareSwap(
|
|
215
|
+
request: SwapRequest,
|
|
216
|
+
recipientMetaAddress?: StealthMetaAddress | string,
|
|
217
|
+
senderAddress?: string,
|
|
218
|
+
): Promise<PreparedSwap> {
|
|
219
|
+
// Validate request
|
|
220
|
+
this.validateRequest(request)
|
|
221
|
+
|
|
222
|
+
// Determine recipient address
|
|
223
|
+
let recipientAddress: string
|
|
224
|
+
let stealthData: PreparedSwap['stealthAddress']
|
|
225
|
+
let sharedSecret: HexString | undefined
|
|
226
|
+
|
|
227
|
+
if (request.privacyLevel !== PrivacyLevel.TRANSPARENT) {
|
|
228
|
+
// Privacy mode requires stealth address
|
|
229
|
+
if (!recipientMetaAddress) {
|
|
230
|
+
throw new ValidationError(
|
|
231
|
+
'recipientMetaAddress is required for shielded/compliant privacy modes',
|
|
232
|
+
'recipientMetaAddress'
|
|
233
|
+
)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Decode if string
|
|
237
|
+
const metaAddr = typeof recipientMetaAddress === 'string'
|
|
238
|
+
? decodeStealthMetaAddress(recipientMetaAddress)
|
|
239
|
+
: recipientMetaAddress
|
|
240
|
+
|
|
241
|
+
// Generate stealth address
|
|
242
|
+
const { stealthAddress, sharedSecret: secret } = generateStealthAddress(metaAddr)
|
|
243
|
+
|
|
244
|
+
recipientAddress = stealthAddress.address
|
|
245
|
+
stealthData = stealthAddress
|
|
246
|
+
sharedSecret = secret
|
|
247
|
+
} else {
|
|
248
|
+
// Transparent mode uses direct address
|
|
249
|
+
if (!senderAddress) {
|
|
250
|
+
throw new ValidationError(
|
|
251
|
+
'senderAddress is required for transparent mode (or use stealth address)',
|
|
252
|
+
'senderAddress'
|
|
253
|
+
)
|
|
254
|
+
}
|
|
255
|
+
recipientAddress = senderAddress
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Build quote request
|
|
259
|
+
const quoteRequest = this.buildQuoteRequest(request, recipientAddress, senderAddress)
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
request,
|
|
263
|
+
quoteRequest,
|
|
264
|
+
stealthAddress: stealthData,
|
|
265
|
+
sharedSecret,
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Get a quote for a prepared swap
|
|
271
|
+
*
|
|
272
|
+
* @param prepared - Prepared swap from prepareSwap()
|
|
273
|
+
* @returns Quote response with deposit address
|
|
274
|
+
*/
|
|
275
|
+
async getQuote(prepared: PreparedSwap): Promise<OneClickQuoteResponse> {
|
|
276
|
+
return this.client.quote(prepared.quoteRequest)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Get a dry quote (preview without deposit address)
|
|
281
|
+
*
|
|
282
|
+
* @param prepared - Prepared swap
|
|
283
|
+
* @returns Quote preview
|
|
284
|
+
*/
|
|
285
|
+
async getDryQuote(prepared: PreparedSwap): Promise<OneClickQuoteResponse> {
|
|
286
|
+
return this.client.dryQuote(prepared.quoteRequest)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Notify 1Click of deposit transaction
|
|
291
|
+
*
|
|
292
|
+
* @param depositAddress - Deposit address from quote
|
|
293
|
+
* @param txHash - Deposit transaction hash
|
|
294
|
+
* @param nearAccount - NEAR account (if depositing from NEAR)
|
|
295
|
+
*/
|
|
296
|
+
async notifyDeposit(
|
|
297
|
+
depositAddress: string,
|
|
298
|
+
txHash: string,
|
|
299
|
+
nearAccount?: string,
|
|
300
|
+
): Promise<void> {
|
|
301
|
+
await this.client.submitDeposit({
|
|
302
|
+
depositAddress,
|
|
303
|
+
txHash,
|
|
304
|
+
nearSenderAccount: nearAccount,
|
|
305
|
+
})
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Get current swap status
|
|
310
|
+
*
|
|
311
|
+
* @param depositAddress - Deposit address from quote
|
|
312
|
+
* @returns Current status
|
|
313
|
+
*/
|
|
314
|
+
async getStatus(depositAddress: string): Promise<OneClickStatusResponse> {
|
|
315
|
+
return this.client.getStatus(depositAddress)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Wait for swap to complete
|
|
320
|
+
*
|
|
321
|
+
* @param depositAddress - Deposit address from quote
|
|
322
|
+
* @param options - Polling options
|
|
323
|
+
* @returns Final status
|
|
324
|
+
*/
|
|
325
|
+
async waitForCompletion(
|
|
326
|
+
depositAddress: string,
|
|
327
|
+
options?: {
|
|
328
|
+
interval?: number
|
|
329
|
+
timeout?: number
|
|
330
|
+
onStatus?: (status: OneClickStatusResponse) => void
|
|
331
|
+
},
|
|
332
|
+
): Promise<OneClickStatusResponse> {
|
|
333
|
+
return this.client.waitForStatus(depositAddress, options)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Execute a full swap flow
|
|
338
|
+
*
|
|
339
|
+
* This is a convenience method that:
|
|
340
|
+
* 1. Prepares the swap with stealth address
|
|
341
|
+
* 2. Gets a quote
|
|
342
|
+
* 3. Returns all info needed for the user to deposit
|
|
343
|
+
*
|
|
344
|
+
* @param request - Swap request parameters
|
|
345
|
+
* @param recipientMetaAddress - Recipient's stealth meta-address
|
|
346
|
+
* @param senderAddress - Sender's address for refunds
|
|
347
|
+
* @returns Swap result with deposit instructions
|
|
348
|
+
*/
|
|
349
|
+
async initiateSwap(
|
|
350
|
+
request: SwapRequest,
|
|
351
|
+
recipientMetaAddress?: StealthMetaAddress | string,
|
|
352
|
+
senderAddress?: string,
|
|
353
|
+
): Promise<SwapResult> {
|
|
354
|
+
// Prepare swap
|
|
355
|
+
const prepared = await this.prepareSwap(request, recipientMetaAddress, senderAddress)
|
|
356
|
+
|
|
357
|
+
// Get quote
|
|
358
|
+
const quote = await this.getQuote(prepared)
|
|
359
|
+
|
|
360
|
+
return {
|
|
361
|
+
requestId: request.requestId,
|
|
362
|
+
quoteId: quote.quoteId,
|
|
363
|
+
depositAddress: quote.depositAddress,
|
|
364
|
+
amountIn: quote.amountIn,
|
|
365
|
+
amountOut: quote.amountOut,
|
|
366
|
+
status: OneClickSwapStatus.PENDING_DEPOSIT,
|
|
367
|
+
stealthRecipient: prepared.stealthAddress?.address,
|
|
368
|
+
ephemeralPublicKey: prepared.stealthAddress?.ephemeralPublicKey,
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// ─── Asset Mapping ────────────────────────────────────────────────────────────
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Convert SIP asset to Defuse asset identifier
|
|
376
|
+
*/
|
|
377
|
+
mapAsset(chain: ChainId, symbol: string): DefuseAssetId {
|
|
378
|
+
const key = `${chain}:${symbol}`
|
|
379
|
+
const mapped = this.assetMappings[key]
|
|
380
|
+
|
|
381
|
+
if (!mapped) {
|
|
382
|
+
throw new ValidationError(
|
|
383
|
+
`Unknown asset mapping for ${key}. Supported: ${Object.keys(this.assetMappings).join(', ')}`,
|
|
384
|
+
'asset',
|
|
385
|
+
{ chain, symbol }
|
|
386
|
+
)
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return mapped
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Convert SIP chain ID to 1Click chain type
|
|
394
|
+
*/
|
|
395
|
+
mapChainType(chain: ChainId): ChainType {
|
|
396
|
+
const mapped = CHAIN_TYPE_MAP[chain]
|
|
397
|
+
|
|
398
|
+
if (!mapped) {
|
|
399
|
+
throw new ValidationError(
|
|
400
|
+
`Unknown chain mapping for ${chain}`,
|
|
401
|
+
'chain',
|
|
402
|
+
{ chain }
|
|
403
|
+
)
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return mapped
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// ─── Private Methods ──────────────────────────────────────────────────────────
|
|
410
|
+
|
|
411
|
+
private validateRequest(request: SwapRequest): void {
|
|
412
|
+
if (!request) {
|
|
413
|
+
throw new ValidationError('request is required', 'request')
|
|
414
|
+
}
|
|
415
|
+
if (!request.requestId) {
|
|
416
|
+
throw new ValidationError('requestId is required', 'request.requestId')
|
|
417
|
+
}
|
|
418
|
+
if (!request.inputAsset) {
|
|
419
|
+
throw new ValidationError('inputAsset is required', 'request.inputAsset')
|
|
420
|
+
}
|
|
421
|
+
if (!request.outputAsset) {
|
|
422
|
+
throw new ValidationError('outputAsset is required', 'request.outputAsset')
|
|
423
|
+
}
|
|
424
|
+
if (request.inputAmount === undefined || request.inputAmount === null) {
|
|
425
|
+
throw new ValidationError('inputAmount is required', 'request.inputAmount')
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
private buildQuoteRequest(
|
|
430
|
+
request: SwapRequest,
|
|
431
|
+
recipient: string,
|
|
432
|
+
refundTo?: string,
|
|
433
|
+
): OneClickQuoteRequest {
|
|
434
|
+
// Map assets
|
|
435
|
+
const originAsset = this.mapAsset(
|
|
436
|
+
request.inputAsset.chain,
|
|
437
|
+
request.inputAsset.symbol
|
|
438
|
+
)
|
|
439
|
+
const destinationAsset = this.mapAsset(
|
|
440
|
+
request.outputAsset.chain,
|
|
441
|
+
request.outputAsset.symbol
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
// Map chain types
|
|
445
|
+
const depositType = this.mapChainType(request.inputAsset.chain)
|
|
446
|
+
const recipientType = this.mapChainType(request.outputAsset.chain)
|
|
447
|
+
const refundType = depositType // Refund to same chain as deposit
|
|
448
|
+
|
|
449
|
+
// Calculate deadline
|
|
450
|
+
const deadline = new Date(Date.now() + this.defaultDeadlineOffset * 1000).toISOString()
|
|
451
|
+
|
|
452
|
+
return {
|
|
453
|
+
swapType: OneClickSwapType.EXACT_INPUT,
|
|
454
|
+
originAsset,
|
|
455
|
+
destinationAsset,
|
|
456
|
+
amount: request.inputAmount.toString(),
|
|
457
|
+
recipient,
|
|
458
|
+
refundTo: refundTo ?? recipient,
|
|
459
|
+
depositType,
|
|
460
|
+
recipientType,
|
|
461
|
+
refundType,
|
|
462
|
+
slippageTolerance: this.defaultSlippage,
|
|
463
|
+
deadline,
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Create a new NEAR Intents adapter
|
|
470
|
+
*/
|
|
471
|
+
export function createNEARIntentsAdapter(
|
|
472
|
+
config?: NEARIntentsAdapterConfig
|
|
473
|
+
): NEARIntentsAdapter {
|
|
474
|
+
return new NEARIntentsAdapter(config)
|
|
475
|
+
}
|