@riftresearch/sdk 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 riftresearch
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # rift-sdk
2
+
3
+ SDK for swapping between bitcoin and evm chains
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add rift-sdk
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { greet } from 'rift-sdk';
15
+
16
+ console.log(greet('World')); // Hello, World!
17
+ ```
18
+
19
+ ## Contributing
20
+
21
+ Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for contribution guidelines.
22
+
23
+ ## License
24
+
25
+ MIT
@@ -0,0 +1,358 @@
1
+ type U256 = string;
2
+ type BitcoinChain = {
3
+ kind: "BITCOIN";
4
+ };
5
+ type EvmChain = {
6
+ kind: "EVM";
7
+ chainId: number;
8
+ };
9
+ type Chain = BitcoinChain | EvmChain;
10
+ type NativeToken = {
11
+ kind: "NATIVE";
12
+ decimals: number;
13
+ };
14
+ type Erc20Token = {
15
+ kind: "TOKEN";
16
+ address: string;
17
+ decimals: number;
18
+ };
19
+ type TokenIdentifier = NativeToken | Erc20Token;
20
+ interface Currency {
21
+ chain: Chain;
22
+ token: TokenIdentifier;
23
+ }
24
+ type SwapStatus = "waiting_user_deposit_initiated" | "waiting_user_deposit_confirmed" | "waiting_mm_deposit_initiated" | "waiting_mm_deposit_confirmed" | "settling" | "settled" | "refunding_user" | "failed";
25
+ interface UserDepositStatus {
26
+ tx_hash: string;
27
+ amount: U256;
28
+ deposit_detected_at: string;
29
+ confirmations: number;
30
+ last_checked: string;
31
+ confirmed_at?: string;
32
+ }
33
+ interface MMDepositStatus {
34
+ tx_hash: string;
35
+ amount: U256;
36
+ deposit_detected_at: string;
37
+ confirmations: number;
38
+ last_checked: string;
39
+ }
40
+ interface SettlementStatus {
41
+ tx_hash: string;
42
+ broadcast_at: string;
43
+ confirmations: number;
44
+ completed_at?: string;
45
+ fee?: U256;
46
+ }
47
+ interface LatestRefund {
48
+ timestamp: string;
49
+ recipient_address: string;
50
+ }
51
+ interface RealizedSwap {
52
+ user_input: U256;
53
+ mm_output: U256;
54
+ protocol_fee: U256;
55
+ liquidity_fee: U256;
56
+ network_fee: U256;
57
+ }
58
+ interface SwapRates {
59
+ liquidity_fee_bps: number;
60
+ protocol_fee_bps: number;
61
+ network_fee_sats: number;
62
+ }
63
+ interface SwapFees {
64
+ liquidity_fee: U256;
65
+ protocol_fee: U256;
66
+ network_fee: U256;
67
+ }
68
+ interface LotCurrency {
69
+ chain: "bitcoin" | "ethereum" | "base" | "solana";
70
+ token: {
71
+ type: "Native";
72
+ } | {
73
+ type: "Address";
74
+ data: string;
75
+ };
76
+ decimals: number;
77
+ }
78
+ interface Lot {
79
+ currency: LotCurrency;
80
+ amount: U256;
81
+ }
82
+ interface SwapQuote {
83
+ id: string;
84
+ market_maker_id: string;
85
+ from: Lot;
86
+ to: Lot;
87
+ rates: SwapRates;
88
+ fees: SwapFees;
89
+ min_input: U256;
90
+ max_input: U256;
91
+ affiliate?: string;
92
+ expires_at: string;
93
+ created_at: string;
94
+ }
95
+ interface Swap {
96
+ id: string;
97
+ market_maker_id: string;
98
+ quote: SwapQuote;
99
+ metadata: {
100
+ start_asset?: string;
101
+ } | Record<string, never>;
102
+ realized?: RealizedSwap | Record<string, never>;
103
+ deposit_vault_salt: string;
104
+ deposit_vault_address: string;
105
+ mm_nonce: string;
106
+ user_destination_address: string;
107
+ refund_address: string;
108
+ status: SwapStatus;
109
+ user_deposit_status?: UserDepositStatus | Record<string, never>;
110
+ mm_deposit_status?: MMDepositStatus | Record<string, never>;
111
+ settlement_status?: SettlementStatus | Record<string, never>;
112
+ latest_refund?: LatestRefund | Record<string, never>;
113
+ failure_reason?: string | null;
114
+ failure_at?: string | null;
115
+ mm_notified_at?: string | null;
116
+ mm_private_key_sent_at?: string | null;
117
+ created_at: string;
118
+ updated_at: string;
119
+ }
120
+ declare const BTC: Currency;
121
+ declare const CBBTC_ETHEREUM: Currency;
122
+ declare const CBBTC_BASE: Currency;
123
+ /**
124
+ * Discriminated union of all possible swap routes.
125
+ *
126
+ * - direct_rift: BTC <-> EVM token (Rift handles directly)
127
+ * - cowswap_then_rift: ERC20 (non-cbBTC) -> BTC (CowSwap to cbBTC, then Rift to BTC)
128
+ */
129
+ type SwapRoute = {
130
+ type: "direct_rift";
131
+ direction: "to_btc" | "from_btc";
132
+ } | {
133
+ type: "cowswap_then_rift";
134
+ evmChainId: number;
135
+ };
136
+ /**
137
+ * Detect the appropriate swap route based on currency pair.
138
+ *
139
+ * Routes:
140
+ * - EVM token → BTC: direct_rift (to_btc) for cbBTC, cowswap_then_rift for other ERC20s
141
+ * - BTC → EVM token: direct_rift (from_btc) - Rift handles all BTC -> EVM swaps directly
142
+ */
143
+ declare function detectRoute(from: Currency, to: Currency): SwapRoute;
144
+ interface SupportedModes {
145
+ exactInput: boolean;
146
+ exactOutput: boolean;
147
+ }
148
+ /**
149
+ * Check which trade modes are supported for a given currency pair.
150
+ *
151
+ * - cbBTC ↔ BTC: both modes supported
152
+ * - BTC → cbBTC: both modes supported
153
+ * - BTC → ERC20 (non-cbBTC): only exact_input (Rift doesn't support exact_output for chained swaps)
154
+ * - ERC20 → BTC: both modes supported (SDK handles via CowSwap + Rift)
155
+ */
156
+ declare function getSupportedModes(from: Currency, to: Currency): SupportedModes;
157
+ import { PublicClient, WalletClient } from "viem";
158
+ type RiftOrder = Swap;
159
+ interface TradeParameters {
160
+ /** The currency to swap from */
161
+ from: Currency;
162
+ /** The currency to swap to */
163
+ to: Currency;
164
+ /** Amount in smallest unit (sats for BTC, wei for ETH, etc.) */
165
+ amount: string;
166
+ /** Whether amount refers to input or output */
167
+ mode: "exact_input" | "exact_output";
168
+ /** Address to receive the output tokens */
169
+ destinationAddress: string;
170
+ /** Address to receive refunds if swap fails. Defaults to source wallet address */
171
+ refundAddress?: string;
172
+ /**
173
+ * Slippage tolerance for the preswap (CowSwap) leg, in basis points.
174
+ * e.g., 50 = 0.5%, 100 = 1%
175
+ *
176
+ * If not provided, CowSwap will use auto slippage which suggests an
177
+ * appropriate value based on the quote and market conditions.
178
+ */
179
+ preswapSlippageBps?: number;
180
+ }
181
+ interface QuoteResult {
182
+ quoteId: string;
183
+ from: {
184
+ currency: Currency;
185
+ amount: string;
186
+ };
187
+ to: {
188
+ currency: Currency;
189
+ amount: string;
190
+ };
191
+ fees: {
192
+ protocol: string;
193
+ liquidity: string;
194
+ network: string;
195
+ totalUsd: number;
196
+ };
197
+ expiresAt: Date;
198
+ priceImpact?: number;
199
+ }
200
+ interface GetQuoteResult {
201
+ quote: QuoteResult;
202
+ executeSwap: () => Promise<SwapResult>;
203
+ }
204
+ /** Raw CowSwap order from the API */
205
+ interface CowSwapOrder {
206
+ uid: string;
207
+ status: string;
208
+ sellToken: string;
209
+ buyToken: string;
210
+ sellAmount: string;
211
+ buyAmount: string;
212
+ executedSellAmount: string;
213
+ executedBuyAmount: string;
214
+ receiver: string;
215
+ validTo: number;
216
+ creationDate: string;
217
+ }
218
+ interface SwapResult {
219
+ swapId: string;
220
+ status: SwapStatus2;
221
+ rift: RiftOrder;
222
+ preswap?: CowSwapOrder;
223
+ }
224
+ type SwapStatus2 = "pending_deposit" | "deposit_detected" | "processing" | "funds_received" | "swapping" | "settling" | "completed" | "failed" | "refunding";
225
+ /**
226
+ * Function type for sending Bitcoin.
227
+ * Implementers provide this function to handle BTC transactions in their app.
228
+ *
229
+ * @example
230
+ * // Using Xverse
231
+ * const sendBitcoin: SendBitcoinFn = async ({ recipient, amountSats }) => {
232
+ * await Wallet.request('sendTransfer', {
233
+ * recipients: [{ address: recipient, amount: Number(amountSats) }],
234
+ * })
235
+ * }
236
+ *
237
+ * @example
238
+ * // Using Leather
239
+ * const sendBitcoin: SendBitcoinFn = async ({ recipient, amountSats }) => {
240
+ * await window.LeatherProvider.request('sendTransfer', {
241
+ * recipients: [{ address: recipient, amount: amountSats }],
242
+ * })
243
+ * }
244
+ */
245
+ type SendBitcoinFn = (params: {
246
+ /** Bitcoin address to send to (deposit vault) */
247
+ recipient: string;
248
+ /** Amount to send in satoshis */
249
+ amountSats: string;
250
+ }) => Promise<void>;
251
+ interface RiftSdkOptions {
252
+ /** Viem PublicClient for reading chain data */
253
+ publicClient: PublicClient;
254
+ /** Viem WalletClient for signing and sending transactions */
255
+ walletClient: WalletClient;
256
+ /** Function to send Bitcoin (implement using your preferred wallet) */
257
+ sendBitcoin: SendBitcoinFn;
258
+ /** Rift API URL. Defaults to production API */
259
+ apiUrl?: string;
260
+ }
261
+ declare class RiftSdk {
262
+ private riftClient;
263
+ private publicClient;
264
+ private walletClient;
265
+ private sendBitcoinFn;
266
+ constructor(options: RiftSdkOptions);
267
+ /**
268
+ * Get a quote for a swap and return a function to execute it.
269
+ *
270
+ * @example
271
+ * const { quote, executeSwap } = await sdk.getQuote({
272
+ * from: CBBTC_BASE,
273
+ * to: BTC,
274
+ * amount: '100000000', // 1 cbBTC
275
+ * mode: 'exact_input',
276
+ * destinationAddress: 'bc1q...',
277
+ * })
278
+ *
279
+ * console.log(`You'll receive: ${quote.to.amount} sats`)
280
+ * const swap = await executeSwap()
281
+ */
282
+ getQuote(params: TradeParameters): Promise<GetQuoteResult>;
283
+ /**
284
+ * Direct cbBTC ↔ BTC swap via Rift only.
285
+ */
286
+ private getDirectRiftQuote;
287
+ /**
288
+ * ERC20 → cbBTC (CowSwap) → BTC (Rift)
289
+ */
290
+ private getCowswapThenRiftQuote;
291
+ /**
292
+ * exact_input: ERC20 (known) → cbBTC → BTC (calculated)
293
+ */
294
+ private getCowswapThenRiftExactInput;
295
+ /**
296
+ * exact_output: ERC20 (calculated) → cbBTC → BTC (known)
297
+ */
298
+ private getCowswapThenRiftExactOutput;
299
+ /**
300
+ * Execute the CowSwap → Rift swap flow.
301
+ *
302
+ * Flow:
303
+ * 1. Create Rift order first to get deposit vault address
304
+ * 2. Ensure CowSwap approval for the sell token (skip for native tokens)
305
+ * 3. Get fresh CowSwap quote with receiver = deposit vault
306
+ * 4. Post CowSwap order → cbBTC goes directly to Rift vault
307
+ */
308
+ private executeCowswapThenRift;
309
+ private buildQuoteResult;
310
+ private buildCombinedQuoteResult;
311
+ private buildSwapResult;
312
+ private executeDeposit;
313
+ private transferErc20;
314
+ private getAddress;
315
+ private getRefundAddress;
316
+ /**
317
+ * Map API status to SDK status.
318
+ *
319
+ * For chained swaps (BTC → non-cbBTC ERC20), the user doesn't receive funds
320
+ * until settlement is complete, so we use different statuses.
321
+ */
322
+ private mapStatus;
323
+ /**
324
+ * Get the current status of a swap by its ID.
325
+ *
326
+ * For multi-leg swaps (ERC20 → BTC via CowSwap), returns both
327
+ * the raw CowSwap order and the raw Rift order.
328
+ */
329
+ getSwapStatus(swapId: string): Promise<SwapResult>;
330
+ private getCowSwapOrder;
331
+ private fetchCowSwapOrder;
332
+ private computeOverallStatus;
333
+ }
334
+ /**
335
+ * URL-safe swap ID encoding/decoding.
336
+ *
337
+ * Format: base64url encoded string containing:
338
+ * - Rift-only: "r|<riftOrderId>" or "r|<riftOrderId>|c" (chained)
339
+ * - CowSwap+Rift: "c|<cowOrderId>|<riftOrderId>"
340
+ */
341
+ type SwapIdData = {
342
+ type: "rift";
343
+ riftOrderId: string;
344
+ chained?: boolean;
345
+ } | {
346
+ type: "cowswap_rift";
347
+ cowOrderId: string;
348
+ riftOrderId: string;
349
+ };
350
+ /**
351
+ * Encode swap ID data into a URL-safe string.
352
+ */
353
+ declare function encodeSwapId(data: SwapIdData): string;
354
+ /**
355
+ * Decode a URL-safe swap ID string back to its components.
356
+ */
357
+ declare function decodeSwapId(encoded: string): SwapIdData;
358
+ export { getSupportedModes, encodeSwapId, detectRoute, decodeSwapId, TradeParameters, TokenIdentifier, SwapStatus2 as SwapStatus, SwapRoute, SwapResult, SwapIdData, SupportedModes, SendBitcoinFn, RiftSdkOptions, RiftSdk, RiftOrder, QuoteResult, NativeToken, GetQuoteResult, EvmChain, Erc20Token, Currency, CowSwapOrder, Chain, CBBTC_ETHEREUM, CBBTC_BASE, BitcoinChain, BTC, SwapStatus as ApiSwapStatus };