diff options
Diffstat (limited to 'tools/ark/custody-test.js')
| -rw-r--r-- | tools/ark/custody-test.js | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/tools/ark/custody-test.js b/tools/ark/custody-test.js index f8106b7..214ab45 100644 --- a/tools/ark/custody-test.js +++ b/tools/ark/custody-test.js @@ -93,4 +93,38 @@ const coin = (id, amountSat, expiryHeight, extra = {}) => ({ id, amountSat, expi await assert.rejects(validateVtxo(v, { serverPubkey: serverPub, chain, acceptExpired: true }), (e) => e instanceof VtxoValidationError && /not confirmed/.test(e.message), 'past the expiry check, on to the anchor'); console.log('✓ validateVtxo: acceptExpired lets a coin past its timelock through the expiry check'); } + +// deep coins: the server's depth cap and its base-fee waiver, mirrored +{ + const m = mk(true); + m.info.refreshFees.deepWaiverDepth = 60; + m.info.maxVtxoExitDepth = 100; + m.exitDepth = (v) => v.depth || 0; + m._tipMemo = async () => 1000; + const shallow = coin('s', 5000, 2000, { depth: 7 }), deep = coin('d', 4000, 2000, { depth: 60 }); + const capped = coin('x', 3000, 2000, { depth: 100 }), near = coin('n', 2500, 2000, { depth: 92 }); + const expiredDeep = coin('e', 6000, 900, { depth: 70 }); + m.state.vtxos = [shallow, deep, capped, near, expiredDeep]; + assert.equal(m.refreshFee([deep], 1000), 0, 'a refresh of deep coins alone pays no base fee'); + assert.equal(m.refreshFee([deep, expiredDeep], 1000), 0); + assert.equal(m.refreshFee([deep, shallow], 1000), 300, '…one shallow coin in the set and it pays'); + assert.equal(m.refreshFee([shallow], 1000), 300); + assert.deepEqual(m.deepCoins().map((v) => v.id).sort(), ['d', 'e', 'n', 'x'], 'deep = at the waiver depth or within 8 hops of the cap, expired or not'); + assert.deepEqual(m._selectInputs(2900).map((v) => v.id), ['d'], 'a coin at the cap is never an input (the cosign would be refused)'); + m.state.vtxos = [capped]; + assert.throws(() => m._selectInputs(1000), /waiting to be renewed/, 'and the shortfall says why'); + m.state.vtxos = [shallow, deep, capped, near, expiredDeep]; + // the worker's orders: one per deep coin still inside its timelock, two blocks out + const orders = []; + m.scheduleRefresh = async (ids, h) => { orders.push([ids.join(), h]); (m.state.scheduled ||= []).push({ inputIds: ids, unlockHash: 'u' + ids }); }; + assert.equal(await m.ensureDeepRefreshes(3), 3); + assert.deepEqual(orders, [['x', 1002], ['n', 1002], ['d', 1002]], 'deepest first, at tip + 2; the expired one waits for the app'); + assert.equal(await m.ensureDeepRefreshes(3), 0, 'covered coins are not ordered twice'); + // no waiver and no cap advertised: nothing is deep + const plain = mk(true); plain.exitDepth = () => 999; plain.state.vtxos = [coin('p', 5000, 2000)]; + assert.deepEqual(plain.deepCoins(), []); + assert.equal(plain.refreshFee(plain.state.vtxos, 1000), 300, 'no waiver advertised: the base fee stands however deep'); + console.log('✓ deep coins: no base fee for a refresh of deep coins alone, a capped coin is never spent, the worker orders them flattened'); +} + console.log('\n✅ custody tiers behave'); |
