58 lines
5.4 KiB
Markdown
58 lines
5.4 KiB
Markdown
# AERE Payments: the risk step and the receipt
|
|
|
|
The two pieces that were missing from the payment chain for people and companies (identity -> authorization -> risk -> payment ->
|
|
proof -> settlement -> receipt), built as pure modules on what already exists: the AIP-23 `settlement` envelope (`proof-kinds/`),
|
|
the notary call of the house (`agents/agent-ancora.mjs`) and the AIP-23 reference verifier. Prices are in USD; the asset is only the
|
|
settlement.
|
|
|
|
**Risk (`risc.mjs`).** A declared policy (`definePolicy`: a per-payment limit and a sliding-window limit in USD per payer, the assets
|
|
allowed, the counterparties refused with the source of each entry) and the inputs of one payment (payer, payee, asset and amount, the
|
|
USD rate DECLARED as an input with its source and time, the payer's history as this issuer recorded it, the time) give one verdict
|
|
(`judeca`): ALLOW or REFUSE, the reasons, what was measured, and what was NOT. The verdict's hash covers the policy's hash and the
|
|
inputs' hash, so anyone with the same policy and inputs reproduces it; a policy with a field the engine does not know is refused, so
|
|
no one can be shown a rule that is not applied. The signals the module does not have are named in every verdict, never simulated:
|
|
sanctions screening (no source), identity tier, device or location, chargeback history, and the payer's payments outside this
|
|
issuer's own receipts. Without a declared rate the USD value is unmeasured and the policy refuses; it is never guessed.
|
|
|
|
**Receipt (`chitanta.mjs`).** An instruction (payer, payee, the amount in the asset and in USD at the declared rate, the transaction
|
|
and its block, the risk verdict with its policy under hash, the unmeasured signals) and the AIP-23 `settlement` envelope that commits
|
|
to it by hash. The envelope is what the issuer notarizes on AereNotary: the receipt's time is then the chain's, read back under a
|
|
post-quantum certified anchor by the reference verifier. `verificaChitanta` checks that the envelope commits to the instruction, that
|
|
the USD amount is exactly amount x rate, that the policy shown hashes to the one under the verdict, that the verdict reproduces from
|
|
the inputs and was ALLOW, and, with the chain facts, that the transaction is this payment (from, to, value, block, status).
|
|
|
|
```
|
|
node proba-risc.mjs # 23 rows, no chain: the verdicts under a policy, a receipt verified, nine forged ones refused by name,
|
|
# a malformed payment refused by name (a verdict, not an exception)
|
|
node proba-risc.mjs --control-negativ # 10 plantings on copies of risc.mjs and chitanta.mjs; each forged fixture must then be accepted
|
|
AERE_TESTNET_KEY_FILE=<key> AERE_ETHERS_DIR=<dir with node_modules/ethers> node proba-plata-28001.mjs # the flow on testnet 28001
|
|
node verifica-chitanta.mjs dovezi/chitanta-28001-<date>.json --rpc https://testnet-rpc.aere.network --verify-proof <verify-proof.mjs>
|
|
```
|
|
|
|
Measured on 2026-10-02 on testnet 28001 (9/9): a person's payment of 0.4 tAERE at a declared 0.5 USD/tAERE = 0.20 USD allowed, paid
|
|
by a plain transfer the payer signed, its receipt issued, notarized by the payee and read back with finality PASSED under a
|
|
post-quantum certified anchor; a payment of 1.50 USD refused above the per-payment limit with no transaction sent; the fourth payment
|
|
in the window refused above the count; the receipt forged (amount changed) INVALID; a looser policy shown under the receipt's policy
|
|
hash INVALID. The public reader (`verifica-chitanta.mjs`) needs only Node.js: the chain is read by plain JSON-RPC.
|
|
|
|
Every refusal names its rule: `rules` on a risk verdict (form, asset, counterparty, rate, limit, window; outside the hashed body, so
|
|
the hash of a verdict already issued is unchanged), `reguli` on a receipt verdict (binding, amount, policy, risk, chain). The rate is a
|
|
decimal string (a JSON number is refused, not rounded), and a history entry the engine cannot count is refused, not left out of the
|
|
window. The conformance suite (`conformance/`) holds a vector for each of these rules and runs any implementation against them.
|
|
|
|
## What it is not, and what is not measured
|
|
|
|
- **Not KYC, not AML, not sanctions screening.** The policy's refused counterparties are addresses this house measured as sinks on
|
|
28001 (contracts with no path to withdraw what is sent to them, with the deployment record as source) and the zero address; no
|
|
sanctions list is consulted, and the verdict says so in `unmeasured`. An identity or compliance record (`identity/`) can be named in
|
|
the inputs; it is not judged here.
|
|
- **The policy is the issuer's word.** One issuer, one policy, one key: the receipt proves that THIS policy, as hashed, gave THIS verdict
|
|
on THESE inputs; it does not prove the policy is a good one, nor that the issuer's history of the payer is complete (it is only the
|
|
issuer's own receipts).
|
|
- **The rate is declared, not observed.** The USD amount is exact at the rate the issuer declares as an input (source and time on the
|
|
receipt); a wrong declared rate gives a wrong USD figure, honestly attributed.
|
|
- **Native transfers only in the measured flow.** An ERC-20 payment (the testnet USD token through x402) is supported by the policy's
|
|
asset list but not measured; the receipt's chain check compares `value` only for the native asset.
|
|
- **Not a payment API.** No service, no queue, no callbacks; the issuer runs these modules in its own process.
|
|
- **Chain 2800: nothing** ran there; test keys only, the payee's derived from the payer's and never printed.
|