aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/sp.js
blob: 92f091f514b2686c01988192ee348202e7f73fe4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// Silent payments (BIP-352) feature — the reusable sp1… receive address and
// the tweak-indexer settings. (The SP scanning/spending machinery itself lives
// in wallet.js/silentpay.js and ships with the core wallet for now.)

import { isSilentPaymentAddress } from '../silentpay.js';
import { installSpWallet } from './sp-wallet.js';
import { getNetwork, getSpIndexerConfig, setSpIndexerConfig, spIndexerPresets } from '../api.js';
import { t } from '../i18n.js';
import { qrSvg } from '../qr.js';

export function spFeature(ctx) {
  const { h, ui, render, wallet, copyBtn } = ctx;
  installSpWallet(wallet); // the BIP-352 engine lives outside the core wallet

  function spIndexerCard() {
    if (!wallet.silentPaymentKeys || !wallet.silentPaymentKeys()) return null;
    const net = getNetwork();
    const cfg = getSpIndexerConfig(net);
    return h(
      'div',
      { class: 'card col' },
      h('h3', {}, t('spIndexerTitle')),
      h('p', { class: 'small muted', style: 'margin:0' }, t('spIndexerDesc')),
      h('select', { onChange: (e) => { setSpIndexerConfig({ server: e.target.value, url: cfg.url }, net); render(); } },
        spIndexerPresets(net).map((o) => h('option', { value: o.id, selected: o.id === cfg.server }, o.id === 'custom' ? o.label : o.url.replace(/^\w+:\/\//, '')))),
      cfg.server === 'custom'
        ? h('label', { class: 'field' },
            h('span', { class: 'lab' }, t('spIndexerUrl')),
            h('input', {
              type: 'text', class: 'mono-input', placeholder: 'https://your-indexer:8888',
              autocapitalize: 'none', autocomplete: 'off', spellcheck: 'false', value: cfg.url,
              onChange: (e) => { setSpIndexerConfig({ server: 'custom', url: e.target.value.trim() }, net); render(); },
            }),
            h('div', { class: 'small faint' }, t('spIndexerHint')))
        : null
    );
  }

  return {
    id: 'sp',
    receiveModes() {
      const spAddr = wallet.silentPaymentsAvailable && wallet.silentPaymentsAvailable() ? wallet.silentPaymentAddress() : null;
      if (!spAddr) return [];
      return [{
        id: 'sp', label: t('receiveSpTab'), icon: '🕶️',
        render: (seg) => h(
          'div',
          { class: 'card col', style: 'align-items:center;gap:14px' },
          seg,
          h('div', { html: qrSvg(spAddr) }),
          h('div', { class: 'addr-box break', style: 'width:100%;font-size:12px' }, spAddr),
          copyBtn(spAddr, t('copyAddress'))
        ),
      }];
    },
    isSendDest(a) { return isSilentPaymentAddress(a); },
    // Silent-payment receipts merge into the main history as on-chain-looking
    // rows (tx.sp) — give them a rail glyph + tag so they're recognizable.
    decorateTxRow(tx) {
      return tx && tx.sp
        ? { icon: '🕶️', label: h('span', {}, t('received'), ' ', h('span', { class: 'tag' }, t('receiveSpTab'))) }
        : null;
    },
    settingsCards() { return [spIndexerCard()]; },
  };
}