feat: script deterministic V1 demo state

This commit is contained in:
golem
2026-08-21 02:17:18 -06:00
parent 6dcbb03f3c
commit 52935acf5e
10 changed files with 1010 additions and 1 deletions
+124
View File
@@ -0,0 +1,124 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.35;
import {Script} from "forge-std/Script.sol";
import {BankV1} from "../../src/BankV1.sol";
import {MockUSDC} from "../../src/MockUSDC.sol";
abstract contract DemoScript is Script {
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);
error InvalidDeploymentBlock();
error InvalidManifestSchema(uint256 schemaVersion);
error UnexpectedState(string label, uint256 expected, uint256 actual);
error UnexpectedAddress(string label, address expected, address actual);
struct Manifest {
uint256 schemaVersion;
string network;
uint256 chainId;
uint256 deploymentBlock;
string rpcUrl;
string explorerUrl;
address token;
address proxy;
address implementation;
address owner;
string[] actorLabels;
address[] actors;
}
function _requireSupportedChain(uint256 chainId) internal pure {
if (chainId != ANVIL_CHAIN_ID && chainId != BASE_SEPOLIA_CHAIN_ID) revert UnsupportedChain(chainId);
}
function _deriveLocalActor(uint256 chainId, uint32 index) internal returns (uint256 privateKey, address actor) {
if (chainId != ANVIL_CHAIN_ID) revert UnsupportedChain(chainId);
privateKey = vm.deriveKey(ANVIL_TEST_PHRASE, index);
actor = vm.addr(privateKey);
}
function _manifestPath(string memory defaultPath) internal view returns (string memory) {
return vm.envOr("DEPLOYMENT_MANIFEST_PATH", defaultPath);
}
function _readManifest(string memory path, bool active) internal view returns (Manifest memory manifest) {
string memory json = vm.readFile(path);
manifest.schemaVersion = vm.parseJsonUint(json, ".schemaVersion");
manifest.network = vm.parseJsonString(json, ".network");
manifest.chainId = vm.parseJsonUint(json, ".chainId");
manifest.deploymentBlock = vm.parseJsonUint(json, ".deploymentBlock");
manifest.rpcUrl = vm.parseJsonString(json, ".rpcUrl");
manifest.explorerUrl = vm.parseJsonString(json, ".explorerUrl");
manifest.token = vm.parseJsonAddress(json, ".token");
manifest.proxy = vm.parseJsonAddress(json, ".proxy");
manifest.implementation = vm.parseJsonAddress(json, ".implementation");
manifest.owner = vm.parseJsonAddress(json, ".owner");
manifest.actorLabels = vm.parseJsonStringArray(json, ".actorLabels");
manifest.actors = vm.parseJsonAddressArray(json, ".actors");
if (manifest.schemaVersion != 1) revert InvalidManifestSchema(manifest.schemaVersion);
if (manifest.chainId != block.chainid) revert ManifestChainMismatch(block.chainid, manifest.chainId);
if (active && manifest.deploymentBlock == 0) revert InvalidDeploymentBlock();
_requireCode("token", manifest.token);
_requireCode("proxy", manifest.proxy);
_requireCode("implementation", manifest.implementation);
}
function _requireCode(string memory label, address target) internal view {
if (target == address(0) || target.code.length == 0) revert MissingCode(label, target);
}
function _serializeManifest(Manifest memory manifest) internal returns (string memory json) {
string memory objectKey = "demo-manifest";
vm.serializeUint(objectKey, "schemaVersion", manifest.schemaVersion);
vm.serializeString(objectKey, "network", manifest.network);
vm.serializeUint(objectKey, "chainId", manifest.chainId);
vm.serializeUint(objectKey, "deploymentBlock", manifest.deploymentBlock);
vm.serializeString(objectKey, "rpcUrl", manifest.rpcUrl);
vm.serializeString(objectKey, "explorerUrl", manifest.explorerUrl);
vm.serializeAddress(objectKey, "token", manifest.token);
vm.serializeAddress(objectKey, "proxy", manifest.proxy);
vm.serializeAddress(objectKey, "implementation", manifest.implementation);
vm.serializeAddress(objectKey, "owner", manifest.owner);
vm.serializeString(objectKey, "actorLabels", manifest.actorLabels);
json = vm.serializeAddress(objectKey, "actors", manifest.actors);
}
function _writeManifest(string memory path, Manifest memory manifest) internal {
vm.writeJson(_serializeManifest(manifest), path);
}
function _assertDeployedState(Manifest memory manifest) internal view {
BankV1 bank = BankV1(manifest.proxy);
_assertAddress("owner", manifest.owner, bank.owner());
_assertAddress("asset", manifest.token, address(bank.asset()));
_assertUint("version", 1, bank.contractVersion());
_assertUint("liabilities", 0, bank.totalLiabilities());
_assertUint("reserves", 0, MockUSDC(manifest.token).balanceOf(manifest.proxy));
}
function _assertV1State(Manifest memory manifest) internal view {
BankV1 bank = BankV1(manifest.proxy);
_assertUint("Alice internal balance", 900e6, bank.balanceOf(manifest.actors[1]));
_assertUint("Bob internal balance", 500e6, bank.balanceOf(manifest.actors[2]));
_assertUint("liabilities", 1_400e6, bank.totalLiabilities());
_assertUint("reserves", 1_400e6, MockUSDC(manifest.token).balanceOf(manifest.proxy));
_assertUint("version", 1, bank.contractVersion());
}
function _assertUint(string memory label, uint256 expected, uint256 actual) internal pure {
if (actual != expected) revert UnexpectedState(label, expected, actual);
}
function _assertAddress(string memory label, address expected, address actual) internal pure {
if (actual != expected) revert UnexpectedAddress(label, expected, actual);
}
}