@riftresearch/sdk 0.3.0 → 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 CHANGED
@@ -28,15 +28,14 @@ const walletClient = createWalletClient({
28
28
  transport: http(process.env.ETH_RPC),
29
29
  })
30
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
+
31
37
  // Initialize SDK
32
- const sdk = new RiftSdk({
33
- publicClient,
34
- walletClient,
35
- sendBitcoin: async ({ recipient, amountSats }) => {
36
- // Implement your Bitcoin wallet connection, e.g.:
37
- // window.bitcoin.transfer({ recipient, amountSats })
38
- },
39
- })
38
+ const sdk = new RiftSdk({})
40
39
 
41
40
  // Optionally create a custom ERC-20
42
41
  const ethereumPepe = createCurrency({
@@ -58,10 +57,14 @@ console.log(`Swapping ${quote.from.amount} USDC for ${quote.to.amount} sats`)
58
57
  console.log(`Fees: $${quote.fees.totalUsd.toFixed(2)}`)
59
58
 
60
59
  // Execute the swap
61
- const swap = await executeSwap()
62
- console.log(`Swap ID: ${swap.swapId}`) // API order ID
60
+ const swap = await executeSwap({
61
+ publicClient,
62
+ walletClient,
63
+ sendBitcoin,
64
+ })
65
+ console.log(`Swap ID: ${swap.swapId}`)
63
66
 
64
67
  // Check status
65
- const status = await sdk.getOrderStatus(swap.swapId)
68
+ const status = await sdk.getSwapStatus(swap.swapId)
66
69
  console.log(`Status: ${status.status}`)
67
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
- type OrderStatus = "waiting_for_deposit" | "deposit_confirming" | "initiating_transfer" | "confirming_transfer" | "swap_complete" | "refunding_user" | "failed";
131
- interface OrderStatusResponse {
132
- status: OrderStatus;
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,10 +193,10 @@ interface BtcTransferStep {
192
193
  */
193
194
  type ExecutionStep = EvmCallStep | BtcTransferStep;
194
195
  /**
195
- * Order response with execution steps that the client must execute.
196
+ * Swap response with execution steps that the client must execute.
196
197
  */
197
- interface OrderResponse {
198
- /** The Rift swap/order ID */
198
+ interface SwapResponse {
199
+ /** The Rift swap ID */
199
200
  swapId: string;
200
201
  /** Normalized quote matching /quote response */
201
202
  quote: QuoteResponse;
@@ -266,19 +267,19 @@ type App = typeof appTyped;
266
267
  * console.log('Quote ID:', quote.id)
267
268
  * console.log('You will receive:', quote.to.amount)
268
269
  *
269
- * // Create an order from the quote
270
- * const { data: order, error: orderError } = await api.order.post({
270
+ * // Create a swap from the quote
271
+ * const { data: swap, error: swapError } = await api.swap.post({
271
272
  * id: quote.id,
272
273
  * destinationAddress: '0x...',
273
274
  * refundAddress: 'bc1q...',
274
275
  * })
275
276
  *
276
- * if (order) {
277
- * console.log('Deposit to:', order.deposit_vault_address)
277
+ * if (swap) {
278
+ * console.log('Deposit to:', swap.deposit_vault_address)
278
279
  * }
279
280
  *
280
- * // Check order status
281
- * const { data: status } = await api.order({ orderId: order.id }).get()
281
+ * // Check swap status
282
+ * const { data: status } = await api.swap({ swapId: swap.id }).get()
282
283
  * ```
283
284
  */
284
285
  /** Type of the Rift API client */
@@ -323,8 +324,9 @@ interface SupportedModes {
323
324
  * - ERC20 → BTC: exact_input only (1inch is exact-input quoting)
324
325
  */
325
326
  declare function getSupportedModes(from: Currency, to: Currency): SupportedModes;
326
- import { PublicClient, WalletClient } from "viem";
327
- type RiftOrder = OrderStatusResponse;
327
+ import { Account, PublicClient, Transport, WalletClient } from "viem";
328
+ import { Chain as Chain2 } from "viem/chains";
329
+ type RiftSwap = SwapStatusResponse;
328
330
  interface TradeParameters {
329
331
  /** The currency to swap from */
330
332
  from: Currency;
@@ -344,11 +346,6 @@ interface TradeParameters {
344
346
  * - "partial": approve only the sell amount
345
347
  */
346
348
  approvalMode?: "full" | "partial";
347
- /**
348
- * Slippage tolerance for the 1inch swap leg, in basis points.
349
- * e.g., 50 = 0.5%, 100 = 1%
350
- */
351
- preswapSlippageBps?: number;
352
349
  }
353
350
  /**
354
351
  * Base fields shared by all quote results.
@@ -388,14 +385,14 @@ interface ExactOutputQuoteResult extends QuoteResultBase {
388
385
  type QuoteResult = ExactInputQuoteResult | ExactOutputQuoteResult;
389
386
  interface GetQuoteResult {
390
387
  quote: QuoteResult;
391
- executeSwap: () => Promise<OrderResult>;
388
+ executeSwap: <chain extends Chain2 | undefined = Chain2 | undefined>(context?: ExecuteSwapContext<chain>) => Promise<SwapResult>;
392
389
  }
393
- interface OrderResult {
390
+ interface SwapResult {
394
391
  swapId: string;
395
392
  status: SwapStatus2;
396
- rift: RiftOrder;
393
+ rift: RiftSwap;
397
394
  }
398
- type SwapStatus2 = OrderStatus;
395
+ type SwapStatus2 = SwapStatus;
399
396
  /**
400
397
  * Function type for sending Bitcoin.
401
398
  * Implementers provide this function to handle BTC transactions in their app.
@@ -422,13 +419,15 @@ type SendBitcoinFn = (params: {
422
419
  /** Amount to send in satoshis */
423
420
  amountSats: string;
424
421
  }) => Promise<void>;
425
- interface RiftSdkOptions {
422
+ type ExecuteSwapContext<chain extends Chain2 | undefined = Chain2 | undefined> = {
426
423
  /** Viem PublicClient for reading chain data */
427
- publicClient: PublicClient;
424
+ publicClient?: PublicClient<Transport, chain>;
428
425
  /** Viem WalletClient for signing and sending transactions */
429
- walletClient: WalletClient;
426
+ walletClient?: WalletClient<Transport, chain, Account | undefined>;
430
427
  /** Function to send Bitcoin (implement using your preferred wallet) */
431
- sendBitcoin: SendBitcoinFn;
428
+ sendBitcoin?: SendBitcoinFn;
429
+ };
430
+ interface RiftSdkOptions {
432
431
  /** Rift API URL. Defaults to production API */
433
432
  apiUrl?: string;
434
433
  /** Optional preflight checks before executing swaps */
@@ -436,13 +435,13 @@ interface RiftSdkOptions {
436
435
  /** Check sender balance before executing EVM steps (default: true) */
437
436
  checkBalances?: boolean;
438
437
  };
438
+ /** Name of the integrator using the SDK */
439
+ integratorName: string;
439
440
  }
440
441
  declare class RiftSdk {
441
442
  private riftClient;
442
- private publicClient;
443
- private walletClient;
444
- private sendBitcoinFn;
445
443
  private preflightCheckBalances;
444
+ private integratorName;
446
445
  constructor(options: RiftSdkOptions);
447
446
  /**
448
447
  * Get a quote for a swap and return a function to execute it.
@@ -457,7 +456,11 @@ declare class RiftSdk {
457
456
  * })
458
457
  *
459
458
  * console.log(`You'll receive: ${quote.to.amount} sats`)
460
- * const swap = await executeSwap()
459
+ * const swap = await executeSwap({
460
+ * publicClient,
461
+ * walletClient,
462
+ * sendBitcoin,
463
+ * })
461
464
  */
462
465
  getQuote(params: TradeParameters): Promise<GetQuoteResult>;
463
466
  /**
@@ -475,15 +478,19 @@ declare class RiftSdk {
475
478
  */
476
479
  private executeBtcTransferStep;
477
480
  private buildQuoteResult;
478
- private buildOrderResult;
481
+ private buildSwapResult;
479
482
  private assertSufficientBalance;
480
483
  private getAddress;
481
484
  private getRefundAddress;
482
485
  private assertEvmChainMatch;
483
486
  private assertEvmChainMatchForSteps;
487
+ private requirePublicClient;
488
+ private requireWalletClient;
489
+ private requireSendBitcoin;
484
490
  /**
485
- * Get the current status of an order by its ID.
491
+ * Get the current status of a swap by its ID.
486
492
  */
487
- getOrderStatus(orderId: string): Promise<OrderStatusResponse>;
493
+ getSwapStatus(swapId: string): Promise<SwapStatusResponse>;
488
494
  }
489
- export { getSupportedModes, detectRoute, createCurrency, createClient, TradeParameters, TokenIdentifier, SwapStatus2 as SwapStatus, SwapRoute, SupportedModes, SendBitcoinFn, RiftSdkOptions, RiftSdk, RiftOrder, RiftClient, QuoteResult, OrderResult, OrderResponse, NativeToken, GetQuoteResult, ExecutionStep, ExecutionAction, EvmChain, EvmCallStep, EvmCallKind, Erc20Token, Currency, Currencies, Chain, BtcTransferStep, BtcTransferKind, BitcoinChain, App };
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
@@ -46,7 +46,7 @@ var Currencies = {
46
46
  }),
47
47
  USDC: createCurrency({
48
48
  chainId: 1,
49
- address: "0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
49
+ address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
50
50
  decimals: 6
51
51
  }),
52
52
  USDT: createCurrency({
@@ -135,14 +135,14 @@ class SwapRouterClient {
135
135
  async quote(request) {
136
136
  return this.request("POST", "/quote", request);
137
137
  }
138
- async createOrder(request) {
139
- return this.request("POST", "/order", request);
138
+ async createSwap(request) {
139
+ return this.request("POST", "/swap", request);
140
140
  }
141
- async getOrder(orderId) {
142
- return this.request("GET", `/order/${orderId}`);
141
+ async getSwap(swapId) {
142
+ return this.request("GET", `/swap/${swapId}`);
143
143
  }
144
- async reportStepResult(orderId, result) {
145
- await this.request("POST", `/order/${orderId}/tx`, result);
144
+ async reportStepResult(swapId, result) {
145
+ await this.request("POST", `/swap/${swapId}/tx`, result);
146
146
  }
147
147
  }
148
148
  // src/client.ts
@@ -210,18 +210,14 @@ function getSupportedModes(from, to) {
210
210
  import { erc20Abi } from "viem";
211
211
  class RiftSdk {
212
212
  riftClient;
213
- publicClient;
214
- walletClient;
215
- sendBitcoinFn;
216
213
  preflightCheckBalances;
214
+ integratorName;
217
215
  constructor(options) {
218
216
  this.riftClient = new SwapRouterClient({
219
217
  baseUrl: options.apiUrl ?? "https://router-api-v2-production.up.railway.app"
220
218
  });
221
- this.publicClient = options.publicClient;
222
- this.walletClient = options.walletClient;
223
- this.sendBitcoinFn = options.sendBitcoin;
224
219
  this.preflightCheckBalances = options.preflight?.checkBalances !== false;
220
+ this.integratorName = options.integratorName;
225
221
  }
226
222
  async getQuote(params) {
227
223
  const route = detectRoute(params.from, params.to);
@@ -237,50 +233,53 @@ class RiftSdk {
237
233
  const isChained = route.type === "direct_rift" && route.direction === "from_btc" && !isCbBtc(params.to);
238
234
  return {
239
235
  quote,
240
- executeSwap: async () => {
241
- const refundAddress = params.refundAddress ?? this.getRefundAddress(params);
236
+ executeSwap: async (context = {}) => {
237
+ const refundAddress = params.refundAddress ?? this.getRefundAddress(params, context);
242
238
  if (this.preflightCheckBalances) {
243
- await this.assertSufficientBalance(params.from, quote.from.amount);
239
+ await this.assertSufficientBalance(params.from, quote.from.amount, context);
244
240
  }
245
- const orderResponse = await this.riftClient.createOrder({
241
+ const swapResponse = await this.riftClient.createSwap({
246
242
  id: riftQuote.id,
247
243
  destinationAddress: params.destinationAddress,
248
244
  refundAddress,
245
+ integratorName: this.integratorName,
249
246
  approvalMode: params.approvalMode
250
247
  });
251
- this.assertEvmChainMatchForSteps(orderResponse.executionSteps);
252
- for (const step of orderResponse.executionSteps) {
253
- 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);
254
251
  if (isMonochain && step.action === "evm_call" && step.kind === "oneinch_swap" && result.txHash) {
255
- await this.riftClient.reportStepResult(orderResponse.swapId, {
252
+ await this.riftClient.reportStepResult(swapResponse.swapId, {
256
253
  stepId: step.id,
257
254
  ...result
258
255
  });
259
256
  }
260
257
  }
261
- const swap = await this.riftClient.getOrder(orderResponse.swapId);
262
- return this.buildOrderResult(swap, {
258
+ const swap = await this.riftClient.getSwap(swapResponse.swapId);
259
+ return this.buildSwapResult(swap, {
263
260
  chained: isChained,
264
- riftOrderId: orderResponse.swapId
261
+ riftSwapId: swapResponse.swapId
265
262
  });
266
263
  }
267
264
  };
268
265
  }
269
- async executeStep(step) {
266
+ async executeStep(step, context) {
270
267
  switch (step.action) {
271
268
  case "evm_call":
272
- return this.executeEvmCallStep(step);
269
+ return this.executeEvmCallStep(step, context);
273
270
  case "btc_transfer":
274
- return this.executeBtcTransferStep(step);
271
+ return this.executeBtcTransferStep(step, context);
275
272
  }
276
273
  }
277
- async executeEvmCallStep(step) {
278
- const account = this.walletClient.account;
274
+ async executeEvmCallStep(step, context) {
275
+ const walletClient = this.requireWalletClient(context);
276
+ const publicClient = this.requirePublicClient(context);
277
+ const account = walletClient.account;
279
278
  if (!account) {
280
279
  throw new Error("No account configured on wallet client");
281
280
  }
282
281
  if (step.kind === "approval" && step.tokenAddress && step.spenderAddress && step.amount) {
283
- const allowance = await this.publicClient.readContract({
282
+ const allowance = await publicClient.readContract({
284
283
  address: step.tokenAddress,
285
284
  abi: erc20Abi,
286
285
  functionName: "allowance",
@@ -290,18 +289,18 @@ class RiftSdk {
290
289
  return {};
291
290
  }
292
291
  }
293
- const txHash = await this.walletClient.sendTransaction({
292
+ const txHash = await walletClient.sendTransaction({
294
293
  account,
295
294
  to: step.to,
296
295
  data: step.calldata,
297
- value: step.value ? BigInt(step.value) : undefined,
298
- chain: this.walletClient.chain
296
+ value: step.value ? BigInt(step.value) : undefined
299
297
  });
300
- await this.publicClient.waitForTransactionReceipt({ hash: txHash });
298
+ await publicClient.waitForTransactionReceipt({ hash: txHash });
301
299
  return { txHash };
302
300
  }
303
- async executeBtcTransferStep(step) {
304
- await this.sendBitcoinFn({
301
+ async executeBtcTransferStep(step, context) {
302
+ const sendBitcoin = this.requireSendBitcoin(context);
303
+ await sendBitcoin({
305
304
  recipient: step.toAddress,
306
305
  amountSats: step.amountSats
307
306
  });
@@ -328,31 +327,32 @@ class RiftSdk {
328
327
  };
329
328
  }
330
329
  }
331
- buildOrderResult(swap, options) {
332
- const riftOrderId = options?.riftOrderId;
333
- if (!riftOrderId) {
334
- throw new Error("Missing rift order id for order result.");
330
+ buildSwapResult(swap, options) {
331
+ const riftSwapId = options?.riftSwapId;
332
+ if (!riftSwapId) {
333
+ throw new Error("Missing rift swap id for swap result.");
335
334
  }
336
335
  return {
337
- swapId: riftOrderId,
336
+ swapId: riftSwapId,
338
337
  status: swap.status,
339
338
  rift: swap
340
339
  };
341
340
  }
342
- async assertSufficientBalance(currency, amount) {
341
+ async assertSufficientBalance(currency, amount, context) {
343
342
  if (currency.chain.kind !== "EVM")
344
343
  return;
345
- this.assertEvmChainMatch(currency.chain.chainId);
344
+ this.assertEvmChainMatch(currency.chain.chainId, context);
346
345
  const required = BigInt(amount);
347
- const owner = this.getAddress();
346
+ const owner = this.getAddress(context);
347
+ const publicClient = this.requirePublicClient(context);
348
348
  if (currency.token.kind === "NATIVE") {
349
- const balance2 = await this.publicClient.getBalance({ address: owner });
349
+ const balance2 = await publicClient.getBalance({ address: owner });
350
350
  if (balance2 < required) {
351
351
  throw new Error(`Insufficient balance for native token. Need ${required.toString()}, have ${balance2.toString()}`);
352
352
  }
353
353
  return;
354
354
  }
355
- const balance = await this.publicClient.readContract({
355
+ const balance = await publicClient.readContract({
356
356
  address: currency.token.address,
357
357
  abi: erc20Abi,
358
358
  functionName: "balanceOf",
@@ -362,28 +362,31 @@ class RiftSdk {
362
362
  throw new Error(`Insufficient balance for token ${currency.token.address}. Need ${required.toString()}, have ${balance.toString()}`);
363
363
  }
364
364
  }
365
- getAddress() {
366
- const account = this.walletClient.account;
365
+ getAddress(context) {
366
+ const walletClient = this.requireWalletClient(context);
367
+ const account = walletClient.account;
367
368
  if (!account) {
368
369
  throw new Error("No account configured on wallet client");
369
370
  }
370
371
  return account.address;
371
372
  }
372
- getRefundAddress(params) {
373
+ getRefundAddress(params, context) {
373
374
  if (params.from.chain.kind === "BITCOIN") {
374
375
  throw new Error("refundAddress is required for BTC swaps (Bitcoin refund address)");
375
376
  }
376
- return this.getAddress();
377
+ return this.getAddress(context);
377
378
  }
378
- assertEvmChainMatch(expectedChainId) {
379
- const walletChainId = this.walletClient.chain?.id;
379
+ assertEvmChainMatch(expectedChainId, context) {
380
+ const walletClient = this.requireWalletClient(context);
381
+ const publicClient = this.requirePublicClient(context);
382
+ const walletChainId = walletClient.chain?.id;
380
383
  if (!walletChainId) {
381
384
  throw new Error("Wallet client is missing an EVM chain configuration");
382
385
  }
383
386
  if (walletChainId !== expectedChainId) {
384
387
  throw new Error(`Wallet client chain mismatch. Expected ${expectedChainId}, got ${walletChainId}`);
385
388
  }
386
- const publicChainId = this.publicClient.chain?.id;
389
+ const publicChainId = publicClient.chain?.id;
387
390
  if (!publicChainId) {
388
391
  throw new Error("Public client is missing an EVM chain configuration");
389
392
  }
@@ -391,7 +394,7 @@ class RiftSdk {
391
394
  throw new Error(`Public client chain mismatch. Expected ${expectedChainId}, got ${publicChainId}`);
392
395
  }
393
396
  }
394
- assertEvmChainMatchForSteps(steps) {
397
+ assertEvmChainMatchForSteps(steps, context) {
395
398
  const evmSteps = steps.filter((step) => step.action === "evm_call");
396
399
  const firstStep = evmSteps[0];
397
400
  if (!firstStep)
@@ -402,15 +405,37 @@ class RiftSdk {
402
405
  throw new Error(`Mixed EVM chain IDs in execution steps. Expected ${expectedChainId}, got ${step.chainId}`);
403
406
  }
404
407
  }
405
- this.assertEvmChainMatch(expectedChainId);
408
+ this.assertEvmChainMatch(expectedChainId, context);
406
409
  }
407
- async getOrderStatus(orderId) {
408
- return this.riftClient.getOrder(orderId);
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;
409
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);
410
434
  }
411
435
  export {
412
436
  getSupportedModes,
413
437
  detectRoute,
438
+ createRiftSdk,
414
439
  createCurrency,
415
440
  createClient,
416
441
  RiftSdk,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riftresearch/sdk",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "SDK for swapping between bitcoin and evm chains",
5
5
  "license": "MIT",
6
6
  "files": [