aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ark/manager.js5
-rw-r--r--src/ark/proto.js3
-rw-r--r--src/features/gifts.js7
3 files changed, 14 insertions, 1 deletions
diff --git a/src/ark/manager.js b/src/ark/manager.js
index 01de06f..f9819a0 100644
--- a/src/ark/manager.js
+++ b/src/ark/manager.js
@@ -1270,6 +1270,11 @@ export class ArkManager {
const tip = await this.chain.tipHeight();
const totalSat = inputs.reduce((n, v) => n + v.amountSat, 0);
const feeSat = this.refreshFee(inputs, tip);
+ // The server refuses round outputs under P2TR dust (330), so a wallet
+ // this small can't renew — fail before the action marks coins pending.
+ if (totalSat - feeSat < 330) {
+ throw new Error(`balance too small to refresh: ${totalSat} sat minus ${feeSat} sat fee is under the 330 sat minimum`);
+ }
const action = {
id: `refresh-${Date.now()}`, type: 'refresh', step: 'created',
inputIds: inputs.map((v) => v.id),
diff --git a/src/ark/proto.js b/src/ark/proto.js
index 6729465..81651ee 100644
--- a/src/ark/proto.js
+++ b/src/ark/proto.js
@@ -29,6 +29,9 @@ export function pbWriter() {
const chunks = [];
const varint = (n) => {
n = BigInt(n);
+ // a negative sign-extends under >>= forever — the do/while would push
+ // bytes until the process dies of memory, so refuse it loudly instead
+ if (n < 0n) throw new Error(`varint: negative value ${n}`);
const bs = [];
do { let b = Number(n & 0x7fn); n >>= 7n; if (n) b |= 0x80; bs.push(b); } while (n);
chunks.push(Uint8Array.from(bs));
diff --git a/src/features/gifts.js b/src/features/gifts.js
index bc16619..0543030 100644
--- a/src/features/gifts.js
+++ b/src/features/gifts.js
@@ -402,11 +402,16 @@ export function giftsFeature(ctx) {
// An ark gift: send the amount to a fresh bearer identity, off-chain and
// instant — no coin locking, no split logic, no claim fee.
+ // Gifts go down to 1 sat: the ASP cosigns all-dust arkoor sends, so a
+ // sub-dust bearer vtxo sweeps to the claimer fine (regtest-proven —
+ // tools/ark/dust-gift-test.js). The trade a sub-330 coin carries — no
+ // unilateral exit on its own, renewable in rounds only alongside bigger
+ // siblings — is the same one dust zaps already make.
async function doCreateArkGift() {
const info = hook('arkGiftInfo');
const avail = info ? info.spendableSat : 0;
const amt = ui.giftMax ? avail : parseAmount(ui.giftAmount, getUnit());
- if (!amt || amt < 330) { ui.giftError = t('giftAmountInvalid', { n: fmtAmount(330) + ' ' + unitLabel() }); render(); return; }
+ if (!amt || amt < 1) { ui.giftError = t('giftAmountInvalid', { n: fmtAmount(1) + ' ' + unitLabel() }); render(); return; }
if (amt > avail) { ui.giftError = t('giftExceedsBalance'); render(); return; }
ui.busy = true; ui.giftError = ''; render();
try {