forked from NSPG13/agent-bounties
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild_canonical_child_verifier_bundle.py
More file actions
134 lines (116 loc) · 5.28 KB
/
Copy pathbuild_canonical_child_verifier_bundle.py
File metadata and controls
134 lines (116 loc) · 5.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/env python3
"""Build the unsigned, immutable Base deployment bundle for canonical-child-v1."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
import re
from typing import Any
from _shared.evm import address_bytes, address_word, artifact_hex, create_address, keccak256
CHAIN_ID = 8453
FACTORY = "0x082c52131aaf0c56e76b075f895eab6fcab6d2f9"
USDC = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"
PROTOCOL_TAG = "0x437e2138276203e007f58857babacb739e6612192c7d9ce8f41e610236edf382"
ACCEPTANCE_CRITERIA_HASH = (
"0xa103c2c907f96e03a2f2b0e6b2209e0a3ca53686f7e9f79d89d7bfa1f8e314de"
)
SOURCE = "contracts/base-escrow/src/CanonicalChildBountyVerifier.sol:CanonicalChildBountyVerifier"
def patched_runtime(artifact: dict[str, Any], factory: str, token: str) -> bytes:
deployed = artifact.get("deployedBytecode")
runtime = bytearray(
artifact_hex(deployed, "deployedBytecode", distinct_odd_length_error=True)
)
references = deployed.get("immutableReferences") if isinstance(deployed, dict) else None
if not isinstance(references, dict) or len(references) != 2:
raise ValueError("expected exactly canonicalFactory and settlementToken immutable references")
# Solidity AST ids increase in source declaration order: factory, then token.
values = [address_word(factory), address_word(token)]
for value, (_, locations) in zip(values, sorted(references.items(), key=lambda item: int(item[0]))):
if not isinstance(locations, list) or not locations:
raise ValueError("immutable reference group is empty")
for location in locations:
start = int(location["start"])
length = int(location["length"])
if length != 32 or start < 0 or start + length > len(runtime):
raise ValueError("invalid immutable reference")
runtime[start : start + length] = value
return bytes(runtime)
def build_bundle(args: argparse.Namespace) -> dict[str, Any]:
artifact = json.loads(args.artifact.read_text(encoding="utf-8"))
creation_code = artifact_hex(
artifact.get("bytecode"), "bytecode", distinct_odd_length_error=True
)
runtime = patched_runtime(artifact, FACTORY, USDC)
constructor_data = creation_code + address_word(FACTORY)
expected_contract = create_address(args.deployer, args.deployer_nonce)
if not re.fullmatch(r"[0-9a-f]{40}", args.source_commit):
raise ValueError("source commit must be a full lowercase Git commit")
if not re.fullmatch(r"0x[0-9a-fA-F]{64}", args.preflight_block_hash):
raise ValueError("preflight block hash must be bytes32 hex")
return {
"schema_version": "agent-bounties/canonical-child-verifier-deployment-v1",
"protocol_version": "agent-bounties/canonical-child-v1",
"network": "base-mainnet",
"chain_id": CHAIN_ID,
"source": SOURCE,
"source_commit": args.source_commit,
"canonical_factory": FACTORY,
"settlement_token": USDC,
"acceptance_criteria_hash": ACCEPTANCE_CRITERIA_HASH,
"protocol_tag": PROTOCOL_TAG,
"preflight_block": {
"number": args.preflight_block_number,
"hash": args.preflight_block_hash.lower(),
},
"deployment": {
"from": args.deployer.lower(),
"deployer_nonce": args.deployer_nonce,
"to": None,
"value_wei": 0,
"expected_contract": expected_contract.lower(),
"data": f"0x{constructor_data.hex()}",
"creation_code_hash": keccak256(constructor_data),
"expected_runtime_code": f"0x{runtime.hex()}",
"runtime_code_hash": keccak256(runtime),
"runtime_code_bytes": len(runtime),
},
"evidence_boundary": (
"This unsigned bundle fixes one contract-creation transaction. A successful receipt and "
"matching runtime/getters prove deployment only; they do not prove bounty funding, "
"completion, or payout."
),
}
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument(
"--artifact",
type=Path,
default=Path(
"contracts/base-escrow/out/CanonicalChildBountyVerifier.sol/CanonicalChildBountyVerifier.json"
),
)
parser.add_argument("--deployer", required=True)
parser.add_argument("--deployer-nonce", type=int, required=True)
parser.add_argument("--source-commit", required=True)
parser.add_argument("--preflight-block-number", type=int, required=True)
parser.add_argument("--preflight-block-hash", required=True)
parser.add_argument("--output", type=Path, required=True)
return parser.parse_args()
def main() -> int:
args = parse_args()
address_bytes(args.deployer)
bundle = build_bundle(args)
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(json.dumps(bundle, indent=2) + "\n", encoding="utf-8")
print(
json.dumps(
{
"output": str(args.output),
"expected_contract": bundle["deployment"]["expected_contract"],
"runtime_code_hash": bundle["deployment"]["runtime_code_hash"],
}
)
)
return 0
if __name__ == "__main__":
raise SystemExit(main())