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:
golem
2026-08-20 14:38:00 -06:00
co-authored by Claude Opus 5
parent 14980e6083
commit fa36215def
28 changed files with 9368 additions and 1 deletions
@@ -0,0 +1,96 @@
### Task 4: Implement V1 custody accounting and adversarial unit tests
**Files:**
- Modify: `src/BankV1.sol`
- Create: `test/BankV1.t.sol`
- Create: `test/mocks/FeeOnTransferToken.sol`
- Create: `test/mocks/ReentrantToken.sol`
**Interfaces:**
- Produces `deposit(uint256)` and `withdraw(uint256)` plus `Deposited`, `Withdrawn`, `ZeroAmount`, `InsufficientBalance`, and `UnexpectedAssetDelta`.
- Consumes only a standard non-rebasing ERC-20 through `IERC20`/`SafeERC20`.
- Preserves `reserves >= totalLiabilities`; direct token transfers may create surplus.
- [ ] Write event and error declarations into the test expectations before production code:
```solidity
event Deposited(address indexed account, uint256 amount);
event Withdrawn(address indexed account, uint256 amount);
error ZeroAmount();
error InsufficientBalance(address account, uint256 available, uint256 requested);
error UnexpectedAssetDelta(uint256 expected, uint256 actual);
```
- [ ] Write failing deposit tests for exact balance/liability/reserve deltas, event emission, zero amount, paused state, inadequate allowance, inadequate wallet balance, and two independent customers. Use six-decimal constants (`1_000e6`) so assertions read like the demo.
- [ ] Add `FeeOnTransferToken` whose `transferFrom` delivers `99%` of the requested amount. Assert a deposit reverts with `UnexpectedAssetDelta(requested, received)` and that the ERC-20 transfer, bank balance, and liabilities are all rolled back.
- [ ] Add `ReentrantToken` that attempts a nested `bank.deposit` during `transferFrom`. Assert the nested call receives `ReentrancyGuardReentrantCall` and the outer call either completes once or reverts atomically according to the mocks configured propagation mode; no double credit is permitted.
- [ ] Write failing withdrawal tests for exact deltas, event emission, zero amount, paused state, insufficient internal balance (including available/requested values), checks-effects-interactions under a transfer callback, and one accounts withdrawal leaving another account unchanged.
- [ ] Write the surplus test: deposit 100 mUSDC, transfer 25 mUSDC directly to the proxy, assert reserves `125e6`, liabilities `100e6`, and a normal 100 mUSDC withdrawal succeeds while the 25 mUSDC surplus remains. Assert there is no owner sweep/rescue behavior by keeping such a function out of the interface.
- [ ] Run red tests:
```bash
npm_config_offline=true forge test --match-path test/BankV1.t.sol -vvv --force
```
Expected red: `deposit`/`withdraw` and their errors/events are absent.
- [ ] Implement `deposit` with exact received-amount validation and state credit only after a successful transfer:
```solidity
function deposit(uint256 amount) external whenNotPaused nonReentrant {
if (amount == 0) revert ZeroAmount();
uint256 reservesBefore = _asset.balanceOf(address(this));
_asset.safeTransferFrom(msg.sender, address(this), amount);
uint256 reservesAfter = _asset.balanceOf(address(this));
uint256 received = reservesAfter >= reservesBefore ? reservesAfter - reservesBefore : 0;
if (received != amount) revert UnexpectedAssetDelta(amount, received);
_balances[msg.sender] += amount;
_totalLiabilities += amount;
emit Deposited(msg.sender, amount);
}
```
- [ ] Implement `withdraw` with checks-effects-interactions:
```solidity
function withdraw(uint256 amount) external whenNotPaused nonReentrant {
if (amount == 0) revert ZeroAmount();
uint256 available = _balances[msg.sender];
if (amount > available) revert InsufficientBalance(msg.sender, available, amount);
_balances[msg.sender] = available - amount;
_totalLiabilities -= amount;
_asset.safeTransfer(msg.sender, amount);
emit Withdrawn(msg.sender, amount);
}
```
- [ ] Add fuzz tests in `BankV1.t.sol`: bound deposit to `[1, 1_000_000e6]`; bound withdrawal to `[1, deposited]`; prove exact reserve/liability/customer deltas and that over-withdraw always reverts. Keep a fixed seed in `foundry.toml` for presentation reproducibility while printing Foundrys replay seed on failure.
- [ ] Run focused and aggregate green tests:
```bash
forge fmt
npm_config_offline=true forge test --match-path test/BankV1.t.sol -vvv --force
npm_config_offline=true forge test --match-path 'test/BankV1*.t.sol' --force
```
Expected: all V1 tests pass with validated proxy deployment enabled.
- [ ] Commit:
```bash
git add src/BankV1.sol test/BankV1.t.sol test/mocks/FeeOnTransferToken.sol test/mocks/ReentrantToken.sol
git commit -m "feat: add V1 custody accounting"
```
---