# Evidence: claim → command → captured output

Captured 2026-10-16 and refreshed 2026-10-17 on the build machine. Raw outputs are in `evidence-logs/`. Run the commands yourself; do not trust the captures alone.
Environment: Linux, Node 24.21.0, pnpm 11.11.0, Foundry 1.7.1.

## 1. Contracts pass 48 tests and fit the size limit
`cd chain && forge test` → (`evidence-logs/forge-test.txt`)
```
Ran 5 test suites: 48 tests passed, 0 failed, 0 skipped
ChatProtocol runtime size: 22,449 bytes (limit 24,576)
```
Suites: ChatRoomId (3), ChatProtocol (18), ChatPrivate (16), ChatPrivateUpgrade (1), **ChatSigned (10, new: gasless EIP-712 / ERC-1271)**.

## 2. The plugin builds deterministically and passes PayBox conformance with 9 tools
`cd plugin && pnpm install --frozen-lockfile && pnpm test` → (`evidence-logs/plugin-pnpm-test.json`)
```
"status":"passed", "sampleCall":{"tool":"resolve_room","status":"passed"}, "discoveredToolCount":9
```
Tool list with descriptions: `evidence-logs/tools.json`. The test builds twice and requires byte-identical output.

## 3. Plugin end-to-end against the real contracts (21 checks)
Local chain (anvil) + `chain/script/DeployLocal.s.sol`, then `cd plugin && PARLEY_PROXY=<proxy> pnpm exec tsx dev/e2e-local.ts` → (`evidence-logs/plugin-e2e.txt`) **ALL PASSED**. Highlights:
- plaintext and the invoice id never appear on-chain (`plaintext never appears on chain`)
- the recipient decrypts text + invoice tag; a stranger cannot
- payment request card travels encrypted; `propose_payment_from_thread` yields an ERC-20 `transfer` of 25.50 USDC (25,500,000 units) to the merchant
- zero-address recipient and amounts above 10,000 USDC are refused
- `send_sealed` with `paid_tx` carries an encrypted receipt; `paid_tx` without `paid_amount` is refused
- `payment_request pay_chain=ethereum` puts the settlement chain on the card, and the card becomes a USDC transfer proposal on chain 1 (`eip155:1`, Circle USDC)

## 3b. The PayBox-wallet path, end to end (local chain, browser)
A PayBox wallet cannot sign in the browser, so it is linked once. Run on local anvil with the bundled plugin, an anvil account standing in for the PayBox wallet, and `plugin/dev/agent-sim.ts` playing the agent (it calls the real `dist/plugin.mjs` and sends each proposal from that account):
1. `send_sealed` before linking → error with a link `…/?chain=local&link=0x90F7…b906`.
2. On that page a Parley key was entered; key + wallet address derive the messaging key on the device (scrypt), and the page showed `Use Parley register_key on local with wallet 0x90F7…b906 and device_id 0x5bd0…ad4c`.
3. `register_key` proposal executed → the page saw the key and opened the wallet's inbox (label "PAYBOX · 0x90F7…").
4. `send_sealed` to the concierge → the concierge's encrypted reply with a 1.00 USDC card appeared in that inbox; the card offered "Copy the prompt for my PayBox agent".
5. `propose_payment_from_thread` executed (USDC transfer), then `send_sealed … paid_tx=<hash> paid_amount=1.00` → the concierge replied "Verified on-chain: I received 1.00 USDC …" and the thread showed **Done: payment verified on-chain**.
6. **Any device:** all browser storage was wiped and the page reloaded; entering only the address and the same Parley key reopened the same inbox and history with no new registration. A wrong key was refused with a warning that the wallet already has keys this one does not match.
Not yet run inside the hosted PayBox product; see SUBMISSION.md "Status of hosted checks".

## 4. Relay and concierge end-to-end (23 checks)
`cd services/relay && PARLEY_PROXY=<proxy> npx tsx test/relay-e2e.ts` → (`evidence-logs/relay-e2e.txt`) **ALL PASSED**. Highlights:
- the concierge stays 2 blocks behind the head, retries a failed reply up to 4 times, never answers the same message twice, and refuses a receipt tx already claimed by another wallet (code: `services/relay/src/concierge.ts`)
- a wallet with **0 balance** registers a key and sends an encrypted message using only signatures (`Alice paid nothing`)
- replayed registration / send are rejected; a tampered ciphertext is rejected by the contract (`InvalidSignedAction`)
- the concierge replies on-chain; the user decrypts it and receives a payment-request card
- **payment loop:** the user pays 1.00 USDC (mock token locally), sends a sealed receipt, and the concierge **verifies the transfer on-chain** (right sender, right recipient, enough amount); a fake receipt and an under-paid receipt are rejected

- **test faucet:** a brand-new wallet receives 1.00 test USDC and gas once; wallets that already have funds are refused; bad addresses are rejected

## 4b. Error catalog (38 cases, 61 catalog entries)
`cd plugin && pnpm run test:errors` → (`evidence-logs/errors-test.txt`) **ALL PASSED**. Each failure maps to a stable code, a plain-language reason and a fix: wallet rejections, wrong network, RPC limits, relay down/limits/budget, every contract revert name, self-pay gas problems, compose validation, inbox decryption, payment failures.

## 5. Contracts are live on Base Sepolia
(`evidence-logs/onchain-base-sepolia.txt`)
```
proxy 0xDc286558B784a959cc313e9D6D0C13FAd9903306 (chain 84532, deployment block 48211756)
implementationVersion: "1.3.0"   supportsPrivateMessaging: true
privateConfig: enabled, direct, groups; dmFee 1e12 wei
```
Deployment transactions: see `chain/deployments/base-sepolia-84532.json` (4 hashes, explorer links).

## 5a. Contracts are live on Base mainnet (2026-10-17)
Record: `chain/deployments/base-8453.json`. Same addresses as Base Sepolia (fresh deployer, nonce 0).
```
cast call 0xDc286558B784a959cc313e9D6D0C13FAd9903306 "implementationVersion()(string)" --rpc-url https://mainnet.base.org  -> "1.3.0"
supportsPrivateMessaging() -> true   baseMessageFee() -> 1e12 wei   deployment block 52725655
```
Tx: implementation 0xe10cf14b…0d1b, controller 0x307e924b…bf36, proxy 0x689745b7…380f, setPrivateConfig 0xddac570e…1a727 (total 0.0000327 ETH).
Why mainnet: the PayBox portal's Validate step rejected Base Sepolia ("deployment does not support the proposal chain") and accepted Base mainnet. Hosted checks with the testnet build: 9 tools, `resolve_room`, `inbox_status` and `propose_payment_from_thread` passed.

## 5b. LIVE smoke test on Base Sepolia through the public relay
`cd services/relay && npx tsx test/live-smoke.ts` → (`evidence-logs/live-smoke-base-sepolia.txt`) **LIVE SMOKE PASSED**: a brand-new throwaway wallet with balance `0n` registered a key and sent an encrypted message through the public relay (reached at `https://parley-panel.vercel.app/relay/…`), its balance stayed `0n`, and the concierge's encrypted reply (with a USDC payment-request card) was decrypted by that wallet. Registration and send transactions are on Base Sepolia (hashes in the log).

## 6. The hosted panel, relay and widget respond
The panel/widget/demo are served from `https://parley-panel.vercel.app`; the relay API through the same site at `https://parley-panel.vercel.app/relay/…`.
- `curl https://parley-panel.vercel.app/relay/health` → `{"ok":true,"relayer":"0x4B76…"}`
- `https://parley-panel.vercel.app/` serves the panel; `/demo.html` serves the merchant demo with the widget; the relay's `/v1/config` lists the chain and contract.

## 7. Security properties and where to look
| Property | Where |
|---|---|
| Plugin holds no keys, signs nothing | `plugin/src/plugin.ts`: tools return read-only data or `proposeEvm(...)` only |
| Gasless entries bind signer, chain, proxy, nonce, deadline | `chain/src/chat/ChatPrivate.sol` (`_verifySigned`, `signedActionsDomainSeparator`), `chain/test/chat/ChatSigned.t.sol` |
| Relay never holds user keys; rate-limited and budget-capped | `services/relay/src/{relay,server,ratelimit}.ts` |
| Service wallet key generated inside the container volume, never printed | `services/relay/src/server.ts` |
| Encryption format and AAD binding | `plugin/src/crypto.ts` |

## 7b. Public rooms and share
Public rooms (any tx hash, invoice id or URL derives the same room on both sides) read and post from the panel; the plugin's `post_public` / `read_room` use the same derivation. Browser-verified locally: invalid reference rejected with a reason, room opened from a tx hash, a public note posted from a funded wallet and read back, Share/QR dialog renders.

## 5c. Live guest loop on the deployed site (2026-10-17)
Fresh browser profile, no wallet extension, zero funds, on https://parley-panel.vercel.app against Base Sepolia: register → message → concierge reply with card (≈20 s) → **Pay** (faucet top-up, transfer, sealed receipt) → concierge "Verified on-chain" → **PAID ✓**. Whole loop ≈90 s.

## 8. What is NOT evidenced here (to be filled by the owner before submission)
- PayBox portal: done, see `ABOUT.md` (checks passed with 9 tools and 4 hosts; `register_key` Validate on Base mainnet passed). The full PayBox-wallet conversation on mainnet uses the same code tested here and is the next run with a funded PayBox wallet.
- Demo video and X post: https://x.com/Amanullah_Bhlm/status/2111519106487009394 (posted 2026-10-17; reposted by @PayBox)
