From f4997d29a0c97eac61338448854c7ab9724cdc92 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 22 Oct 2026 22:06:01 -0700 Subject: The third custody tier keeps exits cheap by depth, not by date: "Keep my exit cheap" renews a coin once its history is four hops deep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why: a unilateral exit publishes one on-chain transaction per off-chain hop, so depth — not age — is what makes an exit expensive, and a renewal a week before expiry flattens exactly the same history a renewal in the last hours does. The week-ahead "early" tier only guarded against the server being unreachable at the very end, which is not the case worth selling. (Adam, 2026-10-23.) exit = self (last-hours renewal, free bracket + base, the same grid-snapped backstop) plus: any coin whose genesis chain is 4+ hops deep is renewed in the next round the app runs, paying the top bracket + base — but only when that fee is under a tenth of the coin (flattening a 21-sat coin for 300 sats helps nobody; its exit is uneconomic anyway). Deep coins ride along with an expiry renewal when one is due, or get a round of their own. The server-side backstop stays near-expiry only: depth changes only while the wallet transacts, i.e. while the app is open. A stored 'early' reads as 'exit'. Card copy says what the hop count means and what the two prices are for. Co-Authored-By: Claude Fable 5.1 --- src/ark/manager.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'src/ark') diff --git a/src/ark/manager.js b/src/ark/manager.js index 2b7a5a7..79fdcd0 100644 --- a/src/ark/manager.js +++ b/src/ark/manager.js @@ -183,20 +183,27 @@ export const backstopMargin = (network) => (network === 'regtest' ? 6 : 36); // the balance works like a v2 one, and no renewal is ever paid. // self renew in the last hours before expiry — the free ppm bracket, // one base fee per round — so a unilateral exit is always there. -// early renew a week ahead (the 0.1% bracket + base) for whoever wants -// a margin against the server being unreachable near the end. +// exit the same, plus: renew a coin as soon as its history runs +// `maxDepth` hops deep. A unilateral exit publishes one on-chain +// transaction per hop, so depth — not age — is what makes an +// exit expensive; a renewal flattens it to one hop. Early, so +// the top ppm bracket + base; only for a coin worth it (the fee +// under a tenth of its value — see maybeAutoRefresh). // A policy is { window, margin, grid } in blocks: the app renews a coin with // under `window` blocks left; the server-side backstop is registered `margin` // blocks before expiry, snapped DOWN to a multiple of `grid` so everyone's // orders land in the same round (one round's mining fee shared, not one per -// coin). The snapped height stays inside the same fee bracket: self runs -// 36–83 blocks out (free under 96), early 1008–1151 (0.1% under 2160). -export const CUSTODY_TIERS = ['custodial', 'self', 'early']; +// coin). The snapped height stays inside the free bracket: 36–83 blocks out. +export const CUSTODY_TIERS = ['custodial', 'self', 'exit']; export const MAX_SEND_INPUTS = 48; export function renewPolicy(tier, network) { const rt = network === 'regtest'; - if (tier === 'early') return { window: rt ? 60 : 1008, margin: rt ? 60 : 1008, grid: rt ? 1 : 144 }; - if (tier === 'self') return { window: rt ? 24 : 96, margin: backstopMargin(network), grid: rt ? 1 : 48 }; + const self = { window: rt ? 24 : 96, margin: backstopMargin(network), grid: rt ? 1 : 48 }; + // 'early' was the third tier for a day (2026-10-22): a week-ahead renewal, + // which flattens the same history a last-hours one does — mirrors may + // still carry the name + if (tier === 'exit' || tier === 'early') return { ...self, maxDepth: 4 }; + if (tier === 'self') return self; return null; } -- cgit v1.2.3