@riftresearch/sdk 0.2.4 → 0.4.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/README.md +27 -26
- package/dist/index.d.ts +69 -43
- package/dist/index.js +150 -70
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,44 +13,41 @@ npm install @riftresearch/sdk
|
|
|
13
13
|
Then use it:
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
|
-
import { RiftSdk,
|
|
16
|
+
import { RiftSdk, Currencies, createCurrency } from '@riftresearch/sdk'
|
|
17
17
|
import { createPublicClient, createWalletClient, http } from 'viem'
|
|
18
18
|
import { privateKeyToAccount } from 'viem/accounts'
|
|
19
|
-
import {
|
|
19
|
+
import { ethereum } from 'viem/chains'
|
|
20
20
|
|
|
21
|
-
// Define USDC on Base
|
|
22
|
-
const USDC_BASE: Currency = {
|
|
23
|
-
chain: { kind: 'EVM', chainId: 8453 },
|
|
24
|
-
token: {
|
|
25
|
-
kind: 'TOKEN',
|
|
26
|
-
address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
27
|
-
decimals: 6,
|
|
28
|
-
},
|
|
29
|
-
}
|
|
30
21
|
|
|
31
22
|
// Setup viem clients
|
|
32
23
|
const account = privateKeyToAccount('0x...')
|
|
33
|
-
const publicClient = createPublicClient({ chain:
|
|
24
|
+
const publicClient = createPublicClient({ chain: ethereum, transport: http(process.env.ETH_RPC) })
|
|
34
25
|
const walletClient = createWalletClient({
|
|
35
26
|
account,
|
|
36
|
-
chain:
|
|
37
|
-
transport: http(),
|
|
27
|
+
chain: ethereum,
|
|
28
|
+
transport: http(process.env.ETH_RPC),
|
|
38
29
|
})
|
|
39
30
|
|
|
31
|
+
// Bitcoin sender implementation
|
|
32
|
+
const sendBitcoin = async ({ recipient, amountSats }) => {
|
|
33
|
+
// Implement your Bitcoin wallet connection, e.g.:
|
|
34
|
+
// window.bitcoin.transfer({ recipient, amountSats })
|
|
35
|
+
}
|
|
36
|
+
|
|
40
37
|
// Initialize SDK
|
|
41
|
-
const sdk = new RiftSdk({
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
const sdk = new RiftSdk({})
|
|
39
|
+
|
|
40
|
+
// Optionally create a custom ERC-20
|
|
41
|
+
const ethereumPepe = createCurrency({
|
|
42
|
+
chainId: 1,
|
|
43
|
+
address: '0x6982508145454Ce325dDbE47a25d4ec3d2311933',
|
|
44
|
+
decimals: 18,
|
|
48
45
|
})
|
|
49
46
|
|
|
50
47
|
// Get a quote
|
|
51
48
|
const { quote, executeSwap } = await sdk.getQuote({
|
|
52
|
-
from:
|
|
53
|
-
to: BTC,
|
|
49
|
+
from: Currencies.Ethereum.USDC,
|
|
50
|
+
to: Currencies.Bitcoin.BTC,
|
|
54
51
|
amount: '100000000', // 100 USDC (6 decimals)
|
|
55
52
|
mode: 'exact_input',
|
|
56
53
|
destinationAddress: 'bc1q...',
|
|
@@ -60,10 +57,14 @@ console.log(`Swapping ${quote.from.amount} USDC for ${quote.to.amount} sats`)
|
|
|
60
57
|
console.log(`Fees: $${quote.fees.totalUsd.toFixed(2)}`)
|
|
61
58
|
|
|
62
59
|
// Execute the swap
|
|
63
|
-
const swap = await executeSwap(
|
|
64
|
-
|
|
60
|
+
const swap = await executeSwap({
|
|
61
|
+
publicClient,
|
|
62
|
+
walletClient,
|
|
63
|
+
sendBitcoin,
|
|
64
|
+
})
|
|
65
|
+
console.log(`Swap ID: ${swap.swapId}`)
|
|
65
66
|
|
|
66
67
|
// Check status
|
|
67
|
-
const status = await sdk.
|
|
68
|
+
const status = await sdk.getSwapStatus(swap.swapId)
|
|
68
69
|
console.log(`Status: ${status.status}`)
|
|
69
70
|
```
|
package/dist/index.d.ts
CHANGED
|
@@ -127,9 +127,10 @@ interface ExactOutputQuoteResponse extends QuoteResponseBase {
|
|
|
127
127
|
* Use `mode` to determine which fields are specified vs calculated.
|
|
128
128
|
*/
|
|
129
129
|
type QuoteResponse = ExactInputQuoteResponse | ExactOutputQuoteResponse;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
declare const SWAP_STATUSES: readonly ["waiting_for_deposit", "deposit_confirming", "initiating_payout", "confirming_payout", "swap_complete", "refunding_user", "failed"];
|
|
131
|
+
type SwapStatus = (typeof SWAP_STATUSES)[number];
|
|
132
|
+
interface SwapStatusResponse {
|
|
133
|
+
status: SwapStatus;
|
|
133
134
|
destinationAddress: Address;
|
|
134
135
|
payoutTransaction?: TxHash;
|
|
135
136
|
depositTransaction?: TxHash;
|
|
@@ -192,22 +193,41 @@ interface BtcTransferStep {
|
|
|
192
193
|
*/
|
|
193
194
|
type ExecutionStep = EvmCallStep | BtcTransferStep;
|
|
194
195
|
/**
|
|
195
|
-
*
|
|
196
|
+
* Swap response with execution steps that the client must execute.
|
|
196
197
|
*/
|
|
197
|
-
interface
|
|
198
|
-
/** The Rift swap
|
|
198
|
+
interface SwapResponse {
|
|
199
|
+
/** The Rift swap ID */
|
|
199
200
|
swapId: string;
|
|
200
201
|
/** Normalized quote matching /quote response */
|
|
201
202
|
quote: QuoteResponse;
|
|
202
203
|
/** Ordered list of steps the client must execute */
|
|
203
204
|
executionSteps: ExecutionStep[];
|
|
204
205
|
}
|
|
205
|
-
/**
|
|
206
|
-
declare
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
206
|
+
/** Create an ERC-20 currency on an EVM chain */
|
|
207
|
+
declare function createCurrency(params: {
|
|
208
|
+
chainId: number;
|
|
209
|
+
address: string;
|
|
210
|
+
decimals: number;
|
|
211
|
+
}): Currency;
|
|
212
|
+
declare const Currencies: {
|
|
213
|
+
Bitcoin: {
|
|
214
|
+
BTC: Currency;
|
|
215
|
+
};
|
|
216
|
+
Ethereum: {
|
|
217
|
+
ETH: Currency;
|
|
218
|
+
WETH: Currency;
|
|
219
|
+
USDC: Currency;
|
|
220
|
+
USDT: Currency;
|
|
221
|
+
CBBTC: Currency;
|
|
222
|
+
WBTC: Currency;
|
|
223
|
+
};
|
|
224
|
+
Base: {
|
|
225
|
+
ETH: Currency;
|
|
226
|
+
WETH: Currency;
|
|
227
|
+
USDC: Currency;
|
|
228
|
+
CBBTC: Currency;
|
|
229
|
+
};
|
|
230
|
+
};
|
|
211
231
|
import { treaty } from "@elysiajs/eden";
|
|
212
232
|
import { Elysia } from "elysia";
|
|
213
233
|
declare const app: Elysia;
|
|
@@ -247,19 +267,19 @@ type App = typeof appTyped;
|
|
|
247
267
|
* console.log('Quote ID:', quote.id)
|
|
248
268
|
* console.log('You will receive:', quote.to.amount)
|
|
249
269
|
*
|
|
250
|
-
* // Create
|
|
251
|
-
* const { data:
|
|
270
|
+
* // Create a swap from the quote
|
|
271
|
+
* const { data: swap, error: swapError } = await api.swap.post({
|
|
252
272
|
* id: quote.id,
|
|
253
273
|
* destinationAddress: '0x...',
|
|
254
274
|
* refundAddress: 'bc1q...',
|
|
255
275
|
* })
|
|
256
276
|
*
|
|
257
|
-
* if (
|
|
258
|
-
* console.log('Deposit to:',
|
|
277
|
+
* if (swap) {
|
|
278
|
+
* console.log('Deposit to:', swap.deposit_vault_address)
|
|
259
279
|
* }
|
|
260
280
|
*
|
|
261
|
-
* // Check
|
|
262
|
-
* const { data: status } = await api.
|
|
281
|
+
* // Check swap status
|
|
282
|
+
* const { data: status } = await api.swap({ swapId: swap.id }).get()
|
|
263
283
|
* ```
|
|
264
284
|
*/
|
|
265
285
|
/** Type of the Rift API client */
|
|
@@ -304,8 +324,9 @@ interface SupportedModes {
|
|
|
304
324
|
* - ERC20 → BTC: exact_input only (1inch is exact-input quoting)
|
|
305
325
|
*/
|
|
306
326
|
declare function getSupportedModes(from: Currency, to: Currency): SupportedModes;
|
|
307
|
-
import { PublicClient, WalletClient } from "viem";
|
|
308
|
-
|
|
327
|
+
import { Account, PublicClient, Transport, WalletClient } from "viem";
|
|
328
|
+
import { Chain as Chain2 } from "viem/chains";
|
|
329
|
+
type RiftSwap = SwapStatusResponse;
|
|
309
330
|
interface TradeParameters {
|
|
310
331
|
/** The currency to swap from */
|
|
311
332
|
from: Currency;
|
|
@@ -325,11 +346,6 @@ interface TradeParameters {
|
|
|
325
346
|
* - "partial": approve only the sell amount
|
|
326
347
|
*/
|
|
327
348
|
approvalMode?: "full" | "partial";
|
|
328
|
-
/**
|
|
329
|
-
* Slippage tolerance for the 1inch swap leg, in basis points.
|
|
330
|
-
* e.g., 50 = 0.5%, 100 = 1%
|
|
331
|
-
*/
|
|
332
|
-
preswapSlippageBps?: number;
|
|
333
349
|
}
|
|
334
350
|
/**
|
|
335
351
|
* Base fields shared by all quote results.
|
|
@@ -369,14 +385,14 @@ interface ExactOutputQuoteResult extends QuoteResultBase {
|
|
|
369
385
|
type QuoteResult = ExactInputQuoteResult | ExactOutputQuoteResult;
|
|
370
386
|
interface GetQuoteResult {
|
|
371
387
|
quote: QuoteResult;
|
|
372
|
-
executeSwap: () => Promise<
|
|
388
|
+
executeSwap: <chain extends Chain2 | undefined = Chain2 | undefined>(context?: ExecuteSwapContext<chain>) => Promise<SwapResult>;
|
|
373
389
|
}
|
|
374
|
-
interface
|
|
390
|
+
interface SwapResult {
|
|
375
391
|
swapId: string;
|
|
376
392
|
status: SwapStatus2;
|
|
377
|
-
rift:
|
|
393
|
+
rift: RiftSwap;
|
|
378
394
|
}
|
|
379
|
-
type SwapStatus2 =
|
|
395
|
+
type SwapStatus2 = SwapStatus;
|
|
380
396
|
/**
|
|
381
397
|
* Function type for sending Bitcoin.
|
|
382
398
|
* Implementers provide this function to handle BTC transactions in their app.
|
|
@@ -403,13 +419,15 @@ type SendBitcoinFn = (params: {
|
|
|
403
419
|
/** Amount to send in satoshis */
|
|
404
420
|
amountSats: string;
|
|
405
421
|
}) => Promise<void>;
|
|
406
|
-
|
|
422
|
+
type ExecuteSwapContext<chain extends Chain2 | undefined = Chain2 | undefined> = {
|
|
407
423
|
/** Viem PublicClient for reading chain data */
|
|
408
|
-
publicClient
|
|
424
|
+
publicClient?: PublicClient<Transport, chain>;
|
|
409
425
|
/** Viem WalletClient for signing and sending transactions */
|
|
410
|
-
walletClient
|
|
426
|
+
walletClient?: WalletClient<Transport, chain, Account | undefined>;
|
|
411
427
|
/** Function to send Bitcoin (implement using your preferred wallet) */
|
|
412
|
-
sendBitcoin
|
|
428
|
+
sendBitcoin?: SendBitcoinFn;
|
|
429
|
+
};
|
|
430
|
+
interface RiftSdkOptions {
|
|
413
431
|
/** Rift API URL. Defaults to production API */
|
|
414
432
|
apiUrl?: string;
|
|
415
433
|
/** Optional preflight checks before executing swaps */
|
|
@@ -417,28 +435,32 @@ interface RiftSdkOptions {
|
|
|
417
435
|
/** Check sender balance before executing EVM steps (default: true) */
|
|
418
436
|
checkBalances?: boolean;
|
|
419
437
|
};
|
|
438
|
+
/** Name of the integrator using the SDK */
|
|
439
|
+
integratorName: string;
|
|
420
440
|
}
|
|
421
441
|
declare class RiftSdk {
|
|
422
442
|
private riftClient;
|
|
423
|
-
private publicClient;
|
|
424
|
-
private walletClient;
|
|
425
|
-
private sendBitcoinFn;
|
|
426
443
|
private preflightCheckBalances;
|
|
444
|
+
private integratorName;
|
|
427
445
|
constructor(options: RiftSdkOptions);
|
|
428
446
|
/**
|
|
429
447
|
* Get a quote for a swap and return a function to execute it.
|
|
430
448
|
*
|
|
431
449
|
* @example
|
|
432
450
|
* const { quote, executeSwap } = await sdk.getQuote({
|
|
433
|
-
* from:
|
|
434
|
-
* to: BTC,
|
|
451
|
+
* from: Currencies.Base.CBBTC,
|
|
452
|
+
* to: Currencies.Bitcoin.BTC,
|
|
435
453
|
* amount: '100000000', // 1 cbBTC
|
|
436
454
|
* mode: 'exact_input',
|
|
437
455
|
* destinationAddress: 'bc1q...',
|
|
438
456
|
* })
|
|
439
457
|
*
|
|
440
458
|
* console.log(`You'll receive: ${quote.to.amount} sats`)
|
|
441
|
-
* const swap = await executeSwap(
|
|
459
|
+
* const swap = await executeSwap({
|
|
460
|
+
* publicClient,
|
|
461
|
+
* walletClient,
|
|
462
|
+
* sendBitcoin,
|
|
463
|
+
* })
|
|
442
464
|
*/
|
|
443
465
|
getQuote(params: TradeParameters): Promise<GetQuoteResult>;
|
|
444
466
|
/**
|
|
@@ -456,15 +478,19 @@ declare class RiftSdk {
|
|
|
456
478
|
*/
|
|
457
479
|
private executeBtcTransferStep;
|
|
458
480
|
private buildQuoteResult;
|
|
459
|
-
private
|
|
481
|
+
private buildSwapResult;
|
|
460
482
|
private assertSufficientBalance;
|
|
461
483
|
private getAddress;
|
|
462
484
|
private getRefundAddress;
|
|
463
485
|
private assertEvmChainMatch;
|
|
464
486
|
private assertEvmChainMatchForSteps;
|
|
487
|
+
private requirePublicClient;
|
|
488
|
+
private requireWalletClient;
|
|
489
|
+
private requireSendBitcoin;
|
|
465
490
|
/**
|
|
466
|
-
* Get the current status of
|
|
491
|
+
* Get the current status of a swap by its ID.
|
|
467
492
|
*/
|
|
468
|
-
|
|
493
|
+
getSwapStatus(swapId: string): Promise<SwapStatusResponse>;
|
|
469
494
|
}
|
|
470
|
-
|
|
495
|
+
declare function createRiftSdk(options: RiftSdkOptions): RiftSdk;
|
|
496
|
+
export { getSupportedModes, detectRoute, createRiftSdk, createCurrency, createClient, TradeParameters, TokenIdentifier, SwapStatus2 as SwapStatus, SwapRoute, SwapResult, SwapResponse, SupportedModes, SendBitcoinFn, RiftSwap, RiftSdkOptions, RiftSdk, RiftClient, QuoteResult, NativeToken, GetQuoteResult, ExecutionStep, ExecutionAction, EvmChain, EvmCallStep, EvmCallKind, Erc20Token, Currency, Currencies, Chain, BtcTransferStep, BtcTransferKind, BitcoinChain, App };
|
package/dist/index.js
CHANGED
|
@@ -17,17 +17,73 @@ var CBBTC_TOKEN = {
|
|
|
17
17
|
address: CBBTC_ADDRESS,
|
|
18
18
|
decimals: 8
|
|
19
19
|
};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
function createCurrency(params) {
|
|
21
|
+
return {
|
|
22
|
+
chain: { kind: "EVM", chainId: params.chainId },
|
|
23
|
+
token: {
|
|
24
|
+
kind: "TOKEN",
|
|
25
|
+
address: params.address,
|
|
26
|
+
decimals: params.decimals
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
var Currencies = {
|
|
31
|
+
Bitcoin: {
|
|
32
|
+
BTC: {
|
|
33
|
+
chain: BTC_CHAIN,
|
|
34
|
+
token: { kind: "NATIVE", decimals: 8 }
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
Ethereum: {
|
|
38
|
+
ETH: {
|
|
39
|
+
chain: ETH_CHAIN,
|
|
40
|
+
token: { kind: "NATIVE", decimals: 18 }
|
|
41
|
+
},
|
|
42
|
+
WETH: createCurrency({
|
|
43
|
+
chainId: 1,
|
|
44
|
+
address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
45
|
+
decimals: 18
|
|
46
|
+
}),
|
|
47
|
+
USDC: createCurrency({
|
|
48
|
+
chainId: 1,
|
|
49
|
+
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
50
|
+
decimals: 6
|
|
51
|
+
}),
|
|
52
|
+
USDT: createCurrency({
|
|
53
|
+
chainId: 1,
|
|
54
|
+
address: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
|
|
55
|
+
decimals: 6
|
|
56
|
+
}),
|
|
57
|
+
CBBTC: {
|
|
58
|
+
chain: ETH_CHAIN,
|
|
59
|
+
token: CBBTC_TOKEN
|
|
60
|
+
},
|
|
61
|
+
WBTC: createCurrency({
|
|
62
|
+
chainId: 1,
|
|
63
|
+
address: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
64
|
+
decimals: 8
|
|
65
|
+
})
|
|
66
|
+
},
|
|
67
|
+
Base: {
|
|
68
|
+
ETH: {
|
|
69
|
+
chain: BASE_CHAIN,
|
|
70
|
+
token: { kind: "NATIVE", decimals: 18 }
|
|
71
|
+
},
|
|
72
|
+
WETH: createCurrency({
|
|
73
|
+
chainId: 8453,
|
|
74
|
+
address: "0x4200000000000000000000000000000000000006",
|
|
75
|
+
decimals: 18
|
|
76
|
+
}),
|
|
77
|
+
USDC: createCurrency({
|
|
78
|
+
chainId: 8453,
|
|
79
|
+
address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
80
|
+
decimals: 6
|
|
81
|
+
}),
|
|
82
|
+
CBBTC: {
|
|
83
|
+
chain: BASE_CHAIN,
|
|
84
|
+
token: CBBTC_TOKEN
|
|
85
|
+
}
|
|
86
|
+
}
|
|
31
87
|
};
|
|
32
88
|
// src/apiClient.ts
|
|
33
89
|
class SwapRouterApiError extends Error {
|
|
@@ -79,14 +135,14 @@ class SwapRouterClient {
|
|
|
79
135
|
async quote(request) {
|
|
80
136
|
return this.request("POST", "/quote", request);
|
|
81
137
|
}
|
|
82
|
-
async
|
|
83
|
-
return this.request("POST", "/
|
|
138
|
+
async createSwap(request) {
|
|
139
|
+
return this.request("POST", "/swap", request);
|
|
84
140
|
}
|
|
85
|
-
async
|
|
86
|
-
return this.request("GET", `/
|
|
141
|
+
async getSwap(swapId) {
|
|
142
|
+
return this.request("GET", `/swap/${swapId}`);
|
|
87
143
|
}
|
|
88
|
-
async reportStepResult(
|
|
89
|
-
await this.request("POST", `/
|
|
144
|
+
async reportStepResult(swapId, result) {
|
|
145
|
+
await this.request("POST", `/swap/${swapId}/tx`, result);
|
|
90
146
|
}
|
|
91
147
|
}
|
|
92
148
|
// src/client.ts
|
|
@@ -154,18 +210,14 @@ function getSupportedModes(from, to) {
|
|
|
154
210
|
import { erc20Abi } from "viem";
|
|
155
211
|
class RiftSdk {
|
|
156
212
|
riftClient;
|
|
157
|
-
publicClient;
|
|
158
|
-
walletClient;
|
|
159
|
-
sendBitcoinFn;
|
|
160
213
|
preflightCheckBalances;
|
|
214
|
+
integratorName;
|
|
161
215
|
constructor(options) {
|
|
162
216
|
this.riftClient = new SwapRouterClient({
|
|
163
217
|
baseUrl: options.apiUrl ?? "https://router-api-v2-production.up.railway.app"
|
|
164
218
|
});
|
|
165
|
-
this.publicClient = options.publicClient;
|
|
166
|
-
this.walletClient = options.walletClient;
|
|
167
|
-
this.sendBitcoinFn = options.sendBitcoin;
|
|
168
219
|
this.preflightCheckBalances = options.preflight?.checkBalances !== false;
|
|
220
|
+
this.integratorName = options.integratorName;
|
|
169
221
|
}
|
|
170
222
|
async getQuote(params) {
|
|
171
223
|
const route = detectRoute(params.from, params.to);
|
|
@@ -181,50 +233,53 @@ class RiftSdk {
|
|
|
181
233
|
const isChained = route.type === "direct_rift" && route.direction === "from_btc" && !isCbBtc(params.to);
|
|
182
234
|
return {
|
|
183
235
|
quote,
|
|
184
|
-
executeSwap: async () => {
|
|
185
|
-
const refundAddress = params.refundAddress ?? this.getRefundAddress(params);
|
|
236
|
+
executeSwap: async (context = {}) => {
|
|
237
|
+
const refundAddress = params.refundAddress ?? this.getRefundAddress(params, context);
|
|
186
238
|
if (this.preflightCheckBalances) {
|
|
187
|
-
await this.assertSufficientBalance(params.from, quote.from.amount);
|
|
239
|
+
await this.assertSufficientBalance(params.from, quote.from.amount, context);
|
|
188
240
|
}
|
|
189
|
-
const
|
|
241
|
+
const swapResponse = await this.riftClient.createSwap({
|
|
190
242
|
id: riftQuote.id,
|
|
191
243
|
destinationAddress: params.destinationAddress,
|
|
192
244
|
refundAddress,
|
|
245
|
+
integratorName: this.integratorName,
|
|
193
246
|
approvalMode: params.approvalMode
|
|
194
247
|
});
|
|
195
|
-
this.assertEvmChainMatchForSteps(
|
|
196
|
-
for (const step of
|
|
197
|
-
const result = await this.executeStep(step);
|
|
248
|
+
this.assertEvmChainMatchForSteps(swapResponse.executionSteps, context);
|
|
249
|
+
for (const step of swapResponse.executionSteps) {
|
|
250
|
+
const result = await this.executeStep(step, context);
|
|
198
251
|
if (isMonochain && step.action === "evm_call" && step.kind === "oneinch_swap" && result.txHash) {
|
|
199
|
-
await this.riftClient.reportStepResult(
|
|
252
|
+
await this.riftClient.reportStepResult(swapResponse.swapId, {
|
|
200
253
|
stepId: step.id,
|
|
201
254
|
...result
|
|
202
255
|
});
|
|
203
256
|
}
|
|
204
257
|
}
|
|
205
|
-
const swap = await this.riftClient.
|
|
206
|
-
return this.
|
|
258
|
+
const swap = await this.riftClient.getSwap(swapResponse.swapId);
|
|
259
|
+
return this.buildSwapResult(swap, {
|
|
207
260
|
chained: isChained,
|
|
208
|
-
|
|
261
|
+
riftSwapId: swapResponse.swapId
|
|
209
262
|
});
|
|
210
263
|
}
|
|
211
264
|
};
|
|
212
265
|
}
|
|
213
|
-
async executeStep(step) {
|
|
266
|
+
async executeStep(step, context) {
|
|
214
267
|
switch (step.action) {
|
|
215
268
|
case "evm_call":
|
|
216
|
-
return this.executeEvmCallStep(step);
|
|
269
|
+
return this.executeEvmCallStep(step, context);
|
|
217
270
|
case "btc_transfer":
|
|
218
|
-
return this.executeBtcTransferStep(step);
|
|
271
|
+
return this.executeBtcTransferStep(step, context);
|
|
219
272
|
}
|
|
220
273
|
}
|
|
221
|
-
async executeEvmCallStep(step) {
|
|
222
|
-
const
|
|
274
|
+
async executeEvmCallStep(step, context) {
|
|
275
|
+
const walletClient = this.requireWalletClient(context);
|
|
276
|
+
const publicClient = this.requirePublicClient(context);
|
|
277
|
+
const account = walletClient.account;
|
|
223
278
|
if (!account) {
|
|
224
279
|
throw new Error("No account configured on wallet client");
|
|
225
280
|
}
|
|
226
281
|
if (step.kind === "approval" && step.tokenAddress && step.spenderAddress && step.amount) {
|
|
227
|
-
const allowance = await
|
|
282
|
+
const allowance = await publicClient.readContract({
|
|
228
283
|
address: step.tokenAddress,
|
|
229
284
|
abi: erc20Abi,
|
|
230
285
|
functionName: "allowance",
|
|
@@ -234,18 +289,18 @@ class RiftSdk {
|
|
|
234
289
|
return {};
|
|
235
290
|
}
|
|
236
291
|
}
|
|
237
|
-
const txHash = await
|
|
292
|
+
const txHash = await walletClient.sendTransaction({
|
|
238
293
|
account,
|
|
239
294
|
to: step.to,
|
|
240
295
|
data: step.calldata,
|
|
241
|
-
value: step.value ? BigInt(step.value) : undefined
|
|
242
|
-
chain: this.walletClient.chain
|
|
296
|
+
value: step.value ? BigInt(step.value) : undefined
|
|
243
297
|
});
|
|
244
|
-
await
|
|
298
|
+
await publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
245
299
|
return { txHash };
|
|
246
300
|
}
|
|
247
|
-
async executeBtcTransferStep(step) {
|
|
248
|
-
|
|
301
|
+
async executeBtcTransferStep(step, context) {
|
|
302
|
+
const sendBitcoin = this.requireSendBitcoin(context);
|
|
303
|
+
await sendBitcoin({
|
|
249
304
|
recipient: step.toAddress,
|
|
250
305
|
amountSats: step.amountSats
|
|
251
306
|
});
|
|
@@ -272,31 +327,32 @@ class RiftSdk {
|
|
|
272
327
|
};
|
|
273
328
|
}
|
|
274
329
|
}
|
|
275
|
-
|
|
276
|
-
const
|
|
277
|
-
if (!
|
|
278
|
-
throw new Error("Missing rift
|
|
330
|
+
buildSwapResult(swap, options) {
|
|
331
|
+
const riftSwapId = options?.riftSwapId;
|
|
332
|
+
if (!riftSwapId) {
|
|
333
|
+
throw new Error("Missing rift swap id for swap result.");
|
|
279
334
|
}
|
|
280
335
|
return {
|
|
281
|
-
swapId:
|
|
336
|
+
swapId: riftSwapId,
|
|
282
337
|
status: swap.status,
|
|
283
338
|
rift: swap
|
|
284
339
|
};
|
|
285
340
|
}
|
|
286
|
-
async assertSufficientBalance(currency, amount) {
|
|
341
|
+
async assertSufficientBalance(currency, amount, context) {
|
|
287
342
|
if (currency.chain.kind !== "EVM")
|
|
288
343
|
return;
|
|
289
|
-
this.assertEvmChainMatch(currency.chain.chainId);
|
|
344
|
+
this.assertEvmChainMatch(currency.chain.chainId, context);
|
|
290
345
|
const required = BigInt(amount);
|
|
291
|
-
const owner = this.getAddress();
|
|
346
|
+
const owner = this.getAddress(context);
|
|
347
|
+
const publicClient = this.requirePublicClient(context);
|
|
292
348
|
if (currency.token.kind === "NATIVE") {
|
|
293
|
-
const balance2 = await
|
|
349
|
+
const balance2 = await publicClient.getBalance({ address: owner });
|
|
294
350
|
if (balance2 < required) {
|
|
295
351
|
throw new Error(`Insufficient balance for native token. Need ${required.toString()}, have ${balance2.toString()}`);
|
|
296
352
|
}
|
|
297
353
|
return;
|
|
298
354
|
}
|
|
299
|
-
const balance = await
|
|
355
|
+
const balance = await publicClient.readContract({
|
|
300
356
|
address: currency.token.address,
|
|
301
357
|
abi: erc20Abi,
|
|
302
358
|
functionName: "balanceOf",
|
|
@@ -306,28 +362,31 @@ class RiftSdk {
|
|
|
306
362
|
throw new Error(`Insufficient balance for token ${currency.token.address}. Need ${required.toString()}, have ${balance.toString()}`);
|
|
307
363
|
}
|
|
308
364
|
}
|
|
309
|
-
getAddress() {
|
|
310
|
-
const
|
|
365
|
+
getAddress(context) {
|
|
366
|
+
const walletClient = this.requireWalletClient(context);
|
|
367
|
+
const account = walletClient.account;
|
|
311
368
|
if (!account) {
|
|
312
369
|
throw new Error("No account configured on wallet client");
|
|
313
370
|
}
|
|
314
371
|
return account.address;
|
|
315
372
|
}
|
|
316
|
-
getRefundAddress(params) {
|
|
373
|
+
getRefundAddress(params, context) {
|
|
317
374
|
if (params.from.chain.kind === "BITCOIN") {
|
|
318
375
|
throw new Error("refundAddress is required for BTC swaps (Bitcoin refund address)");
|
|
319
376
|
}
|
|
320
|
-
return this.getAddress();
|
|
377
|
+
return this.getAddress(context);
|
|
321
378
|
}
|
|
322
|
-
assertEvmChainMatch(expectedChainId) {
|
|
323
|
-
const
|
|
379
|
+
assertEvmChainMatch(expectedChainId, context) {
|
|
380
|
+
const walletClient = this.requireWalletClient(context);
|
|
381
|
+
const publicClient = this.requirePublicClient(context);
|
|
382
|
+
const walletChainId = walletClient.chain?.id;
|
|
324
383
|
if (!walletChainId) {
|
|
325
384
|
throw new Error("Wallet client is missing an EVM chain configuration");
|
|
326
385
|
}
|
|
327
386
|
if (walletChainId !== expectedChainId) {
|
|
328
387
|
throw new Error(`Wallet client chain mismatch. Expected ${expectedChainId}, got ${walletChainId}`);
|
|
329
388
|
}
|
|
330
|
-
const publicChainId =
|
|
389
|
+
const publicChainId = publicClient.chain?.id;
|
|
331
390
|
if (!publicChainId) {
|
|
332
391
|
throw new Error("Public client is missing an EVM chain configuration");
|
|
333
392
|
}
|
|
@@ -335,7 +394,7 @@ class RiftSdk {
|
|
|
335
394
|
throw new Error(`Public client chain mismatch. Expected ${expectedChainId}, got ${publicChainId}`);
|
|
336
395
|
}
|
|
337
396
|
}
|
|
338
|
-
assertEvmChainMatchForSteps(steps) {
|
|
397
|
+
assertEvmChainMatchForSteps(steps, context) {
|
|
339
398
|
const evmSteps = steps.filter((step) => step.action === "evm_call");
|
|
340
399
|
const firstStep = evmSteps[0];
|
|
341
400
|
if (!firstStep)
|
|
@@ -346,18 +405,39 @@ class RiftSdk {
|
|
|
346
405
|
throw new Error(`Mixed EVM chain IDs in execution steps. Expected ${expectedChainId}, got ${step.chainId}`);
|
|
347
406
|
}
|
|
348
407
|
}
|
|
349
|
-
this.assertEvmChainMatch(expectedChainId);
|
|
408
|
+
this.assertEvmChainMatch(expectedChainId, context);
|
|
350
409
|
}
|
|
351
|
-
|
|
352
|
-
|
|
410
|
+
requirePublicClient(context) {
|
|
411
|
+
if (!context.publicClient) {
|
|
412
|
+
throw new Error("publicClient is required to execute EVM steps");
|
|
413
|
+
}
|
|
414
|
+
return context.publicClient;
|
|
415
|
+
}
|
|
416
|
+
requireWalletClient(context) {
|
|
417
|
+
if (!context.walletClient) {
|
|
418
|
+
throw new Error("walletClient is required to execute EVM steps");
|
|
419
|
+
}
|
|
420
|
+
return context.walletClient;
|
|
353
421
|
}
|
|
422
|
+
requireSendBitcoin(context) {
|
|
423
|
+
if (!context.sendBitcoin) {
|
|
424
|
+
throw new Error("sendBitcoin is required to execute BTC transfers");
|
|
425
|
+
}
|
|
426
|
+
return context.sendBitcoin;
|
|
427
|
+
}
|
|
428
|
+
async getSwapStatus(swapId) {
|
|
429
|
+
return this.riftClient.getSwap(swapId);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
function createRiftSdk(options) {
|
|
433
|
+
return new RiftSdk(options);
|
|
354
434
|
}
|
|
355
435
|
export {
|
|
356
436
|
getSupportedModes,
|
|
357
437
|
detectRoute,
|
|
438
|
+
createRiftSdk,
|
|
439
|
+
createCurrency,
|
|
358
440
|
createClient,
|
|
359
441
|
RiftSdk,
|
|
360
|
-
|
|
361
|
-
CBBTC_BASE,
|
|
362
|
-
BTC
|
|
442
|
+
Currencies
|
|
363
443
|
};
|