Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a00525b6d7 |
@@ -2196,6 +2196,15 @@ app.post('/rpc/v1', (req, res) => {
|
|||||||
case 'content.download-peer-paid':
|
case 'content.download-peer-paid':
|
||||||
case 'content.download-peer-invoice':
|
case 'content.download-peer-invoice':
|
||||||
case 'content.download-peer-onchain': {
|
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 filename = params?.filename || 'demo-content'
|
||||||
const body = Buffer.from(
|
const body = Buffer.from(
|
||||||
`Archipelago demo — "${filename}"\n\nThis is sample paid content delivered over the ` +
|
`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)
|
// Wallet / Ecash (Fedimint)
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
case 'wallet.ecash-balance': {
|
case 'wallet.ecash-balance': {
|
||||||
|
const fedSats = (mockState.federations || []).reduce((s, f) => s + (f.balance_sats || 0), 0)
|
||||||
return res.json({
|
return res.json({
|
||||||
result: {
|
result: {
|
||||||
balance_sats: walletState.ecash_sats,
|
balance_sats: walletState.ecash_sats,
|
||||||
balance_msat: walletState.ecash_sats * 1000,
|
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,
|
token_count: walletState.ecash_tokens,
|
||||||
federations: [
|
federations: [
|
||||||
{ federation_id: 'fed1-demo', name: 'Archy Signet Mint', balance_msat: walletState.ecash_sats * 1000, gateway_active: true },
|
{ federation_id: 'fed1-demo', name: 'Archy Signet Mint', balance_msat: walletState.ecash_sats * 1000, gateway_active: true },
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
<!-- Method tabs -->
|
<!-- Method tabs -->
|
||||||
<div class="flex gap-1 mb-4 p-1 bg-white/5 rounded-lg">
|
<div class="flex gap-1 mb-4 p-1 bg-white/5 rounded-lg">
|
||||||
<button
|
<button
|
||||||
v-for="m in (['onchain', 'lightning', 'ecash'] as const)"
|
v-for="m in (['onchain', 'lightning', 'ecash', 'ark'] as const)"
|
||||||
:key="m"
|
:key="m"
|
||||||
@click="receiveMethod = m"
|
@click="receiveMethod = m"
|
||||||
class="flex-1 px-2 py-1.5 rounded text-xs font-medium capitalize transition-colors"
|
class="flex-1 px-2 py-1.5 rounded text-xs font-medium capitalize transition-colors"
|
||||||
:class="receiveMethod === m ? 'bg-white/15 text-white' : 'text-white/50 hover:text-white/80'"
|
:class="receiveMethod === m ? 'bg-white/15 text-white' : 'text-white/50 hover:text-white/80'"
|
||||||
>{{ m === 'onchain' ? t('receiveBitcoin.onChain') : m === 'lightning' ? t('receiveBitcoin.lightning') : t('receiveBitcoin.ecash') }}</button>
|
>{{ m === 'onchain' ? t('receiveBitcoin.onChain') : m === 'lightning' ? t('receiveBitcoin.lightning') : m === 'ecash' ? t('receiveBitcoin.ecash') : 'Ark' }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Lightning -->
|
<!-- Lightning -->
|
||||||
@@ -43,6 +43,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Ark -->
|
||||||
|
<div v-if="receiveMethod === 'ark'">
|
||||||
|
<div v-if="arkAddress" class="mb-3 p-3 bg-white/5 rounded-lg text-center">
|
||||||
|
<canvas ref="arkQrCanvas" class="mx-auto mb-3 rounded-lg" style="image-rendering: pixelated;"></canvas>
|
||||||
|
<p class="text-white/50 text-xs mb-2">Your Ark address</p>
|
||||||
|
<p class="text-sm font-mono text-white/90 break-all">{{ arkAddress }}</p>
|
||||||
|
<button @click="copyText(arkAddress)" class="mt-2 text-xs text-orange-400 hover:text-orange-300">{{ t('common.copy') }}</button>
|
||||||
|
</div>
|
||||||
|
<div v-else class="mb-3 text-center">
|
||||||
|
<p class="text-white/50 text-sm mb-2">Generate a fresh Ark address to receive off-chain sats instantly.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Ecash -->
|
<!-- Ecash -->
|
||||||
<div v-if="receiveMethod === 'ecash'">
|
<div v-if="receiveMethod === 'ecash'">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@@ -57,7 +70,7 @@
|
|||||||
<div class="flex gap-3">
|
<div class="flex gap-3">
|
||||||
<button @click="close" class="flex-1 glass-button px-4 py-2 rounded-lg text-sm">{{ t('common.close') }}</button>
|
<button @click="close" class="flex-1 glass-button px-4 py-2 rounded-lg text-sm">{{ t('common.close') }}</button>
|
||||||
<button @click="receive" :disabled="processing" class="flex-1 glass-button glass-button-success px-4 py-2 rounded-lg text-sm font-medium disabled:opacity-50">
|
<button @click="receive" :disabled="processing" class="flex-1 glass-button glass-button-success px-4 py-2 rounded-lg text-sm font-medium disabled:opacity-50">
|
||||||
{{ processing ? t('receiveBitcoin.processing') : receiveMethod === 'onchain' ? t('receiveBitcoin.generateAddress') : receiveMethod === 'lightning' ? t('receiveBitcoin.createInvoice') : t('receiveBitcoin.receive') }}
|
{{ processing ? t('receiveBitcoin.processing') : receiveMethod === 'onchain' ? t('receiveBitcoin.generateAddress') : receiveMethod === 'lightning' ? t('receiveBitcoin.createInvoice') : receiveMethod === 'ark' ? 'Get Ark address' : t('receiveBitcoin.receive') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
@@ -75,15 +88,17 @@ const { t } = useI18n()
|
|||||||
defineProps<{ show: boolean }>()
|
defineProps<{ show: boolean }>()
|
||||||
const emit = defineEmits<{ close: []; received: [] }>()
|
const emit = defineEmits<{ close: []; received: [] }>()
|
||||||
|
|
||||||
const receiveMethod = ref<'lightning' | 'onchain' | 'ecash'>('onchain')
|
const receiveMethod = ref<'lightning' | 'onchain' | 'ecash' | 'ark'>('onchain')
|
||||||
const invoiceAmount = ref<number>(0)
|
const invoiceAmount = ref<number>(0)
|
||||||
const invoiceMemo = ref('')
|
const invoiceMemo = ref('')
|
||||||
const invoiceResult = ref('')
|
const invoiceResult = ref('')
|
||||||
const onchainAddress = ref('')
|
const onchainAddress = ref('')
|
||||||
|
const arkAddress = ref('')
|
||||||
const ecashToken = ref('')
|
const ecashToken = ref('')
|
||||||
const ecashResult = ref('')
|
const ecashResult = ref('')
|
||||||
const onchainQrCanvas = ref<HTMLCanvasElement | null>(null)
|
const onchainQrCanvas = ref<HTMLCanvasElement | null>(null)
|
||||||
const lightningQrCanvas = ref<HTMLCanvasElement | null>(null)
|
const lightningQrCanvas = ref<HTMLCanvasElement | null>(null)
|
||||||
|
const arkQrCanvas = ref<HTMLCanvasElement | null>(null)
|
||||||
const processing = ref(false)
|
const processing = ref(false)
|
||||||
const error = ref('')
|
const error = ref('')
|
||||||
|
|
||||||
@@ -102,6 +117,7 @@ async function renderQr(data: string, canvas: HTMLCanvasElement | null, prefix =
|
|||||||
function close() {
|
function close() {
|
||||||
invoiceResult.value = ''
|
invoiceResult.value = ''
|
||||||
onchainAddress.value = ''
|
onchainAddress.value = ''
|
||||||
|
arkAddress.value = ''
|
||||||
ecashToken.value = ''
|
ecashToken.value = ''
|
||||||
ecashResult.value = ''
|
ecashResult.value = ''
|
||||||
error.value = ''
|
error.value = ''
|
||||||
@@ -131,6 +147,11 @@ async function receive() {
|
|||||||
}
|
}
|
||||||
onchainAddress.value = res.address
|
onchainAddress.value = res.address
|
||||||
nextTick(() => renderQr(res.address, onchainQrCanvas.value, 'bitcoin:'))
|
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 {
|
} else {
|
||||||
if (!ecashToken.value.trim()) { error.value = t('receiveBitcoin.pasteAnEcashToken'); return }
|
if (!ecashToken.value.trim()) { error.value = t('receiveBitcoin.pasteAnEcashToken'); return }
|
||||||
// The backend auto-detects the token type: a Cashu token (cashuA/B…) is
|
// The backend auto-detects the token type: a Cashu token (cashuA/B…) is
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
<!-- Method tabs -->
|
<!-- Method tabs -->
|
||||||
<div class="flex gap-1 mb-4 p-1 bg-white/5 rounded-lg">
|
<div class="flex gap-1 mb-4 p-1 bg-white/5 rounded-lg">
|
||||||
<button
|
<button
|
||||||
v-for="m in (['auto', 'lightning', 'onchain', 'ecash'] as const)"
|
v-for="m in (['auto', 'lightning', 'onchain', 'ecash', 'ark'] as const)"
|
||||||
:key="m"
|
:key="m"
|
||||||
@click="sendMethod = m"
|
@click="sendMethod = m"
|
||||||
class="flex-1 px-2 py-1.5 rounded text-xs font-medium capitalize transition-colors"
|
class="flex-1 px-2 py-1.5 rounded text-xs font-medium capitalize transition-colors"
|
||||||
:class="sendMethod === m ? 'bg-white/15 text-white' : 'text-white/50 hover:text-white/80'"
|
:class="sendMethod === m ? 'bg-white/15 text-white' : 'text-white/50 hover:text-white/80'"
|
||||||
>{{ m === 'onchain' ? t('sendBitcoin.onChain') : m === 'lightning' ? t('sendBitcoin.lightning') : m === 'ecash' ? t('sendBitcoin.ecash') : t('sendBitcoin.auto') }}</button>
|
>{{ m === 'onchain' ? t('sendBitcoin.onChain') : m === 'lightning' ? t('sendBitcoin.lightning') : m === 'ecash' ? t('sendBitcoin.ecash') : m === 'ark' ? 'Ark' : t('sendBitcoin.auto') }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="sendMethod === 'auto'" class="mb-3 p-2 bg-white/5 rounded-lg">
|
<div v-if="sendMethod === 'auto'" class="mb-3 p-2 bg-white/5 rounded-lg">
|
||||||
@@ -22,9 +22,9 @@
|
|||||||
|
|
||||||
<div v-if="effectiveMethod !== 'ecash'" class="mb-3">
|
<div v-if="effectiveMethod !== 'ecash'" class="mb-3">
|
||||||
<label class="text-white/60 text-sm block mb-1">
|
<label class="text-white/60 text-sm block mb-1">
|
||||||
{{ effectiveMethod === 'lightning' ? t('sendBitcoin.lightningInvoice') : t('sendBitcoin.bitcoinAddress') }}
|
{{ effectiveMethod === 'lightning' ? t('sendBitcoin.lightningInvoice') : effectiveMethod === 'ark' ? 'Ark address, invoice or lightning address' : t('sendBitcoin.bitcoinAddress') }}
|
||||||
</label>
|
</label>
|
||||||
<textarea v-model="dest" rows="2" :placeholder="effectiveMethod === 'lightning' ? 'lnbc...' : 'bc1...'" class="w-full input-glass font-mono"></textarea>
|
<textarea v-model="dest" rows="2" :placeholder="effectiveMethod === 'lightning' ? 'lnbc...' : effectiveMethod === 'ark' ? 'tark1… / lnbc… / user@lnaddress' : 'bc1...'" class="w-full input-glass font-mono"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="ecashToken && effectiveMethod === 'ecash'" class="mb-3 p-2 bg-white/5 rounded-lg">
|
<div v-if="ecashToken && effectiveMethod === 'ecash'" class="mb-3 p-2 bg-white/5 rounded-lg">
|
||||||
@@ -39,6 +39,9 @@
|
|||||||
<div v-if="resultHash" class="mb-3 alert-success">
|
<div v-if="resultHash" class="mb-3 alert-success">
|
||||||
<p class="text-xs">{{ t('sendBitcoin.paidHash', { hash: resultHash }) }}</p>
|
<p class="text-xs">{{ t('sendBitcoin.paidHash', { hash: resultHash }) }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="resultArk" class="mb-3 alert-success">
|
||||||
|
<p class="text-xs">{{ resultArk }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="error" class="mb-3 alert-error">{{ error }}</div>
|
<div v-if="error" class="mb-3 alert-error">{{ error }}</div>
|
||||||
|
|
||||||
@@ -62,13 +65,14 @@ const { t } = useI18n()
|
|||||||
const props = defineProps<{ show: boolean }>()
|
const props = defineProps<{ show: boolean }>()
|
||||||
const emit = defineEmits<{ close: []; sent: [] }>()
|
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<number>(0)
|
const amount = ref<number>(0)
|
||||||
const dest = ref('')
|
const dest = ref('')
|
||||||
const processing = ref(false)
|
const processing = ref(false)
|
||||||
const error = ref('')
|
const error = ref('')
|
||||||
const resultTxid = ref('')
|
const resultTxid = ref('')
|
||||||
const resultHash = ref('')
|
const resultHash = ref('')
|
||||||
|
const resultArk = ref('')
|
||||||
const ecashToken = ref('')
|
const ecashToken = ref('')
|
||||||
|
|
||||||
const effectiveMethod = computed(() => {
|
const effectiveMethod = computed(() => {
|
||||||
@@ -84,6 +88,7 @@ function close() {
|
|||||||
error.value = ''
|
error.value = ''
|
||||||
resultTxid.value = ''
|
resultTxid.value = ''
|
||||||
resultHash.value = ''
|
resultHash.value = ''
|
||||||
|
resultArk.value = ''
|
||||||
ecashToken.value = ''
|
ecashToken.value = ''
|
||||||
emit('close')
|
emit('close')
|
||||||
}
|
}
|
||||||
@@ -99,10 +104,20 @@ async function send() {
|
|||||||
ecashToken.value = ''
|
ecashToken.value = ''
|
||||||
resultTxid.value = ''
|
resultTxid.value = ''
|
||||||
resultHash.value = ''
|
resultHash.value = ''
|
||||||
|
resultArk.value = ''
|
||||||
|
|
||||||
const method = effectiveMethod.value
|
const method = effectiveMethod.value
|
||||||
try {
|
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 }>({
|
const res = await rpcClient.call<{ token: string }>({
|
||||||
method: 'wallet.ecash-send',
|
method: 'wallet.ecash-send',
|
||||||
params: { amount_sats: amount.value },
|
params: { amount_sats: amount.value },
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<BaseModal :show="show" :title="t('transactions.title')" max-width="max-w-2xl" content-class="max-h-[90vh] flex flex-col" @close="close">
|
<!-- Mobile: cap at ~60% of the LIVE visible viewport (not dvh — see
|
||||||
|
syncViewportHeightVar in main.ts) so the tx list doesn't fill the screen. -->
|
||||||
|
<BaseModal :show="show" :title="t('transactions.title')" max-width="max-w-2xl" content-class="max-h-[calc(var(--visual-viewport-height,100dvh)*0.6)] md:max-h-[90vh] flex flex-col" @close="close">
|
||||||
<!-- Rail filter: instant ecash micro-payments pile up fast and bury
|
<!-- Rail filter: instant ecash micro-payments pile up fast and bury
|
||||||
on-chain/Lightning rows; chips keep the standard txs reachable. -->
|
on-chain/Lightning rows; chips keep the standard txs reachable. -->
|
||||||
<div v-if="transactions.length > 0" class="flex gap-1.5 mb-3 shrink-0 flex-wrap">
|
<div v-if="transactions.length > 0" class="flex gap-1.5 mb-3 shrink-0 flex-wrap">
|
||||||
|
|||||||
@@ -441,16 +441,16 @@
|
|||||||
switch to the other if it has enough balance. -->
|
switch to the other if it has enough balance. -->
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<button
|
<button
|
||||||
v-for="b in (['cashu', 'fedimint'] as const)"
|
v-for="b in (['cashu', 'fedimint', 'ark'] as const)"
|
||||||
:key="b"
|
:key="b"
|
||||||
@click="ecashPlan.chosen = b"
|
@click="ecashPlan.chosen = b"
|
||||||
:disabled="ecashBalanceOf(b) < getItemPrice(payItem.access)"
|
:disabled="ecashBalanceOf(b) < getItemPrice(payItem.access)"
|
||||||
class="w-full px-4 py-3 rounded-xl flex items-center gap-3 text-left border transition-colors disabled:opacity-40 disabled:cursor-not-allowed"
|
class="w-full px-4 py-3 rounded-xl flex items-center gap-3 text-left border transition-colors disabled:opacity-40 disabled:cursor-not-allowed"
|
||||||
:class="ecashPlan.chosen === b ? 'border-green-400/70 bg-green-400/10' : 'border-white/10 bg-white/5 hover:bg-white/10'"
|
:class="ecashPlan.chosen === b ? 'border-green-400/70 bg-green-400/10' : 'border-white/10 bg-white/5 hover:bg-white/10'"
|
||||||
>
|
>
|
||||||
<span class="text-xl shrink-0">{{ b === 'cashu' ? '🥜' : '🤝' }}</span>
|
<span class="text-xl shrink-0">{{ b === 'cashu' ? '🥜' : b === 'fedimint' ? '🤝' : '⚓' }}</span>
|
||||||
<span class="flex-1 min-w-0">
|
<span class="flex-1 min-w-0">
|
||||||
<span class="block text-base text-white">{{ b === 'cashu' ? 'Cashu' : 'Fedimint' }}</span>
|
<span class="block text-base text-white">{{ b === 'cashu' ? 'Cashu' : b === 'fedimint' ? 'Fedimint' : 'Ark' }}</span>
|
||||||
<span class="block text-xs text-white/50">Balance: {{ ecashBalanceOf(b).toLocaleString() }} sats<span v-if="ecashBalanceOf(b) < getItemPrice(payItem.access)"> · not enough</span></span>
|
<span class="block text-xs text-white/50">Balance: {{ ecashBalanceOf(b).toLocaleString() }} sats<span v-if="ecashBalanceOf(b) < getItemPrice(payItem.access)"> · not enough</span></span>
|
||||||
</span>
|
</span>
|
||||||
<svg v-if="ecashPlan.chosen === b" class="w-5 h-5 text-green-400 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg v-if="ecashPlan.chosen === b" class="w-5 h-5 text-green-400 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
@@ -707,10 +707,11 @@ const payMode = ref<'choose' | 'ecash-confirm' | 'qr'>('choose')
|
|||||||
// Ecash confirmation step: after the user picks "pay from this node's ecash",
|
// Ecash confirmation step: after the user picks "pay from this node's ecash",
|
||||||
// we look at both balances, decide which backend covers the price, and show a
|
// we look at both balances, decide which backend covers the price, and show a
|
||||||
// confirm screen so they see (and can switch) which ecash is spent (#3).
|
// confirm screen so they see (and can switch) which ecash is spent (#3).
|
||||||
type EcashBackend = 'cashu' | 'fedimint'
|
type EcashBackend = 'cashu' | 'fedimint' | 'ark'
|
||||||
const ecashPlan = ref<{
|
const ecashPlan = ref<{
|
||||||
cashu: number
|
cashu: number
|
||||||
fedimint: number
|
fedimint: number
|
||||||
|
ark: number
|
||||||
total: number
|
total: number
|
||||||
chosen: EcashBackend | null
|
chosen: EcashBackend | null
|
||||||
} | null>(null)
|
} | null>(null)
|
||||||
@@ -1135,7 +1136,7 @@ async function pollOnchain(address: string) {
|
|||||||
/** Spendable balance for a given ecash backend in the current plan. */
|
/** Spendable balance for a given ecash backend in the current plan. */
|
||||||
function ecashBalanceOf(b: EcashBackend): number {
|
function ecashBalanceOf(b: EcashBackend): number {
|
||||||
if (!ecashPlan.value) return 0
|
if (!ecashPlan.value) return 0
|
||||||
return b === 'cashu' ? ecashPlan.value.cashu : ecashPlan.value.fedimint
|
return b === 'cashu' ? ecashPlan.value.cashu : b === 'fedimint' ? ecashPlan.value.fedimint : ecashPlan.value.ark
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1152,23 +1153,25 @@ async function prepareEcashPay() {
|
|||||||
try {
|
try {
|
||||||
let cashu = 0
|
let cashu = 0
|
||||||
let fedimint = 0
|
let fedimint = 0
|
||||||
|
let ark = 0
|
||||||
try {
|
try {
|
||||||
const res = await rpcClient.call<{ cashu_sats?: number; fedimint_sats?: number; total_sats?: number; balance_sats?: number }>({
|
const res = await rpcClient.call<{ cashu_sats?: number; fedimint_sats?: number; ark_sats?: number; total_sats?: number; balance_sats?: number }>({
|
||||||
method: 'wallet.ecash-balance',
|
method: 'wallet.ecash-balance',
|
||||||
})
|
})
|
||||||
cashu = res?.cashu_sats ?? res?.balance_sats ?? 0
|
cashu = res?.cashu_sats ?? res?.balance_sats ?? 0
|
||||||
fedimint = res?.fedimint_sats ?? 0
|
fedimint = res?.fedimint_sats ?? 0
|
||||||
|
ark = res?.ark_sats ?? 0
|
||||||
} catch {
|
} catch {
|
||||||
// Couldn't read balances — let the user try anyway (auto backend).
|
// Couldn't read balances — let the user try anyway (auto backend).
|
||||||
}
|
}
|
||||||
const total = cashu + fedimint
|
const total = cashu + fedimint + ark
|
||||||
// Prefer Cashu when it covers the price, else Fedimint, else leave null
|
// Prefer Cashu when it covers the price, else Fedimint, else Ark, else
|
||||||
// (insufficient — shown in the confirm screen, Confirm disabled).
|
// leave null (insufficient — shown in the confirm screen, Confirm disabled).
|
||||||
const chosen: EcashBackend | null =
|
const chosen: EcashBackend | null =
|
||||||
cashu >= price ? 'cashu' : fedimint >= price ? 'fedimint' : null
|
cashu >= price ? 'cashu' : fedimint >= price ? 'fedimint' : ark >= price ? 'ark' : null
|
||||||
ecashPlan.value = { cashu, fedimint, total, chosen }
|
ecashPlan.value = { cashu, fedimint, ark, total, chosen }
|
||||||
if (!chosen) {
|
if (!chosen) {
|
||||||
purchaseError.value = `Not enough ecash: Cashu ${cashu} + Fedimint ${fedimint} sats, need ${price}. Fund a wallet, or pay another way.`
|
purchaseError.value = `Not enough funds: Cashu ${cashu} + Fedimint ${fedimint} + Ark ${ark} sats, need ${price}. Fund a wallet, or pay another way.`
|
||||||
}
|
}
|
||||||
payMode.value = 'ecash-confirm'
|
payMode.value = 'ecash-confirm'
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user