@lendasat/lendaswap-sdk-pure 0.2.8 → 0.2.10

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.
Files changed (57) hide show
  1. package/README.md +125 -255
  2. package/dist/cctp/attestation.d.ts +35 -0
  3. package/dist/cctp/attestation.d.ts.map +1 -0
  4. package/dist/cctp/attestation.js +63 -0
  5. package/dist/cctp/attestation.js.map +1 -0
  6. package/dist/cctp/constants.d.ts +46 -0
  7. package/dist/cctp/constants.d.ts.map +1 -0
  8. package/dist/cctp/constants.js +80 -0
  9. package/dist/cctp/constants.js.map +1 -0
  10. package/dist/cctp/index.d.ts +13 -0
  11. package/dist/cctp/index.d.ts.map +1 -0
  12. package/dist/cctp/index.js +12 -0
  13. package/dist/cctp/index.js.map +1 -0
  14. package/dist/cctp/types.d.ts +44 -0
  15. package/dist/cctp/types.d.ts.map +1 -0
  16. package/dist/cctp/types.js +5 -0
  17. package/dist/cctp/types.js.map +1 -0
  18. package/dist/cctp/utils.d.ts +29 -0
  19. package/dist/cctp/utils.d.ts.map +1 -0
  20. package/dist/cctp/utils.js +50 -0
  21. package/dist/cctp/utils.js.map +1 -0
  22. package/dist/client.d.ts +129 -1
  23. package/dist/client.d.ts.map +1 -1
  24. package/dist/client.js +320 -11
  25. package/dist/client.js.map +1 -1
  26. package/dist/create/arkade.d.ts.map +1 -1
  27. package/dist/create/arkade.js +2 -0
  28. package/dist/create/arkade.js.map +1 -1
  29. package/dist/create/bitcoin.d.ts.map +1 -1
  30. package/dist/create/bitcoin.js +2 -0
  31. package/dist/create/bitcoin.js.map +1 -1
  32. package/dist/create/index.d.ts +1 -1
  33. package/dist/create/index.d.ts.map +1 -1
  34. package/dist/create/lightning.d.ts.map +1 -1
  35. package/dist/create/lightning.js +2 -0
  36. package/dist/create/lightning.js.map +1 -1
  37. package/dist/create/types.d.ts +49 -3
  38. package/dist/create/types.d.ts.map +1 -1
  39. package/dist/evm/index.d.ts +1 -0
  40. package/dist/evm/index.d.ts.map +1 -1
  41. package/dist/evm/index.js +1 -0
  42. package/dist/evm/index.js.map +1 -1
  43. package/dist/evm/wallet.d.ts +164 -0
  44. package/dist/evm/wallet.d.ts.map +1 -0
  45. package/dist/evm/wallet.js +133 -0
  46. package/dist/evm/wallet.js.map +1 -0
  47. package/dist/generated/api.d.ts +44 -0
  48. package/dist/generated/api.d.ts.map +1 -1
  49. package/dist/index.d.ts +4 -3
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +4 -2
  52. package/dist/index.js.map +1 -1
  53. package/dist/tokens.d.ts +90 -7
  54. package/dist/tokens.d.ts.map +1 -1
  55. package/dist/tokens.js +151 -13
  56. package/dist/tokens.js.map +1 -1
  57. package/package.json +1 -1
package/README.md CHANGED
@@ -15,28 +15,19 @@ This SDK supports the following swap directions:
15
15
 
16
16
  ### BTC to EVM
17
17
 
18
- | Source | Target | Status |
19
- | ------------ | --------------------------- | --------- |
20
- | Lightning | Polygon (USDC, USDT) | Supported |
21
- | Lightning | Arbitrum (USDC, USDT) | Supported |
22
- | Lightning | Ethereum (USDC, USDT, WBTC) | Supported |
23
- | Arkade | Polygon (USDC, USDT) | Supported |
24
- | Arkade | Arbitrum (USDC, USDT) | Supported |
25
- | Arkade | Ethereum (USDC, USDT, WBTC) | Supported |
26
- | On-chain BTC | Polygon (USDC, USDT) | Supported |
27
- | On-chain BTC | Arbitrum (USDC, USDT) | Supported |
28
- | On-chain BTC | Ethereum (USDC, USDT, WBTC) | Supported |
18
+ | Source | Target | Status |
19
+ | --------- | --------------------------- | --------- |
20
+ | Lightning | Ethereum, Polygon, Arbitrum | Supported |
21
+ | Arkade | Ethereum, Polygon, Arbitrum | Supported |
22
+ | On-chain | Ethereum, Polygon, Arbitrum | Supported |
29
23
 
30
24
  ### EVM to BTC
31
25
 
32
26
  | Source | Target | Status |
33
27
  | --------------------------- | --------- | --------- |
34
- | Polygon (USDC, USDT) | Arkade | Supported |
35
- | Polygon (USDC, USDT) | Lightning | Supported |
36
- | Arbitrum (USDC, USDT) | Arkade | Supported |
37
- | Arbitrum (USDC, USDT) | Lightning | Supported |
38
- | Ethereum (USDC, USDT, WBTC) | Arkade | Supported |
39
- | Ethereum (USDC, USDT, WBTC) | Lightning | Supported |
28
+ | Polygon, Arbitrus, Ethereum | Arkade | Supported |
29
+ | Polygon, Arbitrus, Ethereum | Lightning | Supported |
30
+ | Polygon, Arbitrus, Ethereum | On-chain | Supported |
40
31
 
41
32
  **Refund support:**
42
33
 
@@ -50,13 +41,12 @@ This SDK supports the following swap directions:
50
41
  ### Setup
51
42
 
52
43
  ```typescript
53
- import { Client, IdbWalletStorage, IdbSwapStorage } from "@lendasat/lendaswap-sdk-pure";
44
+ import {Client, IdbWalletStorage, IdbSwapStorage} from "@lendasat/lendaswap-sdk-pure";
54
45
 
55
46
  // Create a client with persistent storage (browser)
56
47
  const client = await Client.builder()
57
48
  .withSignerStorage(new IdbWalletStorage())
58
49
  .withSwapStorage(new IdbSwapStorage())
59
- .withApiKey("your-api-key")
60
50
  .build();
61
51
 
62
52
  // Or import an existing wallet
@@ -70,290 +60,178 @@ const client = await Client.builder()
70
60
  const mnemonic = client.getMnemonic();
71
61
  ```
72
62
 
73
- ### Get a Quote
63
+ ### Quotes
74
64
 
75
65
  ```typescript
76
- // Get available asset pairs
77
- const pairs = await client.getAssetPairs();
78
-
79
- // Get a quote for swapping 100k sats to USDC on Polygon
80
- const quote = await client.getQuote("btc_arkade", "usdc_pol", 100000);
66
+ import { Asset } from "@lendasat/lendaswap-sdk-pure";
67
+
68
+ const quote = await client.getQuote({
69
+ sourceChain: Asset.BTC_ARKADE.chain, // "Arkade"
70
+ sourceToken: Asset.BTC_ARKADE.tokenId, // "btc"
71
+ targetChain: Asset.USDC_POLYGON.chain, // "137"
72
+ targetToken: Asset.USDC_POLYGON.tokenId, // "0x3c499c..."
73
+ sourceAmount: 100_000, // sats
74
+ });
81
75
  console.log(`You'll receive: ${quote.target_amount} USDC`);
82
76
  ```
83
77
 
84
78
  ### Create a Swap
85
79
 
86
- #### Lightning to EVM
80
+ Use `createSwap` for all swap directions. The SDK routes automatically based on the source/target asset:
87
81
 
88
82
  ```typescript
89
- const result = await client.createLightningToEvmSwapGeneric({
90
- targetAddress: "0x1234567890abcdef1234567890abcdef12345678",
91
- tokenAddress: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", // USDC on Polygon
92
- evmChainId: 137, // 1 (Ethereum), 137 (Polygon), 42161 (Arbitrum)
93
- amountIn: 100000, // Amount in sats (or use amountOut for target amount)
83
+ // BTC EVM: Arkade to USDC on Polygon
84
+ const result = await client.createSwap({
85
+ source: Asset.BTC_ARKADE,
86
+ target: Asset.USDC_POLYGON,
87
+ sourceAmount: 100_000, // sats
88
+ targetAddress: "0x...", // your EVM address
94
89
  });
95
90
 
96
- // Pay the Lightning invoice to complete the swap
97
- console.log(`Pay this invoice: ${result.response.bolt11_invoice}`);
98
- console.log(`Swap ID: ${result.response.id}`);
99
- ```
100
-
101
- #### Arkade to EVM
91
+ // EVM BTC: USDC on Polygon to Arkade
92
+ const result = await client.createSwap({
93
+ source: Asset.USDC_POLYGON,
94
+ target: Asset.BTC_ARKADE,
95
+ sourceAmount: 10_000_000, // 10 USDC (6 decimals)
96
+ targetAddress: "ark1...", // your Arkade address
97
+ userAddress: "0x...", // your EVM wallet address (required for EVM-sourced swaps)
98
+ });
102
99
 
103
- ```typescript
104
- // Create an Arkade-to-EVM swap (any ERC-20 token via 1inch)
105
- const result = await client.createArkadeToEvmSwapGeneric({
106
- targetAddress: "0x1234567890abcdef1234567890abcdef12345678",
107
- tokenAddress: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", // USDC on Polygon
108
- evmChainId: 137,
109
- sourceAmount: 100000, // sats
100
+ // Or use any token by chain + contract address
101
+ const result = await client.createSwap({
102
+ source: { chain: "42161", tokenId: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831" }, // USDC on Arbitrum
103
+ target: Asset.BTC_LIGHTNING,
104
+ targetAddress: "lnbc...", // BOLT11 invoice
110
105
  });
111
106
 
112
- // Send BTC to the Arkade VHTLC address
113
- console.log(`Send BTC to: ${result.response.btc_vhtlc_address}`);
114
- console.log(`Swap ID: ${result.response.id}`);
115
-
116
- // Once the server has funded the EVM HTLC (status: "serverfunded"),
117
- // claim gaslessly — the server submits the tx on your behalf:
118
- const claimResult = await client.claimViaGasless(
119
- result.response.id,
120
- async (digest) => {
121
- // Sign the EIP-712 digest with your EVM wallet
122
- // e.g. using ethers.js: wallet.signMessage(ethers.getBytes(digest))
123
- return { v: 27, r: "0x...", s: "0x..." };
124
- },
125
- "0x1234567890abcdef1234567890abcdef12345678", // destination
126
- );
127
- console.log(`Claimed! TX: ${claimResult.txHash}`);
107
+ const swapId = result.response.id;
128
108
  ```
129
109
 
130
- #### On-chain BTC to EVM
110
+ ### Fund EVM-Sourced Swaps
111
+
112
+ EVM-sourced swaps need to be funded after creation. The SDK handles the full Permit2 flow (allowance check, ERC-20
113
+ approval, EIP-712 signing, transaction submission) in a single call:
131
114
 
132
115
  ```typescript
133
- const result = await client.createBitcoinToEvmSwap({
134
- targetAddress: "0x1234567890abcdef1234567890abcdef12345678",
135
- tokenAddress: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", // USDC on Polygon
136
- evmChainId: 137,
137
- sourceAmount: 100000, // sats
138
- });
116
+ // Fund with an external wallet
117
+ const {txHash} = await client.fundSwap(swapId, signer);
139
118
 
140
- // Send BTC to the on-chain HTLC address
141
- console.log(`Send BTC to: ${result.response.btc_htlc_address}`);
142
- console.log(`Swap ID: ${result.response.id}`);
119
+ // Or fund gaslessly (SDK signs internally, server submits via relay)
120
+ const {txHash} = await client.fundSwapGasless(swapId);
143
121
  ```
144
122
 
145
- #### EVM to Arkade
123
+ ### The EvmSigner Interface
146
124
 
147
- ```typescript
148
- const result = await client.createEvmToArkadeSwapGeneric({
149
- targetAddress: "ark1...", // Your Arkade address
150
- tokenAddress: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", // USDC on Polygon
151
- evmChainId: 137,
152
- userAddress: "0x...", // Your EVM wallet address
153
- sourceAmount: 100000000n, // Amount in token's smallest unit (e.g., 6 decimals for USDC)
154
- });
125
+ `EvmSigner` is a minimal wallet abstraction. Implement it once for your stack — the SDK stays free of EVM library
126
+ dependencies:
155
127
 
156
- // Fund the EVM HTLC via coordinator
157
- console.log(`Swap ID: ${result.response.id}`);
128
+ ```typescript
129
+ import type {EvmSigner} from "@lendasat/lendaswap-sdk-pure";
158
130
  ```
159
131
 
160
- #### EVM to Lightning
132
+ **wagmi / viem:**
161
133
 
162
134
  ```typescript
163
- const result = await client.createEvmToLightningSwapGeneric({
164
- lightningInvoice: "lnbc...", // BOLT11 invoice (amount derived from invoice)
165
- tokenAddress: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", // USDC on Polygon
166
- evmChainId: 137,
167
- userAddress: "0x...", // Your EVM wallet address
168
- });
169
-
170
- // Fund the EVM HTLC via coordinator
171
- console.log(`Swap ID: ${result.response.id}`);
135
+ import {createPublicClient, http} from "viem";
136
+
137
+ const publicClient = createPublicClient({chain, transport: http()});
138
+
139
+ const signer: EvmSigner = {
140
+ address: walletClient.account.address,
141
+ chainId: chain.id,
142
+ signTypedData: (td) =>
143
+ walletClient.signTypedData({...td, account: walletClient.account}),
144
+ sendTransaction: (tx) =>
145
+ walletClient.sendTransaction({to: tx.to, data: tx.data, chain, gas: tx.gas}),
146
+ waitForReceipt: (hash) =>
147
+ publicClient.waitForTransactionReceipt({hash}).then((r) => ({
148
+ status: r.status,
149
+ blockNumber: r.blockNumber,
150
+ transactionHash: r.transactionHash,
151
+ })),
152
+ getTransaction: (hash) =>
153
+ publicClient.getTransaction({hash}).then((tx) => ({
154
+ to: tx.to ?? null, input: tx.input, from: tx.from,
155
+ })),
156
+ call: (tx) =>
157
+ publicClient.call({to: tx.to, data: tx.data, account: tx.from, blockNumber: tx.blockNumber})
158
+ .then((r) => r.data ?? "0x"),
159
+ };
172
160
  ```
173
161
 
174
- #### EVM to Bitcoin (on-chain)
162
+ **ethers.js v6:**
175
163
 
176
164
  ```typescript
177
- const result = await client.createEvmToBitcoinSwap({
178
- tokenAddress: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", // USDC on Polygon
179
- evmChainId: 137,
180
- userAddress: "0x...", // Your EVM wallet address
181
- targetAddress: "bc1p...", // Your BTC address
182
- sourceAmount: 100000000n, // Amount in token's smallest unit
183
- });
184
-
185
- // Fund the EVM HTLC, then redeem BTC once server funds the BTC HTLC
186
- console.log(`Swap ID: ${result.response.id}`);
165
+ const signer: EvmSigner = {
166
+ address: await wallet.getAddress(),
167
+ chainId: Number((await wallet.provider.getNetwork()).chainId),
168
+ signTypedData: (td) =>
169
+ wallet.signTypedData(td.domain, td.types, td.message),
170
+ sendTransaction: (tx) =>
171
+ wallet.sendTransaction({to: tx.to, data: tx.data, gasLimit: tx.gas})
172
+ .then((r) => r.hash),
173
+ waitForReceipt: (hash) =>
174
+ wallet.provider.waitForTransaction(hash).then((r) => ({
175
+ status: r.status === 1 ? "success" : "reverted",
176
+ blockNumber: BigInt(r.blockNumber),
177
+ transactionHash: r.hash,
178
+ })
179
+ ),
180
+ getTransaction: (hash) =>
181
+ wallet.provider.getTransaction(hash).then((tx) => ({
182
+ to: tx.to, input: tx.data, from: tx.from,
183
+ })),
184
+ call: (tx) =>
185
+ wallet.provider.call({to: tx.to, data: tx.data, from: tx.from, blockTag: tx.blockNumber}),
186
+ };
187
187
  ```
188
188
 
189
189
  ### Monitor Swap Status
190
190
 
191
191
  ```typescript
192
- // Get current swap status
193
- const swap = await client.getSwap("swap-uuid");
192
+ const swap = await client.getSwap(swapId);
194
193
  console.log(`Status: ${swap.status}`);
195
194
 
196
- // Status flow: pending -> clientfunded -> serverfunded -> clientredeemed -> serverredeemed
195
+ // Status flow: pending clientfunded serverfunded clientredeemed serverredeemed
197
196
  ```
198
197
 
199
- ### Claim EVM Tokens
198
+ ### Claim
200
199
 
201
- Once the server has funded the EVM HTLC (`serverfunded` status), claim your tokens:
200
+ For BTC-to-EVM swaps, once the server has funded the EVM HTLC (`serverfunded`), claim your tokens:
202
201
 
203
202
  ```typescript
204
- // Gasless claim for Arkade-to-EVM swaps — the server submits the tx
205
- const claimResult = await client.claimViaGasless(
206
- "swap-uuid",
207
- async (digest) => {
208
- // Sign the EIP-712 digest with your EVM wallet
209
- return { v: 27, r: "0x...", s: "0x..." };
210
- },
211
- "0xYourDestinationAddress",
212
- );
213
- console.log(`Claim tx: ${claimResult.txHash}`);
214
-
215
- // For other swap types (Lightning/On-chain to EVM), use the existing claim:
216
- const result = await client.claim("swap-uuid");
203
+ const result = await client.claim(swapId);
217
204
  ```
218
205
 
219
- ### Refund (if swap times out)
206
+ ### Refund
220
207
 
221
- ```typescript
222
- // For on-chain BTC swaps
223
- const refundResult = await client.refundSwap("swap-uuid", {
224
- destinationAddress: "bc1q...", // Your Bitcoin address
225
- feeRateSatPerVb: 5,
226
- });
208
+ If a swap times out, refund your funds:
227
209
 
228
- // For Arkade swaps
229
- const refundResult = await client.refundSwap("swap-uuid", {
230
- destinationAddress: "ark1...", // Your Arkade address
210
+ ```typescript
211
+ // BTC swaps (on-chain or Arkade)
212
+ const result = await client.refundSwap(swapId, {
213
+ destinationAddress: "bc1q...", // or "ark1..."
231
214
  });
232
- ```
233
-
234
- ### Storage
235
-
236
- The SDK provides pluggable storage interfaces for persisting wallet and swap data.
237
- Browser storage uses [Dexie](https://dexie.org/) for IndexedDB access with the database name `lendaswap-v3`.
238
-
239
- **Storage Types:**
240
215
 
241
- - `WalletStorage` - Stores mnemonic and key derivation index
242
- - `SwapStorage` - Stores `StoredSwap` records (API response + client-side params)
216
+ // EVM swaps manual refund (after timelock expires, user pays gas)
217
+ const {txHash} = await client.refundEvmWithSigner(swapId, signer, "direct");
243
218
 
244
- **StoredSwap Structure:**
219
+ // EVM swaps — collaborative refund (instant, gasless, server cosigns)
220
+ const {txHash} = await client.collabRefundEvmWithSigner(swapId, signer, "swap-back");
245
221
 
246
- Each swap is stored with both the API response and client-side parameters needed for claim/refund operations:
247
-
248
- ```typescript
249
- interface StoredSwap {
250
- version: number; // Schema version for migrations
251
- swapId: string; // Primary key
252
- keyIndex: number; // Key derivation index
253
- response: GetSwapResponse; // Full API response
254
- publicKey: string; // Hex-encoded compressed public key
255
- preimage: string; // Hex-encoded preimage for claiming HTLCs
256
- preimageHash: string; // Hex-encoded hash lock
257
- secretKey: string; // Hex-encoded secret key for signing
258
- storedAt: number; // Timestamp when first stored
259
- updatedAt: number; // Timestamp when last updated
260
- }
222
+ // EVM swaps collaborative refund for gasless swaps (SDK signs internally)
223
+ const {txHash} = await client.collabRefundEvmSwap(swapId, "swap-back");
261
224
  ```
262
225
 
263
- **Usage:**
264
-
265
- ```typescript
266
- import {
267
- InMemoryWalletStorage,
268
- InMemorySwapStorage,
269
- IdbWalletStorage, // Browser only (IndexedDB via Dexie)
270
- IdbSwapStorage, // Browser only (IndexedDB via Dexie)
271
- idbStorageFactory, // Factory for creating IDB storage
272
- inMemoryStorageFactory,
273
- SWAP_STORAGE_VERSION,
274
- type StoredSwap,
275
- } from "@lendasat/lendaswap-sdk-pure";
276
-
277
- // In-memory storage (for testing or temporary sessions)
278
- const walletStorage = new InMemoryWalletStorage();
279
- const swapStorage = new InMemorySwapStorage();
280
-
281
- // IndexedDB storage (for browser persistence)
282
- // Uses shared "lendaswap-v3" database with "wallet" and "swaps" tables
283
- const walletStorage = new IdbWalletStorage();
284
- const swapStorage = new IdbSwapStorage();
285
-
286
- // Store a swap
287
- await swapStorage.store({
288
- version: SWAP_STORAGE_VERSION,
289
- swapId: "uuid",
290
- keyIndex: 0,
291
- response: apiResponse,
292
- publicKey: "02...",
293
- preimage: "...",
294
- preimageHash: "...",
295
- secretKey: "...",
296
- storedAt: Date.now(),
297
- updatedAt: Date.now(),
298
- });
299
-
300
- // Update swap response (e.g., after polling for status)
301
- await swapStorage.update("uuid", newApiResponse);
302
-
303
- // Custom storage (implement the WalletStorage/SwapStorage interfaces)
304
- // For React Native, you might use AsyncStorage or SQLite
305
- ```
226
+ Refund mode controls what token you receive:
306
227
 
307
- ## Development
228
+ - `"direct"` — refund as WBTC/TBTC (the HTLC lock token)
229
+ - `"swap-back"` — refund as the original source token (e.g., USDC) via DEX swap
308
230
 
309
- ### Project Structure
231
+ ### Storage
310
232
 
311
- ```
312
- src/
313
- ├── api/
314
- │ └── client.ts # Low-level API client wrapper
315
- ├── generated/
316
- │ └── api.ts # Auto-generated types from OpenAPI spec
317
- ├── create/
318
- │ ├── index.ts # Swap creation exports
319
- │ ├── types.ts # Type definitions for swap creation
320
- │ ├── arkade.ts # Arkade-to-EVM swap creation
321
- │ ├── bitcoin.ts # Bitcoin-to-EVM swap creation
322
- │ ├── bitcoin-to-arkade.ts # Bitcoin-to-Arkade swap creation
323
- │ ├── evm-to-arkade.ts # EVM-to-Arkade swap creation
324
- │ ├── evm-to-bitcoin.ts # EVM-to-Bitcoin swap creation
325
- │ ├── evm-to-lightning.ts # EVM-to-Lightning swap creation
326
- │ └── lightning.ts # Lightning-to-EVM swap creation
327
- ├── redeem/
328
- │ ├── index.ts # Claim/redeem operation exports
329
- │ ├── arkade.ts # Arkade claim logic
330
- │ ├── ethereum.ts # Ethereum claim logic
331
- │ └── gasless.ts # Gasless claim logic
332
- ├── refund/
333
- │ ├── index.ts # Refund operation exports
334
- │ ├── arkade.ts # Arkade refund logic
335
- │ └── onchain.ts # On-chain refund logic
336
- ├── evm/
337
- │ ├── index.ts # EVM HTLC utilities
338
- │ ├── coordinator.ts # Coordinator interaction
339
- │ ├── htlc.ts # HTLC contract utilities
340
- │ └── signing.ts # EVM signing utilities
341
- ├── signer/
342
- │ └── index.ts # HD wallet key derivation (BIP39/BIP32)
343
- ├── storage/
344
- │ ├── index.ts # Storage interfaces and in-memory implementations
345
- │ ├── idb.ts # IndexedDB storage for browsers
346
- │ ├── sqlite.ts # SQLite storage for Node.js
347
- │ └── types.ts # StoredSwap type definition
348
- ├── client.ts # High-level Client class with convenience methods
349
- ├── arkade.ts # Arkade VHTLC query utilities
350
- ├── delegate.ts # Delegate settlement utilities
351
- ├── tokens.ts # Token helpers and constants
352
- ├── usd-price.ts # USD price fetching via CoinGecko
353
- ├── price-calculations.ts # Price calculation utilities
354
- ├── node.ts # Node.js-specific exports (SQLite storage)
355
- └── index.ts # Public exports
356
- ```
233
+ The SDK provides pluggable storage interfaces for persisting wallet and swap data.
234
+ Browser storage uses [Dexie](https://dexie.org/) for IndexedDB access with the database name `lendaswap-v3`.
357
235
 
358
236
  ### Auto-generated API Types
359
237
 
@@ -402,11 +280,3 @@ When adding new functionality:
402
280
  1. **API methods**: Add convenience methods to `src/client.ts` that wrap the low-level API calls
403
281
  2. **New types**: If the backend adds new endpoints, regenerate the API types first
404
282
  3. **Exports**: Update `src/index.ts` to export any new public types or classes
405
-
406
- ### Dependencies
407
-
408
- - `openapi-fetch` - Type-safe HTTP client for OpenAPI specs
409
- - `@noble/hashes` - Cryptographic hash functions
410
- - `@scure/bip32` - BIP32 HD wallet derivation
411
- - `@scure/bip39` - BIP39 mnemonic phrase handling
412
- - `dexie` - IndexedDB wrapper for browser storage
@@ -0,0 +1,35 @@
1
+ /**
2
+ * CCTP attestation client.
3
+ *
4
+ * Polls Circle's IRIS API for attestations after a USDC burn.
5
+ * Used on the destination chain to call MessageTransmitter.receiveMessage().
6
+ */
7
+ import { type CctpChainName } from "./constants.js";
8
+ export interface FetchAttestationOptions {
9
+ /** Source chain name (e.g. "Polygon"). */
10
+ sourceChain: CctpChainName;
11
+ /** Transaction hash of the burn on the source chain. */
12
+ txHash: string;
13
+ /** IRIS API base URL. Defaults to mainnet. */
14
+ irisApiUrl?: string;
15
+ /** Polling interval in ms. Defaults to 10000 (10s). */
16
+ pollIntervalMs?: number;
17
+ /** Maximum time to wait in ms. Defaults to 900000 (15min). */
18
+ timeoutMs?: number;
19
+ /** Optional abort signal. */
20
+ signal?: AbortSignal;
21
+ }
22
+ export interface AttestationResult {
23
+ /** Raw CCTP message bytes (hex with 0x prefix). */
24
+ message: string;
25
+ /** Attestation signature bytes (hex with 0x prefix). */
26
+ attestation: string;
27
+ }
28
+ /**
29
+ * Poll the IRIS V2 API until the attestation is ready for a given burn tx.
30
+ *
31
+ * @returns The message and attestation bytes needed to call receiveMessage().
32
+ * @throws If the attestation is not ready within the timeout, or the request fails.
33
+ */
34
+ export declare function fetchAttestation(options: FetchAttestationOptions): Promise<AttestationResult>;
35
+ //# sourceMappingURL=attestation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attestation.d.ts","sourceRoot":"","sources":["../../src/cctp/attestation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAEL,KAAK,aAAa,EAEnB,MAAM,gBAAgB,CAAC;AAGxB,MAAM,WAAW,uBAAuB;IACtC,0CAA0C;IAC1C,WAAW,EAAE,aAAa,CAAC;IAC3B,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CA4D5B"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * CCTP attestation client.
3
+ *
4
+ * Polls Circle's IRIS API for attestations after a USDC burn.
5
+ * Used on the destination chain to call MessageTransmitter.receiveMessage().
6
+ */
7
+ import { CCTP_DOMAINS, IRIS_API_MAINNET, } from "./constants.js";
8
+ /**
9
+ * Poll the IRIS V2 API until the attestation is ready for a given burn tx.
10
+ *
11
+ * @returns The message and attestation bytes needed to call receiveMessage().
12
+ * @throws If the attestation is not ready within the timeout, or the request fails.
13
+ */
14
+ export async function fetchAttestation(options) {
15
+ const { sourceChain, txHash, irisApiUrl = IRIS_API_MAINNET, pollIntervalMs = 10_000, timeoutMs = 900_000, signal, } = options;
16
+ const sourceDomain = CCTP_DOMAINS[sourceChain];
17
+ if (sourceDomain === undefined) {
18
+ throw new Error(`Unknown CCTP source chain: ${sourceChain}`);
19
+ }
20
+ const url = `${irisApiUrl}/v2/messages/${sourceDomain}?transactionHash=${txHash}`;
21
+ const startTime = Date.now();
22
+ while (Date.now() - startTime < timeoutMs) {
23
+ signal?.throwIfAborted();
24
+ try {
25
+ const response = await fetch(url);
26
+ if (response.status === 404) {
27
+ // Message not yet indexed, keep polling
28
+ await sleep(pollIntervalMs, signal);
29
+ continue;
30
+ }
31
+ if (!response.ok) {
32
+ throw new Error(`IRIS API error: ${response.status} ${response.statusText}`);
33
+ }
34
+ const data = await response.json();
35
+ if (data.messages.length > 0 && data.messages[0].status === "complete") {
36
+ return {
37
+ message: data.messages[0].message,
38
+ attestation: data.messages[0].attestation,
39
+ };
40
+ }
41
+ // Attestation pending, keep polling
42
+ await sleep(pollIntervalMs, signal);
43
+ }
44
+ catch (err) {
45
+ if (err instanceof DOMException && err.name === "AbortError") {
46
+ throw err;
47
+ }
48
+ // Network errors — retry after delay
49
+ await sleep(pollIntervalMs, signal);
50
+ }
51
+ }
52
+ throw new Error(`Attestation not ready after ${timeoutMs / 1000}s for tx ${txHash} on ${sourceChain}`);
53
+ }
54
+ function sleep(ms, signal) {
55
+ return new Promise((resolve, reject) => {
56
+ const timer = setTimeout(resolve, ms);
57
+ signal?.addEventListener("abort", () => {
58
+ clearTimeout(timer);
59
+ reject(new DOMException("Aborted", "AbortError"));
60
+ }, { once: true });
61
+ });
62
+ }
63
+ //# sourceMappingURL=attestation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attestation.js","sourceRoot":"","sources":["../../src/cctp/attestation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,YAAY,EAEZ,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAyBxB;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAgC;IAEhC,MAAM,EACJ,WAAW,EACX,MAAM,EACN,UAAU,GAAG,gBAAgB,EAC7B,cAAc,GAAG,MAAM,EACvB,SAAS,GAAG,OAAO,EACnB,MAAM,GACP,GAAG,OAAO,CAAC;IAEZ,MAAM,YAAY,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IAC/C,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,8BAA8B,WAAW,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,GAAG,GAAG,GAAG,UAAU,gBAAgB,YAAY,oBAAoB,MAAM,EAAE,CAAC;IAElF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,SAAS,EAAE,CAAC;QAC1C,MAAM,EAAE,cAAc,EAAE,CAAC;QAEzB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;YAElC,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC5B,wCAAwC;gBACxC,MAAM,KAAK,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;gBACpC,SAAS;YACX,CAAC;YAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CACb,mBAAmB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAC5D,CAAC;YACJ,CAAC;YAED,MAAM,IAAI,GAAwB,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YAExD,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;gBACvE,OAAO;oBACL,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO;oBACjC,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW;iBAC1C,CAAC;YACJ,CAAC;YAED,oCAAoC;YACpC,MAAM,KAAK,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,YAAY,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC7D,MAAM,GAAG,CAAC;YACZ,CAAC;YACD,qCAAqC;YACrC,MAAM,KAAK,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CACb,+BAA+B,SAAS,GAAG,IAAI,YAAY,MAAM,OAAO,WAAW,EAAE,CACtF,CAAC;AACJ,CAAC;AAED,SAAS,KAAK,CAAC,EAAU,EAAE,MAAoB;IAC7C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACtC,MAAM,EAAE,gBAAgB,CACtB,OAAO,EACP,GAAG,EAAE;YACH,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,IAAI,YAAY,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;QACpD,CAAC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * CCTP (Cross-Chain Transfer Protocol) constants.
3
+ *
4
+ * Uses CCTP V2 contracts which share the same address across all EVM chains.
5
+ * See: https://developers.circle.com/cctp/references/contract-addresses
6
+ */
7
+ export declare const TOKEN_MESSENGER_V2 = "0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d";
8
+ export declare const MESSAGE_TRANSMITTER_V2 = "0x81D40F21F12A8F0E3252Bccb954D722d4c464B64";
9
+ export declare const CCTP_DOMAINS: {
10
+ readonly Ethereum: 0;
11
+ readonly Avalanche: 1;
12
+ readonly Optimism: 2;
13
+ readonly Arbitrum: 3;
14
+ readonly Solana: 5;
15
+ readonly Base: 6;
16
+ readonly Polygon: 7;
17
+ readonly Unichain: 10;
18
+ readonly Linea: 11;
19
+ readonly Sonic: 13;
20
+ readonly "World Chain": 14;
21
+ readonly Monad: 15;
22
+ readonly Sei: 16;
23
+ readonly HyperEVM: 19;
24
+ readonly Ink: 21;
25
+ };
26
+ export type CctpChainName = keyof typeof CCTP_DOMAINS;
27
+ export declare const USDC_ADDRESSES: Record<string, string>;
28
+ export declare const TOKEN_MESSENGER_ADDRESSES: Record<string, string>;
29
+ export declare const MESSAGE_TRANSMITTER_ADDRESSES: Record<string, string>;
30
+ /**
31
+ * Magic hookData for Circle's Forwarding Service.
32
+ * Encodes "cctp-forward" + version 0 + data length 0.
33
+ * When passed to depositForBurnWithHook, Circle auto-mints on destination — zero gas needed.
34
+ */
35
+ export declare const FORWARDING_SERVICE_HOOK_DATA = "0x636374702d666f72776172640000000000000000000000000000000000000000";
36
+ /** Fast transfer finality threshold. */
37
+ export declare const FINALITY_FAST = 1000;
38
+ /** Standard transfer finality threshold. */
39
+ export declare const FINALITY_STANDARD = 2000;
40
+ /** Forwarding fee for Ethereum destination ($1.25 in USDC units). */
41
+ export declare const FORWARDING_FEE_ETHEREUM = 1250000n;
42
+ /** Forwarding fee for all other destinations ($0.20 in USDC units). */
43
+ export declare const FORWARDING_FEE_OTHER = 200000n;
44
+ export declare const IRIS_API_MAINNET = "https://iris-api.circle.com";
45
+ export declare const IRIS_API_TESTNET = "https://iris-api-sandbox.circle.com";
46
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/cctp/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,eAAO,MAAM,kBAAkB,+CAA+C,CAAC;AAC/E,eAAO,MAAM,sBAAsB,+CACW,CAAC;AAO/C,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;CAgBf,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,YAAY,CAAC;AAMtD,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAejD,CAAC;AAOF,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAG1D,CAAC;AAEJ,eAAO,MAAM,6BAA6B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAG9D,CAAC;AAMJ;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,uEAC6B,CAAC;AAEvE,wCAAwC;AACxC,eAAO,MAAM,aAAa,OAAO,CAAC;AAClC,4CAA4C;AAC5C,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAEtC,qEAAqE;AACrE,eAAO,MAAM,uBAAuB,WAAa,CAAC;AAClD,uEAAuE;AACvE,eAAO,MAAM,oBAAoB,UAAW,CAAC;AAM7C,eAAO,MAAM,gBAAgB,gCAAgC,CAAC;AAC9D,eAAO,MAAM,gBAAgB,wCAAwC,CAAC"}