docs: track superpowers working documents in git
The uups-bank-demo wave's SDD records (ledger, six task briefs and reports, review diffs) and the brainstorm design mockups were git-ignored, so they existed only on one sandbox VM and reached no remote — this repo had no remote at all until now. Removes `.superpowers/` from .gitignore and the `*` .gitignore the superpowers plugin writes inside .superpowers/sdd/; the second blocks the directory even with the first removed. Excluded as ephemeral local-server state, and now ignored by name: .last-port, .last-token (a 64-char session token for a brainstorm server on a port that is long gone), and the per-session state/ directories. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fnwzj6McD6kSkXwjUKFKxe
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
### Task 6: Deploy, seed, inspect, and export deterministic V1 state
|
||||
|
||||
**Files:**
|
||||
- Create: `script/lib/DemoScript.sol`
|
||||
- Create: `script/DeployV1.s.sol`
|
||||
- Create: `script/SeedV1Demo.s.sol`
|
||||
- Create: `script/CheckState.s.sol`
|
||||
- Create: `test/ScriptPreflight.t.sol`
|
||||
- Create: `tools/finalize-manifest.mjs`
|
||||
- Create: `tools/select-manifest.mjs`
|
||||
- Create: `tools/test-finalize-manifest.mjs`
|
||||
- Create: `deployments/.gitkeep`
|
||||
- Modify: `Makefile`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes an RPC, chain ID, explicit broadcaster, pending manifest, and Foundry broadcast receipts.
|
||||
- Produces an active schema-versioned public manifest only after receipt/code/postcondition checks, then the exact Act 1 state.
|
||||
- Establishes local actor indexes: owner `0`, Alice `1`, Bob `2` from Anvil’s standard development mnemonic.
|
||||
|
||||
- [ ] Write `ScriptPreflight.t.sol` around a small public harness for `DemoScript` and cover:
|
||||
|
||||
- chain IDs `31337` and `84532` accepted;
|
||||
- chain IDs `1`, `8453`, and an arbitrary value rejected before broadcast;
|
||||
- missing/invalid manifest, wrong manifest chain, zero address, and address-without-code rejected;
|
||||
- internal pending manifests may use deployment block `0`, while active manifests may not;
|
||||
- local keys derivable only when chain ID is `31337`;
|
||||
- serialized JSON contains public addresses but never the mnemonic, a private key, `PRIVATE_KEY`, or `MNEMONIC`.
|
||||
|
||||
- [ ] Run red:
|
||||
|
||||
```bash
|
||||
forge test --match-path test/ScriptPreflight.t.sol -vvv --force
|
||||
```
|
||||
|
||||
Expected red: `DemoScript` does not exist.
|
||||
|
||||
- [ ] Implement `DemoScript` constants and guards:
|
||||
|
||||
```solidity
|
||||
uint256 internal constant ANVIL_CHAIN_ID = 31337;
|
||||
uint256 internal constant BASE_SEPOLIA_CHAIN_ID = 84532;
|
||||
string internal constant ANVIL_TEST_PHRASE =
|
||||
"test test test test test test test test test test test junk";
|
||||
string internal constant PENDING_MANIFEST_PATH = "deployments/pending.json";
|
||||
string internal constant ACTIVE_MANIFEST_PATH = "deployments/active.json";
|
||||
|
||||
error UnsupportedChain(uint256 chainId);
|
||||
error ManifestChainMismatch(uint256 expected, uint256 actual);
|
||||
error MissingCode(string label, address target);
|
||||
```
|
||||
|
||||
Provide narrow helpers for chain checks, `vm.deriveKey` on local only, manifest read/write through `vm.parseJson*`/`vm.serialize*`, code checks, and exact-state assertions. Resolve the input/output manifest from `DEPLOYMENT_MANIFEST_PATH` with a narrow default appropriate to each script. Never log or serialize a derived private key.
|
||||
|
||||
- [ ] Write `DeployV1.s.sol` red tests/behavior first, then implement:
|
||||
|
||||
1. validate chain and resolve the public `SCRIPT_SENDER` value;
|
||||
2. start broadcast;
|
||||
3. deploy `MockUSDC(sender)`;
|
||||
4. call `Upgrades.deployUUPSProxy("BankV1.sol:BankV1", abi.encodeCall(...))`;
|
||||
5. stop broadcast;
|
||||
6. assert code, owner, asset, version `1`, and implementation identity;
|
||||
7. write `deployments/pending.json` with schema `1`, network, chain, deployment block `0`, display RPC/explorer metadata, token, proxy, implementation, owner, and local actor labels/addresses.
|
||||
|
||||
On local, derive account `0`, require it equals `SCRIPT_SENDER`, and broadcast with that derived development key. On Base Sepolia, require `SCRIPT_SENDER` equals the expected owner and use the signer selected by Forge’s matching `--account`/`--sender` options; never read a raw signing secret from environment.
|
||||
|
||||
- [ ] Test `finalize-manifest.mjs` and `select-manifest.mjs` with temporary pending/broadcast fixtures and an injected fake JSON-RPC function. Cover: a pre-broadcast deploy guard that rejects an existing target-chain canonical file, exact proxy transaction match, successful receipt, receipt-derived block, actual chain-ID match, code at token/proxy/implementation, implementation-slot match, failed/missing/ambiguous receipt, partial broadcast, wrong chain, missing code, an existing active manifest from either network remaining untouched until selection, secret-bearing content, atomic same-directory rename, and selection of only a valid confirmed chain manifest. Prove a failure never creates/changes a confirmed or active manifest, and selecting Base preserves Anvil byte-for-byte (and vice versa).
|
||||
|
||||
- [ ] Implement the finalizer using Node standard modules and JSON-RPC `fetch`. Its network-free `preflight-deploy <network>` fails before Forge runs when the target canonical file exists and prints the exact safe recovery command (`make reset-local` or `make archive-base-manifest`). Deploy finalization reads `broadcast/DeployV1.s.sol/<chainId>/run-latest.json`, matches the transaction whose created address is the pending proxy, matches its transaction hash to a successful receipt, uses that receipt’s real block number, queries `eth_chainId`, `eth_getCode` for all three contracts, and queries the EIP-1967 implementation slot. Atomically write the chain’s canonical `anvil.json` or `base-sepolia.json` only after all checks pass. `select-manifest.mjs` validates a named canonical file and atomically copies it to `active.json`; it never deletes or overwrites the other chain. Never copy a credential-bearing terminal RPC into JSON.
|
||||
|
||||
- [ ] Write and implement `SeedV1Demo.s.sol`, hard-guarded to chain `31337`. It must perform and assert this exact sequence:
|
||||
|
||||
```text
|
||||
owner mints Alice 2,000 mUSDC
|
||||
owner mints Bob 1,000 mUSDC
|
||||
Alice approves and deposits 1,000 mUSDC
|
||||
Bob approves and deposits 500 mUSDC
|
||||
Alice withdraws 100 mUSDC
|
||||
```
|
||||
|
||||
Postconditions: Alice internal `900e6`, Bob internal `500e6`, liabilities `1_400e6`, reserves `1_400e6`, version `1`, no surplus.
|
||||
|
||||
- [ ] Write and implement `CheckState.s.sol`. Always print network, block, token, proxy, implementation, owner, pause state, version, each configured actor balance, reserves, liabilities, and surplus. Always fail on `reserves < liabilities`, implementation/manifest mismatch, or manifest chain mismatch. `DEMO_EXPECTED_STAGE=deployed` asserts version `1` and empty accounting; `v1` asserts exact Act 1 values; `invariants` checks network-independent invariants only. Task 11 adds stage `v2`.
|
||||
|
||||
- [ ] Add direct Make targets that do not start background processes yet:
|
||||
|
||||
```make
|
||||
RPC_LOCAL := http://127.0.0.1:8545
|
||||
ANVIL_OWNER := 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
|
||||
|
||||
.PHONY: deploy-v1 seed-v1 check-state
|
||||
deploy-v1:
|
||||
@node tools/finalize-manifest.mjs preflight-deploy anvil
|
||||
@SCRIPT_SENDER=$(ANVIL_OWNER) DEPLOYMENT_MANIFEST_PATH=deployments/pending.json npm_config_offline=true forge script script/DeployV1.s.sol:DeployV1 --rpc-url $(RPC_LOCAL) --sender $(ANVIL_OWNER) --broadcast --force
|
||||
@DEPLOYMENT_MANIFEST_PATH=deployments/pending.json DEMO_EXPECTED_STAGE=deployed forge script script/CheckState.s.sol:CheckState --rpc-url $(RPC_LOCAL) --force
|
||||
@node tools/finalize-manifest.mjs deploy --rpc-url $(RPC_LOCAL)
|
||||
@node tools/select-manifest.mjs anvil
|
||||
seed-v1:
|
||||
@forge script script/SeedV1Demo.s.sol:SeedV1Demo --rpc-url $(RPC_LOCAL) --broadcast --force
|
||||
check-state:
|
||||
@DEMO_EXPECTED_STAGE=$${DEMO_EXPECTED_STAGE:-v1} forge script script/CheckState.s.sol:CheckState --rpc-url $(RPC_LOCAL) --force
|
||||
```
|
||||
|
||||
- [ ] Run unit/preflight green checks:
|
||||
|
||||
```bash
|
||||
forge fmt
|
||||
forge test --match-path test/ScriptPreflight.t.sol -vvv --force
|
||||
```
|
||||
|
||||
- [ ] Run the first real local smoke test in two terminals. Terminal A:
|
||||
|
||||
```bash
|
||||
anvil --host 127.0.0.1 --port 8545 --chain-id 31337
|
||||
```
|
||||
|
||||
Terminal B:
|
||||
|
||||
```bash
|
||||
make deploy-v1
|
||||
make seed-v1
|
||||
DEMO_EXPECTED_STAGE=v1 make check-state
|
||||
```
|
||||
|
||||
Expected: the exact Act 1 table prints and all commands exit `0`. Inspect identical `deployments/anvil.json` and selected `deployments/active.json`, verify their deployment block matches the confirmed proxy receipt, and verify they contain no secret material. Simulate a failed receipt fixture and confirm the finalizer changes neither confirmed nor active files.
|
||||
|
||||
- [ ] Commit:
|
||||
|
||||
```bash
|
||||
git add script test/ScriptPreflight.t.sol tools/finalize-manifest.mjs tools/select-manifest.mjs tools/test-finalize-manifest.mjs deployments/.gitkeep Makefile
|
||||
git commit -m "feat: script deterministic V1 demo state"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user