diff --git a/neode-ui/mock-backend.js b/neode-ui/mock-backend.js
index a1d8a20f..b0882bf6 100755
--- a/neode-ui/mock-backend.js
+++ b/neode-ui/mock-backend.js
@@ -2196,6 +2196,15 @@ app.post('/rpc/v1', (req, res) => {
case 'content.download-peer-paid':
case 'content.download-peer-invoice':
case 'content.download-peer-onchain': {
+ // Deduct the price from the chosen rail so demo balances react.
+ const paid = params?.price_sats || 0
+ if (paid > 0 && method === 'content.download-peer-paid') {
+ if (params?.method === 'ark') walletState.ark_sats = Math.max(0, walletState.ark_sats - paid)
+ else if (params?.method === 'fedimint') {
+ const fed = (mockState.federations || [])[0]
+ if (fed) fed.balance_sats = Math.max(0, (fed.balance_sats || 0) - paid)
+ } else walletState.ecash_sats = Math.max(0, walletState.ecash_sats - paid)
+ }
const filename = params?.filename || 'demo-content'
const body = Buffer.from(
`Archipelago demo — "${filename}"\n\nThis is sample paid content delivered over the ` +
@@ -3330,10 +3339,15 @@ app.post('/rpc/v1', (req, res) => {
// Wallet / Ecash (Fedimint)
// =====================================================================
case 'wallet.ecash-balance': {
+ const fedSats = (mockState.federations || []).reduce((s, f) => s + (f.balance_sats || 0), 0)
return res.json({
result: {
balance_sats: walletState.ecash_sats,
balance_msat: walletState.ecash_sats * 1000,
+ cashu_sats: walletState.ecash_sats,
+ fedimint_sats: fedSats,
+ ark_sats: walletState.ark_sats,
+ total_sats: walletState.ecash_sats + fedSats + walletState.ark_sats,
token_count: walletState.ecash_tokens,
federations: [
{ federation_id: 'fed1-demo', name: 'Archy Signet Mint', balance_msat: walletState.ecash_sats * 1000, gateway_active: true },
diff --git a/neode-ui/src/components/ReceiveBitcoinModal.vue b/neode-ui/src/components/ReceiveBitcoinModal.vue
index 68e6b4ed..a120a1c7 100644
--- a/neode-ui/src/components/ReceiveBitcoinModal.vue
+++ b/neode-ui/src/components/ReceiveBitcoinModal.vue
@@ -3,12 +3,12 @@
+ >{{ m === 'onchain' ? t('receiveBitcoin.onChain') : m === 'lightning' ? t('receiveBitcoin.lightning') : m === 'ecash' ? t('receiveBitcoin.ecash') : 'Ark' }}
@@ -43,6 +43,19 @@
+
+
+
+
+
Your Ark address
+
{{ arkAddress }}
+
+
+
+
Generate a fresh Ark address to receive off-chain sats instantly.
+
+
+
@@ -57,7 +70,7 @@
@@ -75,15 +88,17 @@ const { t } = useI18n()
defineProps<{ show: boolean }>()
const emit = defineEmits<{ close: []; received: [] }>()
-const receiveMethod = ref<'lightning' | 'onchain' | 'ecash'>('onchain')
+const receiveMethod = ref<'lightning' | 'onchain' | 'ecash' | 'ark'>('onchain')
const invoiceAmount = ref
(0)
const invoiceMemo = ref('')
const invoiceResult = ref('')
const onchainAddress = ref('')
+const arkAddress = ref('')
const ecashToken = ref('')
const ecashResult = ref('')
const onchainQrCanvas = ref(null)
const lightningQrCanvas = ref(null)
+const arkQrCanvas = ref(null)
const processing = ref(false)
const error = ref('')
@@ -102,6 +117,7 @@ async function renderQr(data: string, canvas: HTMLCanvasElement | null, prefix =
function close() {
invoiceResult.value = ''
onchainAddress.value = ''
+ arkAddress.value = ''
ecashToken.value = ''
ecashResult.value = ''
error.value = ''
@@ -131,6 +147,11 @@ async function receive() {
}
onchainAddress.value = res.address
nextTick(() => renderQr(res.address, onchainQrCanvas.value, 'bitcoin:'))
+ } else if (receiveMethod.value === 'ark') {
+ const res = await rpcClient.call<{ address: string }>({ method: 'wallet.ark-address' })
+ if (!res.address) throw new Error('barkd did not return an Ark address')
+ arkAddress.value = res.address
+ nextTick(() => renderQr(res.address, arkQrCanvas.value))
} else {
if (!ecashToken.value.trim()) { error.value = t('receiveBitcoin.pasteAnEcashToken'); return }
// The backend auto-detects the token type: a Cashu token (cashuA/B…) is
diff --git a/neode-ui/src/components/SendBitcoinModal.vue b/neode-ui/src/components/SendBitcoinModal.vue
index 10ead66d..ceb3ada7 100644
--- a/neode-ui/src/components/SendBitcoinModal.vue
+++ b/neode-ui/src/components/SendBitcoinModal.vue
@@ -3,12 +3,12 @@
+ >{{ m === 'onchain' ? t('sendBitcoin.onChain') : m === 'lightning' ? t('sendBitcoin.lightning') : m === 'ecash' ? t('sendBitcoin.ecash') : m === 'ark' ? 'Ark' : t('sendBitcoin.auto') }}
@@ -22,9 +22,9 @@
-
+
@@ -39,6 +39,9 @@
{{ t('sendBitcoin.paidHash', { hash: resultHash }) }}
+
{{ error }}
@@ -62,13 +65,14 @@ const { t } = useI18n()
const props = defineProps<{ show: boolean }>()
const emit = defineEmits<{ close: []; sent: [] }>()
-const sendMethod = ref<'auto' | 'lightning' | 'onchain' | 'ecash'>('auto')
+const sendMethod = ref<'auto' | 'lightning' | 'onchain' | 'ecash' | 'ark'>('auto')
const amount = ref
(0)
const dest = ref('')
const processing = ref(false)
const error = ref('')
const resultTxid = ref('')
const resultHash = ref('')
+const resultArk = ref('')
const ecashToken = ref('')
const effectiveMethod = computed(() => {
@@ -84,6 +88,7 @@ function close() {
error.value = ''
resultTxid.value = ''
resultHash.value = ''
+ resultArk.value = ''
ecashToken.value = ''
emit('close')
}
@@ -99,10 +104,20 @@ async function send() {
ecashToken.value = ''
resultTxid.value = ''
resultHash.value = ''
+ resultArk.value = ''
const method = effectiveMethod.value
try {
- if (method === 'ecash') {
+ if (method === 'ark') {
+ if (!dest.value.trim()) { error.value = 'Enter an Ark address, invoice or lightning address'; return }
+ await rpcClient.call<{ sent: boolean }>({
+ method: 'wallet.ark-send',
+ params: { destination: dest.value.trim(), amount_sats: amount.value },
+ // Ark sends can wait on round participation.
+ timeout: 130000,
+ })
+ resultArk.value = `Sent ${amount.value.toLocaleString()} sats via Ark`
+ } else if (method === 'ecash') {
const res = await rpcClient.call<{ token: string }>({
method: 'wallet.ecash-send',
params: { amount_sats: amount.value },
diff --git a/neode-ui/src/views/PeerFiles.vue b/neode-ui/src/views/PeerFiles.vue
index 4f0ff5f9..fef576c6 100644
--- a/neode-ui/src/views/PeerFiles.vue
+++ b/neode-ui/src/views/PeerFiles.vue
@@ -441,16 +441,16 @@
switch to the other if it has enough balance. -->