@arkade-os/skill 0.1.1 → 0.1.3

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.
@@ -1,15 +1,12 @@
1
1
  /**
2
2
  * LendaSwapSkill - Swap USDC/USDT from/to Arkade via LendaSwap.
3
3
  *
4
- * This skill provides stablecoin swap capabilities for Arkade wallets
5
- * using the LendaSwap SDK for non-custodial BTC/stablecoin exchanges.
4
+ * Uses the @lendasat/lendaswap-sdk-pure SDK for non-custodial
5
+ * BTC/stablecoin atomic swaps via HTLCs.
6
6
  *
7
7
  * @module skills/lendaswap
8
8
  */
9
- /**
10
- * Default LendaSwap API URL.
11
- */
12
- const DEFAULT_API_URL = "https://apilendaswap.lendasat.com/";
9
+ import { Client, InMemoryWalletStorage, InMemorySwapStorage, } from "@lendasat/lendaswap-sdk-pure";
13
10
  /**
14
11
  * Token decimals for stablecoins.
15
12
  */
@@ -21,392 +18,325 @@ const TOKEN_DECIMALS = {
21
18
  usdt_eth: 6,
22
19
  usdt_arb: 6,
23
20
  };
24
- function parseExpiry(raw, fallbackMs) {
25
- if (raw === null || raw === undefined) {
26
- return new Date(Date.now() + fallbackMs);
27
- }
28
- if (typeof raw === "string") {
29
- const parsed = new Date(raw);
30
- if (!Number.isNaN(parsed.getTime())) {
31
- return parsed;
32
- }
33
- }
34
- if (typeof raw === "number") {
35
- const ms = raw < 1000000000000 ? raw * 1000 : raw;
36
- return new Date(ms);
21
+ /**
22
+ * Map SDK swap status to our simplified status.
23
+ */
24
+ function mapSwapStatus(sdkStatus) {
25
+ switch (sdkStatus) {
26
+ case "pending":
27
+ return "pending";
28
+ case "clientfundingseen":
29
+ case "clientfunded":
30
+ return "funded";
31
+ case "serverfunded":
32
+ case "clientredeeming":
33
+ return "processing";
34
+ case "clientredeemed":
35
+ case "serverredeemed":
36
+ case "clientredeemedandclientrefunded":
37
+ return "completed";
38
+ case "expired":
39
+ case "clientfundedtoolate":
40
+ return "expired";
41
+ case "clientrefunded":
42
+ case "clientfundedserverrefunded":
43
+ case "clientrefundedserverfunded":
44
+ case "clientrefundedserverrefunded":
45
+ return "refunded";
46
+ case "clientinvalidfunded":
47
+ return "failed";
48
+ default:
49
+ return "pending";
37
50
  }
38
- return new Date(Date.now() + fallbackMs);
51
+ }
52
+ /**
53
+ * Check if a status is terminal (no longer active).
54
+ */
55
+ function isTerminalStatus(status) {
56
+ return (status === "completed" ||
57
+ status === "expired" ||
58
+ status === "refunded" ||
59
+ status === "failed");
39
60
  }
40
61
  /**
41
62
  * LendaSwapSkill provides stablecoin swap capabilities for Arkade wallets
42
- * using the LendaSwap SDK.
43
- *
44
- * This skill enables:
45
- * - Swapping BTC from Arkade to USDC/USDT on Polygon, Ethereum, or Arbitrum
46
- * - Receiving USDC/USDT and converting to BTC in your Arkade wallet
63
+ * using the LendaSwap SDK for non-custodial atomic swaps.
47
64
  *
48
65
  * @example
49
66
  * ```typescript
50
- * import { Wallet, SingleKey } from "@arkade-os/sdk";
51
- * import { LendaSwapSkill } from "@arkade-os/skill";
67
+ * const lendaswap = new LendaSwapSkill({ wallet });
52
68
  *
53
- * // Create a wallet
54
- * const wallet = await Wallet.create({
55
- * identity: SingleKey.fromHex(privateKeyHex),
56
- * arkServerUrl: "https://arkade.computer",
57
- * });
58
- *
59
- * // Create the LendaSwap skill
60
- * const lendaswap = new LendaSwapSkill({
61
- * wallet,
62
- * apiKey: process.env.LENDASWAP_API_KEY,
63
- * });
64
- *
65
- * // Get a quote for BTC to USDC
69
+ * // Get a quote
66
70
  * const quote = await lendaswap.getQuoteBtcToStablecoin(100000, "usdc_pol");
67
- * console.log("You'll receive:", quote.targetAmount, "USDC");
68
71
  *
69
- * // Execute the swap
72
+ * // Create a swap (BTC → USDC)
70
73
  * const result = await lendaswap.swapBtcToStablecoin({
71
74
  * targetAddress: "0x...",
72
75
  * targetToken: "usdc_pol",
73
76
  * targetChain: "polygon",
74
77
  * sourceAmount: 100000,
75
78
  * });
76
- * console.log("Swap created:", result.swapId);
79
+ *
80
+ * // Fund the VHTLC address from your Arkade wallet, then claim
81
+ * const claim = await lendaswap.claimSwap(result.swapId);
77
82
  * ```
78
83
  */
79
84
  export class LendaSwapSkill {
80
- /**
81
- * Creates a new LendaSwapSkill instance.
82
- *
83
- * @param config - Configuration options
84
- */
85
85
  constructor(config) {
86
86
  this.name = "lendaswap";
87
87
  this.description = "Swap USDC/USDT from/to Arkade via LendaSwap non-custodial exchange";
88
- this.version = "1.0.0";
89
- this.swapStorage = new Map();
88
+ this.version = "2.0.0";
89
+ this.client = null;
90
90
  this.wallet = config.wallet;
91
- this.apiUrl = config.apiUrl || DEFAULT_API_URL;
92
- this.apiKey = config.apiKey;
93
91
  this.referralCode = config.referralCode;
92
+ this.config = config;
94
93
  }
95
94
  /**
96
- * Check if the skill is available and properly configured.
95
+ * Get or create the LendaSwap SDK client (lazy initialization).
97
96
  */
97
+ async getClient() {
98
+ if (this.client)
99
+ return this.client;
100
+ const builder = Client.builder()
101
+ .withSignerStorage(this.config.walletStorage || new InMemoryWalletStorage())
102
+ .withSwapStorage(this.config.swapStorage || new InMemorySwapStorage());
103
+ if (this.config.apiUrl) {
104
+ builder.withBaseUrl(this.config.apiUrl);
105
+ }
106
+ if (this.config.apiKey) {
107
+ builder.withApiKey(this.config.apiKey);
108
+ }
109
+ if (this.config.esploraUrl) {
110
+ builder.withEsploraUrl(this.config.esploraUrl);
111
+ }
112
+ if (this.config.arkadeServerUrl) {
113
+ builder.withArkadeServerUrl(this.config.arkadeServerUrl);
114
+ }
115
+ if (this.config.mnemonic) {
116
+ builder.withMnemonic(this.config.mnemonic);
117
+ }
118
+ this.client = await builder.build();
119
+ return this.client;
120
+ }
98
121
  async isAvailable() {
99
122
  try {
100
- const response = await this.fetchApi("/pairs");
101
- return response.ok;
123
+ const client = await this.getClient();
124
+ const result = await client.healthCheck();
125
+ return result === "ok";
102
126
  }
103
127
  catch {
104
128
  return false;
105
129
  }
106
130
  }
107
131
  /**
108
- * Get a quote for swapping BTC to stablecoins.
132
+ * Get the LendaSwap mnemonic for persistence across sessions.
133
+ */
134
+ async getMnemonic() {
135
+ const client = await this.getClient();
136
+ return client.getMnemonic();
137
+ }
138
+ /**
139
+ * Get the API version info.
109
140
  */
141
+ async getVersion() {
142
+ const client = await this.getClient();
143
+ return client.getVersion();
144
+ }
110
145
  async getQuoteBtcToStablecoin(sourceAmount, targetToken) {
111
- const response = await this.fetchApi("/quote", {
112
- method: "POST",
113
- body: JSON.stringify({
114
- from: "btc_arkade",
115
- to: targetToken,
116
- amount: sourceAmount,
117
- }),
118
- });
119
- if (!response.ok) {
120
- throw new Error(`Failed to get quote: ${response.statusText}`);
121
- }
122
- const data = (await response.json());
146
+ const client = await this.getClient();
147
+ const quote = await client.getQuote("btc_arkade", targetToken, sourceAmount);
148
+ const rate = parseFloat(quote.exchange_rate);
149
+ const netSats = sourceAmount - quote.protocol_fee - quote.network_fee;
150
+ const targetAmount = (netSats / 1e8) * rate;
123
151
  return {
124
152
  sourceToken: "btc_arkade",
125
153
  targetToken,
126
154
  sourceAmount,
127
- targetAmount: data.targetAmount,
128
- exchangeRate: data.exchangeRate,
155
+ targetAmount,
156
+ exchangeRate: rate,
129
157
  fee: {
130
- amount: data.fee?.amount || 0,
131
- percentage: data.fee?.percentage || 0,
158
+ amount: quote.protocol_fee + quote.network_fee,
159
+ percentage: quote.protocol_fee_rate * 100,
132
160
  },
133
- expiresAt: parseExpiry(data.expiresAt, 60000),
161
+ expiresAt: new Date(Date.now() + 60000),
134
162
  };
135
163
  }
136
- /**
137
- * Get a quote for swapping stablecoins to BTC.
138
- */
139
164
  async getQuoteStablecoinToBtc(sourceAmount, sourceToken) {
140
- const response = await this.fetchApi("/quote", {
141
- method: "POST",
142
- body: JSON.stringify({
143
- from: sourceToken,
144
- to: "btc_arkade",
145
- amount: sourceAmount,
146
- }),
147
- });
148
- if (!response.ok) {
149
- throw new Error(`Failed to get quote: ${response.statusText}`);
150
- }
151
- const data = (await response.json());
165
+ const client = await this.getClient();
166
+ const quote = await client.getQuote(sourceToken, "btc_arkade", sourceAmount);
167
+ const rate = parseFloat(quote.exchange_rate);
168
+ const grossSats = (sourceAmount / rate) * 1e8;
169
+ const targetAmount = grossSats - quote.protocol_fee - quote.network_fee;
152
170
  return {
153
171
  sourceToken,
154
172
  targetToken: "btc_arkade",
155
173
  sourceAmount,
156
- targetAmount: data.targetAmount,
157
- exchangeRate: data.exchangeRate,
174
+ targetAmount: Math.max(0, Math.floor(targetAmount)),
175
+ exchangeRate: rate,
158
176
  fee: {
159
- amount: data.fee?.amount || 0,
160
- percentage: data.fee?.percentage || 0,
177
+ amount: quote.protocol_fee + quote.network_fee,
178
+ percentage: quote.protocol_fee_rate * 100,
161
179
  },
162
- expiresAt: parseExpiry(data.expiresAt, 60000),
180
+ expiresAt: new Date(Date.now() + 60000),
163
181
  };
164
182
  }
165
- /**
166
- * Swap BTC from Arkade to stablecoins on EVM.
167
- */
168
183
  async swapBtcToStablecoin(params) {
169
- const arkAddress = await this.wallet.getAddress();
170
- const response = await this.fetchApi("/swap/btc-to-evm", {
171
- method: "POST",
172
- body: JSON.stringify({
173
- sourceAddress: arkAddress,
174
- targetAddress: params.targetAddress,
175
- targetToken: params.targetToken,
176
- targetChain: params.targetChain,
177
- sourceAmount: params.sourceAmount,
178
- targetAmount: params.targetAmount,
179
- referralCode: params.referralCode || this.referralCode,
180
- }),
181
- });
182
- if (!response.ok) {
183
- throw new Error(`Failed to create swap: ${response.statusText}`);
184
- }
185
- const data = (await response.json());
186
- const resolvedSourceAmount = params.sourceAmount ?? data.sourceAmount ?? 0;
187
- // Store swap locally
188
- const storedSwap = {
189
- swapId: data.swapId,
190
- direction: "btc_to_stablecoin",
191
- status: "awaiting_funding",
192
- sourceToken: "btc_arkade",
184
+ const client = await this.getClient();
185
+ const result = await client.createArkadeToEvmSwap({
186
+ targetAddress: params.targetAddress,
193
187
  targetToken: params.targetToken,
194
- sourceAmount: resolvedSourceAmount,
195
- targetAmount: data.targetAmount || 0,
196
- exchangeRate: data.exchangeRate || 0,
197
- createdAt: Date.now(),
198
- response: data,
199
- };
200
- this.swapStorage.set(data.swapId, storedSwap);
188
+ targetChain: params.targetChain,
189
+ sourceAmount: params.sourceAmount,
190
+ targetAmount: params.targetAmount,
191
+ referralCode: params.referralCode || this.referralCode,
192
+ });
193
+ const resp = result.response;
201
194
  return {
202
- swapId: data.swapId,
203
- status: "awaiting_funding",
204
- sourceAmount: resolvedSourceAmount,
205
- targetAmount: data.targetAmount || 0,
206
- exchangeRate: data.exchangeRate || 0,
195
+ swapId: resp.id,
196
+ status: mapSwapStatus(resp.status),
197
+ sourceAmount: resp.source_amount,
198
+ targetAmount: resp.target_amount,
199
+ exchangeRate: 0,
207
200
  fee: {
208
- amount: data.fee?.amount || 0,
209
- percentage: data.fee?.percentage || 0,
201
+ amount: resp.fee_sats,
202
+ percentage: 0,
210
203
  },
211
- expiresAt: new Date(data.expiresAt || Date.now() + 3600000),
204
+ expiresAt: new Date(resp.vhtlc_refund_locktime * 1000),
212
205
  paymentDetails: {
213
- address: data.paymentAddress,
206
+ address: resp.htlc_address_arkade,
214
207
  },
215
208
  };
216
209
  }
217
- /**
218
- * Swap stablecoins from EVM to BTC on Arkade.
219
- */
220
210
  async swapStablecoinToBtc(params) {
221
- const arkAddress = await this.wallet.getAddress();
222
- const targetAddress = params.targetAddress || arkAddress;
223
- const response = await this.fetchApi("/swap/evm-to-arkade", {
224
- method: "POST",
225
- body: JSON.stringify({
226
- sourceChain: params.sourceChain,
227
- sourceToken: params.sourceToken,
228
- sourceAmount: params.sourceAmount,
229
- targetAddress,
230
- userAddress: params.userAddress,
231
- referralCode: params.referralCode || this.referralCode,
232
- }),
233
- });
234
- if (!response.ok) {
235
- throw new Error(`Failed to create swap: ${response.statusText}`);
236
- }
237
- const data = (await response.json());
238
- // Store swap locally
239
- const storedSwap = {
240
- swapId: data.swapId,
241
- direction: "stablecoin_to_btc",
242
- status: "awaiting_funding",
211
+ const client = await this.getClient();
212
+ const arkAddress = params.targetAddress || (await this.wallet.getAddress());
213
+ const result = await client.createEvmToArkadeSwap({
214
+ sourceChain: params.sourceChain,
243
215
  sourceToken: params.sourceToken,
244
- targetToken: "btc_arkade",
245
216
  sourceAmount: params.sourceAmount,
246
- targetAmount: data.targetAmount || 0,
247
- exchangeRate: data.exchangeRate || 0,
248
- createdAt: Date.now(),
249
- response: data,
250
- };
251
- this.swapStorage.set(data.swapId, storedSwap);
217
+ targetAddress: arkAddress,
218
+ userAddress: params.userAddress,
219
+ referralCode: params.referralCode || this.referralCode,
220
+ });
221
+ const resp = result.response;
252
222
  return {
253
- swapId: data.swapId,
254
- status: "awaiting_funding",
255
- sourceAmount: params.sourceAmount,
256
- targetAmount: data.targetAmount || 0,
257
- exchangeRate: data.exchangeRate || 0,
223
+ swapId: resp.id,
224
+ status: mapSwapStatus(resp.status),
225
+ sourceAmount: resp.source_amount,
226
+ targetAmount: resp.target_amount,
227
+ exchangeRate: 0,
258
228
  fee: {
259
- amount: data.fee?.amount || 0,
260
- percentage: data.fee?.percentage || 0,
229
+ amount: resp.fee_sats,
230
+ percentage: 0,
261
231
  },
262
- expiresAt: new Date(data.expiresAt || Date.now() + 3600000),
232
+ expiresAt: new Date(resp.evm_refund_locktime * 1000),
263
233
  paymentDetails: {
264
- address: data.htlcAddress,
265
- callData: data.fundingCallData,
234
+ address: resp.htlc_address_evm,
235
+ callData: resp.source_token_address,
266
236
  },
267
237
  };
268
238
  }
269
- /**
270
- * Get the status of a swap.
271
- */
272
239
  async getSwapStatus(swapId) {
273
- const response = await this.fetchApi(`/swap/${swapId}`);
274
- if (!response.ok) {
275
- throw new Error(`Failed to get swap status: ${response.statusText}`);
276
- }
277
- const data = (await response.json());
278
- // Update local storage
279
- const stored = this.swapStorage.get(swapId);
280
- if (stored) {
281
- stored.status = data.status;
282
- stored.txid = data.txid;
283
- if (data.status === "completed") {
284
- stored.completedAt = Date.now();
285
- }
286
- }
240
+ const client = await this.getClient();
241
+ const data = await client.getSwap(swapId, { updateStorage: true });
242
+ const direction = data.direction === "evm_to_btc"
243
+ ? "stablecoin_to_btc"
244
+ : "btc_to_stablecoin";
245
+ const status = mapSwapStatus(data.status);
287
246
  return {
288
247
  id: swapId,
289
- direction: data.direction || stored?.direction || "btc_to_stablecoin",
290
- status: data.status,
291
- sourceToken: data.sourceToken || stored?.sourceToken || "",
292
- targetToken: data.targetToken || stored?.targetToken || "",
293
- sourceAmount: data.sourceAmount || stored?.sourceAmount || 0,
294
- targetAmount: data.targetAmount || stored?.targetAmount || 0,
295
- exchangeRate: data.exchangeRate || stored?.exchangeRate || 0,
296
- createdAt: new Date(data.createdAt || stored?.createdAt || Date.now()),
297
- completedAt: data.completedAt ? new Date(data.completedAt) : undefined,
298
- txid: data.txid,
248
+ direction,
249
+ status,
250
+ sourceToken: data.source_token,
251
+ targetToken: data.target_token,
252
+ sourceAmount: data.source_amount,
253
+ targetAmount: data.target_amount,
254
+ exchangeRate: 0,
255
+ createdAt: new Date(data.created_at),
256
+ completedAt: status === "completed" ? new Date() : undefined,
257
+ txid: ("evm_htlc_claim_txid" in data
258
+ ? data.evm_htlc_claim_txid
259
+ : undefined) ?? undefined,
299
260
  };
300
261
  }
301
- /**
302
- * Get pending stablecoin swaps.
303
- */
304
262
  async getPendingSwaps() {
263
+ const client = await this.getClient();
264
+ const allSwaps = await client.listAllSwaps();
305
265
  const pending = [];
306
- for (const [id, swap] of this.swapStorage) {
307
- if (swap.status !== "completed" &&
308
- swap.status !== "expired" &&
309
- swap.status !== "refunded" &&
310
- swap.status !== "failed") {
266
+ for (const stored of allSwaps) {
267
+ const status = mapSwapStatus(stored.response.status);
268
+ if (!isTerminalStatus(status)) {
311
269
  try {
312
- const status = await this.getSwapStatus(id);
313
- pending.push(status);
270
+ const info = await this.getSwapStatus(stored.swapId);
271
+ pending.push(info);
314
272
  }
315
273
  catch {
316
- // Swap might not exist on server anymore
317
- pending.push({
318
- id,
319
- direction: swap.direction,
320
- status: swap.status,
321
- sourceToken: swap.sourceToken,
322
- targetToken: swap.targetToken,
323
- sourceAmount: swap.sourceAmount,
324
- targetAmount: swap.targetAmount,
325
- exchangeRate: swap.exchangeRate,
326
- createdAt: new Date(swap.createdAt),
327
- });
274
+ pending.push(this.storedSwapToInfo(stored));
328
275
  }
329
276
  }
330
277
  }
331
278
  return pending;
332
279
  }
333
- /**
334
- * Get stablecoin swap history.
335
- */
336
280
  async getSwapHistory() {
337
- const history = [];
338
- for (const [id, swap] of this.swapStorage) {
339
- history.push({
340
- id,
341
- direction: swap.direction,
342
- status: swap.status,
343
- sourceToken: swap.sourceToken,
344
- targetToken: swap.targetToken,
345
- sourceAmount: swap.sourceAmount,
346
- targetAmount: swap.targetAmount,
347
- exchangeRate: swap.exchangeRate,
348
- createdAt: new Date(swap.createdAt),
349
- completedAt: swap.completedAt ? new Date(swap.completedAt) : undefined,
350
- txid: swap.txid,
351
- });
352
- }
353
- return history.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
281
+ const client = await this.getClient();
282
+ const allSwaps = await client.listAllSwaps();
283
+ return allSwaps
284
+ .map((stored) => this.storedSwapToInfo(stored))
285
+ .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
354
286
  }
355
- /**
356
- * Get available trading pairs.
357
- */
358
287
  async getAvailablePairs() {
359
- const response = await this.fetchApi("/pairs");
360
- if (!response.ok) {
361
- throw new Error(`Failed to get pairs: ${response.statusText}`);
362
- }
363
- const data = (await response.json());
364
- return (data.pairs || data || []).map((pair) => ({
365
- from: pair.from || pair.source,
366
- to: pair.to || pair.target,
367
- minAmount: pair.minAmount || pair.min || 0,
368
- maxAmount: pair.maxAmount || pair.max || 0,
369
- feePercentage: pair.feePercentage || pair.fee || 0,
288
+ const client = await this.getClient();
289
+ const pairs = await client.getAssetPairs();
290
+ return pairs.map((pair) => ({
291
+ from: pair.source.token_id,
292
+ to: pair.target.token_id,
293
+ minAmount: 0,
294
+ maxAmount: 0,
295
+ feePercentage: 0,
370
296
  }));
371
297
  }
372
- /**
373
- * Claim funds from a completed swap.
374
- */
375
298
  async claimSwap(swapId) {
376
- const response = await this.fetchApi(`/swap/${swapId}/claim`, {
377
- method: "POST",
378
- });
379
- if (!response.ok) {
380
- throw new Error(`Failed to claim swap: ${response.statusText}`);
381
- }
382
- const data = (await response.json());
383
- // Update local storage
384
- const stored = this.swapStorage.get(swapId);
385
- if (stored) {
386
- stored.status = "completed";
387
- stored.completedAt = Date.now();
388
- stored.txid = data.txid;
389
- }
390
- return { txid: data.txid };
299
+ const client = await this.getClient();
300
+ const result = await client.claim(swapId);
301
+ return {
302
+ success: result.success,
303
+ message: result.message,
304
+ txHash: result.txHash,
305
+ chain: result.chain,
306
+ };
391
307
  }
392
- /**
393
- * Refund an expired or failed swap.
394
- */
395
- async refundSwap(swapId) {
396
- const response = await this.fetchApi(`/swap/${swapId}/refund`, {
397
- method: "POST",
398
- });
399
- if (!response.ok) {
400
- throw new Error(`Failed to refund swap: ${response.statusText}`);
401
- }
402
- const data = (await response.json());
403
- // Update local storage
404
- const stored = this.swapStorage.get(swapId);
405
- if (stored) {
406
- stored.status = "refunded";
407
- stored.txid = data.txid;
408
- }
409
- return { txid: data.txid };
308
+ async refundSwap(swapId, options) {
309
+ const client = await this.getClient();
310
+ const refundOptions = options?.destinationAddress
311
+ ? { destinationAddress: options.destinationAddress }
312
+ : undefined;
313
+ const result = await client.refundSwap(swapId, refundOptions);
314
+ return {
315
+ success: result.success,
316
+ message: result.message,
317
+ txId: result.txId,
318
+ refundAmount: result.refundAmount
319
+ ? Number(result.refundAmount)
320
+ : undefined,
321
+ };
322
+ }
323
+ async getEvmFundingCallData(swapId, tokenDecimals) {
324
+ const client = await this.getClient();
325
+ const data = await client.getEvmFundingCallData(swapId, tokenDecimals);
326
+ return {
327
+ approve: { to: data.approve.to, data: data.approve.data },
328
+ createSwap: { to: data.createSwap.to, data: data.createSwap.data },
329
+ };
330
+ }
331
+ async getEvmRefundCallData(swapId) {
332
+ const client = await this.getClient();
333
+ const data = await client.getEvmRefundCallData(swapId);
334
+ return {
335
+ to: data.to,
336
+ data: data.data,
337
+ timelockExpired: data.timelockExpired,
338
+ timelockExpiry: data.timelockExpiry,
339
+ };
410
340
  }
411
341
  /**
412
342
  * Get the underlying wallet instance.
@@ -421,32 +351,34 @@ export class LendaSwapSkill {
421
351
  return TOKEN_DECIMALS[token] || 6;
422
352
  }
423
353
  /**
424
- * Helper to fetch from LendaSwap API.
354
+ * Convert a StoredSwap to StablecoinSwapInfo.
425
355
  */
426
- async fetchApi(path, options = {}) {
427
- const url = `${this.apiUrl.replace(/\/$/, "")}${path}`;
428
- return fetch(url, {
429
- ...options,
430
- headers: {
431
- "Content-Type": "application/json",
432
- "X-API-Key": this.apiKey,
433
- ...options.headers,
434
- },
435
- });
356
+ storedSwapToInfo(stored) {
357
+ const resp = stored.response;
358
+ const direction = resp.direction === "evm_to_btc"
359
+ ? "stablecoin_to_btc"
360
+ : "btc_to_stablecoin";
361
+ const status = mapSwapStatus(resp.status);
362
+ return {
363
+ id: stored.swapId,
364
+ direction,
365
+ status,
366
+ sourceToken: resp.source_token,
367
+ targetToken: resp.target_token,
368
+ sourceAmount: resp.source_amount,
369
+ targetAmount: resp.target_amount,
370
+ exchangeRate: 0,
371
+ createdAt: new Date(resp.created_at),
372
+ completedAt: status === "completed" ? new Date() : undefined,
373
+ };
436
374
  }
437
375
  }
438
376
  /**
439
- * Create a LendaSwapSkill from a wallet and API key.
440
- *
441
- * @param wallet - The Arkade wallet to use
442
- * @param apiKey - LendaSwap API key
443
- * @param options - Optional configuration
444
- * @returns A new LendaSwapSkill instance
377
+ * Create a LendaSwapSkill from a wallet.
445
378
  */
446
- export function createLendaSwapSkill(wallet, apiKey, options) {
379
+ export function createLendaSwapSkill(wallet, options) {
447
380
  return new LendaSwapSkill({
448
381
  wallet,
449
- apiKey,
450
382
  ...options,
451
383
  });
452
384
  }