@riftresearch/sdk 0.11.1 → 0.12.1

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/dist/index.d.ts CHANGED
@@ -143,11 +143,12 @@ interface ErrorResponse {
143
143
  /**
144
144
  * Execution actions - the mechanism by which a step is executed.
145
145
  */
146
- type ExecutionAction = "evm_call" | "btc_transfer";
146
+ type ExecutionAction = "evm_call" | "eip712_sign" | "btc_transfer";
147
147
  /**
148
148
  * Step kinds grouped by action type.
149
149
  */
150
- type EvmCallKind = "approval" | "transfer_erc20" | "dex_swap";
150
+ type EvmCallKind = "approval" | "transfer_erc20" | "dex_swap" | "cowswap_eth_order";
151
+ type Eip712SignKind = "cowswap_erc20_order";
151
152
  type BtcTransferKind = "transfer_btc";
152
153
  /**
153
154
  * EVM Call step - execute calldata on an EVM chain.
@@ -178,6 +179,33 @@ interface EvmCallStep {
178
179
  venue?: string;
179
180
  }
180
181
  /**
182
+ * CowSwap order payload signed by the user via EIP-712.
183
+ */
184
+ interface CowSwapOrderToSign {
185
+ sellToken: string;
186
+ buyToken: string;
187
+ receiver: string;
188
+ sellAmount: U256;
189
+ buyAmount: U256;
190
+ validTo: number;
191
+ appData: string;
192
+ feeAmount: U256;
193
+ kind: "sell" | "buy";
194
+ partiallyFillable: boolean;
195
+ sellTokenBalance: "erc20" | "internal" | "external";
196
+ buyTokenBalance: "erc20" | "internal";
197
+ }
198
+ /**
199
+ * EIP-712 sign step - sign and submit an off-chain order.
200
+ */
201
+ interface Eip712SignStep {
202
+ id: string;
203
+ action: "eip712_sign";
204
+ kind: Eip712SignKind;
205
+ chainId: number;
206
+ orderToSign: CowSwapOrderToSign;
207
+ }
208
+ /**
181
209
  * BTC Transfer step - send Bitcoin to an address.
182
210
  * Used for: depositing BTC to Rift vault.
183
211
  */
@@ -197,7 +225,7 @@ interface BtcTransferStep {
197
225
  * Discriminated union of all execution step types.
198
226
  * Discriminate on `action` for execution logic, or `kind` for specific handling.
199
227
  */
200
- type ExecutionStep = EvmCallStep | BtcTransferStep;
228
+ type ExecutionStep = EvmCallStep | Eip712SignStep | BtcTransferStep;
201
229
  /**
202
230
  * Swap response with execution steps that the client must execute.
203
231
  */
@@ -276,6 +304,7 @@ interface SupportedModes {
276
304
  * - BTC → cbBTC: both modes supported
277
305
  * - BTC → ERC20 (non-cbBTC): only exact_input (Rift doesn't support exact_output for chained swaps)
278
306
  * - ERC20 → BTC: both modes supported
307
+ * - EVM → EVM (same chain): both modes supported
279
308
  */
280
309
  declare function getSupportedModes(from: Currency, to: Currency): SupportedModes;
281
310
  import { Account, PublicClient, Transport, WalletClient } from "viem";
@@ -375,7 +404,7 @@ type SendBitcoinFn = (params: {
375
404
  /** Amount to send in satoshis */
376
405
  amountSats: string;
377
406
  }) => Promise<void>;
378
- type ExecuteSwapStepType = "approval" | "transaction";
407
+ type ExecuteSwapStepType = "approval" | "transaction" | "signature";
379
408
  type ExecuteSwapOnExecuteStepCallback = (type: ExecuteSwapStepType) => void | Promise<void>;
380
409
  type ExecuteSwapContext<chain extends Chain2 | undefined = Chain2 | undefined> = {
381
410
  /** Viem PublicClient for reading chain data */
@@ -448,6 +477,7 @@ declare class RiftSdk {
448
477
  * Handles: approval, transfer_evm, dex_swap
449
478
  */
450
479
  private executeEvmCallStep;
480
+ private executeEip712SignStep;
451
481
  /**
452
482
  * Execute a BTC transfer step - send BTC to the vault address.
453
483
  */
@@ -456,6 +486,8 @@ declare class RiftSdk {
456
486
  private buildSwapResult;
457
487
  private buildDexSwapRevertMessage;
458
488
  private resolveDexVenueLabel;
489
+ private shouldReportStepResult;
490
+ private getCowSwapApiBase;
459
491
  private assertSufficientBalance;
460
492
  private getAddress;
461
493
  private getRefundAddress;
package/dist/index.js CHANGED
@@ -142,7 +142,7 @@ function getSupportedModes(from, to) {
142
142
  return { exactInput: true, exactOutput: true };
143
143
  }
144
144
  if (route.type === "dex_monochain") {
145
- return { exactInput: true, exactOutput: false };
145
+ return { exactInput: true, exactOutput: true };
146
146
  }
147
147
  if (route.direction === "to_btc") {
148
148
  return { exactInput: true, exactOutput: true };
@@ -246,6 +246,7 @@ function createClient(baseUrl) {
246
246
  // src/sdk.ts
247
247
  var GAS_LIMIT_MULTIPLIER_NUMERATOR = 3n;
248
248
  var GAS_LIMIT_MULTIPLIER_DENOMINATOR = 2n;
249
+ var GPV2_SETTLEMENT = "0x9008d19f58aabd9ed0d60971565aa8510560ab41";
249
250
 
250
251
  class RiftSdk {
251
252
  riftClient;
@@ -352,12 +353,13 @@ class RiftSdk {
352
353
  const result = await this.executeStep(step, context, swapResponse.swapId, route);
353
354
  this.logDebug("step completed", {
354
355
  stepId: step.id,
355
- txHash: result.txHash
356
+ txHash: result.txHash,
357
+ cowswapOrderId: result.cowswapOrderId
356
358
  });
357
- if (step.action === "evm_call" && step.kind === "dex_swap" && result.txHash) {
359
+ if (this.shouldReportStepResult(step, result)) {
358
360
  this.logDebug("reporting step result", {
359
361
  stepId: step.id,
360
- dexSwap: true,
362
+ kind: "kind" in step ? step.kind : undefined,
361
363
  monochain: isMonochain
362
364
  });
363
365
  this.unwrapEdenResult(await this.riftClient.swap({ swapId: swapResponse.swapId }).tx.post({
@@ -385,6 +387,8 @@ class RiftSdk {
385
387
  switch (step.action) {
386
388
  case "evm_call":
387
389
  return this.executeEvmCallStep(step, context, swapId, route);
390
+ case "eip712_sign":
391
+ return this.executeEip712SignStep(step, context);
388
392
  case "btc_transfer":
389
393
  return this.executeBtcTransferStep(step, context);
390
394
  }
@@ -471,7 +475,91 @@ class RiftSdk {
471
475
  }
472
476
  throw new Error(`EVM step transaction reverted (${effectiveStep.kind}) with hash ${txHash}`);
473
477
  }
474
- return { txHash };
478
+ return step.kind === "cowswap_eth_order" ? { txHash, cowswapOrderId: txHash } : { txHash };
479
+ }
480
+ async executeEip712SignStep(step, context) {
481
+ const walletClient = this.requireWalletClient(context);
482
+ const account = walletClient.account;
483
+ if (!account) {
484
+ throw new Error("No account configured on wallet client");
485
+ }
486
+ await context.onExecuteStep?.("signature");
487
+ const signature = await walletClient.signTypedData({
488
+ account,
489
+ domain: {
490
+ name: "Gnosis Protocol",
491
+ version: "v2",
492
+ chainId: step.chainId,
493
+ verifyingContract: GPV2_SETTLEMENT
494
+ },
495
+ types: {
496
+ Order: [
497
+ { name: "sellToken", type: "address" },
498
+ { name: "buyToken", type: "address" },
499
+ { name: "receiver", type: "address" },
500
+ { name: "sellAmount", type: "uint256" },
501
+ { name: "buyAmount", type: "uint256" },
502
+ { name: "validTo", type: "uint32" },
503
+ { name: "appData", type: "bytes32" },
504
+ { name: "feeAmount", type: "uint256" },
505
+ { name: "kind", type: "string" },
506
+ { name: "partiallyFillable", type: "bool" },
507
+ { name: "sellTokenBalance", type: "string" },
508
+ { name: "buyTokenBalance", type: "string" }
509
+ ]
510
+ },
511
+ primaryType: "Order",
512
+ message: {
513
+ sellToken: step.orderToSign.sellToken,
514
+ buyToken: step.orderToSign.buyToken,
515
+ receiver: step.orderToSign.receiver,
516
+ sellAmount: BigInt(step.orderToSign.sellAmount),
517
+ buyAmount: BigInt(step.orderToSign.buyAmount),
518
+ validTo: step.orderToSign.validTo,
519
+ appData: step.orderToSign.appData,
520
+ feeAmount: BigInt(step.orderToSign.feeAmount),
521
+ kind: step.orderToSign.kind,
522
+ partiallyFillable: step.orderToSign.partiallyFillable,
523
+ sellTokenBalance: step.orderToSign.sellTokenBalance,
524
+ buyTokenBalance: step.orderToSign.buyTokenBalance
525
+ }
526
+ });
527
+ const apiBase = this.getCowSwapApiBase(step.chainId);
528
+ if (!apiBase) {
529
+ throw new Error(`CowSwap is not supported on chain ${step.chainId}`);
530
+ }
531
+ const response = await fetch(`${apiBase}/api/v1/orders`, {
532
+ method: "POST",
533
+ headers: { "Content-Type": "application/json" },
534
+ body: JSON.stringify({
535
+ sellToken: step.orderToSign.sellToken,
536
+ buyToken: step.orderToSign.buyToken,
537
+ receiver: step.orderToSign.receiver,
538
+ sellAmount: step.orderToSign.sellAmount,
539
+ buyAmount: step.orderToSign.buyAmount,
540
+ validTo: step.orderToSign.validTo,
541
+ appData: step.orderToSign.appData,
542
+ feeAmount: step.orderToSign.feeAmount,
543
+ kind: step.orderToSign.kind,
544
+ partiallyFillable: step.orderToSign.partiallyFillable,
545
+ sellTokenBalance: step.orderToSign.sellTokenBalance,
546
+ buyTokenBalance: step.orderToSign.buyTokenBalance,
547
+ signingScheme: "eip712",
548
+ signature,
549
+ from: account.address
550
+ })
551
+ });
552
+ if (!response.ok) {
553
+ const errorText = await response.text();
554
+ throw new Error(`CowSwap order submission failed: ${errorText}`);
555
+ }
556
+ const body = await response.json();
557
+ const uid = body && typeof body === "object" && "uid" in body ? body.uid : undefined;
558
+ const orderId = typeof body === "string" ? body : typeof uid === "string" ? uid : null;
559
+ if (!orderId) {
560
+ throw new Error("CowSwap order submission succeeded but returned no order id");
561
+ }
562
+ return { cowswapOrderId: orderId };
475
563
  }
476
564
  async executeBtcTransferStep(step, context) {
477
565
  const sendBitcoin = this.requireSendBitcoin(context);
@@ -525,6 +613,22 @@ class RiftSdk {
525
613
  const trimmed = venue.trim();
526
614
  return trimmed.length > 0 ? trimmed : "the selected venue";
527
615
  }
616
+ shouldReportStepResult(step, result) {
617
+ if (step.action === "eip712_sign") {
618
+ return Boolean(result.cowswapOrderId);
619
+ }
620
+ if (step.action === "evm_call") {
621
+ return (step.kind === "dex_swap" || step.kind === "cowswap_eth_order") && (Boolean(result.txHash) || Boolean(result.cowswapOrderId));
622
+ }
623
+ return false;
624
+ }
625
+ getCowSwapApiBase(chainId) {
626
+ if (chainId === 1)
627
+ return "https://api.cow.fi/mainnet";
628
+ if (chainId === 8453)
629
+ return "https://api.cow.fi/base";
630
+ return null;
631
+ }
528
632
  async assertSufficientBalance(currency, amount, context) {
529
633
  if (currency.chain.kind !== "EVM")
530
634
  return;
@@ -582,7 +686,7 @@ class RiftSdk {
582
686
  }
583
687
  }
584
688
  assertEvmChainMatchForSteps(steps, context) {
585
- const evmSteps = steps.filter((step) => step.action === "evm_call");
689
+ const evmSteps = steps.filter((step) => step.action === "evm_call" || step.action === "eip712_sign");
586
690
  const firstStep = evmSteps[0];
587
691
  if (!firstStep)
588
692
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riftresearch/sdk",
3
- "version": "0.11.1",
3
+ "version": "0.12.1",
4
4
  "description": "SDK for swapping between bitcoin and evm chains",
5
5
  "license": "MIT",
6
6
  "files": [