@riftresearch/sdk 0.13.0 → 0.14.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
@@ -101,3 +101,16 @@ const result = await sdk.createLimitOrder({
101
101
  console.log(`Order ID: ${result.swapId}`)
102
102
  console.log(`Status: ${result.status}`)
103
103
  ```
104
+
105
+ For supported limit orders, you can later cancel the order. The SDK will fetch the
106
+ correct typed-data payload from the router, sign it with your wallet, and submit the
107
+ cancellation:
108
+
109
+ ```ts
110
+ const cancel = await sdk.cancelOrder({
111
+ swapId: result.swapId,
112
+ walletClient,
113
+ })
114
+
115
+ console.log(`Cancel accepted: ${cancel.accepted}`)
116
+ ```
package/dist/index.d.ts CHANGED
@@ -241,6 +241,14 @@ interface SwapResponse {
241
241
  /** Ordered list of steps the client must execute */
242
242
  executionSteps: ExecutionStep[];
243
243
  }
244
+ interface CancelOrderResponse {
245
+ /** The public swap ID from the router API. */
246
+ swapId: string;
247
+ /** Whether the downstream cancellation request was accepted. */
248
+ accepted: boolean;
249
+ /** Optional downstream CoW order UID for the cancelled order. */
250
+ cowOrderUid?: string;
251
+ }
244
252
  /** Create an ERC-20 currency on an EVM chain */
245
253
  declare function createCurrency(params: {
246
254
  chainId: number;
@@ -383,6 +391,7 @@ interface SwapResult {
383
391
  status: SwapStatus;
384
392
  rift: RiftSwap;
385
393
  }
394
+ type CancelOrderResult = CancelOrderResponse;
386
395
  /**
387
396
  * Function type for sending Bitcoin.
388
397
  * Implementers provide this function to handle BTC transactions in their app.
@@ -440,6 +449,17 @@ type ExecuteSwapOptions<chain extends Chain2 | undefined = Chain2 | undefined> =
440
449
  /** Address to receive refunds if swap fails. Defaults to source wallet address */
441
450
  refundAddress?: string;
442
451
  };
452
+ type CancelOrderOptions<chain extends Chain2 | undefined = Chain2 | undefined> = {
453
+ swapId: string;
454
+ /** Viem WalletClient for signing the router-prepared cancellation typed data */
455
+ walletClient: WalletClient<Transport, chain, Account | undefined>;
456
+ /**
457
+ * Optional absolute Unix timestamp in UTC seconds for tee-swapper
458
+ * cancellation signatures. Defaults to now + 5 minutes and is ignored for
459
+ * direct CoW-backed cancellations.
460
+ */
461
+ deadline?: number;
462
+ };
443
463
  interface RiftSdkOptions {
444
464
  /** Rift API URL. Defaults to production API */
445
465
  apiUrl?: string;
@@ -485,6 +505,9 @@ declare class RiftSdk {
485
505
  createLimitOrder<chain extends Chain3 | undefined = Chain3 | undefined>(options: CreateLimitOrderOptions<chain>): Promise<SwapResult>;
486
506
  private assertPositiveIntegerString;
487
507
  private assertValidLimitValidUntil;
508
+ private assertValidCancelDeadline;
509
+ private assertCancelWalletChain;
510
+ private signPreparedCancellation;
488
511
  private executeOrderFlow;
489
512
  /**
490
513
  * Execute a single step from the server's execution steps.
@@ -519,6 +542,14 @@ declare class RiftSdk {
519
542
  * Get the current status of a swap by its ID.
520
543
  */
521
544
  getSwapStatus(swapId: string): Promise<SwapStatusResponse>;
545
+ /**
546
+ * Cancel a supported limit order through the swap router.
547
+ *
548
+ * The SDK first requests the backend-specific typed-data payload from the
549
+ * router, signs it with the provided wallet, and then submits the signed
550
+ * cancellation request back to the router.
551
+ */
552
+ cancelOrder<chain extends Chain3 | undefined = Chain3 | undefined>(options: CancelOrderOptions<chain>): Promise<CancelOrderResult>;
522
553
  }
523
554
  declare function createRiftSdk(options: RiftSdkOptions): RiftSdk;
524
- export { getSupportedModes, detectRoute, createRiftSdk, createCurrency, TokenIdentifier, SwapStatus, SwapRouterApiError, SwapRoute, SwapResult, SwapResponse, SupportedModes, SendBitcoinFn, RiftSwap, RiftSdkOptions, RiftSdk, QuoteResult, QuoteParameters, NativeToken, LimitPricing, GetQuoteResult, ExecutionStep, ExecutionAction, ExecuteSwapStepType, ExecuteSwapOptions, ExecuteSwapOnExecuteStepCallback, EvmChain, EvmCallStep, EvmCallKind, Erc20Token, Currency, Currencies, CreateLimitOrderOptions, Chain, BtcTransferStep, BtcTransferKind, BitcoinChain };
555
+ export { getSupportedModes, detectRoute, createRiftSdk, createCurrency, TokenIdentifier, SwapStatus, SwapRouterApiError, SwapRoute, SwapResult, SwapResponse, SupportedModes, SendBitcoinFn, RiftSwap, RiftSdkOptions, RiftSdk, QuoteResult, QuoteParameters, NativeToken, LimitPricing, GetQuoteResult, ExecutionStep, ExecutionAction, ExecuteSwapStepType, ExecuteSwapOptions, ExecuteSwapOnExecuteStepCallback, EvmChain, EvmCallStep, EvmCallKind, Erc20Token, Currency, Currencies, CreateLimitOrderOptions, Chain, CancelOrderResult, CancelOrderOptions, BtcTransferStep, BtcTransferKind, BitcoinChain };
package/dist/index.js CHANGED
@@ -226,6 +226,12 @@ function createClient(baseUrl) {
226
226
  const swapId = encodeURIComponent(params.swapId);
227
227
  return {
228
228
  get: () => get(normalizedBaseUrl, `/order/${swapId}`),
229
+ cancel: {
230
+ prepare: {
231
+ post: (body) => postJson(normalizedBaseUrl, `/order/${swapId}/cancel/prepare`, body)
232
+ },
233
+ post: (body) => postJson(normalizedBaseUrl, `/order/${swapId}/cancel`, body)
234
+ },
229
235
  tx: {
230
236
  post: (body) => postJson(normalizedBaseUrl, `/order/${swapId}/tx`, body)
231
237
  },
@@ -259,6 +265,7 @@ var DEFAULT_LIMIT_VALIDITY_WINDOW_SECONDS = 365 * 24 * 60 * 60;
259
265
  var MIN_LIMIT_VALIDITY_LEAD_TIME_SECONDS = 60;
260
266
  var MAX_LIMIT_VALIDITY_WINDOW_SECONDS = DEFAULT_LIMIT_VALIDITY_WINDOW_SECONDS;
261
267
  var MAX_COW_VALID_TO = 4294967295;
268
+ var CANCEL_AUTH_WINDOW_SECONDS = 300;
262
269
 
263
270
  class RiftSdk {
264
271
  riftClient;
@@ -467,6 +474,51 @@ class RiftSdk {
467
474
  throw new Error(`${field} must be between 60 seconds and 31536000 seconds in the future`);
468
475
  }
469
476
  }
477
+ assertValidCancelDeadline(deadline) {
478
+ if (!Number.isInteger(deadline)) {
479
+ throw new Error("deadline must be an integer when provided");
480
+ }
481
+ const nowSeconds = Math.floor(Date.now() / 1000);
482
+ if (deadline < nowSeconds) {
483
+ throw new Error("deadline must be in the future");
484
+ }
485
+ if (deadline > nowSeconds + CANCEL_AUTH_WINDOW_SECONDS) {
486
+ throw new Error(`deadline must be within ${CANCEL_AUTH_WINDOW_SECONDS} seconds`);
487
+ }
488
+ }
489
+ assertCancelWalletChain(walletClient, chainId) {
490
+ const walletChainId = walletClient.chain?.id;
491
+ if (!walletChainId) {
492
+ throw new Error("Wallet client is missing an EVM chain configuration");
493
+ }
494
+ if (walletChainId !== chainId) {
495
+ throw new Error(`Wallet client chain mismatch. Expected ${chainId}, got ${walletChainId}`);
496
+ }
497
+ }
498
+ async signPreparedCancellation(walletClient, account, preparation) {
499
+ if (preparation.kind === "tee_swapper") {
500
+ return walletClient.signTypedData({
501
+ account,
502
+ domain: preparation.typedData.domain,
503
+ types: preparation.typedData.types,
504
+ primaryType: preparation.typedData.primaryType,
505
+ message: {
506
+ swapId: preparation.typedData.message.swapId,
507
+ deadline: BigInt(preparation.typedData.message.deadline)
508
+ }
509
+ });
510
+ }
511
+ return walletClient.signTypedData({
512
+ account,
513
+ domain: {
514
+ ...preparation.typedData.domain,
515
+ verifyingContract: preparation.typedData.domain.verifyingContract
516
+ },
517
+ types: preparation.typedData.types,
518
+ primaryType: preparation.typedData.primaryType,
519
+ message: preparation.typedData.message
520
+ });
521
+ }
470
522
  async executeOrderFlow(params) {
471
523
  const swapResponse = await params.createOrder();
472
524
  this.logDebug("order created", {
@@ -847,6 +899,27 @@ class RiftSdk {
847
899
  async getSwapStatus(swapId) {
848
900
  return this.unwrapEdenResult(await this.riftClient.swap({ swapId }).get());
849
901
  }
902
+ async cancelOrder(options) {
903
+ const walletClient = options.walletClient;
904
+ const account = walletClient.account;
905
+ if (!account) {
906
+ throw new Error("No account configured on wallet client");
907
+ }
908
+ const deadline = options.deadline ?? Math.floor(Date.now() / 1000) + CANCEL_AUTH_WINDOW_SECONDS;
909
+ this.assertValidCancelDeadline(deadline);
910
+ const preparation = this.unwrapEdenResult(await this.riftClient.swap({ swapId: options.swapId }).cancel.prepare.post({
911
+ deadline
912
+ }));
913
+ this.assertCancelWalletChain(walletClient, preparation.cancellation.chainId);
914
+ const signature = await this.signPreparedCancellation(walletClient, account, preparation.cancellation);
915
+ const request2 = {
916
+ authorization: {
917
+ signature,
918
+ ...preparation.cancellation.kind === "tee_swapper" ? { deadline: preparation.cancellation.deadline } : {}
919
+ }
920
+ };
921
+ return this.unwrapEdenResult(await this.riftClient.swap({ swapId: options.swapId }).cancel.post(request2));
922
+ }
850
923
  }
851
924
  function createRiftSdk(options) {
852
925
  return new RiftSdk(options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riftresearch/sdk",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "SDK for swapping between bitcoin and evm chains",
5
5
  "license": "MIT",
6
6
  "files": [