@omnity/ree-client-ts-sdk 0.2.7 → 0.3.2

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
@@ -68,20 +68,30 @@ const poolInfo = await client.getPoolInfo("pool-address");
68
68
  ```typescript
69
69
  // Create a transaction for a single pool operation
70
70
  const transaction = await client.createTransaction({
71
- address: "bc1q...", // Bitcoin address for runes
71
+ address: "bc1p...", // Bitcoin address for runes
72
72
  paymentAddress: "bc1q...", // Payment address for BTC
73
- involvedPoolAddresses: ["bc1q..."], // Pool addresses involved
74
- involvedRuneIds: ["840000:3"], // Optional: rune IDs if trading runes
75
73
  });
76
74
 
77
75
  // Add a single intention (e.g., swap BTC for runes)
78
76
  transaction.addIntention({
79
- poolAddress: "bc1q...",
77
+ poolAddress: "bc1p...",
80
78
  inputCoins: [
81
- { id: "0:0", value: BigInt(100000) }, // Send 0.001 BTC
79
+ {
80
+ coin: {
81
+ id: "0:0",
82
+ value: BigInt(100000)
83
+ }, // Send 0.001 BTC,
84
+ from: paymentAddress,
85
+ },
82
86
  ],
83
87
  outputCoins: [
84
- { id: "840000:3", value: BigInt(1000) }, // Receive 1000 runes
88
+ {
89
+ coin: {
90
+ id: "840000:3",
91
+ value: BigInt(1000)
92
+ }, // Receive 1000 runes,
93
+ to: address,
94
+ },
85
95
  ],
86
96
  action: "swap",
87
97
  nonce: BigInt(1234),
@@ -98,18 +108,23 @@ const result = await transaction.send(signedPsbt.toHex());
98
108
  ```typescript
99
109
  // Create a complex transaction with multiple operations
100
110
  const transaction = await client.createTransaction({
101
- address: "bc1q...",
111
+ address: "bc1p...",
102
112
  paymentAddress: "bc1q...",
103
- involvedPoolAddresses: ["bc1q...pool1", "bc1q...pool2"],
104
- involvedRuneIds: ["840000:3", "840000:5"],
105
113
  });
106
114
 
107
115
  // Add multiple intentions in a single transaction
108
116
  // Intention 1: Deposit BTC to Pool 1
109
117
  transaction.addIntention({
110
- poolAddress: "bc1q...pool1",
118
+ poolAddress: "bc1p...pool1",
111
119
  inputCoins: [
112
- { id: "0:0", value: BigInt(50000) }, // Deposit 0.0005 BTC
120
+ {
121
+ // Deposit 0.0005 BTC
122
+ coin: {
123
+ id: "0:0",
124
+ value: BigInt(50000)
125
+ },
126
+ from: paymentAddress,
127
+ },
113
128
  ],
114
129
  outputCoins: [],
115
130
  action: "deposit",
@@ -120,10 +135,24 @@ transaction.addIntention({
120
135
  transaction.addIntention({
121
136
  poolAddress: "bc1q...pool2",
122
137
  inputCoins: [
123
- { id: "840000:3", value: BigInt(500) }, // Send 500 of rune A
138
+ {
139
+ // Send 500 of rune A,
140
+ coin: {
141
+ id: "840000:3",
142
+ value: BigInt(500)
143
+ },
144
+ from: address,
145
+ },
124
146
  ],
125
147
  outputCoins: [
126
- { id: "840000:5", value: BigInt(250) }, // Receive 250 of rune B
148
+ {
149
+ // Receive 250 of rune B,
150
+ coin: {
151
+ id: "840000:5",
152
+ value: BigInt(250)
153
+ },
154
+ to: address,
155
+ },
127
156
  ],
128
157
  action: "swap",
129
158
  nonce: BigInt(Date.now() + 1),
@@ -149,7 +178,7 @@ function App() {
149
178
  }
150
179
 
151
180
  function WalletComponent() {
152
- const { client, address, updateWallet, createTransaction } = useRee();
181
+ const { client, address, paymentAddress, updateWallet, createTransaction } = useRee();
153
182
  const { balance: btcBalance } = useBtcBalance();
154
183
 
155
184
  const connectWallet = () => {
@@ -161,24 +190,45 @@ function WalletComponent() {
161
190
 
162
191
  const executeComplexTransaction = async () => {
163
192
  // Create transaction with multiple pools
164
- const tx = await createTransaction({
165
- involvedPoolAddresses: ["pool1", "pool2"],
166
- involvedRuneIds: ["840000:3"],
167
- });
193
+ const tx = await createTransaction();
168
194
 
169
195
  // Add multiple intentions
170
196
  tx.addIntention({
171
197
  poolAddress: "pool1",
172
- inputCoins: [{ id: "0:0", value: BigInt(100000) }],
173
- outputCoins: [{ id: "840000:3", value: BigInt(1000) }],
198
+ inputCoins: [{
199
+ coin: {
200
+ id: "0:0",
201
+ value: BigInt(100000)
202
+ },
203
+ from: paymentAddress
204
+ }],
205
+ outputCoins: [
206
+ coint: {
207
+ id: "840000:3",
208
+ value: BigInt(1000)
209
+ },
210
+ to: address
211
+ ],
174
212
  action: "swap",
175
213
  nonce: BigInt(Date.now()),
176
214
  });
177
215
 
178
216
  tx.addIntention({
179
217
  poolAddress: "pool2",
180
- inputCoins: [{ id: "840000:3", value: BigInt(500) }],
181
- outputCoins: [{ id: "0:0", value: BigInt(50000) }],
218
+ inputCoins: [{
219
+ coin: {
220
+ id: "840000:3",
221
+ value: BigInt(500)
222
+ },
223
+ from: address
224
+ }],
225
+ outputCoins: [{
226
+ coin: {
227
+ id: "0:0",
228
+ value: BigInt(50000)
229
+ },
230
+ to: paymentAddress
231
+ }],
182
232
  action: "swap",
183
233
  nonce: BigInt(Date.now() + 1),
184
234
  });
@@ -228,13 +278,17 @@ function MyComponent({ children }) {
228
278
  value: depositBtcAmount,
229
279
  });
230
280
 
231
- const tx = await createTransaction({
232
- involvedPoolAddresses: ["bc1q..."],
233
- });
281
+ const tx = await createTransaction();
234
282
 
235
283
  tx.addIntention({
236
284
  poolAddress: "bc1q...",
237
- inputCoins: [{ id: "0:0", value: depositBtcAmount }],
285
+ inputCoins: [{
286
+ coin: {
287
+ id: "0:0",
288
+ value: depositBtcAmount
289
+ },
290
+ from: paymentAddress
291
+ }],
238
292
  outputCoins: [],
239
293
  action: "deposit",
240
294
  nonce: depositOffer.nonce,
@@ -307,7 +361,7 @@ new ReeClient(config: Config)
307
361
 
308
362
  ##### Transaction Methods
309
363
 
310
- - `createTransaction(params): Promise<Transaction>` - Create a transaction for trading with a liquidity pool
364
+ - `createTransaction(): Promise<Transaction>` - Create a transaction
311
365
 
312
366
  ### Transaction
313
367
 
@@ -324,17 +378,28 @@ Transaction builder for Bitcoin and Rune transactions with multi-intention suppo
324
378
  ```typescript
325
379
  interface Intention {
326
380
  poolAddress: string; // Target pool address
327
- inputCoins: CoinBalance[]; // Coins being sent to the pool
328
- outputCoins: CoinBalance[]; // Coins expected from the pool
381
+ inputCoins: InputCoin[]; // Coins being sent to the pool
382
+ outputCoins: InputCoin[]; // Coins expected from the pool
329
383
  action: string; // Action type (swap, deposit, withdraw, etc.)
330
384
  actionParams?: string; // Optional action parameters
331
385
  nonce: bigint; // Unique nonce for the intention
332
386
  }
333
387
 
334
- interface CoinBalance {
388
+ type CoinBalance = {
335
389
  id: string; // Coin ID ("0:0" for BTC, "840000:3" for runes)
336
390
  value: bigint; // Amount in smallest unit
337
391
  }
392
+
393
+ type InputCoin = {
394
+ coin: CoinBalance;
395
+ from: string;
396
+ };
397
+
398
+ type OutputCoin = {
399
+ coin: CoinBalance;
400
+ to: string;
401
+ };
402
+
338
403
  ```
339
404
 
340
405
  ### Multi-Intention Transaction Benefits
@@ -495,34 +560,3 @@ enum Network {
495
560
  }
496
561
  ```
497
562
 
498
- ## Error Handling
499
-
500
- ```typescript
501
- try {
502
- const transaction = await client.createTransaction({
503
- address: "bc1q...",
504
- paymentAddress: "bc1q...",
505
- involvedPoolAddresses: ["bc1q..."],
506
- });
507
-
508
- transaction.addIntention({
509
- poolAddress: "bc1q...",
510
- inputCoins: [{ id: "0:0", value: BigInt(100000) }],
511
- outputCoins: [{ id: "840000:3", value: BigInt(1000) }],
512
- action: "swap",
513
- nonce: BigInt(Date.now()),
514
- });
515
-
516
- const psbt = await transaction.build();
517
- const signedPsbt = await wallet.signPsbt(psbt);
518
- const result = await transaction.send(signedPsbt.toHex());
519
- } catch (error) {
520
- if (error.message.includes("INSUFFICIENT")) {
521
- console.error("Insufficient funds:", error);
522
- } else if (error.message.includes("Pool")) {
523
- console.error("Pool error:", error);
524
- } else {
525
- console.error("Transaction failed:", error);
526
- }
527
- }
528
- ```
package/dist/index.d.ts CHANGED
@@ -34,7 +34,7 @@ export declare type AddressType = (typeof AddressType)[keyof typeof AddressType]
34
34
 
35
35
  declare function bytesToHex(bytes: Uint8Array): string;
36
36
 
37
- export declare type CoinBalance = {
37
+ declare type CoinBalance = {
38
38
  id: string;
39
39
  value: bigint;
40
40
  };
@@ -53,9 +53,14 @@ declare function getScriptByAddress(address: string, network?: Network): Uint8Ar
53
53
 
54
54
  declare function hexToBytes(hex: string): Uint8Array;
55
55
 
56
+ export declare type InputCoin = {
57
+ coin: CoinBalance;
58
+ from: string;
59
+ };
60
+
56
61
  export declare type Intention = {
57
- inputCoins: CoinBalance[];
58
- outputCoins: CoinBalance[];
62
+ inputCoins: InputCoin[];
63
+ outputCoins: OutputCoin[];
59
64
  action: string;
60
65
  actionParams?: string;
61
66
  poolAddress: string;
@@ -68,7 +73,7 @@ declare class Maestro {
68
73
  baseUrl: string;
69
74
  apiKey: string;
70
75
  });
71
- utxosByAddress(address: string, cursor?: string | null): Promise<{
76
+ utxosByAddress(address: string, cursor?: string | null, excludeMetaprotocols?: boolean): Promise<{
72
77
  next_cursor: string | null;
73
78
  last_updated: {
74
79
  block_hash: string;
@@ -76,29 +81,28 @@ declare class Maestro {
76
81
  };
77
82
  data: RawBtcUtxo[];
78
83
  }>;
79
- inscriptionsByAddress(address: string, cursor?: string | null): Promise<{
84
+ inscriptionIdsByCollectionSymbol(collection: string, cursor?: string | null): Promise<{
80
85
  next_cursor: string | null;
81
86
  last_updated: {
82
87
  block_hash: string;
83
88
  block_height: bigint;
84
89
  };
85
- data: RawInscription[];
90
+ data: string[];
86
91
  }>;
87
- inscriptionIdsByCollectionSymbol(collection: string, cursor?: string | null): Promise<{
92
+ runeUtxosByAddress(address: string, rune: string, cursor?: string | null): Promise<{
88
93
  next_cursor: string | null;
89
94
  last_updated: {
90
95
  block_hash: string;
91
96
  block_height: bigint;
92
97
  };
93
- data: string[];
98
+ data: RawRuneUtxo[];
94
99
  }>;
95
- runeUtxosByAddress(address: string, rune: string, cursor?: string | null): Promise<{
96
- next_cursor: string | null;
100
+ runeInfo(runeId: string): Promise<{
97
101
  last_updated: {
98
102
  block_hash: string;
99
103
  block_height: bigint;
100
104
  };
101
- data: RawRuneUtxo[];
105
+ data: RawRuneInfo;
102
106
  }>;
103
107
  }
104
108
 
@@ -109,6 +113,11 @@ export declare const Network: {
109
113
 
110
114
  export declare type Network = (typeof Network)[keyof typeof Network];
111
115
 
116
+ export declare type OutputCoin = {
117
+ coin: CoinBalance;
118
+ to: string;
119
+ };
120
+
112
121
  export declare type Pool = {
113
122
  name: string;
114
123
  address: string;
@@ -154,14 +163,11 @@ declare type RawBtcUtxo = {
154
163
  address: string;
155
164
  };
156
165
 
157
- declare type RawInscription = {
158
- inscription_id: string;
159
- satoshis: string;
160
- utxo_sat_offset: bigint;
161
- utxo_txid: string;
162
- utxo_vout: number;
163
- utxo_block_height: number;
164
- utxo_confirmations: string;
166
+ declare type RawRuneInfo = {
167
+ id: string;
168
+ symbol: string;
169
+ spaced_name: string;
170
+ divisibility: number;
165
171
  };
166
172
 
167
173
  declare type RawRuneUtxo = {
@@ -207,7 +213,7 @@ export declare class ReeClient {
207
213
  * Handles pagination automatically to fetch all available UTXOs
208
214
  * @returns Array of Bitcoin UTXOs
209
215
  */
210
- getBtcUtxos(paymentAddress: string): Promise<Utxo[]>;
216
+ getBtcUtxos(paymentAddress: string, excludeMetaprotocols?: boolean): Promise<Utxo[]>;
211
217
  /**
212
218
  * Get UTXOs containing a specific rune for the user's address
213
219
  * @param runeId - The rune ID to filter UTXOs by
@@ -259,11 +265,9 @@ export declare class ReeClient {
259
265
  * @param params.involvedRuneId - Optional rune ID for rune swaps
260
266
  * @returns Transaction instance
261
267
  */
262
- createTransaction({ address, paymentAddress, involvedRuneIds, involvedPoolAddresses, }: {
268
+ createTransaction({ address, paymentAddress, }: {
263
269
  address: string;
264
270
  paymentAddress: string;
265
- involvedRuneIds?: string[];
266
- involvedPoolAddresses: string[];
267
271
  }): Promise<Transaction>;
268
272
  }
269
273
 
@@ -276,10 +280,7 @@ declare interface ReeContextValue {
276
280
  address?: string;
277
281
  paymentAddress?: string;
278
282
  }) => void;
279
- createTransaction: (params: {
280
- involvedRuneIds?: string[];
281
- involvedPoolAddresses: string[];
282
- }) => Promise<Transaction>;
283
+ createTransaction: () => Promise<Transaction>;
283
284
  }
284
285
 
285
286
  export declare function ReeProvider({ children, config }: ReeProviderProps): JSX_2.Element;
@@ -305,18 +306,17 @@ declare function toBitcoinNetwork(network: Network): bitcoin.networks.Network;
305
306
  */
306
307
  export declare class Transaction {
307
308
  private psbt;
309
+ private client;
308
310
  private inputAddressTypes;
309
311
  private outputAddressTypes;
310
312
  private config;
311
313
  /** Track dust amounts from user input UTXOs for fee calculation */
312
314
  private userInputUtxoDusts;
313
- /** Orchestrator actor for fee estimation */
314
- readonly orchestrator: ActorSubclass;
315
315
  private intentions;
316
316
  private txFee;
317
317
  private additionalDustNeeded;
318
318
  private inputUtxos;
319
- constructor(config: TransactionConfig, orchestrator: ActorSubclass);
319
+ constructor(config: TransactionConfig, client: ReeClient);
320
320
  /**
321
321
  * Add a UTXO as transaction input
322
322
  * @param utxo - The UTXO to add as input
@@ -358,17 +358,70 @@ export declare class Transaction {
358
358
  */
359
359
  private addBtcAndFees;
360
360
  /**
361
- * Process all intentions and calculate input/output amounts for the transaction
362
- * This method handles multiple intentions in a single transaction, calculating:
363
- * - Pool UTXOs to be consumed as inputs
364
- * - User rune UTXOs needed for input coins
365
- * - Final BTC and rune amounts for all parties (user and pools)
361
+ * Resolve and fetch all UTXOs required by the current intention set, grouped by address.
362
+ *
363
+ * How it works:
364
+ * - Scans every intention to determine, per address, whether BTC UTXOs are needed and which rune IDs are needed.
365
+ * For inputCoins, uses their `from` address.
366
+ * • For outputCoins, uses their `to` address.
367
+ * • Pool address is always considered “involved” for any coin that appears in the intention.
368
+ * • The user's payment address is always flagged as needing BTC (to pay fees/change).
369
+ * - Deduplicates addresses and rune IDs, then fetches UTXOs in parallel via the client:
370
+ * • BTC UTXOs: client.getBtcUtxos(address)
371
+ * • Rune UTXOs: client.getRuneUtxos(address, runeId)
372
+ * - Any fetch error is treated as an empty list for robustness.
373
+ *
374
+ * Returns:
375
+ * - An object with two maps:
376
+ * • btc: Record<address, Utxo[]>
377
+ * • rune: Record<address, Record<runeId, Utxo[]>>
378
+ */
379
+ private getInvolvedAddressUtxos;
380
+ /**
381
+ * Select inputs (UTXOs) according to the intentions and compute the coin outputs per address.
382
+ *
383
+ * Inputs:
384
+ * - addressUtxos: UTXOs grouped as returned by getInvolvedAddressUtxos().
385
+ *
386
+ * Algorithm (high level):
387
+ * 1) Validate there is at least one intention.
388
+ * 2) For each intention, ensure symmetry between inputCoins and outputCoins around the pool:
389
+ * - If a coin is sent from an address to the pool but not listed as output to the pool, add an output-to-pool entry.
390
+ * - If a coin is received from the pool by an address but not listed as input-from-pool, add an input-from-pool entry.
391
+ * 3) Aggregate per-address input and output coin amounts (addressInputCoinAmounts, addressOutputCoinAmounts).
392
+ * 4) For each [address, coinId] in the input amounts:
393
+ * - BTC (coinId === BITCOIN_ID):
394
+ * • If address is the user's payment address, we treat it specially by decrementing its BTC in addressOutputCoinAmounts
395
+ * (the actual funding and fee handling will be done later in addBtcAndFees).
396
+ * • Otherwise, select BTC UTXOs (preferring rune-free for non-pool addresses), add them as inputs, compute change and
397
+ * add that change to addressOutputCoinAmounts[address]. If the address is a pool, also credit any rune balances
398
+ * contained in selected pool BTC UTXOs to addressOutputCoinAmounts for later distribution.
399
+ * - Rune (coinId !== BITCOIN_ID): select rune UTXOs for the required runeId, add as inputs, compute rune change and add
400
+ * to addressOutputCoinAmounts[address].
401
+ * 5) Ensure all pool UTXOs are included: for pool addresses that only appear on the receiving side, add all their BTC/rune
402
+ * UTXOs as inputs and credit their total balances into addressOutputCoinAmounts accordingly.
403
+ *
404
+ * Returns:
405
+ * - addressOutputCoinAmounts: Record<address, Record<coinId, bigint>> — the final coin amounts to be sent to each address.
406
+ */
407
+ private addInputsAndCalculateOutputs;
408
+ /**
409
+ * Materialize outputs from the computed addressReceiveCoinAmounts.
410
+ *
411
+ * Steps:
412
+ * 1) Collect all rune IDs present across recipients. If any runes are to be transferred, first build a Runestone (edicts)
413
+ * and add an OP_RETURN output (at index 0). Edicts reference subsequent output indices.
414
+ * 2) For each address that receives runes, also ensure a BTC output exists at that index:
415
+ * - If an explicit BTC amount is provided for the address and the address is not the user's own rune address, use it.
416
+ * - Otherwise, add a dust-sized BTC output (UTXO_DUST) to carry the runes, and track additionalDustNeeded for fees.
417
+ * After using an explicit BTC amount for a rune recipient, remove it from the remaining BTC-only outputs map.
418
+ * 3) Finally, add any remaining BTC-only outputs where amount > 0.
366
419
  *
367
- * @returns Object containing calculated amounts for transaction outputs
368
- * @throws Error if pools have insufficient funds for the requested operations
420
+ * Notes:
421
+ * - Output values are bigint; scripts use Uint8Array, compatible with bitcoinjs-lib v7.
422
+ * - Output ordering: OP_RETURN (if any) first, then rune recipients in the order we build edicts, then remaining BTC outputs.
369
423
  */
370
- private addInputAndCalculateOutputs;
371
- private addRuneOutputs;
424
+ private addOutputs;
372
425
  /**
373
426
  * Add an intention to the transaction
374
427
  * Multiple intentions can be added to create complex, atomic transactions
@@ -435,9 +488,6 @@ export declare interface TransactionConfig {
435
488
  exchangeId: string;
436
489
  address: string;
437
490
  paymentAddress: string;
438
- btcUtxos: Utxo[];
439
- involvedPoolUtxos: Record<string, Utxo[]>;
440
- involvedRuneUtxos?: Record<string, Utxo[]>;
441
491
  }
442
492
 
443
493
  declare interface UseBalanceOptions {