Files

82 lines
6.8 KiB
Markdown

# UUPS Bank V1 → V2 Demo
> Educational demo — mock token — never use real funds.
This repository is a local-first upgradeability lesson. It deploys a six-decimal mock ERC-20 and a V1 custody ledger behind an ERC-1967 proxy, upgrades the proxy to V2 without losing state, performs a customer-to-customer ledger transfer, and presents the result in a read-only operations console.
> **Trust boundary:** MockUSDC has no value. These contracts are educational and unaudited; real deposits must never be sent here. The owner can pause customer actions and install arbitrary future logic. UUPS mistakes can corrupt state or permanently brick upgradeability. A real custody product requires professional audits, operational key controls, multisig or timelocked governance, incident procedures, legal advice, and jurisdiction-specific compliance work.
## Prerequisites
Use a Linux-like Bash environment with Git, GNU Make, `curl`, Foundry `1.7.1` (`forge`, `anvil`, and `cast`), Node `24.18.0`, and npm `11.17.0`. The exact package graph is committed in the lockfiles. Installation documentation: [Git](https://git-scm.com/downloads), [Foundry](https://getfoundry.sh), [Node](https://nodejs.org/en/download), [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm), [Bash](https://www.gnu.org/software/bash/), [Make](https://www.gnu.org/software/make/), and [curl](https://curl.se/download.html).
```bash
make setup
make doctor
```
`make setup` initializes recursive Git submodules and installs both pinned npm dependency trees. `make doctor` is read-only: it verifies versions, dependencies, writable runtime locations, and that local ports `8545` and `5173` are available.
## Ten-minute local quick start
This complete path is local. It needs no Base Sepolia service, browser wallet, faucet, explorer, public RPC, keystore, secret, or real funds.
In the first terminal:
```bash
make demo-local
```
The command performs a scoped reset, starts deterministic Anvil at `http://127.0.0.1:8545`, deploys and seeds V1, checks its exact state, exports public artifacts, and starts the console at `http://127.0.0.1:5173/`. It remains attached so Ctrl-C safely stops only the recorded project process groups.
In a second terminal:
```bash
DEMO_EXPECTED_STAGE=v1 make check-state
make upgrade-v2
make demo-transfer
DEMO_EXPECTED_STAGE=v2 make check-state
curl --fail http://127.0.0.1:5173/
```
Act 1 proves Alice has `900 mUSDC`, Bob has `500 mUSDC`, liabilities and reserves are both `1,400 mUSDC`, and version is `1`. The upgrade keeps the proxy, owner, asset, pause state, customer balances, liabilities, reserves, surplus, and deployment block unchanged while changing the implementation and version to `2`. The internal `250 mUSDC` transfer then leaves Alice with `650 mUSDC` and Bob with `750 mUSDC`; liabilities and reserves remain `1,400 mUSDC`, and the console decodes `BalanceTransferred` without an ERC-20 reserve transfer.
Stop the attached first terminal with Ctrl-C, then remove only reproducible local state:
```bash
make reset-local
```
## Architecture and guarantees
Foundry scripts are the state-changing control plane; the browser has no connector, signer, transaction client, or write control. `MockUSDC` holds no value. An ERC-1967 proxy keeps the bank address and storage stable while delegating calls to `BankV1` or `BankV2`. The proxy holds token reserves and the internal ledger records liabilities. Confirmed public manifests and generated ABIs connect that system to the React/Vite console through viem and wagmi.
OpenZeppelin supplies the UUPS and access-control primitives plus storage/upgrade validation. Foundry supplies compilation, tests, scripts, and the local chain. The project supplies the application logic, tests, manifests, lifecycle tooling, and UI. Passing those checks does not make the demo audited, decentralized, or suitable for custody.
## Command reference
- `make doctor` — check prerequisites, dependencies, runtime locations, configuration, and local ports without changing chain state.
- `make setup` — initialize pinned submodules and npm dependencies.
- `make demo-local` — run the attached local V1 experience.
- `make verify` — run Solidity format/build/unit/fuzz/invariant/upgrade gates, artifact and shell-safety tests, the project scanner, and web lint/type/tests/build.
- `make check-state` — print and validate the selected stage; use `DEMO_EXPECTED_STAGE=v1` or `v2` for the exact local acts.
- `make upgrade-v2` — validate and perform the owner-authorized local V1-to-V2 upgrade, finalize its manifest, and refresh exported artifacts.
- `make demo-transfer` — perform Alice's local `250 mUSDC` internal transfer to Bob and validate Act 3.
- `make reset-local` — validate recorded process identity, stop only owned groups, and remove only known local artifacts.
- `make deploy-v1` and `make seed-v1` — run the lower-level guarded V1 deployment and deterministic Act 1 setup used by `make demo-local`.
- `make sync-artifacts`, `make sync-artifacts-check`, `make sync-abis`, and `make publish-web-manifest` — regenerate or validate the ABI bridge and publish only the confirmed active manifest.
- `make test-finalize-manifest` — exercise manifest finalization in isolation.
- `make select-anvil` and `make select-base-sepolia` — explicitly select and republish an existing confirmed manifest.
- `make archive-base-manifest` — safely archive the Base canonical manifest before an intentional redeployment.
- `make deploy-base-sepolia`, `make upgrade-base-sepolia`, and `make transfer-base-sepolia` — explicit optional-testnet commands with chain, actor, account, and RPC guards.
## Optional Base Sepolia encore
The local lesson above is complete without a wallet, faucet, explorer, or public RPC. The optional Base Sepolia encore is separate and runs only after the local V1→V2 demo and `make verify` succeed. It uses a named encrypted Foundry keystore through `--account` and the same public address through `--sender`; no supported command accepts a raw private key or mnemonic.
Copy `.env.example` to `.env` and fill only its public configuration. `BASE_SEPOLIA_RPC_URL` is the terminal endpoint and may be credentialed; `BASE_SEPOLIA_PUBLIC_RPC_URL` is intentionally public and is the only RPC serialized for the browser. Foundry requests the keystore password interactively, and that password never belongs in `.env`.
Use `make archive-base-manifest` before an intentional Base redeployment. It moves only the Base canonical manifest to a timestamped sibling while preserving the active browser fallback and Anvil state. See the [presenter runbook](docs/PRESENTER_RUNBOOK.md) for the exact optional onboarding, funding boundary, execution sequence, and recovery rules.
Continue with the [learning guide](docs/LEARNING_GUIDE.md) or rehearse from the [presenter runbook](docs/PRESENTER_RUNBOOK.md).