diff --git a/dincli/cli/system.py b/dincli/cli/system.py index 086925b..6dd2e14 100644 --- a/dincli/cli/system.py +++ b/dincli/cli/system.py @@ -872,20 +872,28 @@ def din_info(ctx: typer.Context, def import_deployments(ctx: typer.Context, file: Optional[Path] = typer.Option( None, "--file", "-f", - help="Deployments JSON written by deploy-platform.ts (default: hardhat/deployments/.json under the current directory, with dincli network 'local' mapped to hardhat's 'localhost')", + help="Explicit deployments JSON path. Mutually exclusive with --foundry.", + ), + foundry: bool = typer.Option( + False, "--foundry", + help="Load from foundry/deployments/.json (dincli 'local' maps to 'localhost'). Mutually exclusive with --file.", ), ): """ - Import platform proxy addresses from a hardhat deployments file into din_info.json. + Import platform proxy addresses from a deployments JSON into din_info.json. - Deploy the platform first with the canonical proxy-aware script: + Hardhat flow (default): cd hardhat && npx hardhat run scripts/deploy-platform.ts --network localhost + dincli system import-deployments + + Foundry flow: - then run this command to point dincli at the deployed proxies: + forge script foundry/script/DeployPlatform.s.sol --rpc-url http://127.0.0.1:8545 --broadcast ... + dincli system import-deployments --foundry - dincli system import-deployments # default file location - dincli system import-deployments --file hardhat/deployments/localhost.json + Both flows write the same address schema; this command reads either. + Pass --file to supply an explicit path (mutually exclusive with --foundry). Only the platform address keys of the active network's din_info entry are updated (coordinator, token, stake, registry, proxy_admin); everything @@ -894,14 +902,24 @@ def import_deployments(ctx: typer.Context, console = ctx.obj.console effective_network = ctx.obj.network + if file is not None and foundry: + console.print("[red]❌ --file and --foundry are mutually exclusive.[/red]") + raise typer.Exit(1) + if file is None: - hardhat_network = _HARDHAT_NETWORK_FOR.get(effective_network, effective_network) - file = Path("hardhat") / "deployments" / f"{hardhat_network}.json" + network_key = _HARDHAT_NETWORK_FOR.get(effective_network, effective_network) + if foundry: + file = Path("foundry") / "deployments" / f"{network_key}.json" + else: + file = Path("hardhat") / "deployments" / f"{network_key}.json" file = file.expanduser() if not file.exists(): console.print(f"[red]❌ Deployments file not found: {file}[/red]") - console.print("[yellow]Run the platform deploy script first:[/yellow] cd hardhat && npx hardhat run scripts/deploy-platform.ts --network ") + if foundry: + console.print("[yellow]Run the Foundry deploy script first:[/yellow] forge script foundry/script/DeployPlatform.s.sol --rpc-url http://127.0.0.1:8545 --broadcast ...") + else: + console.print("[yellow]Run the platform deploy script first:[/yellow] cd hardhat && npx hardhat run scripts/deploy-platform.ts --network ") raise typer.Exit(1) try: diff --git a/foundry/.gitignore b/foundry/.gitignore index e9475b9..dd1248b 100644 --- a/foundry/.gitignore +++ b/foundry/.gitignore @@ -5,8 +5,12 @@ out/ # Ignores development broadcast logs !/broadcast /broadcast/*/31337/ +/broadcast/*/1337/ /broadcast/**/dry-run/ +# Local deployment artifacts (generated by forge script DeployPlatform.s.sol) +deployments/localhost.json + # Docs docs/ @@ -17,3 +21,4 @@ docs/ lib/* node_modules/* script/* +!script/*.sol diff --git a/foundry/foundry.toml b/foundry/foundry.toml index cece81c..3e54a89 100644 --- a/foundry/foundry.toml +++ b/foundry/foundry.toml @@ -11,6 +11,10 @@ ffi = true ast = true build_info = true extra_output = ["storageLayout"] +fs_permissions = [ + {access = "read", path = "out/"}, + {access = "read-write", path = "deployments/"} +] # The "Magic" fix for Stack too Deep via_ir = true diff --git a/foundry/package-lock.json b/foundry/package-lock.json index f2d0beb..ef04586 100644 --- a/foundry/package-lock.json +++ b/foundry/package-lock.json @@ -5,7 +5,23 @@ "packages": { "": { "dependencies": { - "@openzeppelin/contracts": "^5.6.1" + "@openzeppelin/contracts": "^5.6.1", + "@openzeppelin/upgrades-core": "^1.46.0" + } + }, + "node_modules/@bytecodealliance/preview2-shim": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.0.tgz", + "integrity": "sha512-JorcEwe4ud0x5BS/Ar2aQWOQoFzjq/7jcnxYXCvSMh0oRm0dQXzOA+hqLDBnOMks1LLBA7dmiLLsEBl09Yd6iQ==", + "license": "(Apache-2.0 WITH LLVM-exception)" + }, + "node_modules/@nomicfoundation/slang": { + "version": "0.18.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang/-/slang-0.18.3.tgz", + "integrity": "sha512-YqAWgckqbHM0/CZxi9Nlf4hjk9wUNLC9ngWCWBiqMxPIZmzsVKYuChdlrfeBPQyvQQBoOhbx+7C1005kLVQDZQ==", + "license": "MIT", + "dependencies": { + "@bytecodealliance/preview2-shim": "0.17.0" } }, "node_modules/@openzeppelin/contracts": { @@ -13,6 +29,1128 @@ "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.6.1.tgz", "integrity": "sha512-Ly6SlsVJ3mj+b18W3R8gNufB7dTICT105fJhodGAGgyC2oqnBAhqSiNDJ8V8DLY05cCz81GLI0CU5vNYA1EC/w==", "license": "MIT" + }, + "node_modules/@openzeppelin/upgrades-core": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.46.0.tgz", + "integrity": "sha512-UFSeO/4r8eeXj0C/HAwV+J4b72sE1HX0aALQFs5S2RBOsfXvKweyjQf35vrK32LQiyHdP6IPShAsEBVvpSEgGQ==", + "license": "MIT", + "dependencies": { + "@nomicfoundation/slang": "^0.18.3", + "bignumber.js": "^9.1.2", + "cbor": "^10.0.0", + "chalk": "^4.1.0", + "compare-versions": "^6.0.0", + "debug": "^4.1.1", + "ethereumjs-util": "^7.0.3", + "minimatch": "^10.2.5", + "minimist": "^1.2.7", + "proper-lockfile": "^4.1.1", + "solidity-ast": "^0.4.60" + }, + "bin": { + "openzeppelin-upgrades-core": "dist/cli/cli.js" + } + }, + "node_modules/@types/bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "26.1.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.1.tgz", + "integrity": "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==", + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/@types/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/secp256k1": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.7.tgz", + "integrity": "sha512-Rcvjl6vARGAKRO6jHeKMatGrvOMGrR/AR11N1x2LqintPCyDZ7NBhrh238Z2VZc7aM7KIwnFpFQ7fnfK4H/9Qw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "license": "MIT" + }, + "node_modules/bn.js": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.5.tgz", + "integrity": "sha512-Vq886eXykuP5E6HcKSSStP3bJgrE6In5WKxVUvJ8XGpWWYs2xZHWqUwzCtGgEtBcxyd57KBFDPFoUfNzdaHCNg==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "license": "MIT" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "license": "MIT", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "license": "MIT", + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "license": "MIT" + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/cbor": { + "version": "10.0.12", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-10.0.12.tgz", + "integrity": "sha512-exQDevYd7ZQLP4moMQcZkKCVZsXLAtUSflObr3xTh4xzFIv/xBCdvCd6L259kQOUP2kcTC0jvC6PpZIf/WmRXA==", + "license": "MIT", + "dependencies": { + "nofilter": "^3.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cipher-base": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", + "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.5", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz", + "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==", + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "license": "MIT", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "license": "MPL-2.0", + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "license": "MIT", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/hash-base/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/hash-base/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hash-base/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/hash-base/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/hash-base/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, + "node_modules/keccak": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", + "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "license": "MIT" + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/nofilter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "license": "MIT", + "engines": { + "node": ">=12.19" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.6.tgz", + "integrity": "sha512-BT6eelPB1EyGHo8pC0o9Bl6k6SYVhKO1jEbd3lcTrtr7XHdjP8BW1YpfCV3G9Kwkxgattk+S5q2/RvuttCsS1g==", + "license": "MIT", + "dependencies": { + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "ripemd160": "^2.0.3", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.12", + "to-buffer": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ripemd160": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", + "license": "MIT", + "dependencies": { + "hash-base": "^3.1.2", + "inherits": "^2.0.4" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "license": "MPL-2.0", + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "license": "MIT" + }, + "node_modules/secp256k1": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.4.tgz", + "integrity": "sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "elliptic": "^6.5.7", + "node-addon-api": "^5.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/secp256k1/node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "license": "MIT" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, + "node_modules/sha.js": { + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/solidity-ast": { + "version": "0.4.62", + "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.62.tgz", + "integrity": "sha512-jSC7msQCkJXIzM8LlDjRZ5cif5w40g6THlXHFk3zchbL5dm3YLoBETvqPGo5KndYkftjhcs5kz1fnTu4d34lVQ==", + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/which-typed-array": { + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.22.tgz", + "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } } } } diff --git a/foundry/package.json b/foundry/package.json index 9f8b87c..9b8ae98 100644 --- a/foundry/package.json +++ b/foundry/package.json @@ -1,5 +1,6 @@ { "dependencies": { - "@openzeppelin/contracts": "^5.6.1" + "@openzeppelin/contracts": "^5.6.1", + "@openzeppelin/upgrades-core": "^1.46.0" } } diff --git a/foundry/script/DeployPlatform.s.sol b/foundry/script/DeployPlatform.s.sol new file mode 100644 index 0000000..2781156 --- /dev/null +++ b/foundry/script/DeployPlatform.s.sol @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +import {Script, console} from "forge-std/Script.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {Upgrades} from "@openzeppelin/foundry-upgrades/Upgrades.sol"; + +import {DinToken} from "../src/DinToken.sol"; +import {DinCoordinator} from "../src/DinCoordinator.sol"; +import {DinValidatorStake} from "../src/DinValidatorStake.sol"; +import {DINModelRegistry} from "../src/DINModelRegistry.sol"; + +/// @notice Deploys the four DIN platform contracts behind Transparent Proxies +/// on a local anvil chain, wires them together, and writes +/// foundry/deployments/localhost.json in the same schema as +/// hardhat/deployments/localhost.json so dincli import-deployments +/// accepts it without modification. +/// +/// Usage (from repo root): +/// ./foundry/anvil.sh & +/// forge script foundry/script/DeployPlatform.s.sol \ +/// --rpc-url http://127.0.0.1:8545 \ +/// --broadcast \ +/// --sender 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 \ +/// --unlocked +/// +/// Then import into dincli: +/// dincli system import-deployments --foundry +contract DeployPlatform is Script { + using stdJson for string; + + function run() external { + vm.startBroadcast(); + + // 1. DinToken — no init args + address dinTokenProxy = Upgrades.deployTransparentProxy( + "DinToken.sol:DinToken", + msg.sender, + abi.encodeCall(DinToken.initialize, ()) + ); + console.log("DinToken proxy: ", dinTokenProxy); + + // 2. DinCoordinator — receives the DinToken proxy address + address dinCoordinatorProxy = Upgrades.deployTransparentProxy( + "DinCoordinator.sol:DinCoordinator", + msg.sender, + abi.encodeCall(DinCoordinator.initialize, (dinTokenProxy)) + ); + console.log("DinCoordinator proxy: ", dinCoordinatorProxy); + + // 3. Wire DinToken → DinCoordinator (one-shot setter) + DinToken(dinTokenProxy).setCoordinator(dinCoordinatorProxy); + console.log("DinToken coordinator wired"); + + // 4. DinValidatorStake — receives both token and coordinator proxies + address dinValidatorStakeProxy = Upgrades.deployTransparentProxy( + "DinValidatorStake.sol:DinValidatorStake", + msg.sender, + abi.encodeCall(DinValidatorStake.initialize, (dinTokenProxy, dinCoordinatorProxy)) + ); + console.log("DinValidatorStake proxy:", dinValidatorStakeProxy); + + // 5. Wire DinCoordinator → DinValidatorStake + DinCoordinator(payable(dinCoordinatorProxy)).updateValidatorStakeContract(dinValidatorStakeProxy); + console.log("DinCoordinator stake contract wired"); + + // 6. DINModelRegistry — receives the stake proxy + address dinModelRegistryProxy = Upgrades.deployTransparentProxy( + "DINModelRegistry.sol:DINModelRegistry", + msg.sender, + abi.encodeCall(DINModelRegistry.initialize, (dinValidatorStakeProxy)) + ); + console.log("DINModelRegistry proxy: ", dinModelRegistryProxy); + + // 7. ProxyAdmin — shared across all four proxies; read from ERC1967 slot + // of any proxy (they all share the same admin per OZ TransparentProxy) + address proxyAdmin = Upgrades.getAdminAddress(dinTokenProxy); + console.log("ProxyAdmin: ", proxyAdmin); + + vm.stopBroadcast(); + + // 8. Write deployments JSON — same schema as hardhat/deployments/localhost.json + _writeDeployments( + dinTokenProxy, + dinCoordinatorProxy, + dinValidatorStakeProxy, + dinModelRegistryProxy, + proxyAdmin + ); + } + + function _writeDeployments( + address dinToken, + address dinCoordinator, + address dinValidatorStake, + address dinModelRegistry, + address proxyAdmin + ) internal { + string memory json = "deployments"; + vm.serializeAddress(json, "dinToken", dinToken); + vm.serializeAddress(json, "dinCoordinator", dinCoordinator); + vm.serializeAddress(json, "dinValidatorStake", dinValidatorStake); + vm.serializeAddress(json, "dinModelRegistry", dinModelRegistry); + string memory finalJson = vm.serializeAddress(json, "proxyAdmin", proxyAdmin); + + string memory outPath = string.concat( + vm.projectRoot(), "/deployments/localhost.json" + ); + vm.writeJson(finalJson, outPath); + console.log("Deployments written to:", outPath); + } +} diff --git a/foundry/script/UpgradePlatform.s.sol b/foundry/script/UpgradePlatform.s.sol new file mode 100644 index 0000000..d7627ef --- /dev/null +++ b/foundry/script/UpgradePlatform.s.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +import {Script, console} from "forge-std/Script.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {Upgrades} from "@openzeppelin/foundry-upgrades/Upgrades.sol"; + +/// @notice Upgrades a single platform proxy to its V2 implementation. +/// Reads the proxy address from foundry/deployments/localhost.json +/// (written by DeployPlatform.s.sol) and updates the implementation +/// slot via the TransparentUpgradeableProxy admin. +/// +/// Usage (CONTRACT must be one of: DinToken, DinCoordinator, +/// DinValidatorStake, DINModelRegistry): +/// +/// CONTRACT=DinToken forge script foundry/script/UpgradePlatform.s.sol \ +/// --rpc-url http://127.0.0.1:8545 \ +/// --broadcast \ +/// --sender 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 \ +/// --unlocked +contract UpgradePlatform is Script { + using stdJson for string; + + // Maps contract names to their deployments JSON key + string constant KEY_DIN_TOKEN = "dinToken"; + string constant KEY_DIN_COORDINATOR = "dinCoordinator"; + string constant KEY_DIN_VALIDATOR_STAKE = "dinValidatorStake"; + string constant KEY_DIN_MODEL_REGISTRY = "dinModelRegistry"; + + function run() external { + string memory contractName = vm.envString("CONTRACT"); + string memory implName = string.concat(contractName, "V2"); + + string memory deploymentsPath = string.concat( + vm.projectRoot(), "/deployments/localhost.json" + ); + string memory raw = vm.readFile(deploymentsPath); + + string memory proxyKey = _proxyKey(contractName); + address proxyAddress = stdJson.readAddress(raw, string.concat(".", proxyKey)); + + console.log("Contract: ", contractName); + console.log("Proxy: ", proxyAddress); + console.log("New impl: ", implName); + + vm.startBroadcast(); + Upgrades.upgradeProxy( + proxyAddress, + string.concat(implName, ".sol:", implName), + "" + ); + vm.stopBroadcast(); + + address newImpl = Upgrades.getImplementationAddress(proxyAddress); + console.log("Implementation: ", newImpl); + } + + function _proxyKey(string memory contractName) internal pure returns (string memory) { + if (keccak256(bytes(contractName)) == keccak256(bytes("DinToken"))) { + return KEY_DIN_TOKEN; + } else if (keccak256(bytes(contractName)) == keccak256(bytes("DinCoordinator"))) { + return KEY_DIN_COORDINATOR; + } else if (keccak256(bytes(contractName)) == keccak256(bytes("DinValidatorStake"))) { + return KEY_DIN_VALIDATOR_STAKE; + } else if (keccak256(bytes(contractName)) == keccak256(bytes("DINModelRegistry"))) { + return KEY_DIN_MODEL_REGISTRY; + } else { + revert(string.concat( + "Unknown CONTRACT '", contractName, + "'. Expected one of: DinToken, DinCoordinator, DinValidatorStake, DINModelRegistry" + )); + } + } +} diff --git a/foundry/src/upgrade/DINModelRegistryV2.sol b/foundry/src/upgrade/DINModelRegistryV2.sol new file mode 100644 index 0000000..4e0f3ee --- /dev/null +++ b/foundry/src/upgrade/DINModelRegistryV2.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +import "../DINModelRegistry.sol"; + +/// @custom:oz-upgrades-from DINModelRegistry +// missing-initializer is intentional: V2 adds no new state, so it reuses +// V1's initializer. A reinitializer would only be needed if V2 introduced +// new storage variables that require one-time setup. +/// @custom:oz-upgrades-unsafe-allow missing-initializer +contract DINModelRegistryV2 is DINModelRegistry { + function version() external pure returns (uint256) { + return 2; + } +} diff --git a/foundry/src/upgrade/DinCoordinatorV2.sol b/foundry/src/upgrade/DinCoordinatorV2.sol new file mode 100644 index 0000000..c5eb9ca --- /dev/null +++ b/foundry/src/upgrade/DinCoordinatorV2.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.28; + +import "../DinCoordinator.sol"; + +/// @custom:oz-upgrades-from DinCoordinator +// missing-initializer is intentional: V2 adds no new state, so it reuses +// V1's initializer. A reinitializer would only be needed if V2 introduced +// new storage variables that require one-time setup. +/// @custom:oz-upgrades-unsafe-allow missing-initializer +contract DinCoordinatorV2 is DinCoordinator { + function version() external pure returns (uint256) { + return 2; + } +} diff --git a/foundry/src/upgrade/DinTokenV2.sol b/foundry/src/upgrade/DinTokenV2.sol new file mode 100644 index 0000000..44aac86 --- /dev/null +++ b/foundry/src/upgrade/DinTokenV2.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +import "../DinToken.sol"; + +/// @custom:oz-upgrades-from DinToken +// missing-initializer is intentional: V2 adds no new state, so it reuses +// V1's initializer. A reinitializer would only be needed if V2 introduced +// new storage variables that require one-time setup. +/// @custom:oz-upgrades-unsafe-allow missing-initializer +contract DinTokenV2 is DinToken { + function version() external pure returns (uint256) { + return 2; + } +} diff --git a/foundry/src/upgrade/DinValidatorStakeV2.sol b/foundry/src/upgrade/DinValidatorStakeV2.sol new file mode 100644 index 0000000..02bf16f --- /dev/null +++ b/foundry/src/upgrade/DinValidatorStakeV2.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +import "../DinValidatorStake.sol"; + +/// @custom:oz-upgrades-from DinValidatorStake +// missing-initializer is intentional: V2 adds no new state, so it reuses +// V1's initializer. A reinitializer would only be needed if V2 introduced +// new storage variables that require one-time setup. +/// @custom:oz-upgrades-unsafe-allow missing-initializer +contract DinValidatorStakeV2 is DinValidatorStake { + function version() external pure returns (uint256) { + return 2; + } +} diff --git a/foundry/test/DeployPlatform.t.sol b/foundry/test/DeployPlatform.t.sol new file mode 100644 index 0000000..47642ec --- /dev/null +++ b/foundry/test/DeployPlatform.t.sol @@ -0,0 +1,427 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +import {Test, console} from "forge-std/Test.sol"; +import {Upgrades, Options} from "@openzeppelin/foundry-upgrades/Upgrades.sol"; + +import {DinToken} from "../src/DinToken.sol"; +import {DinCoordinator} from "../src/DinCoordinator.sol"; +import {DinValidatorStake} from "../src/DinValidatorStake.sol"; +import {DINModelRegistry} from "../src/DINModelRegistry.sol"; + +import {DinTokenV2} from "../src/upgrade/DinTokenV2.sol"; + +interface IOwnable { + function owner() external view returns (address); +} + +/// @dev Minimal ownable stub used as a stand-in for DINTaskCoordinator / +/// DINTaskAuditor in tests that call requestModelRegistration, which +/// verifies IOwnable(taskCoordinator).owner() == msg.sender. +contract MockTaskContract { + address private _owner; + constructor(address owner_) { _owner = owner_; } + function owner() external view returns (address) { return _owner; } +} +import {DinCoordinatorV2} from "../src/upgrade/DinCoordinatorV2.sol"; +import {DinValidatorStakeV2} from "../src/upgrade/DinValidatorStakeV2.sol"; +import {DINModelRegistryV2} from "../src/upgrade/DINModelRegistryV2.sol"; + +// ─── Shared platform fixture ────────────────────────────────────────────────── + +struct Platform { + address deployer; + address user; + address other; + DinToken dinToken; + DinCoordinator dinCoordinator; + DinValidatorStake dinValidatorStake; + DINModelRegistry dinModelRegistry; +} + +/// @dev Base contract providing deployPlatform() and mintDin() helpers. +/// All test contracts inherit from this so they share the cheatcode VM. +abstract contract PlatformTest is Test { + address internal constant USER = address(0xBEEF); + address internal constant OTHER = address(0xCAFE); + + function _deployPlatform() internal returns (Platform memory p) { + p.deployer = address(this); + p.user = USER; + p.other = OTHER; + + address tokenProxy = Upgrades.deployTransparentProxy( + "DinToken.sol:DinToken", + address(this), + abi.encodeCall(DinToken.initialize, ()) + ); + p.dinToken = DinToken(tokenProxy); + + address coordinatorProxy = Upgrades.deployTransparentProxy( + "DinCoordinator.sol:DinCoordinator", + address(this), + abi.encodeCall(DinCoordinator.initialize, (tokenProxy)) + ); + p.dinCoordinator = DinCoordinator(payable(coordinatorProxy)); + + p.dinToken.setCoordinator(coordinatorProxy); + + address stakeProxy = Upgrades.deployTransparentProxy( + "DinValidatorStake.sol:DinValidatorStake", + address(this), + abi.encodeCall(DinValidatorStake.initialize, (tokenProxy, coordinatorProxy)) + ); + p.dinValidatorStake = DinValidatorStake(stakeProxy); + + p.dinCoordinator.updateValidatorStakeContract(stakeProxy); + + address registryProxy = Upgrades.deployTransparentProxy( + "DINModelRegistry.sol:DINModelRegistry", + address(this), + abi.encodeCall(DINModelRegistry.initialize, (stakeProxy)) + ); + p.dinModelRegistry = DINModelRegistry(registryProxy); + } + + function _mintDin(DinCoordinator coordinator, address user_, uint256 ethAmount) internal { + vm.deal(user_, ethAmount); + vm.prank(user_); + coordinator.depositAndMint{value: ethAmount}(); + } +} + +// ─── §3.2 Proxy wiring ──────────────────────────────────────────────────────── + +contract ProxyWiringTest is PlatformTest { + Platform p; + + function setUp() public { + p = _deployPlatform(); + } + + function test_dinToken_coordinatorWired() public view { + assertEq(p.dinToken.coordinator(), address(p.dinCoordinator)); + } + + function test_dinCoordinator_tokenWired() public view { + assertEq(address(p.dinCoordinator.dinToken()), address(p.dinToken)); + } + + function test_dinCoordinator_stakeContractWired() public view { + assertEq(address(p.dinCoordinator.dinValidatorStakeContract()), address(p.dinValidatorStake)); + } + + function test_dinValidatorStake_tokenWired() public view { + assertEq(address(p.dinValidatorStake.DIN_TOKEN()), address(p.dinToken)); + } + + function test_dinValidatorStake_coordinatorWired() public view { + assertEq(p.dinValidatorStake.DIN_COORDINATOR(), address(p.dinCoordinator)); + } + + function test_allProxyAdminsOwnedByDeployer() public view { + // OZ v5 TransparentUpgradeableProxy deploys one ProxyAdmin per proxy, + // so admin addresses differ. The invariant is that each admin's owner + // is the deployer (address(this) in the test context). + assertEq(IOwnable(Upgrades.getAdminAddress(address(p.dinToken))).owner(), address(this)); + assertEq(IOwnable(Upgrades.getAdminAddress(address(p.dinCoordinator))).owner(), address(this)); + assertEq(IOwnable(Upgrades.getAdminAddress(address(p.dinValidatorStake))).owner(), address(this)); + assertEq(IOwnable(Upgrades.getAdminAddress(address(p.dinModelRegistry))).owner(), address(this)); + } + + function test_depositAndMint_mintsDinViaProxy() public { + uint256 eth = 0.01 ether; + _mintDin(p.dinCoordinator, p.user, eth); + assertGt(p.dinToken.balanceOf(p.user), 0); + } +} + +// ─── §3.4 Re-initializer protection ────────────────────────────────────────── + +contract ReInitializerProtectionTest is PlatformTest { + Platform p; + + function setUp() public { + p = _deployPlatform(); + } + + // Proxy cannot be initialized a second time + function test_proxy_rejectsDoubleInitialize_DinToken() public { + vm.expectRevert(); + p.dinToken.initialize(); + } + + function test_proxy_rejectsDoubleInitialize_DinCoordinator() public { + vm.expectRevert(); + p.dinCoordinator.initialize(address(p.dinToken)); + } + + function test_proxy_rejectsDoubleInitialize_DinValidatorStake() public { + vm.expectRevert(); + p.dinValidatorStake.initialize(address(p.dinToken), address(p.dinCoordinator)); + } + + function test_proxy_rejectsDoubleInitialize_DINModelRegistry() public { + vm.expectRevert(); + p.dinModelRegistry.initialize(address(p.dinValidatorStake)); + } + + // Implementation contract cannot be initialized directly (_disableInitializers) + function test_impl_rejectsDirectInitialize_DinToken() public { + DinToken impl = new DinToken(); + vm.expectRevert(); + impl.initialize(); + } + + function test_impl_rejectsDirectInitialize_DinCoordinator() public { + DinCoordinator impl = new DinCoordinator(); + vm.expectRevert(); + impl.initialize(address(1)); + } + + function test_impl_rejectsDirectInitialize_DinValidatorStake() public { + DinValidatorStake impl = new DinValidatorStake(); + vm.expectRevert(); + impl.initialize(address(1), address(2)); + } + + function test_impl_rejectsDirectInitialize_DINModelRegistry() public { + DINModelRegistry impl = new DINModelRegistry(); + vm.expectRevert(); + impl.initialize(address(1)); + } +} + +// ─── §3.4 DinToken upgrade ──────────────────────────────────────────────────── + +contract DinTokenUpgradeTest is PlatformTest { + Platform p; + + function setUp() public { + p = _deployPlatform(); + } + + function test_preservesBalancesAndWiringAcrossUpgrade() public { + _mintDin(p.dinCoordinator, p.user, 0.01 ether); + uint256 balBefore = p.dinToken.balanceOf(p.user); + + Options memory opts; + opts.referenceContract = "DinToken.sol:DinToken"; + Upgrades.upgradeProxy(address(p.dinToken), "DinTokenV2.sol:DinTokenV2", "", opts); + DinTokenV2 upgraded = DinTokenV2(address(p.dinToken)); + + assertEq(upgraded.coordinator(), address(p.dinCoordinator)); + assertEq(upgraded.balanceOf(p.user), balBefore); + assertEq(upgraded.version(), 2); + + // Minting still works via the coordinator after upgrade + _mintDin(p.dinCoordinator, p.user, 0.001 ether); + assertGt(upgraded.balanceOf(p.user), balBefore); + } + + function test_keepsMintRestrictedToCoordinatorAfterUpgrade() public { + Options memory opts; + opts.referenceContract = "DinToken.sol:DinToken"; + Upgrades.upgradeProxy(address(p.dinToken), "DinTokenV2.sol:DinTokenV2", "", opts); + + vm.expectRevert(DinToken.Unauthorized.selector); + vm.prank(p.user); + p.dinToken.mint(p.user, 1); + } + + function test_keepsCoordinatorSetupRestrictedToOwnerAfterUpgrade() public { + Options memory opts; + opts.referenceContract = "DinToken.sol:DinToken"; + Upgrades.upgradeProxy(address(p.dinToken), "DinTokenV2.sol:DinTokenV2", "", opts); + + vm.expectRevert(); + vm.prank(p.other); + p.dinToken.setCoordinator(address(p.dinCoordinator)); + } +} + +// ─── §3.4 DinCoordinator upgrade ───────────────────────────────────────────── + +contract DinCoordinatorUpgradeTest is PlatformTest { + Platform p; + + function setUp() public { + p = _deployPlatform(); + } + + function test_preservesExchangeRateAndTokenWiringAcrossUpgrade() public { + uint256 newRate = 2_000_000 * 1e18; + p.dinCoordinator.updateDinPerEth(newRate); + _mintDin(p.dinCoordinator, p.user, 0.01 ether); + uint256 balBefore = p.dinToken.balanceOf(p.user); + + Options memory opts; + opts.referenceContract = "DinCoordinator.sol:DinCoordinator"; + Upgrades.upgradeProxy(address(p.dinCoordinator), "DinCoordinatorV2.sol:DinCoordinatorV2", "", opts); + DinCoordinatorV2 upgraded = DinCoordinatorV2(payable(address(p.dinCoordinator))); + + assertEq(address(upgraded.dinToken()), address(p.dinToken)); + assertEq(upgraded.dinPerEth(), newRate); + assertEq(upgraded.version(), 2); + assertEq(p.dinToken.balanceOf(p.user), balBefore); + } + + function test_keepsOwnerOnlyFunctionsRestrictedAfterUpgrade() public { + Options memory opts; + opts.referenceContract = "DinCoordinator.sol:DinCoordinator"; + Upgrades.upgradeProxy(address(p.dinCoordinator), "DinCoordinatorV2.sol:DinCoordinatorV2", "", opts); + + vm.expectRevert(); + vm.prank(p.other); + p.dinCoordinator.updateDinPerEth(1); + } + + function test_keepsSlasherManagementWiredToStakeContractAfterUpgrade() public { + address slasher = address(0xDEAD); + p.dinCoordinator.addSlasherContract(slasher); + assertTrue(p.dinValidatorStake.isSlasherContract(slasher)); + + Options memory opts; + opts.referenceContract = "DinCoordinator.sol:DinCoordinator"; + Upgrades.upgradeProxy(address(p.dinCoordinator), "DinCoordinatorV2.sol:DinCoordinatorV2", "", opts); + + assertTrue(p.dinValidatorStake.isSlasherContract(slasher)); + } +} + +// ─── §3.4 DinValidatorStake upgrade ────────────────────────────────────────── + +contract DinValidatorStakeUpgradeTest is PlatformTest { + uint256 constant MIN_STAKE = 10 * 1e18; + uint256 constant STAKE_DEPOSIT_ETH = 0.01 ether; + + Platform p; + + function setUp() public { + p = _deployPlatform(); + + _mintDin(p.dinCoordinator, p.user, STAKE_DEPOSIT_ETH); + vm.prank(p.user); + p.dinToken.approve(address(p.dinValidatorStake), type(uint256).max); + } + + function test_preservesStakeBalancesAcrossUpgrade() public { + vm.prank(p.user); + p.dinValidatorStake.stake(MIN_STAKE); + uint256 stakeBefore = p.dinValidatorStake.getStake(p.user); + + Options memory opts; + opts.referenceContract = "DinValidatorStake.sol:DinValidatorStake"; + Upgrades.upgradeProxy(address(p.dinValidatorStake), "DinValidatorStakeV2.sol:DinValidatorStakeV2", "", opts); + DinValidatorStakeV2 upgraded = DinValidatorStakeV2(address(p.dinValidatorStake)); + + assertEq(upgraded.getStake(p.user), stakeBefore); + assertTrue(upgraded.isValidatorActive(p.user)); + assertEq(upgraded.version(), 2); + } + + function test_keepsSlasherRegistrationRestrictedToCoordinatorAfterUpgrade() public { + Options memory opts; + opts.referenceContract = "DinValidatorStake.sol:DinValidatorStake"; + Upgrades.upgradeProxy(address(p.dinValidatorStake), "DinValidatorStakeV2.sol:DinValidatorStakeV2", "", opts); + + vm.expectRevert(DinValidatorStake.NotDINCoordinator.selector); + vm.prank(p.other); + p.dinValidatorStake.addSlasherContract(address(0xABCD)); + } + + function test_keepsBlacklistControlWithOwnerAfterUpgrade() public { + vm.prank(p.user); + p.dinValidatorStake.stake(MIN_STAKE); + + Options memory opts; + opts.referenceContract = "DinValidatorStake.sol:DinValidatorStake"; + Upgrades.upgradeProxy(address(p.dinValidatorStake), "DinValidatorStakeV2.sol:DinValidatorStakeV2", "", opts); + + p.dinValidatorStake.blacklistValidator(p.user); + assertFalse(p.dinValidatorStake.isValidatorActive(p.user)); + + vm.expectRevert(); + vm.prank(p.other); + p.dinValidatorStake.unblacklistValidator(p.user); + } +} + +// ─── §3.4 DINModelRegistry upgrade ─────────────────────────────────────────── + +contract DINModelRegistryUpgradeTest is PlatformTest { + Platform p; + + // Minimal slasher stubs — coordinator and auditor must be registered slashers + address taskCoordinator; + address taskAuditor; + + function setUp() public { + p = _deployPlatform(); + + // Deploy mock task contracts owned by p.user — requestModelRegistration + // calls IOwnable(taskCoordinator).owner() and requires it equals msg.sender. + taskCoordinator = address(new MockTaskContract(p.user)); + taskAuditor = address(new MockTaskContract(p.user)); + p.dinCoordinator.addSlasherContract(taskCoordinator); + p.dinCoordinator.addSlasherContract(taskAuditor); + } + + function test_preservesFeeSettingsAndModelStateAcrossUpgrade() public { + uint256 newFee = 42; + p.dinModelRegistry.setProprietaryFee(newFee); + + uint256 fee = p.dinModelRegistry.proprietaryFee(); + bytes32 manifestCID = keccak256("manifest-v1"); + vm.deal(p.user, fee); + vm.prank(p.user); + p.dinModelRegistry.requestModelRegistration{value: fee}( + manifestCID, taskCoordinator, taskAuditor, false + ); + p.dinModelRegistry.approveModel(0); + + Options memory opts; + opts.referenceContract = "DINModelRegistry.sol:DINModelRegistry"; + Upgrades.upgradeProxy(address(p.dinModelRegistry), "DINModelRegistryV2.sol:DINModelRegistryV2", "", opts); + DINModelRegistryV2 upgraded = DINModelRegistryV2(address(p.dinModelRegistry)); + + assertEq(upgraded.proprietaryFee(), newFee); + assertEq(upgraded.totalModels(), 1); + assertEq(upgraded.version(), 2); + + (address owner,,,,, ) = upgraded.getModel(0); + assertEq(owner, p.user); + } + + function test_keepsOwnerOnlyGovernanceRestrictedAfterUpgrade() public { + Options memory opts; + opts.referenceContract = "DINModelRegistry.sol:DINModelRegistry"; + Upgrades.upgradeProxy(address(p.dinModelRegistry), "DINModelRegistryV2.sol:DINModelRegistryV2", "", opts); + + vm.expectRevert(); + vm.prank(p.other); + p.dinModelRegistry.setProprietaryFee(1); + } + + function test_keepsPendingRequestsReadableAfterUpgrade() public { + uint256 fee = p.dinModelRegistry.openSourceFee(); + vm.deal(p.user, fee); + vm.prank(p.user); + p.dinModelRegistry.requestModelRegistration{value: fee}( + keccak256("manifest-pending"), taskCoordinator, taskAuditor, true + ); + + Options memory opts; + opts.referenceContract = "DINModelRegistry.sol:DINModelRegistry"; + Upgrades.upgradeProxy(address(p.dinModelRegistry), "DINModelRegistryV2.sol:DINModelRegistryV2", "", opts); + + assertEq(p.dinModelRegistry.totalModelRequests(), 1); + + (address requester,,,,,, bool processed,,) = p.dinModelRegistry.modelRequests(0); + assertEq(requester, p.user); + assertFalse(processed); + + p.dinModelRegistry.approveModel(0); + assertEq(p.dinModelRegistry.totalModels(), 1); + } +}