taler-deployment

Deployment scripts and configuration files
Log | Files | Refs | README

CONVERSION-TESTING.md (7619B)


      1 # Test currency conversion without a fiat bank
      2 
      3 This runbook tests a complete cash-in and cash-out cycle while the conversion
      4 account is not connected to a real bank. It uses a command-line Taler wallet
      5 and the LibEuFin Nexus testing commands. No EBICS enrollment or payment
      6 submission is needed.
      7 
      8 Only use this mode for a disposable testing deployment. Enabling conversion
      9 records the fiat currency, IBAN, BIC, and account name as part of the
     10 deployment identity. The normal playbook will reject later changes to those
     11 values or an attempt to disable conversion.
     12 
     13 ## Configure and deploy test mode
     14 
     15 Set these values in the target's private inventory file:
     16 
     17 ```yaml
     18 regional_currency_testing_deployment: true
     19 regional_currency_enable_conversion: true
     20 regional_currency_conversion_test_mode: true
     21 regional_currency_fiat_currency: CHF
     22 regional_currency_fiat_bank_name: Synthetic CHF Test Bank
     23 regional_currency_fiat_account_iban: CH8615624QG38ANY0UVER
     24 regional_currency_fiat_account_bic: TSTRCHZZXXX
     25 regional_currency_fiat_account_name: FLODOS Conversion Test
     26 regional_currency_enable_nexus_services: false
     27 ```
     28 
     29 Generate a fresh valid test IBAN instead of copying the example IBAN:
     30 
     31 ```console
     32 $ libeufin-nexus testing iban gen --country CH
     33 CH...
     34 ```
     35 
     36 Conversion test mode is valid only when both testing and conversion are
     37 enabled. It rejects an inventory that enables the Nexus services and configures
     38 Nexus to require manual acknowledgement before an initiated payment can be
     39 submitted.
     40 
     41 Deploy only the intended host:
     42 
     43 ```console
     44 $ ansible -i inventory regio -m ping
     45 $ ansible-playbook -i inventory site.yml --limit regio
     46 ```
     47 
     48 Verify the public configuration from the operator machine:
     49 
     50 ```console
     51 $ curl -fsS https://bank.regio.taler.net/config | jq '{currency, allow_conversion}'
     52 $ curl -fsS https://bank.regio.taler.net/conversion-info/config |
     53     jq '{regional_currency, fiat_currency, conversion_rate}'
     54 $ curl -fsS https://exchange.regio.taler.net/keys |
     55     jq '[.accounts[] | {payto_uri, conversion_url, bank_label, priority}]'
     56 ```
     57 
     58 The bank must report FLODOS conversion enabled with CHF as the fiat currency.
     59 The exchange must advertise a priority-10 IBAN account whose conversion URL is
     60 `https://bank.regio.taler.net/conversion-info/`.
     61 
     62 On the managed host, verify that no EBICS worker is running:
     63 
     64 ```console
     65 # systemctl is-active libeufin-nexus.target \
     66     libeufin-nexus-ebics-fetch.service \
     67     libeufin-nexus-ebics-submit.service
     68 inactive
     69 inactive
     70 inactive
     71 ```
     72 
     73 ## Simulate a conversion withdrawal
     74 
     75 On the operator machine, create a temporary wallet and start a manual
     76 withdrawal. Keep this directory until the whole test has finished:
     77 
     78 ```console
     79 $ REGIO_TEST_DIR=$(mktemp -d)
     80 $ REGIO_WALLET_DB="$REGIO_TEST_DIR/wallet.sqlite3"
     81 $ taler-wallet-cli --wallet-db "$REGIO_WALLET_DB" \
     82     withdraw \
     83     --exchange https://exchange.regio.taler.net/ \
     84     --amount FLODOS:10 | tee "$REGIO_TEST_DIR/withdraw.out"
     85 $ REGIO_TX_ID=$(sed -n 's/^transaction //p' "$REGIO_TEST_DIR/withdraw.out")
     86 $ taler-wallet-cli --wallet-db "$REGIO_WALLET_DB" \
     87     transactions show "$REGIO_TX_ID" > "$REGIO_TEST_DIR/withdraw.json"
     88 $ REGIO_CREDIT_PAYTO=$(jq -r '
     89     [.withdrawalDetails.exchangeCreditAccountDetails[]
     90      | select(.transferAmount | startswith("CHF:"))
     91      | .transferOptions[]
     92      | select(.type == "payto")
     93      | .paytoUri][0]
     94   ' "$REGIO_TEST_DIR/withdraw.json")
     95 $ printf '%s\n' "$REGIO_CREDIT_PAYTO"
     96 ```
     97 
     98 The selected URI includes the synthetic conversion IBAN, the CHF amount, and
     99 the reserve public key as its transfer subject. Copy the complete URI to the
    100 managed host and inject it exactly as produced by the wallet:
    101 
    102 ```console
    103 # REGIO_CREDIT_PAYTO='payto://iban/...?...'
    104 # sudo -u libeufin-nexus \
    105     libeufin-nexus testing fake-incoming \
    106       -c /etc/libeufin/libeufin-nexus.conf \
    107       --credit-payto "$REGIO_CREDIT_PAYTO"
    108 # sudo -u libeufin-nexus \
    109     libeufin-nexus testing list incoming \
    110       -c /etc/libeufin/libeufin-nexus.conf
    111 ```
    112 
    113 Back on the operator machine, wait for the exchange and wallet to process the
    114 reserve, then check the balance:
    115 
    116 ```console
    117 $ taler-wallet-cli --wallet-db "$REGIO_WALLET_DB" \
    118     transactions wait "$REGIO_TX_ID" --state final --timeout 2m
    119 $ taler-wallet-cli --wallet-db "$REGIO_WALLET_DB" balance --pretty
    120 ```
    121 
    122 With the one-to-one rate and zero fees, the wallet balance must be
    123 `FLODOS:10`.
    124 
    125 ## Deposit and cash out
    126 
    127 Create a dedicated zero-debt bank account on the managed host. Its cash-out
    128 IBAN must be different from the synthetic conversion account:
    129 
    130 ```console
    131 # REGIO_TEST_USERNAME="conversion-test-$(date -u +%Y%m%d%H%M%S)"
    132 # REGIO_TEST_PASSWORD=$(uuidgen)
    133 # REGIO_CASHOUT_IBAN=$(libeufin-nexus testing iban gen --country CH)
    134 # REGIO_ACCOUNT_PAYTO=$(sudo -u libeufin-bank \
    135     libeufin-bank create-account \
    136       --username "$REGIO_TEST_USERNAME" \
    137       --password "$REGIO_TEST_PASSWORD" \
    138       --name 'Conversion Test Customer' \
    139       --cashout_payto_uri \
    140         "payto://iban/TSTRCHZZXXX/$REGIO_CASHOUT_IBAN" \
    141       --debit_threshold FLODOS:0)
    142 # printf 'username: %s\naccount: %s\ncash-out IBAN: %s\n' \
    143     "$REGIO_TEST_USERNAME" "$REGIO_ACCOUNT_PAYTO" "$REGIO_CASHOUT_IBAN"
    144 ```
    145 
    146 Copy `REGIO_ACCOUNT_PAYTO` to the operator machine and deposit the complete
    147 wallet balance into it:
    148 
    149 ```console
    150 $ REGIO_ACCOUNT_PAYTO='payto://x-taler-bank/...'
    151 $ taler-wallet-cli --wallet-db "$REGIO_WALLET_DB" \
    152     deposit FLODOS:10 "$REGIO_ACCOUNT_PAYTO" --timeout 2m
    153 ```
    154 
    155 On the managed host, create a one-hour API token and wait until the account
    156 shows a `FLODOS:10` credit balance:
    157 
    158 ```console
    159 # REGIO_TEST_TOKEN=$(sudo -u libeufin-bank \
    160     libeufin-bank create-token \
    161       --username "$REGIO_TEST_USERNAME" \
    162       --scope readwrite \
    163       --duration 3600000000 \
    164       --description 'conversion test')
    165 # curl -fsS \
    166     -H "Authorization: Bearer $REGIO_TEST_TOKEN" \
    167     "https://bank.regio.taler.net/accounts/$REGIO_TEST_USERNAME" | jq .balance
    168 ```
    169 
    170 Ask the bank for the current cash-out quote, then submit exactly that debit and
    171 credit amount with a fresh idempotency key:
    172 
    173 ```console
    174 # REGIO_QUOTE=$(curl -fsS \
    175     "https://bank.regio.taler.net/conversion-info/cashout-rate?amount_debit=FLODOS:10")
    176 # REGIO_CASHOUT_CREDIT=$(printf '%s' "$REGIO_QUOTE" | jq -r .amount_credit)
    177 # REGIO_REQUEST_UID=$(head -c 32 /dev/urandom | gnunet-base32)
    178 # jq -n \
    179     --arg uid "$REGIO_REQUEST_UID" \
    180     --arg debit 'FLODOS:10' \
    181     --arg credit "$REGIO_CASHOUT_CREDIT" \
    182     --arg subject "regio conversion test $REGIO_TEST_USERNAME" \
    183     '{request_uid: $uid, amount_debit: $debit,
    184       amount_credit: $credit, subject: $subject}' |
    185     curl -fsS \
    186       -H "Authorization: Bearer $REGIO_TEST_TOKEN" \
    187       -H 'Content-Type: application/json' \
    188       --data-binary @- \
    189       "https://bank.regio.taler.net/accounts/$REGIO_TEST_USERNAME/cashouts" |
    190     jq .
    191 ```
    192 
    193 Verify that the bank balance has returned to zero and that Nexus contains the
    194 CHF payment it would send to the fiat bank:
    195 
    196 ```console
    197 # curl -fsS \
    198     -H "Authorization: Bearer $REGIO_TEST_TOKEN" \
    199     "https://bank.regio.taler.net/accounts/$REGIO_TEST_USERNAME" | jq .balance
    200 # sudo -u libeufin-nexus \
    201     libeufin-nexus testing list initiated \
    202       -c /etc/libeufin/libeufin-nexus.conf
    203 ```
    204 
    205 The initiated entry must show `CHF:10`, the generated cash-out IBAN, and the
    206 unique test subject. This queued entry is the proof of the outgoing cash-out;
    207 there is deliberately no matching outgoing bank statement in simulated mode.
    208 
    209 Do not run `libeufin-nexus ebics-submit` or manually acknowledge the transfer.
    210 Those operations belong to a deployment connected to a real fiat bank.