fix: align deployment manifest schema

This commit is contained in:
golem
2026-08-21 02:55:41 -06:00
parent be8f01ea4e
commit c6bf8a683f
8 changed files with 389 additions and 139 deletions
+145 -41
View File
@@ -125,18 +125,38 @@ contract ScriptPreflightTest is Test {
harness.readManifest(path, true);
}
function testManifestRejectsNonParallelActorArrays() public {
function testAnvilManifestRejectsUnexpectedActorObjectCount() public {
string memory path = _writeManifest(31337, 1, TOKEN, PROXY, IMPLEMENTATION);
_etchManifestContracts();
vm.writeJson('["owner","Alice"]', path, ".actorLabels");
vm.expectRevert(DemoScript.InvalidActorConfiguration.selector);
vm.writeJson(
string.concat(
'[{"label":"owner","address":"',
vm.toString(OWNER),
'"},{"label":"Alice","address":"',
vm.toString(ALICE),
'"}]'
),
path,
".actors"
);
vm.expectRevert();
harness.readManifest(path, true);
}
function testAnvilManifestRejectsUnexpectedActorLabels() public {
string memory path = _writeManifest(31337, 1, TOKEN, PROXY, IMPLEMENTATION);
_etchManifestContracts();
vm.writeJson('["owner","Mallory","Bob"]', path, ".actorLabels");
vm.writeJson(
string.concat(
'[{"label":"owner","address":"',
vm.toString(OWNER),
'"},{"label":"Mallory","address":"',
vm.toString(ALICE),
'"},{"label":"Bob","address":"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC"}]'
),
path,
".actors"
);
vm.expectRevert(DemoScript.InvalidActorConfiguration.selector);
harness.readManifest(path, true);
}
@@ -146,7 +166,11 @@ contract ScriptPreflightTest is Test {
_etchManifestContracts();
vm.writeJson(
string.concat(
'["', vm.toString(ALICE), '","', vm.toString(OWNER), '","0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC"]'
'[{"label":"owner","address":"',
vm.toString(ALICE),
'"},{"label":"Alice","address":"',
vm.toString(OWNER),
'"},{"label":"Bob","address":"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC"}]'
),
path,
".actors"
@@ -156,11 +180,20 @@ contract ScriptPreflightTest is Test {
}
function testBaseManifestRequiresOnlyOwnerActor() public {
string memory path = _writeBaseManifest();
string memory path = _writePublicBaseManifest();
vm.chainId(84532);
_etchManifestContracts();
vm.writeJson('["owner","Alice"]', path, ".actorLabels");
vm.writeJson(string.concat('["', vm.toString(OWNER), '","', vm.toString(ALICE), '"]'), path, ".actors");
vm.writeJson(
string.concat(
'[{"label":"owner","address":"',
vm.toString(OWNER),
'"},{"label":"Alice","address":"',
vm.toString(ALICE),
'"}]'
),
path,
".actors"
);
vm.expectRevert(DemoScript.InvalidActorConfiguration.selector);
harness.readManifest(path, true);
}
@@ -169,6 +202,41 @@ contract ScriptPreflightTest is Test {
assertEq(harness.educationalWarning(), unicode"Educational demo — mock token — never use real funds.");
}
function testNestedActorsRoundTripThroughManifestSerialization() public {
string memory path = _writePublicAnvilManifest();
_etchManifestContracts();
DemoScript.Manifest memory manifest = harness.readManifest(path, true);
assertEq(manifest.actors[0].label, "owner");
assertEq(manifest.actors[1].address_, ALICE);
string memory serialized = harness.serializeManifest(manifest);
assertFalse(_contains(serialized, "actorLabels"));
assertFalse(_contains(serialized, "explorerUrl"));
vm.writeFile(path, serialized);
DemoScript.Manifest memory roundTrip = harness.readManifest(path, true);
assertEq(roundTrip.actors[2].label, "Bob");
assertEq(roundTrip.actors[2].address_, 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC);
}
function testLegacyParallelActorManifestIsRejected() public {
string memory path = _writeLegacyParallelActorManifest();
_etchManifestContracts();
vm.expectRevert(abi.encodeWithSelector(DemoScript.InvalidManifestSchema.selector, uint256(0)));
harness.readManifest(path, true);
}
function testBaseSepoliaManifestUsesCamelCaseAndOmitsUnavailableUrls() public {
string memory path = _writePublicBaseManifest();
vm.chainId(84532);
_etchManifestContracts();
DemoScript.Manifest memory manifest = harness.readManifest(path, true);
assertEq(manifest.network, "baseSepolia");
assertEq(manifest.rpcUrl, "");
assertEq(manifest.explorerBaseUrl, "");
assertEq(manifest.actors[0].label, "owner");
assertEq(manifest.actors[0].address_, OWNER);
}
function testSerializedManifestContainsPublicAddressesAndNoSecrets() public {
DemoScript.Manifest memory manifest = DemoScript.Manifest({
schemaVersion: 1,
@@ -176,12 +244,11 @@ contract ScriptPreflightTest is Test {
chainId: 31337,
deploymentBlock: 0,
rpcUrl: "http://127.0.0.1:8545",
explorerUrl: "",
explorerBaseUrl: "",
token: TOKEN,
proxy: PROXY,
implementation: IMPLEMENTATION,
owner: OWNER,
actorLabels: _labels(),
actors: _actors()
});
@@ -212,12 +279,12 @@ contract ScriptPreflightTest is Test {
assertEq(BankV1(proxy).owner(), OWNER);
assertEq(address(BankV1(proxy).asset()), token);
assertEq(BankV1(proxy).contractVersion(), 1);
assertEq(manifest.actorLabels[0], "owner");
assertEq(manifest.actorLabels[1], "Alice");
assertEq(manifest.actorLabels[2], "Bob");
assertEq(manifest.actors[0], OWNER);
assertEq(manifest.actors[1], ALICE);
assertEq(manifest.actors[2], 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC);
assertEq(manifest.actors[0].label, "owner");
assertEq(manifest.actors[1].label, "Alice");
assertEq(manifest.actors[2].label, "Bob");
assertEq(manifest.actors[0].address_, OWNER);
assertEq(manifest.actors[1].address_, ALICE);
assertEq(manifest.actors[2].address_, 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC);
}
function testSeedV1DemoExecutesExactActOneStateAndCheckStateAcceptsIt() public {
@@ -227,12 +294,12 @@ contract ScriptPreflightTest is Test {
new SeedV1Demo().run();
BankV1 bank = BankV1(manifest.proxy);
assertEq(bank.balanceOf(manifest.actors[1]), 900e6);
assertEq(bank.balanceOf(manifest.actors[2]), 500e6);
assertEq(bank.balanceOf(manifest.actors[1].address_), 900e6);
assertEq(bank.balanceOf(manifest.actors[2].address_), 500e6);
assertEq(bank.totalLiabilities(), 1_400e6);
assertEq(MockUSDC(manifest.token).balanceOf(manifest.proxy), 1_400e6);
assertEq(MockUSDC(manifest.token).balanceOf(manifest.actors[1]), 1_100e6);
assertEq(MockUSDC(manifest.token).balanceOf(manifest.actors[2]), 500e6);
assertEq(MockUSDC(manifest.token).balanceOf(manifest.actors[1].address_), 1_100e6);
assertEq(MockUSDC(manifest.token).balanceOf(manifest.actors[2].address_), 500e6);
vm.setEnv("DEMO_EXPECTED_STAGE", "v1");
new CheckState().run();
@@ -266,7 +333,7 @@ contract ScriptPreflightTest is Test {
vm.toString(chainId),
',"deploymentBlock":',
vm.toString(deploymentBlock),
',"rpcUrl":"http://127.0.0.1:8545","explorerUrl":"","token":"',
',"rpcUrl":"http://127.0.0.1:8545","token":"',
vm.toString(token),
'","proxy":"',
vm.toString(proxy),
@@ -274,11 +341,11 @@ contract ScriptPreflightTest is Test {
vm.toString(implementation),
'","owner":"',
vm.toString(OWNER),
'","actorLabels":["owner","Alice","Bob"],"actors":["',
'","actors":[{"label":"owner","address":"',
vm.toString(OWNER),
'","',
'"},{"label":"Alice","address":"',
vm.toString(ALICE),
'","0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC"]}'
'"},{"label":"Bob","address":"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC"}]}'
);
vm.writeFile(path, json);
}
@@ -293,12 +360,12 @@ contract ScriptPreflightTest is Test {
manifest = harness.readManifest(path, true);
}
function _writeBaseManifest() internal returns (string memory path) {
path = string.concat(fixtureDir, "/base-manifest.json");
function _writePublicAnvilManifest() internal returns (string memory path) {
path = string.concat(fixtureDir, "/public-anvil-manifest.json");
vm.writeFile(
path,
string.concat(
'{"schemaVersion":1,"network":"base-sepolia","chainId":84532,"deploymentBlock":1,"rpcUrl":"https://sepolia.base.org","explorerUrl":"https://sepolia.basescan.org","token":"',
'{"schemaVersion":1,"network":"anvil","chainId":31337,"deploymentBlock":1,"rpcUrl":"http://127.0.0.1:8545","token":"',
vm.toString(TOKEN),
'","proxy":"',
vm.toString(PROXY),
@@ -306,9 +373,53 @@ contract ScriptPreflightTest is Test {
vm.toString(IMPLEMENTATION),
'","owner":"',
vm.toString(OWNER),
'","actorLabels":["owner"],"actors":["',
'","actors":[{"label":"owner","address":"',
vm.toString(OWNER),
'"]}'
'"},{"label":"Alice","address":"',
vm.toString(ALICE),
'"},{"label":"Bob","address":"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC"}]}'
)
);
}
function _writeLegacyParallelActorManifest() internal returns (string memory path) {
path = string.concat(fixtureDir, "/legacy-parallel-actors.json");
vm.writeFile(
path,
string.concat(
'{"schemaVersion":1,"network":"anvil","chainId":31337,"deploymentBlock":1,"rpcUrl":"http://127.0.0.1:8545","token":"',
vm.toString(TOKEN),
'","proxy":"',
vm.toString(PROXY),
'","implementation":"',
vm.toString(IMPLEMENTATION),
'","owner":"',
vm.toString(OWNER),
'","actorLabels":["owner","Alice","Bob"],"actors":[{"label":"owner","address":"',
vm.toString(OWNER),
'"},{"label":"Alice","address":"',
vm.toString(ALICE),
'"},{"label":"Bob","address":"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC"}]}'
)
);
}
function _writePublicBaseManifest() internal returns (string memory path) {
path = string.concat(fixtureDir, "/public-base-manifest.json");
vm.writeFile(
path,
string.concat(
'{"schemaVersion":1,"network":"baseSepolia","chainId":84532,"deploymentBlock":1,"token":"',
vm.toString(TOKEN),
'","proxy":"',
vm.toString(PROXY),
'","implementation":"',
vm.toString(IMPLEMENTATION),
'","owner":"',
vm.toString(OWNER),
'","actors":[{"label":"owner","address":"',
vm.toString(OWNER),
'"}]}'
)
);
}
@@ -319,18 +430,11 @@ contract ScriptPreflightTest is Test {
vm.etch(IMPLEMENTATION, hex"00");
}
function _labels() internal pure returns (string[] memory labels) {
labels = new string[](3);
labels[0] = "owner";
labels[1] = "Alice";
labels[2] = "Bob";
}
function _actors() internal pure returns (address[] memory actors) {
actors = new address[](3);
actors[0] = OWNER;
actors[1] = ALICE;
actors[2] = 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC;
function _actors() internal pure returns (DemoScript.Actor[] memory actors) {
actors = new DemoScript.Actor[](3);
actors[0] = DemoScript.Actor({label: "owner", address_: OWNER});
actors[1] = DemoScript.Actor({label: "Alice", address_: ALICE});
actors[2] = DemoScript.Actor({label: "Bob", address_: 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC});
}
function _contains(string memory haystack, string memory needle) internal pure returns (bool) {