@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.
- package/README.md +2 -3
- package/SKILL.md +9 -23
- package/cli/arkade.mjs +201 -174
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/skills/index.js +1 -4
- package/dist/cjs/skills/index.js.map +1 -1
- package/dist/cjs/skills/lendaswap.js +248 -316
- package/dist/cjs/skills/lendaswap.js.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/skills/index.js +1 -4
- package/dist/esm/skills/index.js.map +1 -1
- package/dist/esm/skills/lendaswap.js +248 -316
- package/dist/esm/skills/lendaswap.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/skills/index.d.ts +2 -5
- package/dist/types/skills/index.d.ts.map +1 -1
- package/dist/types/skills/lendaswap.d.ts +44 -82
- package/dist/types/skills/lendaswap.d.ts.map +1 -1
- package/dist/types/skills/types.d.ts +80 -12
- package/dist/types/skills/types.d.ts.map +1 -1
- package/package.json +4 -2
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LendaSwapSkill - Swap USDC/USDT from/to Arkade via LendaSwap.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
51
|
-
* import { LendaSwapSkill } from "@arkade-os/skill";
|
|
67
|
+
* const lendaswap = new LendaSwapSkill({ wallet });
|
|
52
68
|
*
|
|
53
|
-
* //
|
|
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
|
-
* //
|
|
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
|
-
*
|
|
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 = "
|
|
89
|
-
this.
|
|
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
|
-
*
|
|
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
|
|
101
|
-
|
|
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
|
|
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
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
|
128
|
-
exchangeRate:
|
|
155
|
+
targetAmount,
|
|
156
|
+
exchangeRate: rate,
|
|
129
157
|
fee: {
|
|
130
|
-
amount:
|
|
131
|
-
percentage:
|
|
158
|
+
amount: quote.protocol_fee + quote.network_fee,
|
|
159
|
+
percentage: quote.protocol_fee_rate * 100,
|
|
132
160
|
},
|
|
133
|
-
expiresAt:
|
|
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
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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:
|
|
157
|
-
exchangeRate:
|
|
174
|
+
targetAmount: Math.max(0, Math.floor(targetAmount)),
|
|
175
|
+
exchangeRate: rate,
|
|
158
176
|
fee: {
|
|
159
|
-
amount:
|
|
160
|
-
percentage:
|
|
177
|
+
amount: quote.protocol_fee + quote.network_fee,
|
|
178
|
+
percentage: quote.protocol_fee_rate * 100,
|
|
161
179
|
},
|
|
162
|
-
expiresAt:
|
|
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
|
|
170
|
-
const
|
|
171
|
-
|
|
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
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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:
|
|
203
|
-
status:
|
|
204
|
-
sourceAmount:
|
|
205
|
-
targetAmount:
|
|
206
|
-
exchangeRate:
|
|
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:
|
|
209
|
-
percentage:
|
|
201
|
+
amount: resp.fee_sats,
|
|
202
|
+
percentage: 0,
|
|
210
203
|
},
|
|
211
|
-
expiresAt: new Date(
|
|
204
|
+
expiresAt: new Date(resp.vhtlc_refund_locktime * 1000),
|
|
212
205
|
paymentDetails: {
|
|
213
|
-
address:
|
|
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
|
|
222
|
-
const
|
|
223
|
-
const
|
|
224
|
-
|
|
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
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
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:
|
|
254
|
-
status:
|
|
255
|
-
sourceAmount:
|
|
256
|
-
targetAmount:
|
|
257
|
-
exchangeRate:
|
|
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:
|
|
260
|
-
percentage:
|
|
229
|
+
amount: resp.fee_sats,
|
|
230
|
+
percentage: 0,
|
|
261
231
|
},
|
|
262
|
-
expiresAt: new Date(
|
|
232
|
+
expiresAt: new Date(resp.evm_refund_locktime * 1000),
|
|
263
233
|
paymentDetails: {
|
|
264
|
-
address:
|
|
265
|
-
callData:
|
|
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
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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
|
|
290
|
-
status
|
|
291
|
-
sourceToken: data.
|
|
292
|
-
targetToken: data.
|
|
293
|
-
sourceAmount: data.
|
|
294
|
-
targetAmount: data.
|
|
295
|
-
exchangeRate:
|
|
296
|
-
createdAt: new Date(data.
|
|
297
|
-
completedAt:
|
|
298
|
-
txid: data
|
|
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
|
|
307
|
-
|
|
308
|
-
|
|
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
|
|
313
|
-
pending.push(
|
|
270
|
+
const info = await this.getSwapStatus(stored.swapId);
|
|
271
|
+
pending.push(info);
|
|
314
272
|
}
|
|
315
273
|
catch {
|
|
316
|
-
|
|
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
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
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
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
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
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
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
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
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
|
-
*
|
|
354
|
+
* Convert a StoredSwap to StablecoinSwapInfo.
|
|
425
355
|
*/
|
|
426
|
-
|
|
427
|
-
const
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
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
|
|
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,
|
|
379
|
+
export function createLendaSwapSkill(wallet, options) {
|
|
447
380
|
return new LendaSwapSkill({
|
|
448
381
|
wallet,
|
|
449
|
-
apiKey,
|
|
450
382
|
...options,
|
|
451
383
|
});
|
|
452
384
|
}
|