aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-07-05 22:43:40 -0700
committerAdam Soltys <[email protected]>2026-07-05 22:43:40 -0700
commit1725e6ca03eacbe1ee16f563c8fdb27435080553 (patch)
treed6e4f00ca41a3bd4c36d386b6518ac71fb0edae2 /src
parent0b3d332c09272a9fa98ccf668a4b4923df54977a (diff)
downloadcoinosv3-1725e6ca03eacbe1ee16f563c8fdb27435080553.tar.gz
coinosv3-1725e6ca03eacbe1ee16f563c8fdb27435080553.zip
Show the ark board fee before boarding
100,000 in, 99,670 out was a surprise: the ASP's board fee (min/base/ ppm from its published schedule; it funds the exit tx's P2A fee anchor) was only visible after the fact. The board form now shows the fee and the net amount live as you type, and the funding tx's detail view gets an 'Ark server fee' line. Co-Authored-By: Claude Fable 5 <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/features/ark.js16
-rw-r--r--src/i18n.js2
2 files changed, 17 insertions, 1 deletions
diff --git a/src/features/ark.js b/src/features/ark.js
index 57a8f82..f886c0a 100644
--- a/src/features/ark.js
+++ b/src/features/ark.js
@@ -7,6 +7,7 @@ import { HDKey } from '@scure/bip32';
import { hex, base32nopad } from '@scure/base';
import { sha256 } from '@noble/hashes/sha256';
import { ArkManager } from '../ark/manager.js';
+import { boardFee } from '../ark/board.js';
import { decodeVtxo, getVtxoStatus, VTXO_STATE_SPENT, concatBytes } from '../ark/proto.js';
import { signedExitTxs, buildBumpChild, buildExitClaim, submitPackage } from '../ark/exit.js';
import { utxoId } from '../wallet.js';
@@ -598,10 +599,18 @@ export function arkFeature(ctx) {
type: 'number', inputmode: 'numeric', min: '0',
placeholder: t('arkBoardPlaceholder', { n: minBoard.toLocaleString() }),
value: ui.arkBoardAmt || '',
- onInput: (e) => { ui.arkBoardAmt = e.target.value; },
+ onInput: (e) => { ui.arkBoardAmt = e.target.value; render(); },
}),
h('button', { class: 'btn-sm', disabled: !!ui.arkBusy || !canBoard, onClick: doArkBoard },
ui.arkBusy === 'board' ? h('span', { class: 'spinner sm' }) : t('arkBoardBtn'))),
+ // show the server's board fee BEFORE the money moves, not after
+ (() => {
+ const sats = parseInt((ui.arkBoardAmt || '').trim(), 10);
+ if (!sats || sats < minBoard) return null;
+ const fee = boardFee(sats, ark.info.boardFees);
+ return h('div', { class: 'small muted', style: 'text-align:center' },
+ t('arkBoardFeeNote', { fee: fmtAmount(fee), net: fmtAmount(sats - fee) }));
+ })(),
canBoard
? h('div', { class: 'small faint', style: 'text-align:center' }, t('arkBoardAvailable', { n: fmtAmount(wallet.spendable) + ' ' + unitLabel() }))
: h('div', { class: 'small faint', style: 'text-align:center' }, t('arkBoardNoFunds', { n: minBoard.toLocaleString() })),
@@ -766,6 +775,11 @@ export function arkFeature(ctx) {
h('div', { class: 'line' },
h('span', { class: 'k' }, t('arkBalance')),
h('span', { class: 'v' }, '+' + fmtAmount(a.amountSat - a.feeSat) + ' ' + unitLabel())),
+ a.feeSat > 0
+ ? h('div', { class: 'line' },
+ h('span', { class: 'k' }, t('arkBoardFeeLabel')),
+ h('span', { class: 'v' }, fmtAmount(a.feeSat) + ' ' + unitLabel()))
+ : null,
done ? null : h('div', { class: 'small muted', style: 'margin-top:2px' }, t('arkBoardedNote')));
},
settingsCards() { return [arkCard()]; },
diff --git a/src/i18n.js b/src/i18n.js
index 6c40a74..8c3058c 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -370,6 +370,8 @@ const STR = {
arkPendingActions: '{n} operation(s) in progress',
arkBoardPlaceholder: 'Board amount (min {n} sats)',
arkBoardBtn: 'Board',
+ arkBoardFeeNote: 'Ark server fee {fee} sats — {net} sats will arrive in your Ark balance (funds the exit-path fee anchor).',
+ arkBoardFeeLabel: 'Ark server fee',
arkBoardedTitle: 'Boarding!',
arkBoardedNote: 'Spendable in the Ark after 1 confirmation.',
arkBoardIntro: 'Or move this wallet\u2019s on-chain funds into Ark:',