@arkade-os/sdk 0.3.4 → 0.3.5

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
@@ -171,7 +171,13 @@ Collaborative exit or "offboarding" allows you to withdraw your virtual funds to
171
171
  ```typescript
172
172
  import { Ramps } from '@arkade-os/sdk'
173
173
 
174
- const exitTxid = await new Ramps(wallet).offboard(onchainAddress);
174
+ // Get fee information from the server
175
+ const info = await wallet.arkProvider.getInfo();
176
+
177
+ const exitTxid = await new Ramps(wallet).offboard(
178
+ onchainAddress,
179
+ info.fees
180
+ );
175
181
  ```
176
182
 
177
183
  ### Unilateral Exit
@@ -46,7 +46,14 @@ class RestArkProvider {
46
46
  })) ?? [],
47
47
  digest: fromServer.digest ?? "",
48
48
  dust: BigInt(fromServer.dust ?? 0),
49
- fees: fromServer.fees,
49
+ fees: {
50
+ intentFee: {
51
+ ...fromServer.fees?.intentFee,
52
+ onchainInput: BigInt(fromServer.fees?.intentFee?.onchainInput ?? 0),
53
+ onchainOutput: BigInt(fromServer.fees?.intentFee?.onchainOutput ?? 0),
54
+ },
55
+ txFeeRate: fromServer?.fees?.txFeeRate ?? "",
56
+ },
50
57
  forfeitAddress: fromServer.forfeitAddress ?? "",
51
58
  forfeitPubkey: fromServer.forfeitPubkey ?? "",
52
59
  network: fromServer.network ?? "",
@@ -14,6 +14,10 @@ function vtxosToTxs(spendable, spent, boardingBatchTxids) {
14
14
  // All vtxos are received unless:
15
15
  // - they resulted from a settlement (either boarding or refresh)
16
16
  // - they are the change of a spend tx
17
+ // - they were spent in a payment (have arkTxId set)
18
+ // - they resulted from a payment (their txid matches an arkTxId of a spent vtxo)
19
+ // First, collect all arkTxIds from spent vtxos to identify payment transactions
20
+ const paymentArkTxIds = new Set(spent.filter((v) => v.arkTxId).map((v) => v.arkTxId));
17
21
  let vtxosLeftToCheck = [...spent];
18
22
  for (const vtxo of [...spendable, ...spent]) {
19
23
  if (vtxo.virtualStatus.state !== "preconfirmed" &&
@@ -21,6 +25,16 @@ function vtxosToTxs(spendable, spent, boardingBatchTxids) {
21
25
  vtxo.virtualStatus.commitmentTxIds.some((txid) => boardingBatchTxids.has(txid))) {
22
26
  continue;
23
27
  }
28
+ // Skip vtxos that were spent in a payment transaction
29
+ // These will be handled in the sent transaction section below
30
+ if (vtxo.arkTxId) {
31
+ continue;
32
+ }
33
+ // Skip vtxos that resulted from a payment transaction
34
+ // (their txid matches an arkTxId from a spent vtxo)
35
+ if (paymentArkTxIds.has(vtxo.txid)) {
36
+ continue;
37
+ }
24
38
  const settleVtxos = findVtxosSpentInSettlement(vtxosLeftToCheck, vtxo);
25
39
  vtxosLeftToCheck = removeVtxosFromList(vtxosLeftToCheck, settleVtxos);
26
40
  const settleAmount = reduceVtxosAmount(settleVtxos);
@@ -56,21 +70,17 @@ function vtxosToTxs(spendable, spent, boardingBatchTxids) {
56
70
  // vtxos by settled by or ark txid
57
71
  const vtxosByTxid = new Map();
58
72
  for (const v of spent) {
59
- if (v.settledBy) {
60
- if (!vtxosByTxid.has(v.settledBy)) {
61
- vtxosByTxid.set(v.settledBy, []);
62
- }
63
- const currentVtxos = vtxosByTxid.get(v.settledBy);
64
- vtxosByTxid.set(v.settledBy, [...currentVtxos, v]);
65
- }
66
- if (!v.arkTxId) {
73
+ // Prefer arkTxId over settledBy to avoid duplicates
74
+ // A vtxo should only be grouped once
75
+ const groupKey = v.arkTxId || v.settledBy;
76
+ if (!groupKey) {
67
77
  continue;
68
78
  }
69
- if (!vtxosByTxid.has(v.arkTxId)) {
70
- vtxosByTxid.set(v.arkTxId, []);
79
+ if (!vtxosByTxid.has(groupKey)) {
80
+ vtxosByTxid.set(groupKey, []);
71
81
  }
72
- const currentVtxos = vtxosByTxid.get(v.arkTxId);
73
- vtxosByTxid.set(v.arkTxId, [...currentVtxos, v]);
82
+ const currentVtxos = vtxosByTxid.get(groupKey);
83
+ vtxosByTxid.set(groupKey, [...currentVtxos, v]);
74
84
  }
75
85
  for (const [sb, vtxos] of vtxosByTxid) {
76
86
  const resultedVtxos = findVtxosResultedFromTxid([...spendable, ...spent], sb);
@@ -85,7 +95,13 @@ function vtxosToTxs(spendable, spent, boardingBatchTxids) {
85
95
  boardingTxid: "",
86
96
  arkTxid: "",
87
97
  };
88
- if (vtxo.virtualStatus.state === "preconfirmed") {
98
+ // Use the grouping key (sb) as arkTxid if it looks like an arkTxId
99
+ // (i.e., if the spent vtxos had arkTxId set, use that instead of result vtxo's txid)
100
+ const isArkTxId = vtxos.some((v) => v.arkTxId === sb);
101
+ if (isArkTxId) {
102
+ txKey.arkTxid = sb;
103
+ }
104
+ else if (vtxo.virtualStatus.state === "preconfirmed") {
89
105
  txKey.arkTxid = vtxo.txid;
90
106
  }
91
107
  txs.push({
@@ -56,10 +56,11 @@ class Ramps {
56
56
  * Offboard vtxos, or "collaborative exit" vtxos to onchain address.
57
57
  *
58
58
  * @param destinationAddress - The destination address to offboard to.
59
+ * @param feeInfo - The fee info to deduct from the offboard amount.
59
60
  * @param amount - The amount to offboard. If not provided, the total amount of vtxos will be offboarded.
60
61
  * @param eventCallback - The callback to receive settlement events. optional.
61
62
  */
62
- async offboard(destinationAddress, amount, eventCallback) {
63
+ async offboard(destinationAddress, feeInfo, amount, eventCallback) {
63
64
  const vtxos = await this.wallet.getVtxos({
64
65
  withRecoverable: true,
65
66
  withUnrolled: false,
@@ -73,6 +74,11 @@ class Ramps {
73
74
  change = totalAmount - amount;
74
75
  }
75
76
  amount = amount ?? totalAmount;
77
+ const fees = feeInfo.intentFee.onchainOutput;
78
+ if (fees > amount) {
79
+ throw new Error(`can't deduct fees from offboard amount (${fees} > ${amount})`);
80
+ }
81
+ amount -= fees;
76
82
  const outputs = [
77
83
  {
78
84
  address: destinationAddress,
@@ -431,14 +431,13 @@ class Wallet {
431
431
  });
432
432
  }
433
433
  const tapTree = this.offchainTapscript.encode();
434
- let offchainTx = (0, arkTransaction_1.buildOffchainTx)(selected.inputs.map((input) => ({
434
+ const offchainTx = (0, arkTransaction_1.buildOffchainTx)(selected.inputs.map((input) => ({
435
435
  ...input,
436
436
  tapLeafScript: selectedLeaf,
437
437
  tapTree,
438
438
  })), outputs, this.serverUnrollScript);
439
439
  const signedVirtualTx = await this.identity.sign(offchainTx.arkTx);
440
440
  const { arkTxid, signedCheckpointTxs } = await this.arkProvider.submitTx(base_1.base64.encode(signedVirtualTx.toPSBT()), offchainTx.checkpoints.map((c) => base_1.base64.encode(c.toPSBT())));
441
- // TODO persist final virtual tx and checkpoints to repository
442
441
  // sign the checkpoints
443
442
  const finalCheckpoints = await Promise.all(signedCheckpointTxs.map(async (c) => {
444
443
  const tx = btc_signer_1.Transaction.fromPSBT(base_1.base64.decode(c));
@@ -446,7 +445,78 @@ class Wallet {
446
445
  return base_1.base64.encode(signedCheckpoint.toPSBT());
447
446
  }));
448
447
  await this.arkProvider.finalizeTx(arkTxid, finalCheckpoints);
449
- return arkTxid;
448
+ try {
449
+ // mark VTXOs as spent and optionally add the change VTXO
450
+ const spentVtxos = [];
451
+ const commitmentTxIds = new Set();
452
+ let batchExpiry = Number.MAX_SAFE_INTEGER;
453
+ for (const [inputIndex, input] of selected.inputs.entries()) {
454
+ const vtxo = (0, utils_1.extendVirtualCoin)(this, input);
455
+ const checkpointB64 = signedCheckpointTxs[inputIndex];
456
+ const checkpoint = btc_signer_1.Transaction.fromPSBT(base_1.base64.decode(checkpointB64));
457
+ spentVtxos.push({
458
+ ...vtxo,
459
+ virtualStatus: { ...vtxo.virtualStatus, state: "spent" },
460
+ spentBy: checkpoint.id,
461
+ arkTxId: arkTxid,
462
+ isSpent: true,
463
+ });
464
+ if (vtxo.virtualStatus.commitmentTxIds) {
465
+ for (const commitmentTxId of vtxo.virtualStatus
466
+ .commitmentTxIds) {
467
+ commitmentTxIds.add(commitmentTxId);
468
+ }
469
+ }
470
+ if (vtxo.virtualStatus.batchExpiry) {
471
+ batchExpiry = Math.min(batchExpiry, vtxo.virtualStatus.batchExpiry);
472
+ }
473
+ }
474
+ const createdAt = Date.now();
475
+ const addr = this.arkAddress.encode();
476
+ if (selected.changeAmount > 0n &&
477
+ batchExpiry !== Number.MAX_SAFE_INTEGER) {
478
+ const changeVtxo = {
479
+ txid: arkTxid,
480
+ vout: outputs.length - 1,
481
+ createdAt: new Date(createdAt),
482
+ forfeitTapLeafScript: this.offchainTapscript.forfeit(),
483
+ intentTapLeafScript: this.offchainTapscript.exit(),
484
+ isUnrolled: false,
485
+ isSpent: false,
486
+ tapTree: this.offchainTapscript.encode(),
487
+ value: Number(selected.changeAmount),
488
+ virtualStatus: {
489
+ state: "preconfirmed",
490
+ commitmentTxIds: Array.from(commitmentTxIds),
491
+ batchExpiry,
492
+ },
493
+ status: {
494
+ confirmed: false,
495
+ },
496
+ };
497
+ await this.walletRepository.saveVtxos(addr, [changeVtxo]);
498
+ }
499
+ await this.walletRepository.saveVtxos(addr, spentVtxos);
500
+ await this.walletRepository.saveTransactions(addr, [
501
+ {
502
+ key: {
503
+ boardingTxid: "",
504
+ commitmentTxid: "",
505
+ arkTxid: arkTxid,
506
+ },
507
+ amount: params.amount,
508
+ type: _1.TxType.TxSent,
509
+ settled: false,
510
+ createdAt: Date.now(),
511
+ },
512
+ ]);
513
+ }
514
+ catch (e) {
515
+ console.warn("error saving offchain tx to repository", e);
516
+ }
517
+ finally {
518
+ return arkTxid;
519
+ }
450
520
  }
451
521
  async settle(params, eventCallback) {
452
522
  if (params?.inputs) {
@@ -719,7 +789,8 @@ class Wallet {
719
789
  (async () => {
720
790
  try {
721
791
  for await (const update of subscription) {
722
- if (update.newVtxos?.length > 0) {
792
+ if (update.newVtxos?.length > 0 ||
793
+ update.spentVtxos?.length > 0) {
723
794
  eventCallback({
724
795
  type: "vtxo",
725
796
  newVtxos: update.newVtxos.map((vtxo) => (0, utils_1.extendVirtualCoin)(this, vtxo)),
@@ -42,7 +42,14 @@ export class RestArkProvider {
42
42
  })) ?? [],
43
43
  digest: fromServer.digest ?? "",
44
44
  dust: BigInt(fromServer.dust ?? 0),
45
- fees: fromServer.fees,
45
+ fees: {
46
+ intentFee: {
47
+ ...fromServer.fees?.intentFee,
48
+ onchainInput: BigInt(fromServer.fees?.intentFee?.onchainInput ?? 0),
49
+ onchainOutput: BigInt(fromServer.fees?.intentFee?.onchainOutput ?? 0),
50
+ },
51
+ txFeeRate: fromServer?.fees?.txFeeRate ?? "",
52
+ },
46
53
  forfeitAddress: fromServer.forfeitAddress ?? "",
47
54
  forfeitPubkey: fromServer.forfeitPubkey ?? "",
48
55
  network: fromServer.network ?? "",
@@ -11,6 +11,10 @@ export function vtxosToTxs(spendable, spent, boardingBatchTxids) {
11
11
  // All vtxos are received unless:
12
12
  // - they resulted from a settlement (either boarding or refresh)
13
13
  // - they are the change of a spend tx
14
+ // - they were spent in a payment (have arkTxId set)
15
+ // - they resulted from a payment (their txid matches an arkTxId of a spent vtxo)
16
+ // First, collect all arkTxIds from spent vtxos to identify payment transactions
17
+ const paymentArkTxIds = new Set(spent.filter((v) => v.arkTxId).map((v) => v.arkTxId));
14
18
  let vtxosLeftToCheck = [...spent];
15
19
  for (const vtxo of [...spendable, ...spent]) {
16
20
  if (vtxo.virtualStatus.state !== "preconfirmed" &&
@@ -18,6 +22,16 @@ export function vtxosToTxs(spendable, spent, boardingBatchTxids) {
18
22
  vtxo.virtualStatus.commitmentTxIds.some((txid) => boardingBatchTxids.has(txid))) {
19
23
  continue;
20
24
  }
25
+ // Skip vtxos that were spent in a payment transaction
26
+ // These will be handled in the sent transaction section below
27
+ if (vtxo.arkTxId) {
28
+ continue;
29
+ }
30
+ // Skip vtxos that resulted from a payment transaction
31
+ // (their txid matches an arkTxId from a spent vtxo)
32
+ if (paymentArkTxIds.has(vtxo.txid)) {
33
+ continue;
34
+ }
21
35
  const settleVtxos = findVtxosSpentInSettlement(vtxosLeftToCheck, vtxo);
22
36
  vtxosLeftToCheck = removeVtxosFromList(vtxosLeftToCheck, settleVtxos);
23
37
  const settleAmount = reduceVtxosAmount(settleVtxos);
@@ -53,21 +67,17 @@ export function vtxosToTxs(spendable, spent, boardingBatchTxids) {
53
67
  // vtxos by settled by or ark txid
54
68
  const vtxosByTxid = new Map();
55
69
  for (const v of spent) {
56
- if (v.settledBy) {
57
- if (!vtxosByTxid.has(v.settledBy)) {
58
- vtxosByTxid.set(v.settledBy, []);
59
- }
60
- const currentVtxos = vtxosByTxid.get(v.settledBy);
61
- vtxosByTxid.set(v.settledBy, [...currentVtxos, v]);
62
- }
63
- if (!v.arkTxId) {
70
+ // Prefer arkTxId over settledBy to avoid duplicates
71
+ // A vtxo should only be grouped once
72
+ const groupKey = v.arkTxId || v.settledBy;
73
+ if (!groupKey) {
64
74
  continue;
65
75
  }
66
- if (!vtxosByTxid.has(v.arkTxId)) {
67
- vtxosByTxid.set(v.arkTxId, []);
76
+ if (!vtxosByTxid.has(groupKey)) {
77
+ vtxosByTxid.set(groupKey, []);
68
78
  }
69
- const currentVtxos = vtxosByTxid.get(v.arkTxId);
70
- vtxosByTxid.set(v.arkTxId, [...currentVtxos, v]);
79
+ const currentVtxos = vtxosByTxid.get(groupKey);
80
+ vtxosByTxid.set(groupKey, [...currentVtxos, v]);
71
81
  }
72
82
  for (const [sb, vtxos] of vtxosByTxid) {
73
83
  const resultedVtxos = findVtxosResultedFromTxid([...spendable, ...spent], sb);
@@ -82,7 +92,13 @@ export function vtxosToTxs(spendable, spent, boardingBatchTxids) {
82
92
  boardingTxid: "",
83
93
  arkTxid: "",
84
94
  };
85
- if (vtxo.virtualStatus.state === "preconfirmed") {
95
+ // Use the grouping key (sb) as arkTxid if it looks like an arkTxId
96
+ // (i.e., if the spent vtxos had arkTxId set, use that instead of result vtxo's txid)
97
+ const isArkTxId = vtxos.some((v) => v.arkTxId === sb);
98
+ if (isArkTxId) {
99
+ txKey.arkTxid = sb;
100
+ }
101
+ else if (vtxo.virtualStatus.state === "preconfirmed") {
86
102
  txKey.arkTxid = vtxo.txid;
87
103
  }
88
104
  txs.push({
@@ -53,10 +53,11 @@ export class Ramps {
53
53
  * Offboard vtxos, or "collaborative exit" vtxos to onchain address.
54
54
  *
55
55
  * @param destinationAddress - The destination address to offboard to.
56
+ * @param feeInfo - The fee info to deduct from the offboard amount.
56
57
  * @param amount - The amount to offboard. If not provided, the total amount of vtxos will be offboarded.
57
58
  * @param eventCallback - The callback to receive settlement events. optional.
58
59
  */
59
- async offboard(destinationAddress, amount, eventCallback) {
60
+ async offboard(destinationAddress, feeInfo, amount, eventCallback) {
60
61
  const vtxos = await this.wallet.getVtxos({
61
62
  withRecoverable: true,
62
63
  withUnrolled: false,
@@ -70,6 +71,11 @@ export class Ramps {
70
71
  change = totalAmount - amount;
71
72
  }
72
73
  amount = amount ?? totalAmount;
74
+ const fees = feeInfo.intentFee.onchainOutput;
75
+ if (fees > amount) {
76
+ throw new Error(`can't deduct fees from offboard amount (${fees} > ${amount})`);
77
+ }
78
+ amount -= fees;
73
79
  const outputs = [
74
80
  {
75
81
  address: destinationAddress,
@@ -394,14 +394,13 @@ export class Wallet {
394
394
  });
395
395
  }
396
396
  const tapTree = this.offchainTapscript.encode();
397
- let offchainTx = buildOffchainTx(selected.inputs.map((input) => ({
397
+ const offchainTx = buildOffchainTx(selected.inputs.map((input) => ({
398
398
  ...input,
399
399
  tapLeafScript: selectedLeaf,
400
400
  tapTree,
401
401
  })), outputs, this.serverUnrollScript);
402
402
  const signedVirtualTx = await this.identity.sign(offchainTx.arkTx);
403
403
  const { arkTxid, signedCheckpointTxs } = await this.arkProvider.submitTx(base64.encode(signedVirtualTx.toPSBT()), offchainTx.checkpoints.map((c) => base64.encode(c.toPSBT())));
404
- // TODO persist final virtual tx and checkpoints to repository
405
404
  // sign the checkpoints
406
405
  const finalCheckpoints = await Promise.all(signedCheckpointTxs.map(async (c) => {
407
406
  const tx = Transaction.fromPSBT(base64.decode(c));
@@ -409,7 +408,78 @@ export class Wallet {
409
408
  return base64.encode(signedCheckpoint.toPSBT());
410
409
  }));
411
410
  await this.arkProvider.finalizeTx(arkTxid, finalCheckpoints);
412
- return arkTxid;
411
+ try {
412
+ // mark VTXOs as spent and optionally add the change VTXO
413
+ const spentVtxos = [];
414
+ const commitmentTxIds = new Set();
415
+ let batchExpiry = Number.MAX_SAFE_INTEGER;
416
+ for (const [inputIndex, input] of selected.inputs.entries()) {
417
+ const vtxo = extendVirtualCoin(this, input);
418
+ const checkpointB64 = signedCheckpointTxs[inputIndex];
419
+ const checkpoint = Transaction.fromPSBT(base64.decode(checkpointB64));
420
+ spentVtxos.push({
421
+ ...vtxo,
422
+ virtualStatus: { ...vtxo.virtualStatus, state: "spent" },
423
+ spentBy: checkpoint.id,
424
+ arkTxId: arkTxid,
425
+ isSpent: true,
426
+ });
427
+ if (vtxo.virtualStatus.commitmentTxIds) {
428
+ for (const commitmentTxId of vtxo.virtualStatus
429
+ .commitmentTxIds) {
430
+ commitmentTxIds.add(commitmentTxId);
431
+ }
432
+ }
433
+ if (vtxo.virtualStatus.batchExpiry) {
434
+ batchExpiry = Math.min(batchExpiry, vtxo.virtualStatus.batchExpiry);
435
+ }
436
+ }
437
+ const createdAt = Date.now();
438
+ const addr = this.arkAddress.encode();
439
+ if (selected.changeAmount > 0n &&
440
+ batchExpiry !== Number.MAX_SAFE_INTEGER) {
441
+ const changeVtxo = {
442
+ txid: arkTxid,
443
+ vout: outputs.length - 1,
444
+ createdAt: new Date(createdAt),
445
+ forfeitTapLeafScript: this.offchainTapscript.forfeit(),
446
+ intentTapLeafScript: this.offchainTapscript.exit(),
447
+ isUnrolled: false,
448
+ isSpent: false,
449
+ tapTree: this.offchainTapscript.encode(),
450
+ value: Number(selected.changeAmount),
451
+ virtualStatus: {
452
+ state: "preconfirmed",
453
+ commitmentTxIds: Array.from(commitmentTxIds),
454
+ batchExpiry,
455
+ },
456
+ status: {
457
+ confirmed: false,
458
+ },
459
+ };
460
+ await this.walletRepository.saveVtxos(addr, [changeVtxo]);
461
+ }
462
+ await this.walletRepository.saveVtxos(addr, spentVtxos);
463
+ await this.walletRepository.saveTransactions(addr, [
464
+ {
465
+ key: {
466
+ boardingTxid: "",
467
+ commitmentTxid: "",
468
+ arkTxid: arkTxid,
469
+ },
470
+ amount: params.amount,
471
+ type: TxType.TxSent,
472
+ settled: false,
473
+ createdAt: Date.now(),
474
+ },
475
+ ]);
476
+ }
477
+ catch (e) {
478
+ console.warn("error saving offchain tx to repository", e);
479
+ }
480
+ finally {
481
+ return arkTxid;
482
+ }
413
483
  }
414
484
  async settle(params, eventCallback) {
415
485
  if (params?.inputs) {
@@ -682,7 +752,8 @@ export class Wallet {
682
752
  (async () => {
683
753
  try {
684
754
  for await (const update of subscription) {
685
- if (update.newVtxos?.length > 0) {
755
+ if (update.newVtxos?.length > 0 ||
756
+ update.spentVtxos?.length > 0) {
686
757
  eventCallback({
687
758
  type: "vtxo",
688
759
  newVtxos: update.newVtxos.map((vtxo) => extendVirtualCoin(this, vtxo)),
@@ -18,7 +18,7 @@ import { Worker } from "./wallet/serviceWorker/worker";
18
18
  import { Request } from "./wallet/serviceWorker/request";
19
19
  import { Response } from "./wallet/serviceWorker/response";
20
20
  import { ESPLORA_URL, EsploraProvider, OnchainProvider, ExplorerTransaction } from "./providers/onchain";
21
- import { RestArkProvider, ArkProvider, SettlementEvent, SettlementEventType, ArkInfo, SignedIntent, Output, TxNotification, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent, TreeNoncesEvent, BatchStartedEvent, TreeTxEvent, TreeSignatureEvent, ScheduledSession } from "./providers/ark";
21
+ import { RestArkProvider, ArkProvider, SettlementEvent, SettlementEventType, ArkInfo, SignedIntent, Output, TxNotification, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent, TreeNoncesEvent, BatchStartedEvent, TreeTxEvent, TreeSignatureEvent, ScheduledSession, FeeInfo } from "./providers/ark";
22
22
  import { CLTVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CSVMultisigTapscript, decodeTapscript, MultisigTapscript, TapscriptType, ArkTapscript, RelativeTimelock } from "./script/tapscript";
23
23
  import { hasBoardingTxExpired, buildOffchainTx, verifyTapscriptSignatures, ArkTxInput, OffchainTx, combineTapscriptSigs } from "./utils/arkTransaction";
24
24
  import { VtxoTaprootTree, ConditionWitness, getArkPsbtFields, setArkPsbtField, ArkPsbtFieldCoder, ArkPsbtFieldKey, ArkPsbtFieldKeyType, CosignerPublicKey, VtxoTreeExpiry } from "./utils/unknownFields";
@@ -34,4 +34,4 @@ import { WalletRepositoryImpl } from "./repositories/walletRepository";
34
34
  import { ContractRepositoryImpl } from "./repositories/contractRepository";
35
35
  import { ArkError, maybeArkError } from "./providers/errors";
36
36
  export { Wallet, SingleKey, OnchainWallet, Ramps, VtxoManager, ESPLORA_URL, EsploraProvider, RestArkProvider, RestIndexerProvider, ArkAddress, DefaultVtxo, VtxoScript, VHTLC, TxType, IndexerTxType, ChainTxType, SettlementEventType, setupServiceWorker, Worker, ServiceWorkerWallet, Request, Response, decodeTapscript, MultisigTapscript, CSVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CLTVMultisigTapscript, TapTreeCoder, ArkPsbtFieldKey, ArkPsbtFieldKeyType, setArkPsbtField, getArkPsbtFields, CosignerPublicKey, VtxoTreeExpiry, VtxoTaprootTree, ConditionWitness, buildOffchainTx, verifyTapscriptSignatures, waitForIncomingFunds, hasBoardingTxExpired, combineTapscriptSigs, ArkNote, networks, WalletRepositoryImpl, ContractRepositoryImpl, Intent, TxTree, P2A, Unroll, Transaction, ArkError, maybeArkError, };
37
- export type { Identity, IWallet, WalletConfig, ProviderClass, ArkTransaction, Coin, ExtendedCoin, ExtendedVirtualCoin, WalletBalance, SendBitcoinParams, Recipient, SettleParams, Status, VirtualStatus, Outpoint, VirtualCoin, TxKey, TapscriptType, ArkTxInput, OffchainTx, TapLeaves, IncomingFunds, IndexerProvider, PageResponse, Batch, ChainTx, CommitmentTx, TxHistoryRecord, Vtxo, VtxoChain, Tx, OnchainProvider, ArkProvider, SettlementEvent, ArkInfo, SignedIntent, Output, TxNotification, ExplorerTransaction, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent, TreeNoncesEvent, BatchStartedEvent, TreeTxEvent, TreeSignatureEvent, ScheduledSession, PaginationOptions, SubscriptionResponse, SubscriptionHeartbeat, SubscriptionEvent, Network, NetworkName, ArkTapscript, RelativeTimelock, EncodedVtxoScript, TapLeafScript, SignerSession, TreeNonces, TreePartialSigs, GetVtxosFilter, Nonces, PartialSig, ArkPsbtFieldCoder, TxTreeNode, AnchorBumper, };
37
+ export type { Identity, IWallet, WalletConfig, ProviderClass, ArkTransaction, Coin, ExtendedCoin, ExtendedVirtualCoin, WalletBalance, SendBitcoinParams, Recipient, SettleParams, Status, VirtualStatus, Outpoint, VirtualCoin, TxKey, TapscriptType, ArkTxInput, OffchainTx, TapLeaves, IncomingFunds, IndexerProvider, PageResponse, Batch, ChainTx, CommitmentTx, TxHistoryRecord, Vtxo, VtxoChain, Tx, OnchainProvider, ArkProvider, SettlementEvent, FeeInfo, ArkInfo, SignedIntent, Output, TxNotification, ExplorerTransaction, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent, TreeNoncesEvent, BatchStartedEvent, TreeTxEvent, TreeSignatureEvent, ScheduledSession, PaginationOptions, SubscriptionResponse, SubscriptionHeartbeat, SubscriptionEvent, Network, NetworkName, ArkTapscript, RelativeTimelock, EncodedVtxoScript, TapLeafScript, SignerSession, TreeNonces, TreePartialSigs, GetVtxosFilter, Nonces, PartialSig, ArkPsbtFieldCoder, TxTreeNode, AnchorBumper, };
@@ -75,8 +75,8 @@ export interface ScheduledSession {
75
75
  export interface IntentFeeInfo {
76
76
  offchainInput: string;
77
77
  offchainOutput: string;
78
- onchainInput: string;
79
- onchainOutput: string;
78
+ onchainInput: bigint;
79
+ onchainOutput: bigint;
80
80
  }
81
81
  export interface FeeInfo {
82
82
  intentFee: IntentFeeInfo;
@@ -1,5 +1,5 @@
1
1
  import { ExtendedCoin, IWallet } from ".";
2
- import { SettlementEvent } from "../providers/ark";
2
+ import { FeeInfo, SettlementEvent } from "../providers/ark";
3
3
  /**
4
4
  * Ramps is a class wrapping IWallet.settle method to provide a more convenient interface for onboarding and offboarding operations.
5
5
  *
@@ -25,8 +25,9 @@ export declare class Ramps {
25
25
  * Offboard vtxos, or "collaborative exit" vtxos to onchain address.
26
26
  *
27
27
  * @param destinationAddress - The destination address to offboard to.
28
+ * @param feeInfo - The fee info to deduct from the offboard amount.
28
29
  * @param amount - The amount to offboard. If not provided, the total amount of vtxos will be offboarded.
29
30
  * @param eventCallback - The callback to receive settlement events. optional.
30
31
  */
31
- offboard(destinationAddress: string, amount?: bigint, eventCallback?: (event: SettlementEvent) => void): ReturnType<IWallet["settle"]>;
32
+ offboard(destinationAddress: string, feeInfo: FeeInfo, amount?: bigint, eventCallback?: (event: SettlementEvent) => void): ReturnType<IWallet["settle"]>;
32
33
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkade-os/sdk",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "description": "Bitcoin wallet SDK with Taproot and Ark integration",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -63,8 +63,8 @@
63
63
  "@types/node": "24.3.1",
64
64
  "@vitest/coverage-v8": "3.2.4",
65
65
  "esbuild": "^0.25.9",
66
- "expo": "~52.0.47",
67
66
  "eventsource": "4.0.0",
67
+ "expo": "~52.0.47",
68
68
  "glob": "11.0.3",
69
69
  "husky": "9.1.7",
70
70
  "prettier": "3.6.2",