@enclave-e3/contracts 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json +1 -1
- package/artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/artifacts.d.ts +1 -1
- package/artifacts/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/ITransparentUpgradeableProxy.json +1 -1
- package/artifacts/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json +1 -1
- package/artifacts/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/artifacts.d.ts +2 -2
- package/artifacts/build-info/{solc-0_8_28-4bcd87d14b711a4c77809b8506304ad531199f84.json → solc-0_8_28-bc4924096d79c352c47e61609b2798186ce67999.json} +7 -7
- package/artifacts/build-info/{solc-0_8_28-4bcd87d14b711a4c77809b8506304ad531199f84.output.json → solc-0_8_28-bc4924096d79c352c47e61609b2798186ce67999.output.json} +1 -1
- package/artifacts/contracts/Enclave.sol/Enclave.json +25 -10
- package/artifacts/contracts/Enclave.sol/artifacts.d.ts +4 -4
- package/artifacts/contracts/interfaces/IBondingRegistry.sol/IBondingRegistry.json +1 -1
- package/artifacts/contracts/interfaces/IBondingRegistry.sol/artifacts.d.ts +1 -1
- package/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json +6 -1
- package/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/artifacts.d.ts +2 -2
- package/artifacts/contracts/interfaces/IComputeProvider.sol/IComputeProvider.json +1 -1
- package/artifacts/contracts/interfaces/IComputeProvider.sol/artifacts.d.ts +1 -1
- package/artifacts/contracts/interfaces/IDecryptionVerifier.sol/IDecryptionVerifier.json +1 -1
- package/artifacts/contracts/interfaces/IDecryptionVerifier.sol/artifacts.d.ts +1 -1
- package/artifacts/contracts/interfaces/IE3Program.sol/IE3Program.json +1 -1
- package/artifacts/contracts/interfaces/IE3Program.sol/artifacts.d.ts +1 -1
- package/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json +18 -8
- package/artifacts/contracts/interfaces/IEnclave.sol/artifacts.d.ts +2 -2
- package/artifacts/contracts/interfaces/ISlashVerifier.sol/ISlashVerifier.json +1 -1
- package/artifacts/contracts/interfaces/ISlashVerifier.sol/artifacts.d.ts +1 -1
- package/artifacts/contracts/interfaces/ISlashingManager.sol/ISlashingManager.json +1 -1
- package/artifacts/contracts/interfaces/ISlashingManager.sol/artifacts.d.ts +1 -1
- package/artifacts/contracts/lib/ExitQueueLib.sol/ExitQueueLib.json +1 -1
- package/artifacts/contracts/lib/ExitQueueLib.sol/artifacts.d.ts +1 -1
- package/artifacts/contracts/registry/BondingRegistry.sol/BondingRegistry.json +1 -1
- package/artifacts/contracts/registry/BondingRegistry.sol/artifacts.d.ts +1 -1
- package/artifacts/contracts/registry/CiphernodeRegistryOwnable.sol/CiphernodeRegistryOwnable.json +18 -13
- package/artifacts/contracts/registry/CiphernodeRegistryOwnable.sol/artifacts.d.ts +6 -6
- package/artifacts/contracts/slashing/SlashingManager.sol/SlashingManager.json +1 -1
- package/artifacts/contracts/slashing/SlashingManager.sol/artifacts.d.ts +1 -1
- package/artifacts/contracts/test/MockCiphernodeRegistry.sol/MockCiphernodeRegistry.json +8 -3
- package/artifacts/contracts/test/MockCiphernodeRegistry.sol/MockCiphernodeRegistryEmptyKey.json +13 -3
- package/artifacts/contracts/test/MockCiphernodeRegistry.sol/artifacts.d.ts +8 -8
- package/artifacts/contracts/test/MockComputeProvider.sol/MockComputeProvider.json +1 -1
- package/artifacts/contracts/test/MockComputeProvider.sol/artifacts.d.ts +1 -1
- package/artifacts/contracts/test/MockDecryptionVerifier.sol/MockDecryptionVerifier.json +1 -1
- package/artifacts/contracts/test/MockDecryptionVerifier.sol/artifacts.d.ts +1 -1
- package/artifacts/contracts/test/MockE3Program.sol/MockE3Program.json +1 -1
- package/artifacts/contracts/test/MockE3Program.sol/artifacts.d.ts +1 -1
- package/artifacts/contracts/test/MockSlashingVerifier.sol/MockSlashingVerifier.json +1 -1
- package/artifacts/contracts/test/MockSlashingVerifier.sol/artifacts.d.ts +1 -1
- package/artifacts/contracts/test/MockStableToken.sol/MockUSDC.json +1 -1
- package/artifacts/contracts/test/MockStableToken.sol/artifacts.d.ts +1 -1
- package/artifacts/contracts/token/EnclaveTicketToken.sol/EnclaveTicketToken.json +1 -1
- package/artifacts/contracts/token/EnclaveTicketToken.sol/artifacts.d.ts +1 -1
- package/artifacts/contracts/token/EnclaveToken.sol/EnclaveToken.json +1 -1
- package/artifacts/contracts/token/EnclaveToken.sol/artifacts.d.ts +1 -1
- package/artifacts/poseidon-solidity/PoseidonT3.sol/PoseidonT3.json +1 -1
- package/artifacts/poseidon-solidity/PoseidonT3.sol/artifacts.d.ts +1 -1
- package/contracts/Enclave.sol +5 -10
- package/contracts/interfaces/ICiphernodeRegistry.sol +3 -1
- package/contracts/interfaces/IE3.sol +3 -1
- package/contracts/interfaces/IEnclave.sol +3 -7
- package/contracts/registry/CiphernodeRegistryOwnable.sol +4 -3
- package/contracts/test/MockCiphernodeRegistry.sol +7 -3
- package/dist/hardhat.config.d.ts.map +1 -1
- package/dist/hardhat.config.js +2 -1
- package/dist/scripts/deployEnclave.d.ts.map +1 -1
- package/dist/scripts/deployEnclave.js +10 -4
- package/dist/scripts/verify.d.ts.map +1 -1
- package/dist/scripts/verify.js +8 -9
- package/dist/tasks/ciphernode.d.ts +1 -0
- package/dist/tasks/ciphernode.d.ts.map +1 -1
- package/dist/tasks/ciphernode.js +24 -0
- package/dist/tasks/enclave.d.ts.map +1 -1
- package/dist/tasks/enclave.js +13 -21
- package/dist/test/Enclave.spec.js +38 -37
- package/dist/test/Registry/CiphernodeRegistryOwnable.spec.js +5 -5
- package/dist/types/contracts/Enclave.d.ts +11 -9
- package/dist/types/contracts/Enclave.d.ts.map +1 -1
- package/dist/types/contracts/interfaces/ICiphernodeRegistry.d.ts +5 -3
- package/dist/types/contracts/interfaces/ICiphernodeRegistry.d.ts.map +1 -1
- package/dist/types/contracts/interfaces/IEnclave.d.ts +7 -7
- package/dist/types/contracts/interfaces/IEnclave.d.ts.map +1 -1
- package/dist/types/contracts/registry/CiphernodeRegistryOwnable.d.ts +5 -3
- package/dist/types/contracts/registry/CiphernodeRegistryOwnable.d.ts.map +1 -1
- package/dist/types/contracts/test/MockCiphernodeRegistry.sol/MockCiphernodeRegistry.d.ts +5 -3
- package/dist/types/contracts/test/MockCiphernodeRegistry.sol/MockCiphernodeRegistry.d.ts.map +1 -1
- package/dist/types/contracts/test/MockCiphernodeRegistry.sol/MockCiphernodeRegistryEmptyKey.d.ts +5 -3
- package/dist/types/contracts/test/MockCiphernodeRegistry.sol/MockCiphernodeRegistryEmptyKey.d.ts.map +1 -1
- package/dist/types/factories/contracts/Enclave__factory.d.ts +19 -7
- package/dist/types/factories/contracts/Enclave__factory.d.ts.map +1 -1
- package/dist/types/factories/contracts/Enclave__factory.js +23 -8
- package/dist/types/factories/contracts/interfaces/ICiphernodeRegistry__factory.d.ts +4 -0
- package/dist/types/factories/contracts/interfaces/ICiphernodeRegistry__factory.d.ts.map +1 -1
- package/dist/types/factories/contracts/interfaces/ICiphernodeRegistry__factory.js +5 -0
- package/dist/types/factories/contracts/interfaces/IEnclave__factory.d.ts +14 -6
- package/dist/types/factories/contracts/interfaces/IEnclave__factory.d.ts.map +1 -1
- package/dist/types/factories/contracts/interfaces/IEnclave__factory.js +17 -7
- package/dist/types/factories/contracts/registry/CiphernodeRegistryOwnable__factory.d.ts +5 -1
- package/dist/types/factories/contracts/registry/CiphernodeRegistryOwnable__factory.d.ts.map +1 -1
- package/dist/types/factories/contracts/registry/CiphernodeRegistryOwnable__factory.js +6 -1
- package/dist/types/factories/contracts/test/MockCiphernodeRegistry.sol/MockCiphernodeRegistryEmptyKey__factory.d.ts +9 -1
- package/dist/types/factories/contracts/test/MockCiphernodeRegistry.sol/MockCiphernodeRegistryEmptyKey__factory.d.ts.map +1 -1
- package/dist/types/factories/contracts/test/MockCiphernodeRegistry.sol/MockCiphernodeRegistryEmptyKey__factory.js +11 -1
- package/dist/types/factories/contracts/test/MockCiphernodeRegistry.sol/MockCiphernodeRegistry__factory.d.ts +5 -1
- package/dist/types/factories/contracts/test/MockCiphernodeRegistry.sol/MockCiphernodeRegistry__factory.d.ts.map +1 -1
- package/dist/types/factories/contracts/test/MockCiphernodeRegistry.sol/MockCiphernodeRegistry__factory.js +6 -1
- package/package.json +5 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_format": "hh3-sol-build-info-1",
|
|
3
|
-
"id": "solc-0_8_28-
|
|
3
|
+
"id": "solc-0_8_28-bc4924096d79c352c47e61609b2798186ce67999",
|
|
4
4
|
"solcVersion": "0.8.28",
|
|
5
5
|
"solcLongVersion": "0.8.28+commit.7893614a",
|
|
6
6
|
"userSourceNameMap": {
|
|
@@ -241,13 +241,13 @@
|
|
|
241
241
|
"content": "/// SPDX-License-Identifier: MIT\npragma solidity >=0.7.0;\n\nlibrary PoseidonT3 {\n uint constant M00 = 0x109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b;\n uint constant M01 = 0x2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771;\n uint constant M02 = 0x143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7;\n uint constant M10 = 0x16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e0;\n uint constant M11 = 0x2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe23;\n uint constant M12 = 0x176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee2911;\n\n // See here for a simplified implementation: https://github.com/vimwitch/poseidon-solidity/blob/e57becdabb65d99fdc586fe1e1e09e7108202d53/contracts/Poseidon.sol#L40\n // Inspired by: https://github.com/iden3/circomlibjs/blob/v0.0.8/src/poseidon_slow.js\n function hash(uint[2] memory) public pure returns (uint) {\n assembly {\n let F := 21888242871839275222246405745257275088548364400416034343698204186575808495617\n let M20 := 0x2b90bba00fca0589f617e7dcbfe82e0df706ab640ceb247b791a93b74e36736d\n let M21 := 0x101071f0032379b697315876690f053d148d4e109f5fb065c8aacc55a0f89bfa\n let M22 := 0x19a3fc0a56702bf417ba7fee3802593fa644470307043f7773279cd71d25d5e0\n\n // load the inputs from memory\n let state1 := add(mod(mload(0x80), F), 0x00f1445235f2148c5986587169fc1bcd887b08d4d00868df5696fff40956e864)\n let state2 := add(mod(mload(0xa0), F), 0x08dff3487e8ac99e1f29a058d0fa80b930c728730b7ab36ce879f3890ecf73f5)\n let scratch0 := mulmod(state1, state1, F)\n state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F)\n scratch0 := mulmod(state2, state2, F)\n state2 := mulmod(mulmod(scratch0, scratch0, F), state2, F)\n scratch0 := add(\n 0x2f27be690fdaee46c3ce28f7532b13c856c35342c84bda6e20966310fadc01d0,\n add(add(15452833169820924772166449970675545095234312153403844297388521437673434406763, mulmod(state1, M10, F)), mulmod(state2, M20, F))\n )\n let scratch1 := add(\n 0x2b2ae1acf68b7b8d2416bebf3d4f6234b763fe04b8043ee48b8327bebca16cf2,\n add(add(18674271267752038776579386132900109523609358935013267566297499497165104279117, mulmod(state1, M11, F)), mulmod(state2, M21, F))\n )\n let scratch2 := add(\n 0x0319d062072bef7ecca5eac06f97d4d55952c175ab6b03eae64b44c7dbf11cfa,\n add(add(14817777843080276494683266178512808687156649753153012854386334860566696099579, mulmod(state1, M12, F)), mulmod(state2, M22, F))\n )\n let state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := mulmod(scratch1, scratch1, F)\n scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F)\n state0 := mulmod(scratch2, scratch2, F)\n scratch2 := mulmod(mulmod(state0, state0, F), scratch2, F)\n state0 := add(0x28813dcaebaeaa828a376df87af4a63bc8b7bf27ad49c6298ef7b387bf28526d, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x2727673b2ccbc903f181bf38e1c1d40d2033865200c352bc150928adddf9cb78, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x234ec45ca27727c2e74abd2b2a1494cd6efbd43e340587d6b8fb9e31e65cc632, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := mulmod(state1, state1, F)\n state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F)\n scratch0 := mulmod(state2, state2, F)\n state2 := mulmod(mulmod(scratch0, scratch0, F), state2, F)\n scratch0 := add(0x15b52534031ae18f7f862cb2cf7cf760ab10a8150a337b1ccd99ff6e8797d428, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x0dc8fad6d9e4b35f5ed9a3d186b79ce38e0e8a8d1b58b132d701d4eecf68d1f6, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x1bcd95ffc211fbca600f705fad3fb567ea4eb378f62e1fec97805518a47e4d9c, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := mulmod(scratch1, scratch1, F)\n scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F)\n state0 := mulmod(scratch2, scratch2, F)\n scratch2 := mulmod(mulmod(state0, state0, F), scratch2, F)\n state0 := add(0x10520b0ab721cadfe9eff81b016fc34dc76da36c2578937817cb978d069de559, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x1f6d48149b8e7f7d9b257d8ed5fbbaf42932498075fed0ace88a9eb81f5627f6, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x1d9655f652309014d29e00ef35a2089bfff8dc1c816f0dc9ca34bdb5460c8705, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x04df5a56ff95bcafb051f7b1cd43a99ba731ff67e47032058fe3d4185697cc7d, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x0672d995f8fff640151b3d290cedaf148690a10a8c8424a7f6ec282b6e4be828, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x099952b414884454b21200d7ffafdd5f0c9a9dcc06f2708e9fc1d8209b5c75b9, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x052cba2255dfd00c7c483143ba8d469448e43586a9b4cd9183fd0e843a6b9fa6, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x0b8badee690adb8eb0bd74712b7999af82de55707251ad7716077cb93c464ddc, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x119b1590f13307af5a1ee651020c07c749c15d60683a8050b963d0a8e4b2bdd1, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x03150b7cd6d5d17b2529d36be0f67b832c4acfc884ef4ee5ce15be0bfb4a8d09, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x2cc6182c5e14546e3cf1951f173912355374efb83d80898abe69cb317c9ea565, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x005032551e6378c450cfe129a404b3764218cadedac14e2b92d2cd73111bf0f9, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x233237e3289baa34bb147e972ebcb9516469c399fcc069fb88f9da2cc28276b5, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x05c8f4f4ebd4a6e3c980d31674bfbe6323037f21b34ae5a4e80c2d4c24d60280, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x0a7b1db13042d396ba05d818a319f25252bcf35ef3aeed91ee1f09b2590fc65b, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x2a73b71f9b210cf5b14296572c9d32dbf156e2b086ff47dc5df542365a404ec0, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x1ac9b0417abcc9a1935107e9ffc91dc3ec18f2c4dbe7f22976a760bb5c50c460, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x12c0339ae08374823fabb076707ef479269f3e4d6cb104349015ee046dc93fc0, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x0b7475b102a165ad7f5b18db4e1e704f52900aa3253baac68246682e56e9a28e, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x037c2849e191ca3edb1c5e49f6e8b8917c843e379366f2ea32ab3aa88d7f8448, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x05a6811f8556f014e92674661e217e9bd5206c5c93a07dc145fdb176a716346f, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x29a795e7d98028946e947b75d54e9f044076e87a7b2883b47b675ef5f38bd66e, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x20439a0c84b322eb45a3857afc18f5826e8c7382c8a1585c507be199981fd22f, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x2e0ba8d94d9ecf4a94ec2050c7371ff1bb50f27799a84b6d4a2a6f2a0982c887, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x143fd115ce08fb27ca38eb7cce822b4517822cd2109048d2e6d0ddcca17d71c8, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x0c64cbecb1c734b857968dbbdcf813cdf8611659323dbcbfc84323623be9caf1, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x028a305847c683f646fca925c163ff5ae74f348d62c2b670f1426cef9403da53, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x2e4ef510ff0b6fda5fa940ab4c4380f26a6bcb64d89427b824d6755b5db9e30c, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x0081c95bc43384e663d79270c956ce3b8925b4f6d033b078b96384f50579400e, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x2ed5f0c91cbd9749187e2fade687e05ee2491b349c039a0bba8a9f4023a0bb38, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x30509991f88da3504bbf374ed5aae2f03448a22c76234c8c990f01f33a735206, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x1c3f20fd55409a53221b7c4d49a356b9f0a1119fb2067b41a7529094424ec6ad, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x10b4e7f3ab5df003049514459b6e18eec46bb2213e8e131e170887b47ddcb96c, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x2a1982979c3ff7f43ddd543d891c2abddd80f804c077d775039aa3502e43adef, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x1c74ee64f15e1db6feddbead56d6d55dba431ebc396c9af95cad0f1315bd5c91, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x07533ec850ba7f98eab9303cace01b4b9e4f2e8b82708cfa9c2fe45a0ae146a0, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x21576b438e500449a151e4eeaf17b154285c68f42d42c1808a11abf3764c0750, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x2f17c0559b8fe79608ad5ca193d62f10bce8384c815f0906743d6930836d4a9e, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x2d477e3862d07708a79e8aae946170bc9775a4201318474ae665b0b1b7e2730e, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x162f5243967064c390e095577984f291afba2266c38f5abcd89be0f5b2747eab, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x2b4cb233ede9ba48264ecd2c8ae50d1ad7a8596a87f29f8a7777a70092393311, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x2c8fbcb2dd8573dc1dbaf8f4622854776db2eece6d85c4cf4254e7c35e03b07a, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x1d6f347725e4816af2ff453f0cd56b199e1b61e9f601e9ade5e88db870949da9, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x204b0c397f4ebe71ebc2d8b3df5b913df9e6ac02b68d31324cd49af5c4565529, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x0c4cb9dc3c4fd8174f1149b3c63c3c2f9ecb827cd7dc25534ff8fb75bc79c502, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x174ad61a1448c899a25416474f4930301e5c49475279e0639a616ddc45bc7b54, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x1a96177bcf4d8d89f759df4ec2f3cde2eaaa28c177cc0fa13a9816d49a38d2ef, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x066d04b24331d71cd0ef8054bc60c4ff05202c126a233c1a8242ace360b8a30a, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x2a4c4fc6ec0b0cf52195782871c6dd3b381cc65f72e02ad527037a62aa1bd804, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x13ab2d136ccf37d447e9f2e14a7cedc95e727f8446f6d9d7e55afc01219fd649, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x1121552fca26061619d24d843dc82769c1b04fcec26f55194c2e3e869acc6a9a, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x00ef653322b13d6c889bc81715c37d77a6cd267d595c4a8909a5546c7c97cff1, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x0e25483e45a665208b261d8ba74051e6400c776d652595d9845aca35d8a397d3, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x29f536dcb9dd7682245264659e15d88e395ac3d4dde92d8c46448db979eeba89, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x2a56ef9f2c53febadfda33575dbdbd885a124e2780bbea170e456baace0fa5be, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x1c8361c78eb5cf5decfb7a2d17b5c409f2ae2999a46762e8ee416240a8cb9af1, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x151aff5f38b20a0fc0473089aaf0206b83e8e68a764507bfd3d0ab4be74319c5, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x04c6187e41ed881dc1b239c88f7f9d43a9f52fc8c8b6cdd1e76e47615b51f100, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x13b37bd80f4d27fb10d84331f6fb6d534b81c61ed15776449e801b7ddc9c2967, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x01a5c536273c2d9df578bfbd32c17b7a2ce3664c2a52032c9321ceb1c4e8a8e4, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x2ab3561834ca73835ad05f5d7acb950b4a9a2c666b9726da832239065b7c3b02, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x1d4d8ec291e720db200fe6d686c0d613acaf6af4e95d3bf69f7ed516a597b646, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x041294d2cc484d228f5784fe7919fd2bb925351240a04b711514c9c80b65af1d, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x154ac98e01708c611c4fa715991f004898f57939d126e392042971dd90e81fc6, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x0b339d8acca7d4f83eedd84093aef51050b3684c88f8b0b04524563bc6ea4da4, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x0955e49e6610c94254a4f84cfbab344598f0e71eaff4a7dd81ed95b50839c82e, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x06746a6156eba54426b9e22206f15abca9a6f41e6f535c6f3525401ea0654626, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x0f18f5a0ecd1423c496f3820c549c27838e5790e2bd0a196ac917c7ff32077fb, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x04f6eeca1751f7308ac59eff5beb261e4bb563583ede7bc92a738223d6f76e13, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x2b56973364c4c4f5c1a3ec4da3cdce038811eb116fb3e45bc1768d26fc0b3758, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x123769dd49d5b054dcd76b89804b1bcb8e1392b385716a5d83feb65d437f29ef, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x2147b424fc48c80a88ee52b91169aacea989f6446471150994257b2fb01c63e9, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x0fdc1f58548b85701a6c5505ea332a29647e6f34ad4243c2ea54ad897cebe54d, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x12373a8251fea004df68abcf0f7786d4bceff28c5dbbe0c3944f685cc0a0b1f2, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x21e4f4ea5f35f85bad7ea52ff742c9e8a642756b6af44203dd8a1f35c1a90035, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x16243916d69d2ca3dfb4722224d4c462b57366492f45e90d8a81934f1bc3b147, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x1efbe46dd7a578b4f66f9adbc88b4378abc21566e1a0453ca13a4159cac04ac2, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x07ea5e8537cf5dd08886020e23a7f387d468d5525be66f853b672cc96a88969a, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x05a8c4f9968b8aa3b7b478a30f9a5b63650f19a75e7ce11ca9fe16c0b76c00bc, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x20f057712cc21654fbfe59bd345e8dac3f7818c701b9c7882d9d57b72a32e83f, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x04a12ededa9dfd689672f8c67fee31636dcd8e88d01d49019bd90b33eb33db69, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x27e88d8c15f37dcee44f1e5425a51decbd136ce5091a6767e49ec9544ccd101a, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x2feed17b84285ed9b8a5c8c5e95a41f66e096619a7703223176c41ee433de4d1, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x1ed7cc76edf45c7c404241420f729cf394e5942911312a0d6972b8bd53aff2b8, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x15742e99b9bfa323157ff8c586f5660eac6783476144cdcadf2874be45466b1a, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x1aac285387f65e82c895fc6887ddf40577107454c6ec0317284f033f27d0c785, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x25851c3c845d4790f9ddadbdb6057357832e2e7a49775f71ec75a96554d67c77, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x15a5821565cc2ec2ce78457db197edf353b7ebba2c5523370ddccc3d9f146a67, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x2411d57a4813b9980efa7e31a1db5966dcf64f36044277502f15485f28c71727, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x002e6f8d6520cd4713e335b8c0b6d2e647e9a98e12f4cd2558828b5ef6cb4c9b, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x2ff7bc8f4380cde997da00b616b0fcd1af8f0e91e2fe1ed7398834609e0315d2, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x00b9831b948525595ee02724471bcd182e9521f6b7bb68f1e93be4febb0d3cbe, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x0a2f53768b8ebf6a86913b0e57c04e011ca408648a4743a87d77adbf0c9c3512, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x00248156142fd0373a479f91ff239e960f599ff7e94be69b7f2a290305e1198d, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x171d5620b87bfb1328cf8c02ab3f0c9a397196aa6a542c2350eb512a2b2bcda9, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x170a4f55536f7dc970087c7c10d6fad760c952172dd54dd99d1045e4ec34a808, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x29aba33f799fe66c2ef3134aea04336ecc37e38c1cd211ba482eca17e2dbfae1, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x1e9bc179a4fdd758fdd1bb1945088d47e70d114a03f6a0e8b5ba650369e64973, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x1dd269799b660fad58f7f4892dfb0b5afeaad869a9c4b44f9c9e1c43bdaf8f09, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x22cdbc8b70117ad1401181d02e15459e7ccd426fe869c7c95d1dd2cb0f24af38, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x0ef042e454771c533a9f57a55c503fcefd3150f52ed94a7cd5ba93b9c7dacefd, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x11609e06ad6c8fe2f287f3036037e8851318e8b08a0359a03b304ffca62e8284, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x1166d9e554616dba9e753eea427c17b7fecd58c076dfe42708b08f5b783aa9af, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x2de52989431a859593413026354413db177fbf4cd2ac0b56f855a888357ee466, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x3006eb4ffc7a85819a6da492f3a8ac1df51aee5b17b8e89d74bf01cf5f71e9ad, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x2af41fbb61ba8a80fdcf6fff9e3f6f422993fe8f0a4639f962344c8225145086, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x119e684de476155fe5a6b41a8ebc85db8718ab27889e85e781b214bace4827c3, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x1835b786e2e8925e188bea59ae363537b51248c23828f047cff784b97b3fd800, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x28201a34c594dfa34d794996c6433a20d152bac2a7905c926c40e285ab32eeb6, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x083efd7a27d1751094e80fefaf78b000864c82eb571187724a761f88c22cc4e7, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x0b6f88a3577199526158e61ceea27be811c16df7774dd8519e079564f61fd13b, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x0ec868e6d15e51d9644f66e1d6471a94589511ca00d29e1014390e6ee4254f5b, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x2af33e3f866771271ac0c9b3ed2e1142ecd3e74b939cd40d00d937ab84c98591, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x0b520211f904b5e7d09b5d961c6ace7734568c547dd6858b364ce5e47951f178, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x0b2d722d0919a1aad8db58f10062a92ea0c56ac4270e822cca228620188a1d40, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x1f790d4d7f8cf094d980ceb37c2453e957b54a9991ca38bbe0061d1ed6e562d4, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x0171eb95dfbf7d1eaea97cd385f780150885c16235a2a6a8da92ceb01e504233, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x0c2d0e3b5fd57549329bf6885da66b9b790b40defd2c8650762305381b168873, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x1162fb28689c27154e5a8228b4e72b377cbcafa589e283c35d3803054407a18d, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x2f1459b65dee441b64ad386a91e8310f282c5a92a89e19921623ef8249711bc0, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x1e6ff3216b688c3d996d74367d5cd4c1bc489d46754eb712c243f70d1b53cfbb, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x01ca8be73832b8d0681487d27d157802d741a6f36cdc2a0576881f9326478875, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x1f7735706ffe9fc586f976d5bdf223dc680286080b10cea00b9b5de315f9650e, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x2522b60f4ea3307640a0c2dce041fba921ac10a3d5f096ef4745ca838285f019, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x23f0bee001b1029d5255075ddc957f833418cad4f52b6c3f8ce16c235572575b, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x2bc1ae8b8ddbb81fcaac2d44555ed5685d142633e9df905f66d9401093082d59, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x0f9406b8296564a37304507b8dba3ed162371273a07b1fc98011fcd6ad72205f, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x2360a8eb0cc7defa67b72998de90714e17e75b174a52ee4acb126c8cd995f0a8, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x15871a5cddead976804c803cbaef255eb4815a5e96df8b006dcbbc2767f88948, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x193a56766998ee9e0a8652dd2f3b1da0362f4f54f72379544f957ccdeefb420f, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x2a394a43934f86982f9be56ff4fab1703b2e63c8ad334834e4309805e777ae0f, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x1859954cfeb8695f3e8b635dcb345192892cd11223443ba7b4166e8876c0d142, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x04e1181763050e58013444dbcb99f1902b11bc25d90bbdca408d3819f4fed32b, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x0fdb253dee83869d40c335ea64de8c5bb10eb82db08b5e8b1f5e5552bfd05f23, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x058cbe8a9a5027bdaa4efb623adead6275f08686f1c08984a9d7c5bae9b4f1c0, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x1382edce9971e186497eadb1aeb1f52b23b4b83bef023ab0d15228b4cceca59a, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x03464990f045c6ee0819ca51fd11b0be7f61b8eb99f14b77e1e6634601d9e8b5, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x23f7bfc8720dc296fff33b41f98ff83c6fcab4605db2eb5aaa5bc137aeb70a58, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x0a59a158e3eec2117e6e94e7f0e9decf18c3ffd5e1531a9219636158bbaf62f2, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x06ec54c80381c052b58bf23b312ffd3ce2c4eba065420af8f4c23ed0075fd07b, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x118872dc832e0eb5476b56648e867ec8b09340f7a7bcb1b4962f0ff9ed1f9d01, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x13d69fa127d834165ad5c7cba7ad59ed52e0b0f0e42d7fea95e1906b520921b1, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x169a177f63ea681270b1c6877a73d21bde143942fb71dc55fd8a49f19f10c77b, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x04ef51591c6ead97ef42f287adce40d93abeb032b922f66ffb7e9a5a7450544d, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x256e175a1dc079390ecd7ca703fb2e3b19ec61805d4f03ced5f45ee6dd0f69ec, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x30102d28636abd5fe5f2af412ff6004f75cc360d3205dd2da002813d3e2ceeb2, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x10998e42dfcd3bbf1c0714bc73eb1bf40443a3fa99bef4a31fd31be182fcc792, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x193edd8e9fcf3d7625fa7d24b598a1d89f3362eaf4d582efecad76f879e36860, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x18168afd34f2d915d0368ce80b7b3347d1c7a561ce611425f2664d7aa51f0b5d, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x29383c01ebd3b6ab0c017656ebe658b6a328ec77bc33626e29e2e95b33ea6111, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x10646d2f2603de39a1f4ae5e7771a64a702db6e86fb76ab600bf573f9010c711, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x0beb5e07d1b27145f575f1395a55bf132f90c25b40da7b3864d0242dcb1117fb, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x16d685252078c133dc0d3ecad62b5c8830f95bb2e54b59abdffbf018d96fa336, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x0a6abd1d833938f33c74154e0404b4b40a555bbbec21ddfafd672dd62047f01a, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x1a679f5d36eb7b5c8ea12a4c2dedc8feb12dffeec450317270a6f19b34cf1860, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x0980fb233bd456c23974d50e0ebfde4726a423eada4e8f6ffbc7592e3f1b93d6, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x161b42232e61b84cbf1810af93a38fc0cece3d5628c9282003ebacb5c312c72b, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x0ada10a90c7f0520950f7d47a60d5e6a493f09787f1564e5d09203db47de1a0b, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x1a730d372310ba82320345a29ac4238ed3f07a8a2b4e121bb50ddb9af407f451, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x2c8120f268ef054f817064c369dda7ea908377feaba5c4dffbda10ef58e8c556, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x1c7c8824f758753fa57c00789c684217b930e95313bcb73e6e7b8649a4968f70, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x2cd9ed31f5f8691c8e39e4077a74faa0f400ad8b491eb3f7b47b27fa3fd1cf77, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x23ff4f9d46813457cf60d92f57618399a5e022ac321ca550854ae23918a22eea, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x09945a5d147a4f66ceece6405dddd9d0af5a2c5103529407dff1ea58f180426d, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x188d9c528025d4c2b67660c6b771b90f7c7da6eaa29d3f268a6dd223ec6fc630, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x3050e37996596b7f81f68311431d8734dba7d926d3633595e0c0d8ddf4f0f47f, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x15af1169396830a91600ca8102c35c426ceae5461e3f95d89d829518d30afd78, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x1da6d09885432ea9a06d9f37f873d985dae933e351466b2904284da3320d8acc, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := add(0x2796ea90d269af29f5f8acf33921124e4e4fad3dbe658945e546ee411ddaa9cb, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x202d7dd1da0f6b4b0325c8b3307742f01e15612ec8e9304a7cb0319e01d32d60, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x096d6790d05bb759156a952ba263d672a2d7f9c788f4c831a29dace4c0f8be5f, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := add(0x054efa1f65b0fce283808965275d877b438da23ce5b13e1963798cb1447d25a4, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x1b162f83d917e93edb3308c29802deb9d8aa690113b2e14864ccf6e18e4165f1, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x21e5241e12564dd6fd9f1cdd2a0de39eedfefc1466cc568ec5ceb745a0506edc, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := mulmod(scratch1, scratch1, F)\n scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F)\n state0 := mulmod(scratch2, scratch2, F)\n scratch2 := mulmod(mulmod(state0, state0, F), scratch2, F)\n state0 := add(0x1cfb5662e8cf5ac9226a80ee17b36abecb73ab5f87e161927b4349e10e4bdf08, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x0f21177e302a771bbae6d8d1ecb373b62c99af346220ac0129c53f666eb24100, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x1671522374606992affb0dd7f71b12bec4236aede6290546bcef7e1f515c2320, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := mulmod(state1, state1, F)\n state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F)\n scratch0 := mulmod(state2, state2, F)\n state2 := mulmod(mulmod(scratch0, scratch0, F), state2, F)\n scratch0 := add(0x0fa3ec5b9488259c2eb4cf24501bfad9be2ec9e42c5cc8ccd419d2a692cad870, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))\n scratch1 := add(0x193c0e04e0bd298357cb266c1506080ed36edce85c648cc085e8c57b1ab54bba, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))\n scratch2 := add(0x102adf8ef74735a27e9128306dcbc3c99f6f7291cd406578ce14ea2adaba68f8, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))\n state0 := mulmod(scratch0, scratch0, F)\n scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)\n state0 := mulmod(scratch1, scratch1, F)\n scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F)\n state0 := mulmod(scratch2, scratch2, F)\n scratch2 := mulmod(mulmod(state0, state0, F), scratch2, F)\n state0 := add(0x0fe0af7858e49859e2a54d6f1ad945b1316aa24bfbdd23ae40a6d0cb70c3eab1, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))\n state1 := add(0x216f6717bbc7dedb08536a2220843f4e2da5f1daa9ebdefde8a5ea7344798d22, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))\n state2 := add(0x1da55cc900f0d21f4a3e694391918a1b3c23b2ac773c6b3ef88e2e4228325161, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))\n scratch0 := mulmod(state0, state0, F)\n state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)\n scratch0 := mulmod(state1, state1, F)\n state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F)\n scratch0 := mulmod(state2, state2, F)\n state2 := mulmod(mulmod(scratch0, scratch0, F), state2, F)\n\n mstore(0x0, mod(add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)), F))\n\n return(0, 0x20)\n }\n }\n}\n"
|
|
242
242
|
},
|
|
243
243
|
"project/contracts/Enclave.sol": {
|
|
244
|
-
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\npragma solidity >=0.8.27;\n\nimport { IEnclave, E3, IE3Program } from \"./interfaces/IEnclave.sol\";\nimport { ICiphernodeRegistry } from \"./interfaces/ICiphernodeRegistry.sol\";\nimport { IBondingRegistry } from \"./interfaces/IBondingRegistry.sol\";\nimport { IDecryptionVerifier } from \"./interfaces/IDecryptionVerifier.sol\";\nimport {\n OwnableUpgradeable\n} from \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport {\n SafeERC20\n} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Enclave\n * @notice Main contract for managing Encrypted Execution Environments (E3)\n * @dev Coordinates E3 lifecycle including request, activation, input publishing, and output verification\n */\ncontract Enclave is IEnclave, OwnableUpgradeable {\n using SafeERC20 for IERC20;\n\n ////////////////////////////////////////////////////////////\n // //\n // Storage Variables //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Address of the Ciphernode Registry contract.\n /// @dev Manages the pool of ciphernodes and committee selection.\n ICiphernodeRegistry public ciphernodeRegistry;\n\n /// @notice Address of the Bonding Registry contract.\n /// @dev Handles staking and reward distribution for ciphernodes.\n IBondingRegistry public bondingRegistry;\n\n /// @notice Address of the ERC20 token used for E3 fees.\n /// @dev All E3 request fees must be paid in this token.\n IERC20 public feeToken;\n\n /// @notice Maximum allowed duration for an E3 computation in seconds.\n /// @dev Requests with duration exceeding this value will be rejected.\n uint256 public maxDuration;\n\n /// @notice ID counter for the next E3 to be created.\n /// @dev Incremented after each successful E3 request.\n uint256 public nexte3Id;\n\n /// @notice Mapping of allowed E3 Programs.\n /// @dev Only enabled E3 Programs can be used in computation requests.\n mapping(IE3Program e3Program => bool allowed) public e3Programs;\n\n /// @notice Mapping storing all E3 instances by their ID.\n /// @dev Contains the full state and configuration of each E3.\n mapping(uint256 e3Id => E3 e3) public e3s;\n\n /// @notice Mapping of enabled encryption schemes to their decryption verifiers.\n /// @dev Each encryption scheme ID maps to a contract that can verify decrypted outputs.\n mapping(bytes32 encryptionSchemeId => IDecryptionVerifier decryptionVerifier)\n public decryptionVerifiers;\n\n /// @notice Mapping storing valid E3 program ABI encoded parameter sets.\n /// @dev Stores allowed encryption scheme parameters (e.g., BFV parameters).\n mapping(bytes e3ProgramParams => bool allowed) public e3ProgramsParams;\n\n /// @notice Mapping tracking fee payments for each E3.\n /// @dev Stores the amount paid for an E3, distributed to committee upon completion.\n mapping(uint256 e3Id => uint256 e3Payment) public e3Payments;\n\n ////////////////////////////////////////////////////////////\n // //\n // Errors //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Thrown when committee selection fails during E3 request or activation.\n error CommitteeSelectionFailed();\n\n /// @notice Thrown when an E3 request uses a program that is not enabled.\n /// @param e3Program The E3 program address that is not allowed.\n error E3ProgramNotAllowed(IE3Program e3Program);\n\n /// @notice Thrown when attempting to activate an E3 that is already activated.\n /// @param e3Id The ID of the E3 that is already activated.\n error E3AlreadyActivated(uint256 e3Id);\n\n /// @notice Thrown when the E3 start window or computation period has expired.\n error E3Expired();\n\n /// @notice Thrown when attempting operations on an E3 that has not been activated yet.\n /// @param e3Id The ID of the E3 that is not activated.\n error E3NotActivated(uint256 e3Id);\n\n /// @notice Thrown when attempting to activate an E3 before its start window begins.\n error E3NotReady();\n\n /// @notice Thrown when attempting to access an E3 that does not exist.\n /// @param e3Id The ID of the non-existent E3.\n error E3DoesNotExist(uint256 e3Id);\n\n /// @notice Thrown when attempting to enable a module or program that is already enabled.\n /// @param module The address of the module that is already enabled.\n error ModuleAlreadyEnabled(address module);\n\n /// @notice Thrown when attempting to disable a module or program that is not enabled.\n /// @param module The address of the module that is not enabled.\n error ModuleNotEnabled(address module);\n\n /// @notice Thrown when an invalid or disabled encryption scheme is used.\n /// @param encryptionSchemeId The ID of the invalid encryption scheme.\n error InvalidEncryptionScheme(bytes32 encryptionSchemeId);\n\n /// @notice Thrown when attempting to publish input after the computation deadline has passed.\n /// @param e3Id The ID of the E3.\n /// @param expiration The expiration timestamp that has passed.\n error InputDeadlinePassed(uint256 e3Id, uint256 expiration);\n\n /// @notice Thrown when attempting to publish output before the input deadline has passed.\n /// @param e3Id The ID of the E3.\n /// @param expiration The expiration timestamp that has not yet passed.\n error InputDeadlineNotPassed(uint256 e3Id, uint256 expiration);\n\n /// @notice Thrown when attempting to set an invalid ciphernode registry address.\n /// @param ciphernodeRegistry The invalid ciphernode registry address.\n error InvalidCiphernodeRegistry(ICiphernodeRegistry ciphernodeRegistry);\n\n /// @notice Thrown when the requested duration exceeds maxDuration or is zero.\n /// @param duration The invalid duration value.\n error InvalidDuration(uint256 duration);\n\n /// @notice Thrown when output verification fails.\n /// @param output The invalid output data.\n error InvalidOutput(bytes output);\n\n /// @notice Thrown when input data is invalid.\n error InvalidInput();\n\n /// @notice Thrown when the start window parameters are invalid.\n error InvalidStartWindow();\n\n /// @notice Thrown when the threshold parameters are invalid (e.g., M > N or M = 0).\n /// @param threshold The invalid threshold array [M, N].\n error InvalidThreshold(uint32[2] threshold);\n\n /// @notice Thrown when attempting to publish ciphertext output that has already been published.\n /// @param e3Id The ID of the E3.\n error CiphertextOutputAlreadyPublished(uint256 e3Id);\n\n /// @notice Thrown when attempting to publish plaintext output before ciphertext output.\n /// @param e3Id The ID of the E3.\n error CiphertextOutputNotPublished(uint256 e3Id);\n\n /// @notice Thrown when payment is required but not provided or insufficient.\n /// @param value The required payment amount.\n error PaymentRequired(uint256 value);\n\n /// @notice Thrown when attempting to publish plaintext output that has already been published.\n /// @param e3Id The ID of the E3.\n error PlaintextOutputAlreadyPublished(uint256 e3Id);\n\n /// @notice Thrown when attempting to set an invalid bonding registry address.\n /// @param bondingRegistry The invalid bonding registry address.\n error InvalidBondingRegistry(IBondingRegistry bondingRegistry);\n\n /// @notice Thrown when attempting to set an invalid fee token address.\n /// @param feeToken The invalid fee token address.\n error InvalidFeeToken(IERC20 feeToken);\n\n ////////////////////////////////////////////////////////////\n // //\n // Initialization //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Constructor that disables initializers.\n /// @dev Prevents the implementation contract from being initialized. Initialization is performed\n /// via the initialize() function when deployed behind a proxy.\n constructor() {\n _disableInitializers();\n }\n\n /// @notice Initializes the Enclave contract with initial configuration.\n /// @dev This function can only be called once due to the initializer modifier. Sets up core dependencies.\n /// @param _owner The owner address of this contract.\n /// @param _ciphernodeRegistry The address of the Ciphernode Registry contract.\n /// @param _bondingRegistry The address of the Bonding Registry contract.\n /// @param _feeToken The address of the ERC20 token used for E3 fees.\n /// @param _maxDuration The maximum duration of a computation in seconds.\n /// @param _e3ProgramsParams Array of ABI encoded E3 encryption scheme parameters sets (e.g., for BFV).\n function initialize(\n address _owner,\n ICiphernodeRegistry _ciphernodeRegistry,\n IBondingRegistry _bondingRegistry,\n IERC20 _feeToken,\n uint256 _maxDuration,\n bytes[] memory _e3ProgramsParams\n ) public initializer {\n __Ownable_init(msg.sender);\n setMaxDuration(_maxDuration);\n setCiphernodeRegistry(_ciphernodeRegistry);\n setBondingRegistry(_bondingRegistry);\n setFeeToken(_feeToken);\n setE3ProgramsParams(_e3ProgramsParams);\n if (_owner != owner()) transferOwnership(_owner);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Core Entrypoints //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @inheritdoc IEnclave\n function request(\n E3RequestParams calldata requestParams\n ) external returns (uint256 e3Id, E3 memory e3) {\n uint256 e3Fee = getE3Quote(requestParams);\n require(\n requestParams.threshold[1] >= requestParams.threshold[0] &&\n requestParams.threshold[0] > 0,\n InvalidThreshold(requestParams.threshold)\n );\n require(\n // TODO: do we need a minimum start window to allow time for committee selection?\n requestParams.startWindow[1] >= requestParams.startWindow[0] &&\n requestParams.startWindow[1] >= block.timestamp,\n InvalidStartWindow()\n );\n require(\n requestParams.duration > 0 && requestParams.duration <= maxDuration,\n InvalidDuration(requestParams.duration)\n );\n require(\n e3Programs[requestParams.e3Program],\n E3ProgramNotAllowed(requestParams.e3Program)\n );\n\n // TODO: should IDs be incremental or produced deterministically?\n e3Id = nexte3Id;\n nexte3Id++;\n uint256 seed = uint256(keccak256(abi.encode(block.prevrandao, e3Id)));\n\n e3.seed = seed;\n e3.threshold = requestParams.threshold;\n e3.requestBlock = block.number;\n e3.startWindow = requestParams.startWindow;\n e3.duration = requestParams.duration;\n e3.expiration = 0;\n e3.e3Program = requestParams.e3Program;\n e3.e3ProgramParams = requestParams.e3ProgramParams;\n e3.customParams = requestParams.customParams;\n e3.committeePublicKey = hex\"\";\n e3.ciphertextOutput = hex\"\";\n e3.plaintextOutput = hex\"\";\n\n bytes32 encryptionSchemeId = requestParams.e3Program.validate(\n e3Id,\n seed,\n requestParams.e3ProgramParams,\n requestParams.computeProviderParams\n );\n IDecryptionVerifier decryptionVerifier = decryptionVerifiers[\n encryptionSchemeId\n ];\n\n require(\n decryptionVerifiers[encryptionSchemeId] !=\n IDecryptionVerifier(address(0)),\n InvalidEncryptionScheme(encryptionSchemeId)\n );\n\n e3.encryptionSchemeId = encryptionSchemeId;\n e3.decryptionVerifier = decryptionVerifier;\n\n e3s[e3Id] = e3;\n e3Payments[e3Id] = e3Fee;\n\n feeToken.safeTransferFrom(msg.sender, address(this), e3Fee);\n\n require(\n ciphernodeRegistry.requestCommittee(\n e3Id,\n seed,\n requestParams.threshold\n ),\n CommitteeSelectionFailed()\n );\n\n emit E3Requested(e3Id, e3, requestParams.e3Program);\n }\n\n /// @inheritdoc IEnclave\n function activate(\n uint256 e3Id,\n bytes calldata publicKey\n ) external returns (bool success) {\n E3 memory e3 = getE3(e3Id);\n\n require(e3.expiration == 0, E3AlreadyActivated(e3Id));\n require(e3.startWindow[0] <= block.timestamp, E3NotReady());\n // TODO: handle what happens to the payment if the start window has passed.\n require(e3.startWindow[1] >= block.timestamp, E3Expired());\n\n bytes32 publicKeyHash = ciphernodeRegistry.committeePublicKey(e3Id);\n require(\n keccak256(publicKey) == publicKeyHash,\n CommitteeSelectionFailed()\n );\n uint256 expiresAt = block.timestamp + e3.duration;\n e3s[e3Id].expiration = expiresAt;\n e3s[e3Id].committeePublicKey = keccak256(publicKey);\n\n emit E3Activated(e3Id, expiresAt, publicKey);\n\n return true;\n }\n\n /// @inheritdoc IEnclave\n function publishInput(\n uint256 e3Id,\n bytes calldata data\n ) external returns (bool success) {\n E3 memory e3 = getE3(e3Id);\n\n // Note: if we make 0 a no expiration, this has to be refactored\n require(e3.expiration > 0, E3NotActivated(e3Id));\n // TODO: should we have an input window, including both a start and end timestamp?\n require(\n e3.expiration > block.timestamp,\n InputDeadlinePassed(e3Id, e3.expiration)\n );\n\n e3.e3Program.validateInput(e3Id, msg.sender, data);\n\n success = true;\n }\n\n /// @inheritdoc IEnclave\n function publishCiphertextOutput(\n uint256 e3Id,\n bytes calldata ciphertextOutput,\n bytes calldata proof\n ) external returns (bool success) {\n E3 memory e3 = getE3(e3Id);\n\n // Note: if we make 0 a no expiration, this has to be refactored\n require(e3.expiration > 0, E3NotActivated(e3Id));\n require(\n e3.expiration <= block.timestamp,\n InputDeadlineNotPassed(e3Id, e3.expiration)\n );\n // TODO: should the output verifier be able to change its mind?\n //i.e. should we be able to call this multiple times?\n require(\n e3.ciphertextOutput == bytes32(0),\n CiphertextOutputAlreadyPublished(e3Id)\n );\n\n bytes32 ciphertextOutputHash = keccak256(ciphertextOutput);\n e3s[e3Id].ciphertextOutput = ciphertextOutputHash;\n\n (success) = e3.e3Program.verify(e3Id, ciphertextOutputHash, proof);\n require(success, InvalidOutput(ciphertextOutput));\n\n emit CiphertextOutputPublished(e3Id, ciphertextOutput);\n }\n\n /// @inheritdoc IEnclave\n function publishPlaintextOutput(\n uint256 e3Id,\n bytes calldata plaintextOutput,\n bytes calldata proof\n ) external returns (bool success) {\n E3 memory e3 = getE3(e3Id);\n\n // Note: if we make 0 a no expiration, this has to be refactored\n require(e3.expiration > 0, E3NotActivated(e3Id));\n require(\n e3.ciphertextOutput != bytes32(0),\n CiphertextOutputNotPublished(e3Id)\n );\n require(\n e3.plaintextOutput.length == 0,\n PlaintextOutputAlreadyPublished(e3Id)\n );\n\n e3s[e3Id].plaintextOutput = plaintextOutput;\n\n (success) = e3.decryptionVerifier.verify(\n e3Id,\n keccak256(plaintextOutput),\n proof\n );\n require(success, InvalidOutput(plaintextOutput));\n\n _distributeRewards(e3Id);\n\n emit PlaintextOutputPublished(e3Id, plaintextOutput);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Internal Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Distributes rewards to committee members after successful E3 completion.\n /// @dev Divides the E3 payment equally among all committee members and transfers via bonding registry.\n /// @dev Emits RewardsDistributed event upon successful distribution.\n /// @param e3Id The ID of the E3 for which to distribute rewards.\n function _distributeRewards(uint256 e3Id) internal {\n address[] memory committeeNodes = ciphernodeRegistry.getCommitteeNodes(\n e3Id\n );\n uint256 committeeLength = committeeNodes.length;\n uint256[] memory amounts = new uint256[](committeeLength);\n\n // TODO: do we need to pay different amounts to different nodes?\n // For now, we'll pay the same amount to all nodes.\n uint256 amount = e3Payments[e3Id] / committeeLength;\n for (uint256 i = 0; i < committeeLength; i++) {\n amounts[i] = amount;\n }\n\n uint256 totalAmount = e3Payments[e3Id];\n e3Payments[e3Id] = 0;\n\n feeToken.approve(address(bondingRegistry), totalAmount);\n\n bondingRegistry.distributeRewards(feeToken, committeeNodes, amounts);\n\n // TODO: decide where does dust go? Treasury maybe?\n feeToken.approve(address(bondingRegistry), 0);\n\n emit RewardsDistributed(e3Id, committeeNodes, amounts);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Set Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @inheritdoc IEnclave\n function setMaxDuration(\n uint256 _maxDuration\n ) public onlyOwner returns (bool success) {\n maxDuration = _maxDuration;\n success = true;\n emit MaxDurationSet(_maxDuration);\n }\n\n /// @inheritdoc IEnclave\n function setCiphernodeRegistry(\n ICiphernodeRegistry _ciphernodeRegistry\n ) public onlyOwner returns (bool success) {\n require(\n address(_ciphernodeRegistry) != address(0) &&\n _ciphernodeRegistry != ciphernodeRegistry,\n InvalidCiphernodeRegistry(_ciphernodeRegistry)\n );\n ciphernodeRegistry = _ciphernodeRegistry;\n success = true;\n emit CiphernodeRegistrySet(address(_ciphernodeRegistry));\n }\n\n /// @inheritdoc IEnclave\n function setBondingRegistry(\n IBondingRegistry _bondingRegistry\n ) public onlyOwner returns (bool success) {\n require(\n address(_bondingRegistry) != address(0) &&\n _bondingRegistry != bondingRegistry,\n InvalidBondingRegistry(_bondingRegistry)\n );\n bondingRegistry = _bondingRegistry;\n success = true;\n emit BondingRegistrySet(address(_bondingRegistry));\n }\n\n /// @inheritdoc IEnclave\n function setFeeToken(\n IERC20 _feeToken\n ) public onlyOwner returns (bool success) {\n require(\n address(_feeToken) != address(0) && _feeToken != feeToken,\n InvalidFeeToken(_feeToken)\n );\n feeToken = _feeToken;\n success = true;\n emit FeeTokenSet(address(_feeToken));\n }\n\n /// @inheritdoc IEnclave\n function enableE3Program(\n IE3Program e3Program\n ) public onlyOwner returns (bool success) {\n require(\n !e3Programs[e3Program],\n ModuleAlreadyEnabled(address(e3Program))\n );\n e3Programs[e3Program] = true;\n success = true;\n emit E3ProgramEnabled(e3Program);\n }\n\n /// @inheritdoc IEnclave\n function disableE3Program(\n IE3Program e3Program\n ) public onlyOwner returns (bool success) {\n require(e3Programs[e3Program], ModuleNotEnabled(address(e3Program)));\n delete e3Programs[e3Program];\n success = true;\n emit E3ProgramDisabled(e3Program);\n }\n\n /// @inheritdoc IEnclave\n function setDecryptionVerifier(\n bytes32 encryptionSchemeId,\n IDecryptionVerifier decryptionVerifier\n ) public onlyOwner returns (bool success) {\n require(\n decryptionVerifier != IDecryptionVerifier(address(0)) &&\n decryptionVerifiers[encryptionSchemeId] != decryptionVerifier,\n InvalidEncryptionScheme(encryptionSchemeId)\n );\n decryptionVerifiers[encryptionSchemeId] = decryptionVerifier;\n success = true;\n emit EncryptionSchemeEnabled(encryptionSchemeId);\n }\n\n /// @inheritdoc IEnclave\n function disableEncryptionScheme(\n bytes32 encryptionSchemeId\n ) public onlyOwner returns (bool success) {\n require(\n decryptionVerifiers[encryptionSchemeId] !=\n IDecryptionVerifier(address(0)),\n InvalidEncryptionScheme(encryptionSchemeId)\n );\n decryptionVerifiers[encryptionSchemeId] = IDecryptionVerifier(\n address(0)\n );\n success = true;\n emit EncryptionSchemeDisabled(encryptionSchemeId);\n }\n\n /// @inheritdoc IEnclave\n function setE3ProgramsParams(\n bytes[] memory _e3ProgramsParams\n ) public onlyOwner returns (bool success) {\n uint256 length = _e3ProgramsParams.length;\n for (uint256 i; i < length; ) {\n e3ProgramsParams[_e3ProgramsParams[i]] = true;\n unchecked {\n ++i;\n }\n }\n success = true;\n emit AllowedE3ProgramsParamsSet(_e3ProgramsParams);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Get Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @inheritdoc IEnclave\n function getE3(uint256 e3Id) public view returns (E3 memory e3) {\n e3 = e3s[e3Id];\n require(e3.e3Program != IE3Program(address(0)), E3DoesNotExist(e3Id));\n }\n\n /// @inheritdoc IEnclave\n function getE3Quote(\n E3RequestParams calldata\n ) public pure returns (uint256 fee) {\n fee = 1 * 10 ** 6;\n require(fee > 0, PaymentRequired(fee));\n }\n\n /// @inheritdoc IEnclave\n function getDecryptionVerifier(\n bytes32 encryptionSchemeId\n ) public view returns (IDecryptionVerifier) {\n return decryptionVerifiers[encryptionSchemeId];\n }\n}\n"
|
|
244
|
+
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\npragma solidity >=0.8.27;\n\nimport { IEnclave, E3, IE3Program } from \"./interfaces/IEnclave.sol\";\nimport { ICiphernodeRegistry } from \"./interfaces/ICiphernodeRegistry.sol\";\nimport { IBondingRegistry } from \"./interfaces/IBondingRegistry.sol\";\nimport { IDecryptionVerifier } from \"./interfaces/IDecryptionVerifier.sol\";\nimport {\n OwnableUpgradeable\n} from \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport {\n SafeERC20\n} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Enclave\n * @notice Main contract for managing Encrypted Execution Environments (E3)\n * @dev Coordinates E3 lifecycle including request, activation, input publishing, and output verification\n */\ncontract Enclave is IEnclave, OwnableUpgradeable {\n using SafeERC20 for IERC20;\n\n ////////////////////////////////////////////////////////////\n // //\n // Storage Variables //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Address of the Ciphernode Registry contract.\n /// @dev Manages the pool of ciphernodes and committee selection.\n ICiphernodeRegistry public ciphernodeRegistry;\n\n /// @notice Address of the Bonding Registry contract.\n /// @dev Handles staking and reward distribution for ciphernodes.\n IBondingRegistry public bondingRegistry;\n\n /// @notice Address of the ERC20 token used for E3 fees.\n /// @dev All E3 request fees must be paid in this token.\n IERC20 public feeToken;\n\n /// @notice Maximum allowed duration for an E3 computation in seconds.\n /// @dev Requests with duration exceeding this value will be rejected.\n uint256 public maxDuration;\n\n /// @notice ID counter for the next E3 to be created.\n /// @dev Incremented after each successful E3 request.\n uint256 public nexte3Id;\n\n /// @notice Mapping of allowed E3 Programs.\n /// @dev Only enabled E3 Programs can be used in computation requests.\n mapping(IE3Program e3Program => bool allowed) public e3Programs;\n\n /// @notice Mapping storing all E3 instances by their ID.\n /// @dev Contains the full state and configuration of each E3.\n mapping(uint256 e3Id => E3 e3) public e3s;\n\n /// @notice Mapping of enabled encryption schemes to their decryption verifiers.\n /// @dev Each encryption scheme ID maps to a contract that can verify decrypted outputs.\n mapping(bytes32 encryptionSchemeId => IDecryptionVerifier decryptionVerifier)\n public decryptionVerifiers;\n\n /// @notice Mapping storing valid E3 program ABI encoded parameter sets.\n /// @dev Stores allowed encryption scheme parameters (e.g., BFV parameters).\n mapping(bytes e3ProgramParams => bool allowed) public e3ProgramsParams;\n\n /// @notice Mapping tracking fee payments for each E3.\n /// @dev Stores the amount paid for an E3, distributed to committee upon completion.\n mapping(uint256 e3Id => uint256 e3Payment) public e3Payments;\n\n ////////////////////////////////////////////////////////////\n // //\n // Errors //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Thrown when committee selection fails during E3 request or activation.\n error CommitteeSelectionFailed();\n\n /// @notice Thrown when an E3 request uses a program that is not enabled.\n /// @param e3Program The E3 program address that is not allowed.\n error E3ProgramNotAllowed(IE3Program e3Program);\n\n /// @notice Thrown when attempting to activate an E3 that is already activated.\n /// @param e3Id The ID of the E3 that is already activated.\n error E3AlreadyActivated(uint256 e3Id);\n\n /// @notice Thrown when the E3 start window or computation period has expired.\n error E3Expired();\n\n /// @notice Thrown when attempting operations on an E3 that has not been activated yet.\n /// @param e3Id The ID of the E3 that is not activated.\n error E3NotActivated(uint256 e3Id);\n\n /// @notice Thrown when attempting to activate an E3 before its start window begins.\n error E3NotReady();\n\n /// @notice Thrown when attempting to access an E3 that does not exist.\n /// @param e3Id The ID of the non-existent E3.\n error E3DoesNotExist(uint256 e3Id);\n\n /// @notice Thrown when attempting to enable a module or program that is already enabled.\n /// @param module The address of the module that is already enabled.\n error ModuleAlreadyEnabled(address module);\n\n /// @notice Thrown when attempting to disable a module or program that is not enabled.\n /// @param module The address of the module that is not enabled.\n error ModuleNotEnabled(address module);\n\n /// @notice Thrown when an invalid or disabled encryption scheme is used.\n /// @param encryptionSchemeId The ID of the invalid encryption scheme.\n error InvalidEncryptionScheme(bytes32 encryptionSchemeId);\n\n /// @notice Thrown when attempting to publish input after the computation deadline has passed.\n /// @param e3Id The ID of the E3.\n /// @param expiration The expiration timestamp that has passed.\n error InputDeadlinePassed(uint256 e3Id, uint256 expiration);\n\n /// @notice Thrown when attempting to publish output before the input deadline has passed.\n /// @param e3Id The ID of the E3.\n /// @param expiration The expiration timestamp that has not yet passed.\n error InputDeadlineNotPassed(uint256 e3Id, uint256 expiration);\n\n /// @notice Thrown when attempting to set an invalid ciphernode registry address.\n /// @param ciphernodeRegistry The invalid ciphernode registry address.\n error InvalidCiphernodeRegistry(ICiphernodeRegistry ciphernodeRegistry);\n\n /// @notice Thrown when the requested duration exceeds maxDuration or is zero.\n /// @param duration The invalid duration value.\n error InvalidDuration(uint256 duration);\n\n /// @notice Thrown when output verification fails.\n /// @param output The invalid output data.\n error InvalidOutput(bytes output);\n\n /// @notice Thrown when input data is invalid.\n error InvalidInput();\n\n /// @notice Thrown when the start window parameters are invalid.\n error InvalidStartWindow();\n\n /// @notice Thrown when the threshold parameters are invalid (e.g., M > N or M = 0).\n /// @param threshold The invalid threshold array [M, N].\n error InvalidThreshold(uint32[2] threshold);\n\n /// @notice Thrown when attempting to publish ciphertext output that has already been published.\n /// @param e3Id The ID of the E3.\n error CiphertextOutputAlreadyPublished(uint256 e3Id);\n\n /// @notice Thrown when attempting to publish plaintext output before ciphertext output.\n /// @param e3Id The ID of the E3.\n error CiphertextOutputNotPublished(uint256 e3Id);\n\n /// @notice Thrown when payment is required but not provided or insufficient.\n /// @param value The required payment amount.\n error PaymentRequired(uint256 value);\n\n /// @notice Thrown when attempting to publish plaintext output that has already been published.\n /// @param e3Id The ID of the E3.\n error PlaintextOutputAlreadyPublished(uint256 e3Id);\n\n /// @notice Thrown when attempting to set an invalid bonding registry address.\n /// @param bondingRegistry The invalid bonding registry address.\n error InvalidBondingRegistry(IBondingRegistry bondingRegistry);\n\n /// @notice Thrown when attempting to set an invalid fee token address.\n /// @param feeToken The invalid fee token address.\n error InvalidFeeToken(IERC20 feeToken);\n\n ////////////////////////////////////////////////////////////\n // //\n // Initialization //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Constructor that disables initializers.\n /// @dev Prevents the implementation contract from being initialized. Initialization is performed\n /// via the initialize() function when deployed behind a proxy.\n constructor() {\n _disableInitializers();\n }\n\n /// @notice Initializes the Enclave contract with initial configuration.\n /// @dev This function can only be called once due to the initializer modifier. Sets up core dependencies.\n /// @param _owner The owner address of this contract.\n /// @param _ciphernodeRegistry The address of the Ciphernode Registry contract.\n /// @param _bondingRegistry The address of the Bonding Registry contract.\n /// @param _feeToken The address of the ERC20 token used for E3 fees.\n /// @param _maxDuration The maximum duration of a computation in seconds.\n /// @param _e3ProgramsParams Array of ABI encoded E3 encryption scheme parameters sets (e.g., for BFV).\n function initialize(\n address _owner,\n ICiphernodeRegistry _ciphernodeRegistry,\n IBondingRegistry _bondingRegistry,\n IERC20 _feeToken,\n uint256 _maxDuration,\n bytes[] memory _e3ProgramsParams\n ) public initializer {\n __Ownable_init(msg.sender);\n setMaxDuration(_maxDuration);\n setCiphernodeRegistry(_ciphernodeRegistry);\n setBondingRegistry(_bondingRegistry);\n setFeeToken(_feeToken);\n setE3ProgramsParams(_e3ProgramsParams);\n if (_owner != owner()) transferOwnership(_owner);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Core Entrypoints //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @inheritdoc IEnclave\n function request(\n E3RequestParams calldata requestParams\n ) external returns (uint256 e3Id, E3 memory e3) {\n uint256 e3Fee = getE3Quote(requestParams);\n require(\n requestParams.threshold[1] >= requestParams.threshold[0] &&\n requestParams.threshold[0] > 0,\n InvalidThreshold(requestParams.threshold)\n );\n require(\n // TODO: do we need a minimum start window to allow time for committee selection?\n requestParams.startWindow[1] >= requestParams.startWindow[0] &&\n requestParams.startWindow[1] >= block.timestamp,\n InvalidStartWindow()\n );\n require(\n requestParams.duration > 0 && requestParams.duration <= maxDuration,\n InvalidDuration(requestParams.duration)\n );\n require(\n e3Programs[requestParams.e3Program],\n E3ProgramNotAllowed(requestParams.e3Program)\n );\n\n // TODO: should IDs be incremental or produced deterministically?\n e3Id = nexte3Id;\n nexte3Id++;\n uint256 seed = uint256(keccak256(abi.encode(block.prevrandao, e3Id)));\n\n e3.seed = seed;\n e3.threshold = requestParams.threshold;\n e3.requestBlock = block.number;\n e3.startWindow = requestParams.startWindow;\n e3.duration = requestParams.duration;\n e3.expiration = 0;\n e3.e3Program = requestParams.e3Program;\n e3.e3ProgramParams = requestParams.e3ProgramParams;\n e3.customParams = requestParams.customParams;\n e3.committeePublicKey = hex\"\";\n e3.ciphertextOutput = hex\"\";\n e3.plaintextOutput = hex\"\";\n e3.requester = msg.sender;\n\n bytes32 encryptionSchemeId = requestParams.e3Program.validate(\n e3Id,\n seed,\n requestParams.e3ProgramParams,\n requestParams.computeProviderParams\n );\n IDecryptionVerifier decryptionVerifier = decryptionVerifiers[\n encryptionSchemeId\n ];\n\n require(\n decryptionVerifiers[encryptionSchemeId] !=\n IDecryptionVerifier(address(0)),\n InvalidEncryptionScheme(encryptionSchemeId)\n );\n\n e3.encryptionSchemeId = encryptionSchemeId;\n e3.decryptionVerifier = decryptionVerifier;\n\n e3s[e3Id] = e3;\n e3Payments[e3Id] = e3Fee;\n\n feeToken.safeTransferFrom(msg.sender, address(this), e3Fee);\n\n require(\n ciphernodeRegistry.requestCommittee(\n e3Id,\n seed,\n requestParams.threshold\n ),\n CommitteeSelectionFailed()\n );\n\n emit E3Requested(e3Id, e3, requestParams.e3Program);\n }\n\n /// @inheritdoc IEnclave\n function activate(uint256 e3Id) external returns (bool success) {\n E3 memory e3 = getE3(e3Id);\n\n require(e3.expiration == 0, E3AlreadyActivated(e3Id));\n require(e3.startWindow[0] <= block.timestamp, E3NotReady());\n // TODO: handle what happens to the payment if the start window has passed.\n require(e3.startWindow[1] >= block.timestamp, E3Expired());\n\n bytes32 publicKeyHash = ciphernodeRegistry.committeePublicKey(e3Id);\n\n uint256 expiresAt = block.timestamp + e3.duration;\n e3s[e3Id].expiration = expiresAt;\n e3s[e3Id].committeePublicKey = publicKeyHash;\n\n emit E3Activated(e3Id, expiresAt, publicKeyHash);\n\n return true;\n }\n\n /// @inheritdoc IEnclave\n function publishInput(\n uint256 e3Id,\n bytes calldata data\n ) external returns (bool success) {\n E3 memory e3 = getE3(e3Id);\n\n // Note: if we make 0 a no expiration, this has to be refactored\n require(e3.expiration > 0, E3NotActivated(e3Id));\n // TODO: should we have an input window, including both a start and end timestamp?\n require(\n e3.expiration > block.timestamp,\n InputDeadlinePassed(e3Id, e3.expiration)\n );\n\n e3.e3Program.validateInput(e3Id, msg.sender, data);\n\n success = true;\n }\n\n /// @inheritdoc IEnclave\n function publishCiphertextOutput(\n uint256 e3Id,\n bytes calldata ciphertextOutput,\n bytes calldata proof\n ) external returns (bool success) {\n E3 memory e3 = getE3(e3Id);\n\n // Note: if we make 0 a no expiration, this has to be refactored\n require(e3.expiration > 0, E3NotActivated(e3Id));\n require(\n e3.expiration <= block.timestamp,\n InputDeadlineNotPassed(e3Id, e3.expiration)\n );\n // TODO: should the output verifier be able to change its mind?\n //i.e. should we be able to call this multiple times?\n require(\n e3.ciphertextOutput == bytes32(0),\n CiphertextOutputAlreadyPublished(e3Id)\n );\n\n bytes32 ciphertextOutputHash = keccak256(ciphertextOutput);\n e3s[e3Id].ciphertextOutput = ciphertextOutputHash;\n\n (success) = e3.e3Program.verify(e3Id, ciphertextOutputHash, proof);\n require(success, InvalidOutput(ciphertextOutput));\n\n emit CiphertextOutputPublished(e3Id, ciphertextOutput);\n }\n\n /// @inheritdoc IEnclave\n function publishPlaintextOutput(\n uint256 e3Id,\n bytes calldata plaintextOutput,\n bytes calldata proof\n ) external returns (bool success) {\n E3 memory e3 = getE3(e3Id);\n\n // Note: if we make 0 a no expiration, this has to be refactored\n require(e3.expiration > 0, E3NotActivated(e3Id));\n require(\n e3.ciphertextOutput != bytes32(0),\n CiphertextOutputNotPublished(e3Id)\n );\n require(\n e3.plaintextOutput.length == 0,\n PlaintextOutputAlreadyPublished(e3Id)\n );\n\n e3s[e3Id].plaintextOutput = plaintextOutput;\n\n (success) = e3.decryptionVerifier.verify(\n e3Id,\n keccak256(plaintextOutput),\n proof\n );\n require(success, InvalidOutput(plaintextOutput));\n\n _distributeRewards(e3Id);\n\n emit PlaintextOutputPublished(e3Id, plaintextOutput);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Internal Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Distributes rewards to committee members after successful E3 completion.\n /// @dev Divides the E3 payment equally among all committee members and transfers via bonding registry.\n /// @dev Emits RewardsDistributed event upon successful distribution.\n /// @param e3Id The ID of the E3 for which to distribute rewards.\n function _distributeRewards(uint256 e3Id) internal {\n address[] memory committeeNodes = ciphernodeRegistry.getCommitteeNodes(\n e3Id\n );\n uint256 committeeLength = committeeNodes.length;\n uint256[] memory amounts = new uint256[](committeeLength);\n\n // TODO: do we need to pay different amounts to different nodes?\n // For now, we'll pay the same amount to all nodes.\n uint256 amount = e3Payments[e3Id] / committeeLength;\n for (uint256 i = 0; i < committeeLength; i++) {\n amounts[i] = amount;\n }\n\n uint256 totalAmount = e3Payments[e3Id];\n e3Payments[e3Id] = 0;\n\n feeToken.approve(address(bondingRegistry), totalAmount);\n\n bondingRegistry.distributeRewards(feeToken, committeeNodes, amounts);\n\n // TODO: decide where does dust go? Treasury maybe?\n feeToken.approve(address(bondingRegistry), 0);\n\n emit RewardsDistributed(e3Id, committeeNodes, amounts);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Set Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @inheritdoc IEnclave\n function setMaxDuration(\n uint256 _maxDuration\n ) public onlyOwner returns (bool success) {\n maxDuration = _maxDuration;\n success = true;\n emit MaxDurationSet(_maxDuration);\n }\n\n /// @inheritdoc IEnclave\n function setCiphernodeRegistry(\n ICiphernodeRegistry _ciphernodeRegistry\n ) public onlyOwner returns (bool success) {\n require(\n address(_ciphernodeRegistry) != address(0) &&\n _ciphernodeRegistry != ciphernodeRegistry,\n InvalidCiphernodeRegistry(_ciphernodeRegistry)\n );\n ciphernodeRegistry = _ciphernodeRegistry;\n success = true;\n emit CiphernodeRegistrySet(address(_ciphernodeRegistry));\n }\n\n /// @inheritdoc IEnclave\n function setBondingRegistry(\n IBondingRegistry _bondingRegistry\n ) public onlyOwner returns (bool success) {\n require(\n address(_bondingRegistry) != address(0) &&\n _bondingRegistry != bondingRegistry,\n InvalidBondingRegistry(_bondingRegistry)\n );\n bondingRegistry = _bondingRegistry;\n success = true;\n emit BondingRegistrySet(address(_bondingRegistry));\n }\n\n /// @inheritdoc IEnclave\n function setFeeToken(\n IERC20 _feeToken\n ) public onlyOwner returns (bool success) {\n require(\n address(_feeToken) != address(0) && _feeToken != feeToken,\n InvalidFeeToken(_feeToken)\n );\n feeToken = _feeToken;\n success = true;\n emit FeeTokenSet(address(_feeToken));\n }\n\n /// @inheritdoc IEnclave\n function enableE3Program(\n IE3Program e3Program\n ) public onlyOwner returns (bool success) {\n require(\n !e3Programs[e3Program],\n ModuleAlreadyEnabled(address(e3Program))\n );\n e3Programs[e3Program] = true;\n success = true;\n emit E3ProgramEnabled(e3Program);\n }\n\n /// @inheritdoc IEnclave\n function disableE3Program(\n IE3Program e3Program\n ) public onlyOwner returns (bool success) {\n require(e3Programs[e3Program], ModuleNotEnabled(address(e3Program)));\n delete e3Programs[e3Program];\n success = true;\n emit E3ProgramDisabled(e3Program);\n }\n\n /// @inheritdoc IEnclave\n function setDecryptionVerifier(\n bytes32 encryptionSchemeId,\n IDecryptionVerifier decryptionVerifier\n ) public onlyOwner returns (bool success) {\n require(\n decryptionVerifier != IDecryptionVerifier(address(0)) &&\n decryptionVerifiers[encryptionSchemeId] != decryptionVerifier,\n InvalidEncryptionScheme(encryptionSchemeId)\n );\n decryptionVerifiers[encryptionSchemeId] = decryptionVerifier;\n success = true;\n emit EncryptionSchemeEnabled(encryptionSchemeId);\n }\n\n /// @inheritdoc IEnclave\n function disableEncryptionScheme(\n bytes32 encryptionSchemeId\n ) public onlyOwner returns (bool success) {\n require(\n decryptionVerifiers[encryptionSchemeId] !=\n IDecryptionVerifier(address(0)),\n InvalidEncryptionScheme(encryptionSchemeId)\n );\n decryptionVerifiers[encryptionSchemeId] = IDecryptionVerifier(\n address(0)\n );\n success = true;\n emit EncryptionSchemeDisabled(encryptionSchemeId);\n }\n\n /// @inheritdoc IEnclave\n function setE3ProgramsParams(\n bytes[] memory _e3ProgramsParams\n ) public onlyOwner returns (bool success) {\n uint256 length = _e3ProgramsParams.length;\n for (uint256 i; i < length; ) {\n e3ProgramsParams[_e3ProgramsParams[i]] = true;\n unchecked {\n ++i;\n }\n }\n success = true;\n emit AllowedE3ProgramsParamsSet(_e3ProgramsParams);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Get Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @inheritdoc IEnclave\n function getE3(uint256 e3Id) public view returns (E3 memory e3) {\n e3 = e3s[e3Id];\n require(e3.e3Program != IE3Program(address(0)), E3DoesNotExist(e3Id));\n }\n\n /// @inheritdoc IEnclave\n function getE3Quote(\n E3RequestParams calldata\n ) public pure returns (uint256 fee) {\n fee = 1 * 10 ** 6;\n require(fee > 0, PaymentRequired(fee));\n }\n\n /// @inheritdoc IEnclave\n function getDecryptionVerifier(\n bytes32 encryptionSchemeId\n ) public view returns (IDecryptionVerifier) {\n return decryptionVerifiers[encryptionSchemeId];\n }\n}\n"
|
|
245
245
|
},
|
|
246
246
|
"project/contracts/interfaces/IBondingRegistry.sol": {
|
|
247
247
|
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\npragma solidity >=0.8.27;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { ICiphernodeRegistry } from \"./ICiphernodeRegistry.sol\";\nimport { EnclaveTicketToken } from \"../token/EnclaveTicketToken.sol\";\n\n/**\n * @title IBondingRegistry\n * @notice Interface for the main bonding registry that holds operator balance and license bonds\n */\ninterface IBondingRegistry {\n // ======================\n // Custom Errors\n // ======================\n\n // General\n error ZeroAddress();\n error ZeroAmount();\n error CiphernodeBanned();\n error Unauthorized();\n error InsufficientBalance();\n error NotLicensed();\n error AlreadyRegistered();\n error NotRegistered();\n error ExitInProgress();\n error ExitNotReady();\n error InvalidAmount();\n error InvalidConfiguration();\n error NoPendingDeregistration();\n error OnlyRewardDistributor();\n error ArrayLengthMismatch();\n\n // ======================\n // Events (Protocol-Named)\n // ======================\n\n /**\n * @notice Emitted when operator's ticket balance changes\n * @param operator Address of the operator\n * @param delta Change in balance (positive for increase, negative for decrease)\n * @param newBalance New total balance\n * @param reason Reason for the change (e.g., \"DEPOSIT\", \"WITHDRAW\", slash reason)\n */\n event TicketBalanceUpdated(\n address indexed operator,\n int256 delta,\n uint256 newBalance,\n bytes32 indexed reason\n );\n\n /**\n * @notice Emitted when operator's license bond changes\n * @param operator Address of the operator\n * @param delta Change in bond (positive for increase, negative for decrease)\n * @param newBond New total license bond\n * @param reason Reason for the change (e.g., \"BOND\", \"UNBOND\", slash reason)\n */\n event LicenseBondUpdated(\n address indexed operator,\n int256 delta,\n uint256 newBond,\n bytes32 indexed reason\n );\n\n /**\n * @notice Emitted when operator requests deregistration from the protocol\n * @param operator Address of the operator\n * @param unlockAt Timestamp when deregistration can be finalized\n */\n event CiphernodeDeregistrationRequested(\n address indexed operator,\n uint64 unlockAt\n );\n\n /**\n * @notice Emitted when operator active status changes\n * @param operator Address of the operator\n * @param active True if active, false if inactive\n */\n event OperatorActivationChanged(address indexed operator, bool active);\n\n /**\n * @notice Emitted when configuration is updated\n * @param parameter Name of the parameter\n * @param oldValue Previous value\n * @param newValue New value\n */\n event ConfigurationUpdated(\n bytes32 indexed parameter,\n uint256 oldValue,\n uint256 newValue\n );\n\n /**\n * @notice Emitted when treasury withdraws slashed funds\n * @param to Treasury address\n * @param ticketAmount Amount of slashed ticket balance withdrawn\n * @param licenseAmount Amount of slashed license bond withdrawn\n */\n event SlashedFundsWithdrawn(\n address indexed to,\n uint256 ticketAmount,\n uint256 licenseAmount\n );\n\n // ======================\n // View Functions\n // ======================\n\n /**\n * @notice Get license token address\n * @return License token address\n */\n function getLicenseToken() external view returns (address);\n\n /**\n * @notice Get ticket token address\n * @return Ticket token address\n */\n function getTicketToken() external view returns (address);\n\n /**\n * @notice Get operator's current ticket balance\n * @param operator Address of the operator\n * @return Current collateral balance\n */\n function getTicketBalance(address operator) external view returns (uint256);\n\n /**\n * @notice Get operator's current license bond\n * @param operator Address of the operator\n * @return Current license bond\n */\n function getLicenseBond(address operator) external view returns (uint256);\n\n /**\n * @notice Get current ticket price\n * @return Price per ticket in collateral token units\n */\n function ticketPrice() external view returns (uint256);\n\n /**\n * @notice Calculate available tickets for an operator\n * @param operator Address of the operator\n * @return Number of tickets available (floor(balance / ticketPrice))\n */\n function availableTickets(address operator) external view returns (uint256);\n\n /**\n * @notice Check if operator is licensed\n * @param operator Address of the operator\n * @return True if operator has sufficient license bond\n */\n function isLicensed(address operator) external view returns (bool);\n\n /**\n * @notice Check if operator is registered\n * @param operator Address of the operator\n * @return True if operator is registered\n */\n function isRegistered(address operator) external view returns (bool);\n\n /**\n * @notice Check if operator is active\n * @param operator Address of the operator\n * @return True if operator is active (licensed, registered, and has min tickets)\n */\n function isActive(address operator) external view returns (bool);\n\n /**\n * @notice Check if operator has deregistration in progress\n * @param operator Address of the operator\n * @return True if exit requested but not finalized\n */\n function hasExitInProgress(address operator) external view returns (bool);\n\n /**\n * @notice Get license bond price required\n * @return License bond price amount\n */\n function licenseRequiredBond() external view returns (uint256);\n\n /**\n * @notice Get minimum ticket balance required for activation\n * @return Minimum number of tickets required\n */\n function minTicketBalance() external view returns (uint256);\n\n /**\n * @notice Get exit delay period\n * @return Number of seconds operators must wait after requesting exit\n */\n function exitDelay() external view returns (uint64);\n\n /**\n * @notice Get operator's ticket balance at a specific block\n * @param operator Address of the operator\n * @param blockNumber Block number to query\n * @return Ticket balance at the specified block\n */\n function getTicketBalanceAtBlock(\n address operator,\n uint256 blockNumber\n ) external view returns (uint256);\n\n /**\n * @notice Get operator's total pending exit amounts\n * @param operator Address of the operator\n * @return ticket Total pending ticket balance in exit queue\n * @return license Total pending license bond in exit queue\n */\n function pendingExits(\n address operator\n ) external view returns (uint256 ticket, uint256 license);\n\n /**\n * @notice Preview how much an operator can currently claim\n * @param operator Address of the operator\n * @return ticket Claimable ticket balance\n * @return license Claimable license bond\n */\n function previewClaimable(\n address operator\n ) external view returns (uint256 ticket, uint256 license);\n\n /**\n * @notice Get slashed funds treasury address\n * @return Address where slashed funds are sent\n */\n function slashedFundsTreasury() external view returns (address);\n\n /**\n * @notice Get total slashed ticket balance\n * @return Amount of ticket balance slashed and available for treasury withdrawal\n */\n function slashedTicketBalance() external view returns (uint256);\n\n /**\n * @notice Get total slashed license bond\n * @return Amount of license bond slashed and available for treasury withdrawal\n */\n function slashedLicenseBond() external view returns (uint256);\n\n // ======================\n // Operator Functions\n // ======================\n\n /**\n * @notice Register as an operator (callable by licensed operators)\n * @dev Requires sufficient license bond and calls registry\n */\n function registerOperator() external;\n\n /**\n * @notice Deregister as an operator and remove from IMT\n * @param siblingNodes Sibling node proofs for IMT removal\n * @dev Requires operator to provide sibling nodes for immediate IMT removal\n */\n function deregisterOperator(uint256[] calldata siblingNodes) external;\n\n /**\n * @notice Increase operator's ticket balance by depositing tokens\n * @param amount Amount of ticket tokens to deposit\n * @dev Requires approval for ticket token transfer\n */\n function addTicketBalance(uint256 amount) external;\n\n /**\n * @notice Decrease operator's ticket balance by withdrawing tokens\n * @param amount Amount of ticket tokens to withdraw\n * @dev Reverts if operator is in any active committee\n */\n function removeTicketBalance(uint256 amount) external;\n\n /**\n * @notice Bond license tokens to become eligible for registration\n * @param amount Amount of license tokens to bond\n * @dev Requires approval for license token transfer\n */\n function bondLicense(uint256 amount) external;\n\n /**\n * @notice Unbond license tokens\n * @param amount Amount of license tokens to unbond\n * @dev Reverts if operator is in any active committee or still registered\n */\n function unbondLicense(uint256 amount) external;\n\n // ======================\n // Claim Functions\n // ======================\n\n /**\n * @notice Claim operator's ticket balance and license bond\n * @param maxTicketAmount Maximum amount of ticket tokens to claim\n * @param maxLicenseAmount Maximum amount of license tokens to claim\n */\n function claimExits(\n uint256 maxTicketAmount,\n uint256 maxLicenseAmount\n ) external;\n\n // ======================\n // Slashing Functions\n // ======================\n\n /**\n * @notice Slash operator's ticket balance by absolute amount\n * @param operator Address of the operator to slash\n * @param amount Amount to slash\n * @param reason Reason for slashing (stored in event)\n * @dev Only callable by authorized slashing manager\n */\n function slashTicketBalance(\n address operator,\n uint256 amount,\n bytes32 reason\n ) external;\n\n /**\n * @notice Slash operator's license bond by absolute amount\n * @param operator Address of the operator to slash\n * @param amount Amount to slash\n * @param reason Reason for slashing (stored in event)\n * @dev Only callable by authorized slashing manager\n */\n function slashLicenseBond(\n address operator,\n uint256 amount,\n bytes32 reason\n ) external;\n\n // ======================\n // Reward Distribution Functions\n // ======================\n /**\n * @notice Distribute rewards to operators\n * @param rewardToken Reward token contract\n * @param operators Addresses of the operators to distribute rewards to\n * @param amounts Amounts of rewards to distribute to each operator\n * @dev Only callable by contract owner\n */\n function distributeRewards(\n IERC20 rewardToken,\n address[] calldata operators,\n uint256[] calldata amounts\n ) external;\n\n // ======================\n // Admin Functions\n // ======================\n\n /**\n * @notice Set ticket price\n * @param newTicketPrice New price per ticket\n * @dev Only callable by contract owner\n */\n function setTicketPrice(uint256 newTicketPrice) external;\n\n /**\n * @notice Set license bond price required\n * @param newLicenseRequiredBond New license bond price\n * @dev Only callable by contract owner\n */\n function setLicenseRequiredBond(uint256 newLicenseRequiredBond) external;\n\n /**\n * @notice Set license active BPS\n * @param newBps New license active BPS\n * @dev Only callable by contract owner\n */\n function setLicenseActiveBps(uint256 newBps) external;\n\n /**\n * @notice Set minimum ticket balance required for activation\n * @param newMinTicketBalance New minimum ticket balance\n * @dev Only callable by contract owner\n */\n function setMinTicketBalance(uint256 newMinTicketBalance) external;\n\n /**\n * @notice Set exit delay period\n * @param newExitDelay New exit delay in seconds\n * @dev Only callable by contract owner\n */\n function setExitDelay(uint64 newExitDelay) external;\n\n /**\n * @notice Set ticket token\n * @param newTicketToken New ticket token\n * @dev Only callable by contract owner\n */\n function setTicketToken(EnclaveTicketToken newTicketToken) external;\n\n /**\n * @notice Set license token\n * @param newLicenseToken New license token\n * @dev Only callable by contract owner\n */\n function setLicenseToken(IERC20 newLicenseToken) external;\n\n /**\n * @notice Set slashed funds treasury address\n * @param newSlashedFundsTreasury New slashed funds treasury address\n * @dev Only callable by contract owner\n */\n function setSlashedFundsTreasury(address newSlashedFundsTreasury) external;\n\n /**\n * @notice Set registry address\n * @param newRegistry New registry contract address\n * @dev Only callable by contract owner\n */\n function setRegistry(ICiphernodeRegistry newRegistry) external;\n\n /**\n * @notice Set slashing manager address\n * @param newSlashingManager New slashing manager contract address\n * @dev Only callable by contract owner\n */\n function setSlashingManager(address newSlashingManager) external;\n\n /**\n * @notice Set reward distributor address\n * @param newRewardDistributor New reward distributor address\n * @dev Only callable by contract owner\n */\n function setRewardDistributor(address newRewardDistributor) external;\n\n /**\n * @notice Withdraw slashed funds to treasury\n * @param ticketAmount Amount of slashed ticket balance to withdraw\n * @param licenseAmount Amount of slashed license bond to withdraw\n * @dev Only callable by contract owner, sends to treasury address\n */\n function withdrawSlashedFunds(\n uint256 ticketAmount,\n uint256 licenseAmount\n ) external;\n}\n"
|
|
248
248
|
},
|
|
249
249
|
"project/contracts/interfaces/ICiphernodeRegistry.sol": {
|
|
250
|
-
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\npragma solidity >=0.8.27;\n\n/**\n * @title ICiphernodeRegistry\n * @notice Interface for managing ciphernode registration and committee selection\n * @dev This registry maintains an Incremental Merkle Tree (IMT) of registered ciphernodes\n * and coordinates committee selection for E3 computations\n */\ninterface ICiphernodeRegistry {\n /// @notice Struct representing the sortition state for an E3 round.\n /// @param initialized Whether the round has been initialized.\n /// @param finalized Whether the round has been finalized.\n /// @param requestBlock The block number when the committee was requested.\n /// @param submissionDeadline The deadline for submitting tickets.\n /// @param threshold The M/N threshold for the committee ([M, N]).\n /// @param publicKey Hash of the committee's public key.\n /// @param seed The seed for the round.\n /// @param topNodes The top nodes in the round.\n /// @param committee The committee for the round.\n /// @param submitted Mapping of nodes to their submission status.\n /// @param scoreOf Mapping of nodes to their scores.\n struct Committee {\n bool initialized;\n bool finalized;\n uint256 seed;\n uint256 requestBlock;\n uint256 submissionDeadline;\n bytes32 publicKey;\n uint32[2] threshold;\n address[] topNodes;\n address[] committee;\n mapping(address node => bool submitted) submitted;\n mapping(address node => uint256 score) scoreOf;\n }\n\n /// @notice This event MUST be emitted when a committee is selected for an E3.\n /// @param e3Id ID of the E3 for which the committee was selected.\n /// @param seed Random seed for score computation.\n /// @param threshold The M/N threshold for the committee.\n /// @param requestBlock Block number for snapshot validation.\n /// @param submissionDeadline Deadline for submitting tickets.\n event CommitteeRequested(\n uint256 indexed e3Id,\n uint256 seed,\n uint32[2] threshold,\n uint256 requestBlock,\n uint256 submissionDeadline\n );\n\n /// @notice This event MUST be emitted when a ticket is submitted for sortition\n /// @param e3Id ID of the E3 computation\n /// @param node Address of the ciphernode submitting the ticket\n /// @param ticketId The ticket number being submitted\n /// @param score The computed score for the ticket\n event TicketSubmitted(\n uint256 indexed e3Id,\n address indexed node,\n uint256 ticketId,\n uint256 score\n );\n\n /// @notice This event MUST be emitted when a committee is finalized\n /// @param e3Id ID of the E3 computation\n /// @param committee Array of selected ciphernode addresses\n event CommitteeFinalized(uint256 indexed e3Id, address[] committee);\n\n /// @notice This event MUST be emitted when a committee is selected for an E3.\n /// @param e3Id ID of the E3 for which the committee was selected.\n /// @param publicKey Public key of the committee.\n event CommitteePublished(\n uint256 indexed e3Id,\n address[] nodes,\n bytes publicKey\n );\n\n /// @notice This event MUST be emitted when a committee's active status changes.\n /// @param e3Id ID of the E3 for which the committee status changed.\n /// @param active True if committee is now active, false if completed.\n event CommitteeActivationChanged(uint256 indexed e3Id, bool active);\n\n /// @notice This event MUST be emitted when `enclave` is set.\n /// @param enclave Address of the enclave contract.\n event EnclaveSet(address indexed enclave);\n\n /// @notice This event MUST be emitted when a ciphernode is added to the registry.\n /// @param node Address of the ciphernode.\n /// @param index Index of the ciphernode in the registry.\n /// @param numNodes Number of ciphernodes in the registry.\n /// @param size Size of the registry.\n event CiphernodeAdded(\n address indexed node,\n uint256 index,\n uint256 numNodes,\n uint256 size\n );\n\n /// @notice This event MUST be emitted when a ciphernode is removed from the registry.\n /// @param node Address of the ciphernode.\n /// @param index Index of the ciphernode in the registry.\n /// @param numNodes Number of ciphernodes in the registry.\n /// @param size Size of the registry.\n event CiphernodeRemoved(\n address indexed node,\n uint256 index,\n uint256 numNodes,\n uint256 size\n );\n\n /// @notice This event MUST be emitted any time the `sortitionSubmissionWindow` is set.\n /// @param sortitionSubmissionWindow The submission window for the E3 sortition in seconds.\n event SortitionSubmissionWindowSet(uint256 sortitionSubmissionWindow);\n\n /// @notice Check if a ciphernode is eligible for committee selection\n /// @dev A ciphernode is eligible if it is enabled in the registry and meets bonding requirements\n /// @param ciphernode Address of the ciphernode to check\n /// @return eligible Whether the ciphernode is eligible for committee selection\n function isCiphernodeEligible(address ciphernode) external returns (bool);\n\n /// @notice Check if a ciphernode is enabled in the registry\n /// @param node Address of the ciphernode\n /// @return enabled Whether the ciphernode is enabled\n function isEnabled(address node) external view returns (bool enabled);\n\n /// @notice Add a ciphernode to the registry\n /// @param node Address of the ciphernode to add\n function addCiphernode(address node) external;\n\n /// @notice Remove a ciphernode from the registry\n /// @param node Address of the ciphernode to remove\n /// @param siblingNodes Array of sibling node indices for tree operations\n function removeCiphernode(\n address node,\n uint256[] calldata siblingNodes\n ) external;\n\n /// @notice Initiates the committee selection process for a specified E3.\n /// @dev This function MUST revert when not called by the Enclave contract.\n /// @param e3Id ID of the E3 for which to select the committee.\n /// @param seed Random seed for score computation.\n /// @param threshold The M/N threshold for the committee.\n /// @return success True if committee selection was successfully initiated.\n function requestCommittee(\n uint256 e3Id,\n uint256 seed,\n uint32[2] calldata threshold\n ) external returns (bool success);\n\n /// @notice Publishes the public key resulting from the committee selection process.\n /// @dev This function MUST revert if not called by the owner.\n /// @param e3Id ID of the E3 for which to select the committee.\n /// @param nodes Array of ciphernode addresses selected for the committee.\n /// @param publicKey The public key generated by the given committee.\n function publishCommittee(\n uint256 e3Id,\n address[] calldata nodes,\n bytes calldata publicKey\n ) external;\n\n /// @notice This function should be called by the Enclave contract to get the public key of a committee.\n /// @dev This function MUST revert if no committee has been requested for the given E3.\n /// @dev This function MUST revert if the committee has not yet published a public key.\n /// @param e3Id ID of the E3 for which to get the committee public key.\n /// @return publicKeyHash The hash of the public key of the given committee.\n function committeePublicKey(\n uint256 e3Id\n ) external view returns (bytes32 publicKeyHash);\n\n /// @notice This function should be called by the Enclave contract to get the committee for a given E3.\n /// @dev This function MUST revert if no committee has been requested for the given E3.\n /// @param e3Id ID of the E3 for which to get the committee.\n /// @return committeeNodes The nodes in the committee for the given E3.\n function getCommitteeNodes(\n uint256 e3Id\n ) external view returns (address[] memory committeeNodes);\n\n /// @notice Returns the current root of the ciphernode IMT\n /// @return Current IMT root\n function root() external view returns (uint256);\n\n /// @notice Returns the IMT root at the time a committee was requested\n /// @param e3Id ID of the E3\n /// @return IMT root at time of committee request\n function rootAt(uint256 e3Id) external view returns (uint256);\n\n /// @notice Returns the current size of the ciphernode IMT\n /// @return Size of the IMT\n function treeSize() external view returns (uint256);\n\n /// @notice Returns the address of the bonding registry\n /// @return Address of the bonding registry contract\n function getBondingRegistry() external view returns (address);\n\n /// @notice Sets the Enclave contract address\n /// @dev Only callable by owner\n /// @param _enclave Address of the Enclave contract\n function setEnclave(address _enclave) external;\n\n /// @notice Sets the bonding registry contract address\n /// @dev Only callable by owner\n /// @param _bondingRegistry Address of the bonding registry contract\n function setBondingRegistry(address _bondingRegistry) external;\n\n /// @notice This function should be called to set the submission window for the E3 sortition.\n /// @param _sortitionSubmissionWindow The submission window for the E3 sortition in seconds.\n function setSortitionSubmissionWindow(\n uint256 _sortitionSubmissionWindow\n ) external;\n\n /// @notice Submit a ticket for sortition\n /// @dev Validates ticket against node's balance at request block\n /// @param e3Id ID of the E3 computation\n /// @param ticketNumber The ticket number to submit\n function submitTicket(uint256 e3Id, uint256 ticketNumber) external;\n\n /// @notice Finalize the committee after submission window closes\n /// @param e3Id ID of the E3 computation\n function finalizeCommittee(uint256 e3Id) external;\n\n /// @notice Check if submission window is still open for an E3\n /// @param e3Id ID of the E3 computation\n /// @return Whether the submission window is open\n function isOpen(uint256 e3Id) external view returns (bool);\n}\n"
|
|
250
|
+
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\npragma solidity >=0.8.27;\n\n/**\n * @title ICiphernodeRegistry\n * @notice Interface for managing ciphernode registration and committee selection\n * @dev This registry maintains an Incremental Merkle Tree (IMT) of registered ciphernodes\n * and coordinates committee selection for E3 computations\n */\ninterface ICiphernodeRegistry {\n /// @notice Struct representing the sortition state for an E3 round.\n /// @param initialized Whether the round has been initialized.\n /// @param finalized Whether the round has been finalized.\n /// @param requestBlock The block number when the committee was requested.\n /// @param submissionDeadline The deadline for submitting tickets.\n /// @param threshold The M/N threshold for the committee ([M, N]).\n /// @param publicKey Hash of the committee's public key.\n /// @param seed The seed for the round.\n /// @param topNodes The top nodes in the round.\n /// @param committee The committee for the round.\n /// @param submitted Mapping of nodes to their submission status.\n /// @param scoreOf Mapping of nodes to their scores.\n struct Committee {\n bool initialized;\n bool finalized;\n uint256 seed;\n uint256 requestBlock;\n uint256 submissionDeadline;\n bytes32 publicKey;\n uint32[2] threshold;\n address[] topNodes;\n address[] committee;\n mapping(address node => bool submitted) submitted;\n mapping(address node => uint256 score) scoreOf;\n }\n\n /// @notice This event MUST be emitted when a committee is selected for an E3.\n /// @param e3Id ID of the E3 for which the committee was selected.\n /// @param seed Random seed for score computation.\n /// @param threshold The M/N threshold for the committee.\n /// @param requestBlock Block number for snapshot validation.\n /// @param submissionDeadline Deadline for submitting tickets.\n event CommitteeRequested(\n uint256 indexed e3Id,\n uint256 seed,\n uint32[2] threshold,\n uint256 requestBlock,\n uint256 submissionDeadline\n );\n\n /// @notice This event MUST be emitted when a ticket is submitted for sortition\n /// @param e3Id ID of the E3 computation\n /// @param node Address of the ciphernode submitting the ticket\n /// @param ticketId The ticket number being submitted\n /// @param score The computed score for the ticket\n event TicketSubmitted(\n uint256 indexed e3Id,\n address indexed node,\n uint256 ticketId,\n uint256 score\n );\n\n /// @notice This event MUST be emitted when a committee is finalized\n /// @param e3Id ID of the E3 computation\n /// @param committee Array of selected ciphernode addresses\n event CommitteeFinalized(uint256 indexed e3Id, address[] committee);\n\n /// @notice This event MUST be emitted when a committee is selected for an E3.\n /// @param e3Id ID of the E3 for which the committee was selected.\n /// @param publicKey Public key of the committee.\n event CommitteePublished(\n uint256 indexed e3Id,\n address[] nodes,\n bytes publicKey\n );\n\n /// @notice This event MUST be emitted when a committee's active status changes.\n /// @param e3Id ID of the E3 for which the committee status changed.\n /// @param active True if committee is now active, false if completed.\n event CommitteeActivationChanged(uint256 indexed e3Id, bool active);\n\n /// @notice This event MUST be emitted when `enclave` is set.\n /// @param enclave Address of the enclave contract.\n event EnclaveSet(address indexed enclave);\n\n /// @notice This event MUST be emitted when a ciphernode is added to the registry.\n /// @param node Address of the ciphernode.\n /// @param index Index of the ciphernode in the registry.\n /// @param numNodes Number of ciphernodes in the registry.\n /// @param size Size of the registry.\n event CiphernodeAdded(\n address indexed node,\n uint256 index,\n uint256 numNodes,\n uint256 size\n );\n\n /// @notice This event MUST be emitted when a ciphernode is removed from the registry.\n /// @param node Address of the ciphernode.\n /// @param index Index of the ciphernode in the registry.\n /// @param numNodes Number of ciphernodes in the registry.\n /// @param size Size of the registry.\n event CiphernodeRemoved(\n address indexed node,\n uint256 index,\n uint256 numNodes,\n uint256 size\n );\n\n /// @notice This event MUST be emitted any time the `sortitionSubmissionWindow` is set.\n /// @param sortitionSubmissionWindow The submission window for the E3 sortition in seconds.\n event SortitionSubmissionWindowSet(uint256 sortitionSubmissionWindow);\n\n /// @notice Check if a ciphernode is eligible for committee selection\n /// @dev A ciphernode is eligible if it is enabled in the registry and meets bonding requirements\n /// @param ciphernode Address of the ciphernode to check\n /// @return eligible Whether the ciphernode is eligible for committee selection\n function isCiphernodeEligible(address ciphernode) external returns (bool);\n\n /// @notice Check if a ciphernode is enabled in the registry\n /// @param node Address of the ciphernode\n /// @return enabled Whether the ciphernode is enabled\n function isEnabled(address node) external view returns (bool enabled);\n\n /// @notice Add a ciphernode to the registry\n /// @param node Address of the ciphernode to add\n function addCiphernode(address node) external;\n\n /// @notice Remove a ciphernode from the registry\n /// @param node Address of the ciphernode to remove\n /// @param siblingNodes Array of sibling node indices for tree operations\n function removeCiphernode(\n address node,\n uint256[] calldata siblingNodes\n ) external;\n\n /// @notice Initiates the committee selection process for a specified E3.\n /// @dev This function MUST revert when not called by the Enclave contract.\n /// @param e3Id ID of the E3 for which to select the committee.\n /// @param seed Random seed for score computation.\n /// @param threshold The M/N threshold for the committee.\n /// @return success True if committee selection was successfully initiated.\n function requestCommittee(\n uint256 e3Id,\n uint256 seed,\n uint32[2] calldata threshold\n ) external returns (bool success);\n\n /// @notice Publishes the public key resulting from the committee selection process.\n /// @dev This function MUST revert if not called by the owner.\n /// @param e3Id ID of the E3 for which to select the committee.\n /// @param nodes Array of ciphernode addresses selected for the committee.\n /// @param publicKey The public key generated by the given committee.\n /// @param publicKeyHash The hash of the public key.\n function publishCommittee(\n uint256 e3Id,\n address[] calldata nodes,\n bytes calldata publicKey,\n bytes32 publicKeyHash\n ) external;\n\n /// @notice This function should be called by the Enclave contract to get the public key of a committee.\n /// @dev This function MUST revert if no committee has been requested for the given E3.\n /// @dev This function MUST revert if the committee has not yet published a public key.\n /// @param e3Id ID of the E3 for which to get the committee public key.\n /// @return publicKeyHash The hash of the public key of the given committee.\n function committeePublicKey(\n uint256 e3Id\n ) external view returns (bytes32 publicKeyHash);\n\n /// @notice This function should be called by the Enclave contract to get the committee for a given E3.\n /// @dev This function MUST revert if no committee has been requested for the given E3.\n /// @param e3Id ID of the E3 for which to get the committee.\n /// @return committeeNodes The nodes in the committee for the given E3.\n function getCommitteeNodes(\n uint256 e3Id\n ) external view returns (address[] memory committeeNodes);\n\n /// @notice Returns the current root of the ciphernode IMT\n /// @return Current IMT root\n function root() external view returns (uint256);\n\n /// @notice Returns the IMT root at the time a committee was requested\n /// @param e3Id ID of the E3\n /// @return IMT root at time of committee request\n function rootAt(uint256 e3Id) external view returns (uint256);\n\n /// @notice Returns the current size of the ciphernode IMT\n /// @return Size of the IMT\n function treeSize() external view returns (uint256);\n\n /// @notice Returns the address of the bonding registry\n /// @return Address of the bonding registry contract\n function getBondingRegistry() external view returns (address);\n\n /// @notice Sets the Enclave contract address\n /// @dev Only callable by owner\n /// @param _enclave Address of the Enclave contract\n function setEnclave(address _enclave) external;\n\n /// @notice Sets the bonding registry contract address\n /// @dev Only callable by owner\n /// @param _bondingRegistry Address of the bonding registry contract\n function setBondingRegistry(address _bondingRegistry) external;\n\n /// @notice This function should be called to set the submission window for the E3 sortition.\n /// @param _sortitionSubmissionWindow The submission window for the E3 sortition in seconds.\n function setSortitionSubmissionWindow(\n uint256 _sortitionSubmissionWindow\n ) external;\n\n /// @notice Submit a ticket for sortition\n /// @dev Validates ticket against node's balance at request block\n /// @param e3Id ID of the E3 computation\n /// @param ticketNumber The ticket number to submit\n function submitTicket(uint256 e3Id, uint256 ticketNumber) external;\n\n /// @notice Finalize the committee after submission window closes\n /// @param e3Id ID of the E3 computation\n function finalizeCommittee(uint256 e3Id) external;\n\n /// @notice Check if submission window is still open for an E3\n /// @param e3Id ID of the E3 computation\n /// @return Whether the submission window is open\n function isOpen(uint256 e3Id) external view returns (bool);\n}\n"
|
|
251
251
|
},
|
|
252
252
|
"project/contracts/interfaces/IComputeProvider.sol": {
|
|
253
253
|
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\npragma solidity >=0.8.27;\n\nimport { IDecryptionVerifier } from \"./IDecryptionVerifier.sol\";\n\n/**\n * @title IComputeProvider\n * @notice Interface for compute provider validation and configuration\n * @dev Compute providers define how computations are executed and verified in the E3 system\n */\ninterface IComputeProvider {\n /// @notice Validate compute provider parameters and return the appropriate decryption verifier\n /// @dev This function is called by the Enclave contract during E3 request to validate\n /// compute provider configuration\n /// @param e3Id ID of the E3 computation\n /// @param seed Random seed for the computation\n /// @param params ABI encoded compute provider parameters\n /// @return decryptionVerifier The decryption verifier contract to use for this computation\n function validate(\n uint256 e3Id,\n uint256 seed,\n bytes calldata params\n ) external returns (IDecryptionVerifier decryptionVerifier);\n}\n"
|
|
@@ -256,13 +256,13 @@
|
|
|
256
256
|
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\npragma solidity >=0.8.27;\n\n/**\n * @title IDecryptionVerifier\n * @notice Interface for verifying decrypted computation outputs\n * @dev Implements cryptographic verification of plaintext outputs from encrypted computations\n */\ninterface IDecryptionVerifier {\n /// @notice Verify the decryption of a computation output\n /// @dev This function is called by the Enclave contract when plaintext output is published\n /// @param e3Id ID of the E3 computation\n /// @param plaintextOutputHash The keccak256 hash of the plaintext output to be verified\n /// @param proof ABI encoded proof of the decryption validity\n /// @return success Whether the plaintextOutputHash was successfully verified\n function verify(\n uint256 e3Id,\n bytes32 plaintextOutputHash,\n bytes memory proof\n ) external view returns (bool success);\n}\n"
|
|
257
257
|
},
|
|
258
258
|
"project/contracts/interfaces/IE3.sol": {
|
|
259
|
-
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\npragma solidity >=0.8.27;\n\nimport { IE3Program } from \"./IE3Program.sol\";\nimport { IDecryptionVerifier } from \"./IDecryptionVerifier.sol\";\n\n/**\n * @title E3\n * @notice Represents a complete E3 (Encrypted Execution Environment) computation request and its lifecycle\n * @dev This struct tracks all parameters, state, and results of an encrypted computation\n * from request through completion\n * @param seed Random seed for committee selection and computation initialization\n * @param threshold M/N threshold for the committee (M required out of N total members)\n * @param requestBlock Block number when the E3 computation was requested\n * @param startWindow Start window for the computation: index 0 is minimum block, index 1 is the maximum block\n * @param duration Duration of the E3 computation in blocks or time units\n * @param expiration Timestamp when committee duties expire and computation is considered failed\n * @param encryptionSchemeId Identifier for the encryption scheme used in this computation\n * @param e3Program Address of the E3 Program contract that validates and verifies the computation\n * @param e3ProgramParams ABI encoded computation parameters specific to the E3 program\n * @param customParams Arbitrary ABI-encoded application-defined parameters.\n * @param decryptionVerifier Address of the output verifier contract for decryption verification\n * @param committeePublicKey
|
|
259
|
+
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\npragma solidity >=0.8.27;\n\nimport { IE3Program } from \"./IE3Program.sol\";\nimport { IDecryptionVerifier } from \"./IDecryptionVerifier.sol\";\n\n/**\n * @title E3\n * @notice Represents a complete E3 (Encrypted Execution Environment) computation request and its lifecycle\n * @dev This struct tracks all parameters, state, and results of an encrypted computation\n * from request through completion\n * @param seed Random seed for committee selection and computation initialization\n * @param threshold M/N threshold for the committee (M required out of N total members)\n * @param requestBlock Block number when the E3 computation was requested\n * @param startWindow Start window for the computation: index 0 is minimum block, index 1 is the maximum block\n * @param duration Duration of the E3 computation in blocks or time units\n * @param expiration Timestamp when committee duties expire and computation is considered failed\n * @param encryptionSchemeId Identifier for the encryption scheme used in this computation\n * @param e3Program Address of the E3 Program contract that validates and verifies the computation\n * @param e3ProgramParams ABI encoded computation parameters specific to the E3 program\n * @param customParams Arbitrary ABI-encoded application-defined parameters.\n * @param decryptionVerifier Address of the output verifier contract for decryption verification\n * @param committeePublicKey Hash of the public key of the selected committee for this computation\n * @param ciphertextOutput Hash of the encrypted output data produced by the computation\n * @param plaintextOutput Decrypted output data after committee decryption\n * @param requester Address of the entity that requested the E3 computation\n */\nstruct E3 {\n uint256 seed;\n uint32[2] threshold;\n uint256 requestBlock;\n uint256[2] startWindow;\n uint256 duration;\n uint256 expiration;\n bytes32 encryptionSchemeId;\n IE3Program e3Program;\n bytes e3ProgramParams;\n bytes customParams;\n IDecryptionVerifier decryptionVerifier;\n bytes32 committeePublicKey;\n bytes32 ciphertextOutput;\n bytes plaintextOutput;\n address requester;\n}\n"
|
|
260
260
|
},
|
|
261
261
|
"project/contracts/interfaces/IE3Program.sol": {
|
|
262
262
|
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\npragma solidity >=0.8.27;\n\n/**\n * @title IE3Program\n * @notice Interface for E3 program validation and verification\n * @dev E3 programs define the computation logic and validation rules for encrypted execution environments\n */\ninterface IE3Program {\n /// @notice Validate E3 computation parameters and return encryption scheme and input validator\n /// @dev This function is called by the Enclave contract during E3 request to configure the computation\n /// @param e3Id ID of the E3 computation\n /// @param seed Random seed for the computation\n /// @param e3ProgramParams ABI encoded E3 program parameters\n /// @param computeProviderParams ABI encoded compute provider parameters\n /// @return encryptionSchemeId ID of the encryption scheme to be used for the computation\n function validate(\n uint256 e3Id,\n uint256 seed,\n bytes calldata e3ProgramParams,\n bytes calldata computeProviderParams\n ) external returns (bytes32 encryptionSchemeId);\n\n /// @notice Verify the ciphertext output of an E3 computation\n /// @dev This function is called by the Enclave contract when ciphertext output is published\n /// @param e3Id ID of the E3 computation\n /// @param ciphertextOutputHash The keccak256 hash of output data to be verified\n /// @param proof ABI encoded data to verify the ciphertextOutputHash\n /// @return success Whether the output data is valid\n function verify(\n uint256 e3Id,\n bytes32 ciphertextOutputHash,\n bytes memory proof\n ) external returns (bool success);\n\n /// @notice Validate and process input data for a computation\n /// @dev This function is called by the Enclave contract when input is published\n /// @param e3Id ID of the E3 computation\n /// @param sender The account that is submitting the input\n /// @param data The input data to be validated\n function validateInput(\n uint256 e3Id,\n address sender,\n bytes memory data\n ) external;\n}\n"
|
|
263
263
|
},
|
|
264
264
|
"project/contracts/interfaces/IEnclave.sol": {
|
|
265
|
-
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\npragma solidity >=0.8.27;\n\nimport { E3, IE3Program } from \"./IE3.sol\";\nimport { ICiphernodeRegistry } from \"./ICiphernodeRegistry.sol\";\nimport { IBondingRegistry } from \"./IBondingRegistry.sol\";\nimport { IDecryptionVerifier } from \"./IDecryptionVerifier.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IEnclave {\n ////////////////////////////////////////////////////////////\n // //\n // Events //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice This event MUST be emitted when an Encrypted Execution Environment (E3) is successfully requested.\n /// @param e3Id ID of the E3.\n /// @param e3 Details of the E3.\n /// @param e3Program Address of the Computation module selected.\n event E3Requested(uint256 e3Id, E3 e3, IE3Program indexed e3Program);\n\n /// @notice This event MUST be emitted when an Encrypted Execution Environment (E3) is successfully activated.\n /// @param e3Id ID of the E3.\n /// @param expiration Timestamp when committee duties expire.\n /// @param committeePublicKey Public key of the committee.\n event E3Activated(\n uint256 e3Id,\n uint256 expiration,\n bytes committeePublicKey\n );\n\n /// @notice This event MUST be emitted when an input to an Encrypted Execution Environment (E3) is\n /// successfully published.\n /// @param e3Id ID of the E3.\n /// @param data ABI encoded input data.\n event InputPublished(\n uint256 indexed e3Id,\n bytes data,\n uint256 inputHash,\n uint256 index\n );\n\n /// @notice This event MUST be emitted when the plaintext output of an Encrypted Execution Environment (E3)\n /// is successfully published.\n /// @param e3Id ID of the E3.\n /// @param plaintextOutput ABI encoded plaintext output.\n event PlaintextOutputPublished(uint256 indexed e3Id, bytes plaintextOutput);\n\n /// @notice This event MUST be emitted when the ciphertext output of an Encrypted Execution Environment (E3)\n /// is successfully published.\n /// @param e3Id ID of the E3.\n /// @param ciphertextOutput ABI encoded ciphertext output.\n event CiphertextOutputPublished(\n uint256 indexed e3Id,\n bytes ciphertextOutput\n );\n\n /// @notice This event MUST be emitted any time the `maxDuration` is set.\n /// @param maxDuration The maximum duration of a computation in seconds.\n event MaxDurationSet(uint256 maxDuration);\n\n /// @notice This event MUST be emitted any time the CiphernodeRegistry is set.\n /// @param ciphernodeRegistry The address of the CiphernodeRegistry contract.\n event CiphernodeRegistrySet(address ciphernodeRegistry);\n\n /// @notice This event MUST be emitted any time the BondingRegistry is set.\n /// @param bondingRegistry The address of the BondingRegistry contract.\n event BondingRegistrySet(address bondingRegistry);\n\n /// @notice This event MUST be emitted any time the fee token is set.\n /// @param feeToken The address of the fee token.\n event FeeTokenSet(address feeToken);\n\n /// @notice This event MUST be emitted when rewards are distributed to committee members.\n /// @param e3Id The ID of the E3 computation.\n /// @param nodes The addresses of the committee members receiving rewards.\n /// @param amounts The reward amounts for each committee member.\n event RewardsDistributed(\n uint256 indexed e3Id,\n address[] nodes,\n uint256[] amounts\n );\n\n /// @notice The event MUST be emitted any time an encryption scheme is enabled.\n /// @param encryptionSchemeId The ID of the encryption scheme that was enabled.\n event EncryptionSchemeEnabled(bytes32 encryptionSchemeId);\n\n /// @notice This event MUST be emitted any time an encryption scheme is disabled.\n /// @param encryptionSchemeId The ID of the encryption scheme that was disabled.\n event EncryptionSchemeDisabled(bytes32 encryptionSchemeId);\n\n /// @notice This event MUST be emitted any time a E3 Program is enabled.\n /// @param e3Program The address of the E3 Program.\n event E3ProgramEnabled(IE3Program e3Program);\n\n /// @notice This event MUST be emitted any time a E3 Program is disabled.\n /// @param e3Program The address of the E3 Program.\n event E3ProgramDisabled(IE3Program e3Program);\n\n /// @notice Emitted when the allowed E3 encryption scheme parameters are configured.\n /// @param e3ProgramParams Array of encoded encryption scheme parameters (e.g, for BFV)\n event AllowedE3ProgramsParamsSet(bytes[] e3ProgramParams);\n\n ////////////////////////////////////////////////////////////\n // //\n // Structs //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice This struct contains the parameters to submit a request to Enclave.\n /// @param threshold The M/N threshold for the committee.\n /// @param startWindow The start window for the computation.\n /// @param duration The duration of the computation in seconds.\n /// @param e3Program The address of the E3 Program.\n /// @param e3ProgramParams The ABI encoded computation parameters.\n /// @param computeProviderParams The ABI encoded compute provider parameters.\n /// @param customParams Arbitrary ABI-encoded application-defined parameters.\n struct E3RequestParams {\n uint32[2] threshold;\n uint256[2] startWindow;\n uint256 duration;\n IE3Program e3Program;\n bytes e3ProgramParams;\n bytes computeProviderParams;\n bytes customParams;\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Core Entrypoints //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice This function should be called to request a computation within an Encrypted Execution Environment (E3).\n /// @dev This function MUST emit the E3Requested event.\n /// @param requestParams The parameters for the E3 request.\n /// @return e3Id ID of the E3.\n /// @return e3 The E3 struct.\n function request(\n E3RequestParams calldata requestParams\n ) external returns (uint256 e3Id, E3 memory e3);\n\n /// @notice This function should be called to activate an Encrypted Execution Environment (E3) once it has been\n /// initialized and is ready for input.\n /// @dev This function MUST emit the E3Activated event.\n /// @dev This function MUST revert if the given E3 has not yet been requested.\n /// @dev This function MUST revert if the selected node committee has not yet published a public key.\n /// @param e3Id ID of the E3.\n /// @param publicKey Public key of the committee.\n /// @return success True if the E3 was successfully activated.\n function activate(\n uint256 e3Id,\n bytes calldata publicKey\n ) external returns (bool success);\n\n /// @notice This function should be called to publish input data for Encrypted Execution Environment (E3).\n /// @dev This function MUST revert if the E3 is not yet activated.\n /// @dev This function MUST emit the InputPublished event.\n /// @param e3Id ID of the E3.\n /// @param data ABI encoded input data to publish.\n /// @return success True if the input was successfully published.\n function publishInput(\n uint256 e3Id,\n bytes calldata data\n ) external returns (bool success);\n\n /// @notice This function should be called to publish output data for an Encrypted Execution Environment (E3).\n /// @dev This function MUST emit the CiphertextOutputPublished event.\n /// @param e3Id ID of the E3.\n /// @param ciphertextOutput ABI encoded output data to verify.\n /// @param proof ABI encoded data to verify the ciphertextOutput.\n /// @return success True if the output was successfully published.\n function publishCiphertextOutput(\n uint256 e3Id,\n bytes calldata ciphertextOutput,\n bytes calldata proof\n ) external returns (bool success);\n\n /// @notice This function publishes the plaintext output of an Encrypted Execution Environment (E3).\n /// @dev This function MUST revert if the output has not been published.\n /// @dev This function MUST emit the PlaintextOutputPublished event.\n /// @param e3Id ID of the E3.\n /// @param plaintextOutput ABI encoded plaintext output.\n /// @param proof ABI encoded data to verify the plaintextOutput.\n function publishPlaintextOutput(\n uint256 e3Id,\n bytes calldata plaintextOutput,\n bytes calldata proof\n ) external returns (bool success);\n\n ////////////////////////////////////////////////////////////\n // //\n // Set Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice This function should be called to set the maximum duration of requested computations.\n /// @param _maxDuration The maximum duration of a computation in seconds.\n /// @return success True if the max duration was successfully set.\n function setMaxDuration(\n uint256 _maxDuration\n ) external returns (bool success);\n\n /// @notice Sets the Ciphernode Registry contract address.\n /// @dev This function MUST revert if the address is zero or the same as the current registry.\n /// @param _ciphernodeRegistry The address of the new Ciphernode Registry contract.\n /// @return success True if the registry was successfully set.\n function setCiphernodeRegistry(\n ICiphernodeRegistry _ciphernodeRegistry\n ) external returns (bool success);\n\n /// @notice Sets the Bonding Registry contract address.\n /// @dev This function MUST revert if the address is zero or the same as the current registry.\n /// @param _bondingRegistry The address of the new Bonding Registry contract.\n /// @return success True if the registry was successfully set.\n function setBondingRegistry(\n IBondingRegistry _bondingRegistry\n ) external returns (bool success);\n\n /// @notice Sets the fee token used for E3 payments.\n /// @dev This function MUST revert if the address is zero or the same as the current fee token.\n /// @param _feeToken The address of the new fee token.\n /// @return success True if the fee token was successfully set.\n function setFeeToken(IERC20 _feeToken) external returns (bool success);\n\n /// @notice This function should be called to enable an E3 Program.\n /// @param e3Program The address of the E3 Program.\n /// @return success True if the E3 Program was successfully enabled.\n function enableE3Program(\n IE3Program e3Program\n ) external returns (bool success);\n\n /// @notice This function should be called to disable an E3 Program.\n /// @param e3Program The address of the E3 Program.\n /// @return success True if the E3 Program was successfully disabled.\n function disableE3Program(\n IE3Program e3Program\n ) external returns (bool success);\n\n /// @notice Sets or enables a decryption verifier for a specific encryption scheme.\n /// @dev This function MUST revert if the verifier address is zero or already set to the same value.\n /// @param encryptionSchemeId The unique identifier for the encryption scheme.\n /// @param decryptionVerifier The address of the decryption verifier contract.\n /// @return success True if the verifier was successfully set.\n function setDecryptionVerifier(\n bytes32 encryptionSchemeId,\n IDecryptionVerifier decryptionVerifier\n ) external returns (bool success);\n\n /// @notice Disables a previously enabled encryption scheme.\n /// @dev This function MUST revert if the encryption scheme is not currently enabled.\n /// @param encryptionSchemeId The unique identifier for the encryption scheme to disable.\n /// @return success True if the encryption scheme was successfully disabled.\n function disableEncryptionScheme(\n bytes32 encryptionSchemeId\n ) external returns (bool success);\n\n /// @notice Sets the allowed E3 program parameters.\n /// @dev This function enables specific parameter sets for E3 programs (e.g., BFV encryption parameters).\n /// @param _e3ProgramsParams Array of ABI encoded parameter sets to allow.\n /// @return success True if the parameters were successfully set.\n function setE3ProgramsParams(\n bytes[] memory _e3ProgramsParams\n ) external returns (bool success);\n\n ////////////////////////////////////////////////////////////\n // //\n // Get Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice This function should be called to retrieve the details of an Encrypted Execution Environment (E3).\n /// @dev This function MUST revert if the E3 does not exist.\n /// @param e3Id ID of the E3.\n /// @return e3 The struct representing the requested E3.\n function getE3(uint256 e3Id) external view returns (E3 memory e3);\n\n /// @notice This function returns the fee of an E3\n /// @dev This function MUST revert if the E3 parameters are invalid.\n /// @param e3Params the struct representing the E3 request parameters\n /// @return fee the fee of the E3\n function getE3Quote(\n E3RequestParams calldata e3Params\n ) external view returns (uint256 fee);\n\n /// @notice Returns the decryption verifier for a given encryption scheme.\n /// @param encryptionSchemeId The unique identifier for the encryption scheme.\n /// @return The decryption verifier contract for the specified encryption scheme.\n function getDecryptionVerifier(\n bytes32 encryptionSchemeId\n ) external view returns (IDecryptionVerifier);\n\n /// @notice Returns the ERC20 token used to pay for E3 fees.\n function feeToken() external view returns (IERC20);\n}\n"
|
|
265
|
+
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\npragma solidity >=0.8.27;\n\nimport { E3, IE3Program } from \"./IE3.sol\";\nimport { ICiphernodeRegistry } from \"./ICiphernodeRegistry.sol\";\nimport { IBondingRegistry } from \"./IBondingRegistry.sol\";\nimport { IDecryptionVerifier } from \"./IDecryptionVerifier.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IEnclave {\n ////////////////////////////////////////////////////////////\n // //\n // Events //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice This event MUST be emitted when an Encrypted Execution Environment (E3) is successfully requested.\n /// @param e3Id ID of the E3.\n /// @param e3 Details of the E3.\n /// @param e3Program Address of the Computation module selected.\n event E3Requested(uint256 e3Id, E3 e3, IE3Program indexed e3Program);\n\n /// @notice This event MUST be emitted when an Encrypted Execution Environment (E3) is successfully activated.\n /// @param e3Id ID of the E3.\n /// @param expiration Timestamp when committee duties expire.\n /// @param committeePublicKey Hash of the public key of the committee.\n event E3Activated(\n uint256 e3Id,\n uint256 expiration,\n bytes32 committeePublicKey\n );\n\n /// @notice This event MUST be emitted when an input to an Encrypted Execution Environment (E3) is\n /// successfully published.\n /// @param e3Id ID of the E3.\n /// @param data ABI encoded input data.\n event InputPublished(\n uint256 indexed e3Id,\n bytes data,\n uint256 inputHash,\n uint256 index\n );\n\n /// @notice This event MUST be emitted when the plaintext output of an Encrypted Execution Environment (E3)\n /// is successfully published.\n /// @param e3Id ID of the E3.\n /// @param plaintextOutput ABI encoded plaintext output.\n event PlaintextOutputPublished(uint256 indexed e3Id, bytes plaintextOutput);\n\n /// @notice This event MUST be emitted when the ciphertext output of an Encrypted Execution Environment (E3)\n /// is successfully published.\n /// @param e3Id ID of the E3.\n /// @param ciphertextOutput ABI encoded ciphertext output.\n event CiphertextOutputPublished(\n uint256 indexed e3Id,\n bytes ciphertextOutput\n );\n\n /// @notice This event MUST be emitted any time the `maxDuration` is set.\n /// @param maxDuration The maximum duration of a computation in seconds.\n event MaxDurationSet(uint256 maxDuration);\n\n /// @notice This event MUST be emitted any time the CiphernodeRegistry is set.\n /// @param ciphernodeRegistry The address of the CiphernodeRegistry contract.\n event CiphernodeRegistrySet(address ciphernodeRegistry);\n\n /// @notice This event MUST be emitted any time the BondingRegistry is set.\n /// @param bondingRegistry The address of the BondingRegistry contract.\n event BondingRegistrySet(address bondingRegistry);\n\n /// @notice This event MUST be emitted any time the fee token is set.\n /// @param feeToken The address of the fee token.\n event FeeTokenSet(address feeToken);\n\n /// @notice This event MUST be emitted when rewards are distributed to committee members.\n /// @param e3Id The ID of the E3 computation.\n /// @param nodes The addresses of the committee members receiving rewards.\n /// @param amounts The reward amounts for each committee member.\n event RewardsDistributed(\n uint256 indexed e3Id,\n address[] nodes,\n uint256[] amounts\n );\n\n /// @notice The event MUST be emitted any time an encryption scheme is enabled.\n /// @param encryptionSchemeId The ID of the encryption scheme that was enabled.\n event EncryptionSchemeEnabled(bytes32 encryptionSchemeId);\n\n /// @notice This event MUST be emitted any time an encryption scheme is disabled.\n /// @param encryptionSchemeId The ID of the encryption scheme that was disabled.\n event EncryptionSchemeDisabled(bytes32 encryptionSchemeId);\n\n /// @notice This event MUST be emitted any time a E3 Program is enabled.\n /// @param e3Program The address of the E3 Program.\n event E3ProgramEnabled(IE3Program e3Program);\n\n /// @notice This event MUST be emitted any time a E3 Program is disabled.\n /// @param e3Program The address of the E3 Program.\n event E3ProgramDisabled(IE3Program e3Program);\n\n /// @notice Emitted when the allowed E3 encryption scheme parameters are configured.\n /// @param e3ProgramParams Array of encoded encryption scheme parameters (e.g, for BFV)\n event AllowedE3ProgramsParamsSet(bytes[] e3ProgramParams);\n\n ////////////////////////////////////////////////////////////\n // //\n // Structs //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice This struct contains the parameters to submit a request to Enclave.\n /// @param threshold The M/N threshold for the committee.\n /// @param startWindow The start window for the computation.\n /// @param duration The duration of the computation in seconds.\n /// @param e3Program The address of the E3 Program.\n /// @param e3ProgramParams The ABI encoded computation parameters.\n /// @param computeProviderParams The ABI encoded compute provider parameters.\n /// @param customParams Arbitrary ABI-encoded application-defined parameters.\n struct E3RequestParams {\n uint32[2] threshold;\n uint256[2] startWindow;\n uint256 duration;\n IE3Program e3Program;\n bytes e3ProgramParams;\n bytes computeProviderParams;\n bytes customParams;\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Core Entrypoints //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice This function should be called to request a computation within an Encrypted Execution Environment (E3).\n /// @dev This function MUST emit the E3Requested event.\n /// @param requestParams The parameters for the E3 request.\n /// @return e3Id ID of the E3.\n /// @return e3 The E3 struct.\n function request(\n E3RequestParams calldata requestParams\n ) external returns (uint256 e3Id, E3 memory e3);\n\n /// @notice This function should be called to activate an Encrypted Execution Environment (E3) once it has been\n /// initialized and is ready for input.\n /// @dev This function MUST emit the E3Activated event.\n /// @dev This function MUST revert if the given E3 has not yet been requested.\n /// @dev This function MUST revert if the selected node committee has not yet published a public key.\n /// @param e3Id ID of the E3.\n /// @return success True if the E3 was successfully activated.\n function activate(uint256 e3Id) external returns (bool success);\n\n /// @notice This function should be called to publish input data for Encrypted Execution Environment (E3).\n /// @dev This function MUST revert if the E3 is not yet activated.\n /// @dev This function MUST emit the InputPublished event.\n /// @param e3Id ID of the E3.\n /// @param data ABI encoded input data to publish.\n /// @return success True if the input was successfully published.\n function publishInput(\n uint256 e3Id,\n bytes calldata data\n ) external returns (bool success);\n\n /// @notice This function should be called to publish output data for an Encrypted Execution Environment (E3).\n /// @dev This function MUST emit the CiphertextOutputPublished event.\n /// @param e3Id ID of the E3.\n /// @param ciphertextOutput ABI encoded output data to verify.\n /// @param proof ABI encoded data to verify the ciphertextOutput.\n /// @return success True if the output was successfully published.\n function publishCiphertextOutput(\n uint256 e3Id,\n bytes calldata ciphertextOutput,\n bytes calldata proof\n ) external returns (bool success);\n\n /// @notice This function publishes the plaintext output of an Encrypted Execution Environment (E3).\n /// @dev This function MUST revert if the output has not been published.\n /// @dev This function MUST emit the PlaintextOutputPublished event.\n /// @param e3Id ID of the E3.\n /// @param plaintextOutput ABI encoded plaintext output.\n /// @param proof ABI encoded data to verify the plaintextOutput.\n function publishPlaintextOutput(\n uint256 e3Id,\n bytes calldata plaintextOutput,\n bytes calldata proof\n ) external returns (bool success);\n\n ////////////////////////////////////////////////////////////\n // //\n // Set Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice This function should be called to set the maximum duration of requested computations.\n /// @param _maxDuration The maximum duration of a computation in seconds.\n /// @return success True if the max duration was successfully set.\n function setMaxDuration(\n uint256 _maxDuration\n ) external returns (bool success);\n\n /// @notice Sets the Ciphernode Registry contract address.\n /// @dev This function MUST revert if the address is zero or the same as the current registry.\n /// @param _ciphernodeRegistry The address of the new Ciphernode Registry contract.\n /// @return success True if the registry was successfully set.\n function setCiphernodeRegistry(\n ICiphernodeRegistry _ciphernodeRegistry\n ) external returns (bool success);\n\n /// @notice Sets the Bonding Registry contract address.\n /// @dev This function MUST revert if the address is zero or the same as the current registry.\n /// @param _bondingRegistry The address of the new Bonding Registry contract.\n /// @return success True if the registry was successfully set.\n function setBondingRegistry(\n IBondingRegistry _bondingRegistry\n ) external returns (bool success);\n\n /// @notice Sets the fee token used for E3 payments.\n /// @dev This function MUST revert if the address is zero or the same as the current fee token.\n /// @param _feeToken The address of the new fee token.\n /// @return success True if the fee token was successfully set.\n function setFeeToken(IERC20 _feeToken) external returns (bool success);\n\n /// @notice This function should be called to enable an E3 Program.\n /// @param e3Program The address of the E3 Program.\n /// @return success True if the E3 Program was successfully enabled.\n function enableE3Program(\n IE3Program e3Program\n ) external returns (bool success);\n\n /// @notice This function should be called to disable an E3 Program.\n /// @param e3Program The address of the E3 Program.\n /// @return success True if the E3 Program was successfully disabled.\n function disableE3Program(\n IE3Program e3Program\n ) external returns (bool success);\n\n /// @notice Sets or enables a decryption verifier for a specific encryption scheme.\n /// @dev This function MUST revert if the verifier address is zero or already set to the same value.\n /// @param encryptionSchemeId The unique identifier for the encryption scheme.\n /// @param decryptionVerifier The address of the decryption verifier contract.\n /// @return success True if the verifier was successfully set.\n function setDecryptionVerifier(\n bytes32 encryptionSchemeId,\n IDecryptionVerifier decryptionVerifier\n ) external returns (bool success);\n\n /// @notice Disables a previously enabled encryption scheme.\n /// @dev This function MUST revert if the encryption scheme is not currently enabled.\n /// @param encryptionSchemeId The unique identifier for the encryption scheme to disable.\n /// @return success True if the encryption scheme was successfully disabled.\n function disableEncryptionScheme(\n bytes32 encryptionSchemeId\n ) external returns (bool success);\n\n /// @notice Sets the allowed E3 program parameters.\n /// @dev This function enables specific parameter sets for E3 programs (e.g., BFV encryption parameters).\n /// @param _e3ProgramsParams Array of ABI encoded parameter sets to allow.\n /// @return success True if the parameters were successfully set.\n function setE3ProgramsParams(\n bytes[] memory _e3ProgramsParams\n ) external returns (bool success);\n\n ////////////////////////////////////////////////////////////\n // //\n // Get Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice This function should be called to retrieve the details of an Encrypted Execution Environment (E3).\n /// @dev This function MUST revert if the E3 does not exist.\n /// @param e3Id ID of the E3.\n /// @return e3 The struct representing the requested E3.\n function getE3(uint256 e3Id) external view returns (E3 memory e3);\n\n /// @notice This function returns the fee of an E3\n /// @dev This function MUST revert if the E3 parameters are invalid.\n /// @param e3Params the struct representing the E3 request parameters\n /// @return fee the fee of the E3\n function getE3Quote(\n E3RequestParams calldata e3Params\n ) external view returns (uint256 fee);\n\n /// @notice Returns the decryption verifier for a given encryption scheme.\n /// @param encryptionSchemeId The unique identifier for the encryption scheme.\n /// @return The decryption verifier contract for the specified encryption scheme.\n function getDecryptionVerifier(\n bytes32 encryptionSchemeId\n ) external view returns (IDecryptionVerifier);\n\n /// @notice Returns the ERC20 token used to pay for E3 fees.\n function feeToken() external view returns (IERC20);\n}\n"
|
|
266
266
|
},
|
|
267
267
|
"project/contracts/interfaces/ISlashingManager.sol": {
|
|
268
268
|
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\npragma solidity >=0.8.27;\n\nimport { IBondingRegistry } from \"./IBondingRegistry.sol\";\n\n/**\n * @title ISlashingManager\n * @notice Interface for managing slashing proposals, appeals, and execution\n * @dev Maintains policy table and handles slash workflows with appeals\n */\ninterface ISlashingManager {\n // ======================\n // Structs\n // ======================\n\n /**\n * @notice Slashing policy configuration for different slash reasons\n * @dev Defines penalties, proof requirements, and appeal mechanisms for each slash type\n * @param ticketPenalty Amount of ticket collateral to slash (in wei)\n * @param licensePenalty Amount of license bond to slash (in wei)\n * @param requiresProof Whether this slash type requires cryptographic proof verification\n * @param proofVerifier Address of the ISlashVerifier contract for proof validation\n * @param banNode Whether executing this slash will permanently ban the node\n * @param appealWindow Time window in seconds for operators to appeal (0 = immediate execution, no appeals)\n * @param enabled Whether this slash type is currently active and can be proposed\n */\n struct SlashPolicy {\n uint256 ticketPenalty;\n uint256 licensePenalty;\n bool requiresProof;\n address proofVerifier;\n bool banNode;\n uint256 appealWindow;\n bool enabled;\n }\n\n /**\n * @notice Slash proposal details tracking the full lifecycle of a slash\n * @dev Stores all state needed for proposal, appeal, and execution workflows\n * @param operator Address of the ciphernode operator being slashed\n * @param reason Hash of the slash reason (maps to SlashPolicy configuration)\n * @param ticketAmount Amount of ticket collateral to slash (copied from policy at proposal time)\n * @param licenseAmount Amount of license bond to slash (copied from policy at proposal time)\n * @param executed Whether the slashing penalties have been executed\n * @param appealed Whether the operator has filed an appeal\n * @param resolved Whether the appeal has been resolved by governance\n * @param appealUpheld Whether the appeal was approved (true = cancel slash, false = slash proceeds)\n * @param proposedAt Block timestamp when the slash was proposed\n * @param executableAt Block timestamp when execution becomes possible (proposedAt + appealWindow)\n * @param proposer Address that created this slash proposal\n * @param proofHash Keccak256 hash of the proof data submitted with the proposal\n * @param proofVerified Whether the proof was successfully verified by the proof verifier contract\n */\n struct SlashProposal {\n address operator;\n bytes32 reason;\n uint256 ticketAmount;\n uint256 licenseAmount;\n bool executed;\n bool appealed;\n bool resolved;\n bool appealUpheld;\n uint256 proposedAt;\n uint256 executableAt;\n address proposer;\n bytes32 proofHash;\n bool proofVerified;\n }\n\n // ======================\n // Errors\n // ======================\n\n /// @notice Thrown when a zero address is provided where a valid address is required\n error ZeroAddress();\n\n /// @notice Thrown when caller lacks required role permissions for the operation\n error Unauthorized();\n\n /// @notice Thrown when a slash policy configuration is invalid\n error InvalidPolicy();\n\n /// @notice Thrown when referencing a proposal ID that doesn't exist or is in invalid state\n error InvalidProposal();\n\n /// @notice Thrown when proof is required by policy but not provided\n error ProofRequired();\n\n /// @notice Thrown when provided proof fails verification\n error InvalidProof();\n\n /// @notice Thrown when attempting to execute a slash whose appeal was upheld\n error AppealUpheld();\n\n /// @notice Thrown when attempting to execute a slash with an unresolved appeal\n error AppealPending();\n\n /// @notice Thrown when attempting to file an appeal after the appeal window has closed\n error AppealWindowExpired();\n\n /// @notice Thrown when attempting to execute a slash before the appeal window has closed\n error AppealWindowActive();\n\n /// @notice Thrown when attempting to file a second appeal for the same proposal\n error AlreadyAppealed();\n\n /// @notice Thrown when attempting to execute a slash that has already been executed\n error AlreadyExecuted();\n\n /// @notice Thrown when attempting to resolve an appeal that has already been resolved\n error AlreadyResolved();\n\n /// @notice Thrown when referencing a slash reason that doesn't exist\n error SlashReasonNotFound();\n\n /// @notice Thrown when attempting to propose a slash for a disabled reason\n error SlashReasonDisabled();\n\n /// @notice Thrown when a banned ciphernode attempts a restricted operation\n error CiphernodeBanned();\n\n /// @notice Thrown when a policy requires proof but no verifier contract is configured\n error VerifierNotSet();\n\n // ======================\n // Events\n // ======================\n\n /**\n * @notice Emitted when a slash policy is created or updated\n * @param reason Hash of the slash reason being configured\n * @param policy The complete policy configuration including penalties and appeal settings\n */\n event SlashPolicyUpdated(bytes32 indexed reason, SlashPolicy policy);\n\n /**\n * @notice Emitted when a new slash proposal is created\n * @param proposalId Unique ID of the created proposal\n * @param operator Address of the ciphernode operator being slashed\n * @param reason Hash of the slash reason\n * @param ticketAmount Amount of ticket collateral to be slashed\n * @param licenseAmount Amount of license bond to be slashed\n * @param executableAt Timestamp when the slash can be executed (after appeal window)\n * @param proposer Address that created the proposal\n */\n event SlashProposed(\n uint256 indexed proposalId,\n address indexed operator,\n bytes32 indexed reason,\n uint256 ticketAmount,\n uint256 licenseAmount,\n uint256 executableAt,\n address proposer\n );\n\n /**\n * @notice Emitted when a slash proposal is executed and penalties are applied\n * @param proposalId ID of the executed proposal\n * @param operator Address of the slashed operator\n * @param reason Hash of the slash reason\n * @param ticketAmount Amount of ticket collateral slashed\n * @param licenseAmount Amount of license bond slashed\n * @param executed Execution status (should always be true)\n */\n event SlashExecuted(\n uint256 indexed proposalId,\n address indexed operator,\n bytes32 indexed reason,\n uint256 ticketAmount,\n uint256 licenseAmount,\n bool executed\n );\n\n /**\n * @notice Emitted when an operator files an appeal against a slash proposal\n * @param proposalId ID of the proposal being appealed\n * @param operator Address of the operator filing the appeal\n * @param reason Hash of the slash reason being appealed\n * @param evidence Evidence string provided by the operator supporting their appeal\n */\n event AppealFiled(\n uint256 indexed proposalId,\n address indexed operator,\n bytes32 indexed reason,\n string evidence\n );\n\n /**\n * @notice Emitted when governance resolves an appeal\n * @param proposalId ID of the proposal with the resolved appeal\n * @param operator Address of the operator who appealed\n * @param appealUpheld Whether the appeal was approved (true = slash cancelled, false = slash proceeds)\n * @param resolver Address of the governance account that resolved the appeal\n * @param resolution Explanation string for the resolution decision\n */\n event AppealResolved(\n uint256 indexed proposalId,\n address indexed operator,\n bool appealUpheld,\n address resolver,\n string resolution\n );\n\n /**\n * @notice Emitted when a node is banned or unbanned from the network\n * @param node Address of the node\n * @param status Whether the node is banned\n * @param reason Hash of the reason for banning or unbanning\n * @param updater Address that executed the ban (governance or contract)\n */\n event NodeBanUpdated(\n address indexed node,\n bool status,\n bytes32 indexed reason,\n address updater\n );\n\n // ======================\n // View Functions\n // ======================\n\n /**\n * @notice Retrieves the slash policy configuration for a given reason\n * @param reason Hash of the slash reason to query\n * @return policy The complete SlashPolicy struct (returns default empty struct if not configured)\n */\n function getSlashPolicy(\n bytes32 reason\n ) external view returns (SlashPolicy memory policy);\n\n /**\n * @notice Retrieves the details of a slash proposal\n * @param proposalId ID of the proposal to query\n * @return proposal The complete SlashProposal struct\n * @dev Reverts with InvalidProposal if proposalId >= totalProposals\n */\n function getSlashProposal(\n uint256 proposalId\n ) external view returns (SlashProposal memory proposal);\n\n /**\n * @notice Returns the total number of slash proposals ever created\n * @return count The total count of proposals (next proposalId will be this value)\n */\n function totalProposals() external view returns (uint256 count);\n\n /**\n * @notice Checks whether a node is currently banned\n * @param node Address of the node to check\n * @return isBanned True if the node is banned, false otherwise\n */\n function isBanned(address node) external view returns (bool isBanned);\n\n /**\n * @notice Returns the bonding registry contract used for executing slashes\n * @return registry The IBondingRegistry contract instance\n */\n function bondingRegistry()\n external\n view\n returns (IBondingRegistry registry);\n\n // ======================\n // Admin Functions\n // ======================\n\n /**\n * @notice Creates or updates the slash policy for a specific reason\n * @dev Only callable by GOVERNANCE_ROLE. Validates policy constraints before setting\n * @param reason Hash of the slash reason to configure (must be non-zero)\n * @param policy Complete policy configuration including penalties, proof requirements, and appeal settings\n * Requirements:\n * - reason must not be bytes32(0)\n * - policy.enabled must be true\n * - At least one of ticketPenalty or licensePenalty must be non-zero\n * - If requiresProof is true, proofVerifier must be set and appealWindow must be 0\n * - If requiresProof is false, appealWindow must be greater than 0\n */\n function setSlashPolicy(\n bytes32 reason,\n SlashPolicy calldata policy\n ) external;\n\n /**\n * @notice Updates the bonding registry contract address\n * @dev Only callable by DEFAULT_ADMIN_ROLE. Used to execute actual slashing of funds\n * @param newBondingRegistry Address of the new IBondingRegistry contract (must be non-zero)\n */\n function setBondingRegistry(address newBondingRegistry) external;\n\n /**\n * @notice Grants SLASHER_ROLE to an address\n * @dev Only callable by DEFAULT_ADMIN_ROLE. Slashers can propose and execute slashes\n * @param slasher Address to grant slashing permissions (must be non-zero)\n */\n function addSlasher(address slasher) external;\n\n /**\n * @notice Revokes SLASHER_ROLE from an address\n * @dev Only callable by DEFAULT_ADMIN_ROLE\n * @param slasher Address to revoke slashing permissions from\n */\n function removeSlasher(address slasher) external;\n\n /**\n * @notice Grants VERIFIER_ROLE to an address\n * @dev Only callable by DEFAULT_ADMIN_ROLE. Verifiers can validate proof-based slashes\n * @param verifier Address to grant verification permissions (must be non-zero)\n */\n function addVerifier(address verifier) external;\n\n /**\n * @notice Revokes VERIFIER_ROLE from an address\n * @dev Only callable by DEFAULT_ADMIN_ROLE\n * @param verifier Address to revoke verification permissions from\n */\n function removeVerifier(address verifier) external;\n\n // ======================\n // Slashing Functions\n // ======================\n\n /**\n * @notice Creates a new slash proposal against an operator\n * @dev Only callable by SLASHER_ROLE. Validates policy and proof if required\n * @param operator Address of the ciphernode operator to slash (must be non-zero)\n * @param reason Hash of the slash reason (must have an enabled policy configured)\n * @param proof Proof data to be verified (required if policy.requiresProof is true, can be empty otherwise)\n * @return proposalId Sequential ID of the created proposal\n * Requirements:\n * - operator must not be zero address\n * - reason must have an enabled policy configured\n * - If policy requires proof, proof must be non-empty and pass verification\n * - Caller must have SLASHER_ROLE\n */\n function proposeSlash(\n address operator,\n bytes32 reason,\n bytes calldata proof\n ) external returns (uint256 proposalId);\n\n /**\n * @notice Executes a slash proposal and applies penalties to the operator\n * @dev Only callable by SLASHER_ROLE. Validates execution conditions and applies slashing\n * @param proposalId ID of the proposal to execute (must exist and not be already executed)\n * Requirements:\n * - Proposal must exist and not be already executed\n * - For proof-required slashes: proof must be verified\n * - For evidence-based slashes: appeal window must have expired\n * - If appeal was filed and resolved, appeal must not have been upheld\n * - Caller must have SLASHER_ROLE\n * Effects:\n * - Marks proposal as executed\n * - Slashes ticket balance if ticketAmount > 0\n * - Slashes license bond if licenseAmount > 0\n * - Bans node if policy.banNode is true\n */\n function executeSlash(uint256 proposalId) external;\n\n // ======================\n // Appeal Functions\n // ======================\n\n /**\n * @notice Allows an operator to file an appeal against a slash proposal\n * @dev Only the operator being slashed can file an appeal, and only within the appeal window\n * @param proposalId ID of the proposal to appeal (must exist)\n * @param evidence String containing evidence and arguments supporting the appeal\n * Requirements:\n * - Proposal must exist\n * - Caller must be the operator being slashed\n * - Current timestamp must be before proposal.executableAt (within appeal window)\n * - Proposal must not already have an appeal filed\n */\n function fileAppeal(uint256 proposalId, string calldata evidence) external;\n\n /**\n * @notice Resolves an appeal by accepting or rejecting it\n * @dev Only callable by GOVERNANCE_ROLE. If appeal is upheld, the slash cannot be executed\n * @param proposalId ID of the proposal with the appeal to resolve (must exist and have an appeal)\n * @param appealUpheld True to uphold the appeal (cancel the slash), false to deny the appeal\n * (allow slash to proceed)\n * @param resolution String explaining the governance decision\n * Requirements:\n * - Proposal must exist and have an appeal filed\n * - Appeal must not already be resolved\n * - Caller must have GOVERNANCE_ROLE\n * Effects:\n * - Marks appeal as resolved\n * - Sets appealUpheld flag (true = slash cancelled, false = slash can proceed)\n */\n function resolveAppeal(\n uint256 proposalId,\n bool appealUpheld,\n string calldata resolution\n ) external;\n\n // ======================\n // Ban Management\n // ======================\n\n /**\n * @notice Bans or unbans a node from the network\n * @dev Only callable by GOVERNANCE_ROLE. Bans can also occur automatically via executeSlash\n * @param node Address of the node to ban (must be non-zero)\n * @param status Whether to ban the node\n * @param reason Hash of the reason for banning\n * Requirements:\n * - node must not be zero address\n * - Caller must have GOVERNANCE_ROLE\n * Effects:\n * - Sets banned[node] to status\n * - Emits NodeBanned event if status is true\n * - Emits NodeUnbanned event if status is false\n */\n function updateBanStatus(\n address node,\n bool status,\n bytes32 reason\n ) external;\n}\n"
|
|
@@ -277,13 +277,13 @@
|
|
|
277
277
|
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\npragma solidity >=0.8.27;\n\nimport {\n OwnableUpgradeable\n} from \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {\n SafeERC20\n} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { ExitQueueLib } from \"../lib/ExitQueueLib.sol\";\n\nimport { IBondingRegistry } from \"../interfaces/IBondingRegistry.sol\";\nimport { ICiphernodeRegistry } from \"../interfaces/ICiphernodeRegistry.sol\";\nimport { ISlashingManager } from \"../interfaces/ISlashingManager.sol\";\nimport { EnclaveTicketToken } from \"../token/EnclaveTicketToken.sol\";\n\n/**\n * @title BondingRegistry\n * @notice Implementation of the bonding registry managing operator ticket balances and license bonds\n * @dev Handles deposits, withdrawals, slashing, exits, and integrates with registry and slashing manager\n */\ncontract BondingRegistry is IBondingRegistry, OwnableUpgradeable {\n using SafeERC20 for IERC20;\n using ExitQueueLib for ExitQueueLib.ExitQueueState;\n\n // ======================\n // Constants\n // ======================\n\n /// @dev Reason code for ticket balance deposits\n bytes32 private constant REASON_DEPOSIT = bytes32(\"DEPOSIT\");\n\n /// @dev Reason code for ticket balance withdrawals\n bytes32 private constant REASON_WITHDRAW = bytes32(\"WITHDRAW\");\n\n /// @dev Reason code for license bond operations\n bytes32 private constant REASON_BOND = bytes32(\"BOND\");\n\n /// @dev Reason code for license unbond operations\n bytes32 private constant REASON_UNBOND = bytes32(\"UNBOND\");\n\n // ======================\n // Storage\n // ======================\n\n /// @notice Ticket token (ETK with underlying USDC) used for collateral\n EnclaveTicketToken public ticketToken;\n\n /// @notice License token (ENCL) required for operator registration\n IERC20 public licenseToken;\n\n /// @notice Registry contract for managing committee membership\n ICiphernodeRegistry public registry;\n\n /// @notice Address authorized to perform slashing operations\n address public slashingManager;\n\n /// @notice Address authorized to distribute rewards to operators\n address public rewardDistributor;\n\n /// @notice Treasury address that receives slashed funds\n address public slashedFundsTreasury;\n\n /// @notice Price per ticket in ticket token units\n uint256 public ticketPrice;\n\n /// @notice Minimum license bond required for initial registration\n uint256 public licenseRequiredBond;\n\n /// @notice Minimum number of tickets required to maintain active status\n uint256 public minTicketBalance;\n\n /// @notice Time delay in seconds before exits can be claimed\n uint64 public exitDelay;\n\n /// @notice Percentage (in basis points) of license bond that must remain bonded to stay active\n /// @dev Default 8000 = 80%. Allows operators to unbond up to 20% while remaining active\n uint256 public licenseActiveBps;\n\n /// @notice Operator state data structure\n /// @param licenseBond Amount of license tokens currently bonded\n /// @param exitUnlocksAt Timestamp when pending exit can be claimed\n /// @param registered Whether operator is registered in the protocol\n /// @param exitRequested Whether operator has requested to exit\n /// @param active Whether operator meets all requirements for active status\n struct Operator {\n uint256 licenseBond;\n uint64 exitUnlocksAt;\n bool registered;\n bool exitRequested;\n bool active;\n }\n\n /// @notice Maps operator address to their state data\n mapping(address operator => Operator data) internal operators;\n\n /// @notice Total slashed ticket balance available for treasury withdrawal\n uint256 public slashedTicketBalance;\n\n /// @notice Total slashed license bond available for treasury withdrawal\n uint256 public slashedLicenseBond;\n\n // ======================\n // Exit Queue library state\n // ======================\n\n /// @dev Internal state for managing exit queue of tickets and licenses\n ExitQueueLib.ExitQueueState private _exits;\n\n // ======================\n // Modifiers\n // ======================\n\n /// @dev Restricts function access to only the slashing manager\n modifier onlySlashingManager() {\n if (msg.sender != slashingManager) revert Unauthorized();\n _;\n }\n\n /// @dev Reverts if operator has an exit in progress that hasn't unlocked yet\n /// @param operator Address of the operator to check\n modifier noExitInProgress(address operator) {\n Operator memory op = operators[operator];\n if (op.exitRequested && block.timestamp < op.exitUnlocksAt) {\n revert ExitInProgress();\n }\n _;\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Initialization //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Constructor that disables initializers.\n /// @dev Prevents the implementation contract from being initialized. Initialization is performed\n /// via the initialize() function when deployed behind a proxy.\n constructor() {\n _disableInitializers();\n }\n\n /// @notice Initializes the bonding registry contract\n /// @dev Can only be called once due to initializer modifier\n /// @param _owner Address that will own the contract\n /// @param _ticketToken Ticket token contract for collateral\n /// @param _licenseToken License token contract for bonding\n /// @param _registry Ciphernode registry contract\n /// @param _slashedFundsTreasury Address to receive slashed funds\n /// @param _ticketPrice Initial price per ticket\n /// @param _licenseRequiredBond Initial required license bond for registration\n /// @param _minTicketBalance Initial minimum ticket balance for activation\n /// @param _exitDelay Initial exit delay period in seconds\n function initialize(\n address _owner,\n EnclaveTicketToken _ticketToken,\n IERC20 _licenseToken,\n ICiphernodeRegistry _registry,\n address _slashedFundsTreasury,\n uint256 _ticketPrice,\n uint256 _licenseRequiredBond,\n uint256 _minTicketBalance,\n uint64 _exitDelay\n ) public initializer {\n __Ownable_init(msg.sender);\n setTicketToken(_ticketToken);\n setLicenseToken(_licenseToken);\n setRegistry(_registry);\n setSlashedFundsTreasury(_slashedFundsTreasury);\n setTicketPrice(_ticketPrice);\n setLicenseRequiredBond(_licenseRequiredBond);\n setMinTicketBalance(_minTicketBalance);\n setExitDelay(_exitDelay);\n setLicenseActiveBps(8_000);\n if (_owner != owner()) transferOwnership(_owner);\n }\n\n // ======================\n // View Functions\n // ======================\n\n /// @inheritdoc IBondingRegistry\n function getLicenseToken() external view returns (address) {\n return address(licenseToken);\n }\n\n /// @inheritdoc IBondingRegistry\n function getTicketToken() external view returns (address) {\n return address(ticketToken);\n }\n\n /// @inheritdoc IBondingRegistry\n function getTicketBalance(\n address operator\n ) external view returns (uint256) {\n return ticketToken.balanceOf(operator);\n }\n\n /// @inheritdoc IBondingRegistry\n function getLicenseBond(address operator) external view returns (uint256) {\n return operators[operator].licenseBond;\n }\n\n /// @inheritdoc IBondingRegistry\n function availableTickets(\n address operator\n ) external view returns (uint256) {\n return ticketToken.balanceOf(operator) / ticketPrice;\n }\n\n /// @notice Get operator's ticket balance at a specific block\n /// @dev Uses checkpoint mechanism from ticket token\n /// @param operator Address of the operator\n /// @param blockNumber Block number to query\n /// @return Ticket balance at the specified block\n function getTicketBalanceAtBlock(\n address operator,\n uint256 blockNumber\n ) external view returns (uint256) {\n return ticketToken.getPastVotes(operator, blockNumber);\n }\n\n /// @notice Get operator's total pending exit amounts\n /// @param operator Address of the operator\n /// @return ticket Total pending ticket balance in exit queue\n /// @return license Total pending license bond in exit queue\n function pendingExits(\n address operator\n ) external view returns (uint256 ticket, uint256 license) {\n return _exits.getPendingAmounts(operator);\n }\n\n /// @notice Preview how much an operator can currently claim\n /// @param operator Address of the operator\n /// @return ticket Claimable ticket balance\n /// @return license Claimable license bond\n function previewClaimable(\n address operator\n ) external view returns (uint256 ticket, uint256 license) {\n return _exits.previewClaimableAmounts(operator);\n }\n\n /// @inheritdoc IBondingRegistry\n function isLicensed(address operator) external view returns (bool) {\n return operators[operator].licenseBond >= _minLicenseBond();\n }\n\n /// @inheritdoc IBondingRegistry\n function isRegistered(address operator) external view returns (bool) {\n return operators[operator].registered;\n }\n\n /// @inheritdoc IBondingRegistry\n function isActive(address operator) external view returns (bool) {\n return operators[operator].active;\n }\n\n /// @inheritdoc IBondingRegistry\n function hasExitInProgress(address operator) external view returns (bool) {\n Operator memory op = operators[operator];\n return op.exitRequested && block.timestamp < op.exitUnlocksAt;\n }\n\n // ======================\n // Operator Functions\n // ======================\n\n /// @inheritdoc IBondingRegistry\n function registerOperator() external noExitInProgress(msg.sender) {\n // Clear previous exit request\n if (operators[msg.sender].exitRequested) {\n operators[msg.sender].exitRequested = false;\n operators[msg.sender].exitUnlocksAt = 0;\n }\n\n require(\n !ISlashingManager(slashingManager).isBanned(msg.sender),\n CiphernodeBanned()\n );\n require(!operators[msg.sender].registered, AlreadyRegistered());\n require(\n operators[msg.sender].licenseBond >= licenseRequiredBond,\n NotLicensed()\n );\n\n operators[msg.sender].registered = true;\n\n // CiphernodeRegistry already emits an event when a ciphernode is added\n registry.addCiphernode(msg.sender);\n\n _updateOperatorStatus(msg.sender);\n }\n\n /// @inheritdoc IBondingRegistry\n function deregisterOperator(\n uint256[] calldata siblingNodes\n ) external noExitInProgress(msg.sender) {\n Operator storage op = operators[msg.sender];\n require(op.registered, NotRegistered());\n\n op.registered = false;\n op.exitRequested = true;\n op.exitUnlocksAt = uint64(block.timestamp) + exitDelay;\n\n uint256 ticketOut = ticketToken.balanceOf(msg.sender);\n uint256 licenseOut = op.licenseBond;\n if (ticketOut != 0) {\n ticketToken.burnTickets(msg.sender, ticketOut);\n emit TicketBalanceUpdated(\n msg.sender,\n -int256(ticketOut),\n 0,\n REASON_WITHDRAW\n );\n }\n if (licenseOut != 0) {\n op.licenseBond = 0;\n emit LicenseBondUpdated(\n msg.sender,\n -int256(licenseOut),\n 0,\n REASON_UNBOND\n );\n }\n\n if (ticketOut != 0 || licenseOut != 0) {\n _exits.queueAssetsForExit(\n msg.sender,\n exitDelay,\n ticketOut,\n licenseOut\n );\n }\n\n // CiphernodeRegistry already emits an event when a ciphernode is removed\n registry.removeCiphernode(msg.sender, siblingNodes);\n\n emit CiphernodeDeregistrationRequested(msg.sender, op.exitUnlocksAt);\n _updateOperatorStatus(msg.sender);\n }\n\n /// @inheritdoc IBondingRegistry\n function addTicketBalance(\n uint256 amount\n ) external noExitInProgress(msg.sender) {\n require(amount != 0, ZeroAmount());\n require(operators[msg.sender].registered, NotRegistered());\n\n ticketToken.depositFrom(msg.sender, msg.sender, amount);\n\n emit TicketBalanceUpdated(\n msg.sender,\n int256(amount),\n ticketToken.balanceOf(msg.sender),\n REASON_DEPOSIT\n );\n\n _updateOperatorStatus(msg.sender);\n }\n\n /// @inheritdoc IBondingRegistry\n function removeTicketBalance(\n uint256 amount\n ) external noExitInProgress(msg.sender) {\n require(amount != 0, ZeroAmount());\n require(operators[msg.sender].registered, NotRegistered());\n require(\n ticketToken.balanceOf(msg.sender) >= amount,\n InsufficientBalance()\n );\n\n ticketToken.burnTickets(msg.sender, amount);\n _exits.queueTicketsForExit(msg.sender, exitDelay, amount);\n\n emit TicketBalanceUpdated(\n msg.sender,\n -int256(amount),\n ticketToken.balanceOf(msg.sender),\n REASON_WITHDRAW\n );\n\n _updateOperatorStatus(msg.sender);\n }\n\n /// @inheritdoc IBondingRegistry\n function bondLicense(uint256 amount) external noExitInProgress(msg.sender) {\n require(amount != 0, ZeroAmount());\n\n uint256 balanceBefore = licenseToken.balanceOf(address(this));\n licenseToken.safeTransferFrom(msg.sender, address(this), amount);\n uint256 actualReceived = licenseToken.balanceOf(address(this)) -\n balanceBefore;\n\n operators[msg.sender].licenseBond += actualReceived;\n\n emit LicenseBondUpdated(\n msg.sender,\n int256(actualReceived),\n operators[msg.sender].licenseBond,\n REASON_BOND\n );\n\n _updateOperatorStatus(msg.sender);\n }\n\n /// @inheritdoc IBondingRegistry\n function unbondLicense(\n uint256 amount\n ) external noExitInProgress(msg.sender) {\n require(amount != 0, ZeroAmount());\n require(\n operators[msg.sender].licenseBond >= amount,\n InsufficientBalance()\n );\n\n operators[msg.sender].licenseBond -= amount;\n _exits.queueLicensesForExit(msg.sender, exitDelay, amount);\n\n emit LicenseBondUpdated(\n msg.sender,\n -int256(amount),\n operators[msg.sender].licenseBond,\n REASON_UNBOND\n );\n\n _updateOperatorStatus(msg.sender);\n }\n\n // ======================\n // Claim Functions\n // ======================\n\n /// @inheritdoc IBondingRegistry\n function claimExits(\n uint256 maxTicketAmount,\n uint256 maxLicenseAmount\n ) external {\n (uint256 ticketClaim, uint256 licenseClaim) = _exits.claimAssets(\n msg.sender,\n maxTicketAmount,\n maxLicenseAmount\n );\n require(ticketClaim > 0 || licenseClaim > 0, ExitNotReady());\n\n if (ticketClaim > 0) ticketToken.payout(msg.sender, ticketClaim);\n if (licenseClaim > 0) {\n licenseToken.safeTransfer(msg.sender, licenseClaim);\n }\n }\n\n // ======================\n // Slashing Functions\n // ======================\n\n /// @inheritdoc IBondingRegistry\n function slashTicketBalance(\n address operator,\n uint256 requestedSlashAmount,\n bytes32 slashReason\n ) external onlySlashingManager {\n require(requestedSlashAmount != 0, ZeroAmount());\n\n (uint256 pendingTicketBalance, ) = _exits.getPendingAmounts(operator);\n uint256 activeBalance = ticketToken.balanceOf(operator);\n uint256 totalAvailableBalance = activeBalance + pendingTicketBalance;\n\n uint256 actualSlashAmount = Math.min(\n requestedSlashAmount,\n totalAvailableBalance\n );\n\n if (actualSlashAmount == 0) {\n return;\n }\n\n // Slash from active balance first\n uint256 slashedFromActiveBalance = Math.min(\n actualSlashAmount,\n activeBalance\n );\n if (slashedFromActiveBalance > 0) {\n ticketToken.burnTickets(operator, slashedFromActiveBalance);\n }\n\n // Slash remaining amount from pending queue\n uint256 remainingToSlash = actualSlashAmount - slashedFromActiveBalance;\n if (remainingToSlash > 0) {\n _exits.slashPendingAssets(\n operator,\n remainingToSlash,\n 0, // licenseAmount\n true\n );\n }\n\n slashedTicketBalance += actualSlashAmount;\n emit TicketBalanceUpdated(\n operator,\n -int256(actualSlashAmount),\n ticketToken.balanceOf(operator),\n slashReason\n );\n\n _updateOperatorStatus(operator);\n }\n\n /// @inheritdoc IBondingRegistry\n function slashLicenseBond(\n address operator,\n uint256 requestedSlashAmount,\n bytes32 slashReason\n ) external onlySlashingManager {\n require(requestedSlashAmount != 0, ZeroAmount());\n\n Operator storage operatorData = operators[operator];\n (, uint256 pendingLicenseBalance) = _exits.getPendingAmounts(operator);\n uint256 totalAvailableBalance = operatorData.licenseBond +\n pendingLicenseBalance;\n uint256 actualSlashAmount = Math.min(\n requestedSlashAmount,\n totalAvailableBalance\n );\n\n if (actualSlashAmount == 0) return;\n\n // Slash from active balance first\n uint256 slashedFromActiveBalance = Math.min(\n actualSlashAmount,\n operatorData.licenseBond\n );\n if (slashedFromActiveBalance > 0) {\n operatorData.licenseBond -= slashedFromActiveBalance;\n }\n\n // Slash remaining amount from pending queue\n uint256 remainingToSlash = actualSlashAmount - slashedFromActiveBalance;\n if (remainingToSlash > 0) {\n _exits.slashPendingAssets(\n operator,\n 0, // ticketAmount\n remainingToSlash,\n true\n );\n }\n\n slashedLicenseBond += actualSlashAmount;\n emit LicenseBondUpdated(\n operator,\n -int256(actualSlashAmount),\n operatorData.licenseBond,\n slashReason\n );\n\n _updateOperatorStatus(operator);\n }\n\n // ======================\n // Reward Distribution Functions\n // ======================\n\n /// @inheritdoc IBondingRegistry\n function distributeRewards(\n IERC20 rewardToken,\n address[] calldata recipients,\n uint256[] calldata amounts\n ) external {\n require(msg.sender == rewardDistributor, OnlyRewardDistributor());\n require(recipients.length == amounts.length, ArrayLengthMismatch());\n\n uint256 len = recipients.length;\n for (uint256 i = 0; i < len; i++) {\n if (amounts[i] > 0 && operators[recipients[i]].registered) {\n rewardToken.safeTransferFrom(\n rewardDistributor,\n recipients[i],\n amounts[i]\n );\n }\n }\n }\n\n // ======================\n // Admin Functions\n // ======================\n\n /// @inheritdoc IBondingRegistry\n function setTicketPrice(uint256 newTicketPrice) public onlyOwner {\n require(newTicketPrice != 0, InvalidConfiguration());\n\n uint256 oldValue = ticketPrice;\n ticketPrice = newTicketPrice;\n\n emit ConfigurationUpdated(\"ticketPrice\", oldValue, newTicketPrice);\n }\n\n /// @inheritdoc IBondingRegistry\n function setLicenseRequiredBond(\n uint256 newLicenseRequiredBond\n ) public onlyOwner {\n require(newLicenseRequiredBond != 0, InvalidConfiguration());\n\n uint256 oldValue = licenseRequiredBond;\n licenseRequiredBond = newLicenseRequiredBond;\n\n emit ConfigurationUpdated(\n \"licenseRequiredBond\",\n oldValue,\n newLicenseRequiredBond\n );\n }\n\n /// @inheritdoc IBondingRegistry\n function setLicenseActiveBps(uint256 newBps) public onlyOwner {\n require(newBps > 0 && newBps <= 10_000, InvalidConfiguration());\n\n uint256 oldValue = licenseActiveBps;\n licenseActiveBps = newBps;\n\n emit ConfigurationUpdated(\"licenseActiveBps\", oldValue, newBps);\n }\n\n /// @inheritdoc IBondingRegistry\n function setMinTicketBalance(uint256 newMinTicketBalance) public onlyOwner {\n uint256 oldValue = minTicketBalance;\n minTicketBalance = newMinTicketBalance;\n\n emit ConfigurationUpdated(\n \"minTicketBalance\",\n oldValue,\n newMinTicketBalance\n );\n }\n\n /// @inheritdoc IBondingRegistry\n function setExitDelay(uint64 newExitDelay) public onlyOwner {\n uint256 oldValue = uint256(exitDelay);\n exitDelay = newExitDelay;\n\n emit ConfigurationUpdated(\"exitDelay\", oldValue, uint256(newExitDelay));\n }\n\n /// @inheritdoc IBondingRegistry\n function setSlashedFundsTreasury(\n address newSlashedFundsTreasury\n ) public onlyOwner {\n require(newSlashedFundsTreasury != address(0), ZeroAddress());\n slashedFundsTreasury = newSlashedFundsTreasury;\n }\n\n /// @inheritdoc IBondingRegistry\n function setTicketToken(\n EnclaveTicketToken newTicketToken\n ) public onlyOwner {\n ticketToken = newTicketToken;\n }\n\n /// @inheritdoc IBondingRegistry\n function setLicenseToken(IERC20 newLicenseToken) public onlyOwner {\n licenseToken = newLicenseToken;\n }\n\n /// @inheritdoc IBondingRegistry\n function setRegistry(ICiphernodeRegistry newRegistry) public onlyOwner {\n registry = newRegistry;\n }\n\n /// @inheritdoc IBondingRegistry\n function setSlashingManager(address newSlashingManager) public onlyOwner {\n slashingManager = newSlashingManager;\n }\n\n /// @notice Sets the reward distributor address\n /// @dev Only callable by owner\n /// @param newRewardDistributor Address of the reward distributor\n function setRewardDistributor(\n address newRewardDistributor\n ) public onlyOwner {\n rewardDistributor = newRewardDistributor;\n }\n\n /// @inheritdoc IBondingRegistry\n function withdrawSlashedFunds(\n uint256 ticketAmount,\n uint256 licenseAmount\n ) public onlyOwner {\n require(ticketAmount <= slashedTicketBalance, InsufficientBalance());\n require(licenseAmount <= slashedLicenseBond, InsufficientBalance());\n\n if (ticketAmount > 0) {\n slashedTicketBalance -= ticketAmount;\n ticketToken.payout(slashedFundsTreasury, ticketAmount);\n }\n\n if (licenseAmount > 0) {\n slashedLicenseBond -= licenseAmount;\n licenseToken.safeTransfer(slashedFundsTreasury, licenseAmount);\n }\n\n emit SlashedFundsWithdrawn(\n slashedFundsTreasury,\n ticketAmount,\n licenseAmount\n );\n }\n\n // ======================\n // Internal Functions\n // ======================\n\n /// @dev Updates operator's active status based on current conditions\n /// @dev Operator is active if: registered, has minimum license bond, and has minimum tickets\n /// @param operator Address of the operator to update\n function _updateOperatorStatus(address operator) internal {\n Operator storage op = operators[operator];\n bool newActiveStatus = op.registered &&\n op.licenseBond >= _minLicenseBond() &&\n (ticketToken.balanceOf(operator) / ticketPrice >= minTicketBalance);\n\n if (op.active != newActiveStatus) {\n op.active = newActiveStatus;\n emit OperatorActivationChanged(operator, newActiveStatus);\n }\n }\n\n /// @dev Calculates the minimum license bond required to maintain active status\n /// @return Minimum license bond (licenseRequiredBond * licenseActiveBps / 10000)\n function _minLicenseBond() internal view returns (uint256) {\n return (licenseRequiredBond * licenseActiveBps) / 10_000;\n }\n}\n"
|
|
278
278
|
},
|
|
279
279
|
"project/contracts/registry/CiphernodeRegistryOwnable.sol": {
|
|
280
|
-
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\npragma solidity >=0.8.27;\n\nimport { ICiphernodeRegistry } from \"../interfaces/ICiphernodeRegistry.sol\";\nimport { IBondingRegistry } from \"../interfaces/IBondingRegistry.sol\";\nimport {\n OwnableUpgradeable\n} from \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport {\n InternalLeanIMT,\n LeanIMTData\n} from \"@zk-kit/lean-imt.sol/InternalLeanIMT.sol\";\n\n/**\n * @title CiphernodeRegistryOwnable\n * @notice Ownable implementation of the ciphernode registry with IMT-based membership tracking\n * @dev Manages ciphernode registration, committee selection, and integrates with bonding registry\n */\ncontract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable {\n using InternalLeanIMT for LeanIMTData;\n\n ////////////////////////////////////////////////////////////\n // //\n // Events //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Emitted when the bonding registry address is set\n /// @param bondingRegistry Address of the bonding registry contract\n event BondingRegistrySet(address indexed bondingRegistry);\n\n ////////////////////////////////////////////////////////////\n // //\n // Storage Variables //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Address of the Enclave contract authorized to request committees\n address public enclave;\n\n /// @notice Address of the bonding registry for checking node eligibility\n address public bondingRegistry;\n\n /// @notice Current number of registered ciphernodes\n uint256 public numCiphernodes;\n\n /// @notice Submission Window for an E3 Sortition.\n /// @dev The submission window is the time period during which the ciphernodes can submit\n /// their tickets to be a part of the committee.\n uint256 public sortitionSubmissionWindow;\n\n /// @notice Incremental Merkle Tree (IMT) containing all registered ciphernodes\n LeanIMTData public ciphernodes;\n\n /// @notice Maps E3 ID to the IMT root at the time of committee request\n mapping(uint256 e3Id => uint256 root) public roots;\n\n /// @notice Maps E3 ID to the hash of the committee's public key\n mapping(uint256 e3Id => bytes32 publicKeyHash) public publicKeyHashes;\n\n /// @notice Maps E3 ID to its committee data\n mapping(uint256 e3Id => Committee committee) internal committees;\n\n ////////////////////////////////////////////////////////////\n // //\n // Errors //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Committee has already been requested for this E3\n error CommitteeAlreadyRequested();\n\n /// @notice Committee has already been published for this E3\n error CommitteeAlreadyPublished();\n\n /// @notice Committee has not been published yet for this E3\n error CommitteeNotPublished();\n\n /// @notice Committee has not been requested yet for this E3\n error CommitteeNotRequested();\n\n /// @notice Committee Not Initialized or Finalized\n error CommitteeNotInitializedOrFinalized();\n\n /// @notice Submission Window has been closed for this E3\n error SubmissionWindowClosed();\n\n /// @notice Submission deadline has been reached for this E3\n error SubmissionDeadlineReached();\n\n /// @notice Committee has already been finalized for this E3\n error CommitteeAlreadyFinalized();\n\n /// @notice Committee has not been finalized yet for this E3\n error CommitteeNotFinalized();\n\n /// @notice Node has already submitted a ticket for this E3\n error NodeAlreadySubmitted();\n\n /// @notice Node has not submitted a ticket for this E3\n error NodeNotSubmitted();\n\n /// @notice Node is not eligible for this E3\n error NodeNotEligible();\n\n /// @notice Ciphernode is not enabled in the registry\n /// @param node Address of the ciphernode\n error CiphernodeNotEnabled(address node);\n\n /// @notice Caller is not the Enclave contract\n error OnlyEnclave();\n\n /// @notice Caller is not the bonding registry\n error OnlyBondingRegistry();\n\n /// @notice Caller is neither owner nor bonding registry\n error NotOwnerOrBondingRegistry();\n\n /// @notice Node is not bonded\n /// @param node Address of the node\n error NodeNotBonded(address node);\n\n /// @notice Address cannot be zero\n error ZeroAddress();\n\n /// @notice Bonding registry has not been set\n error BondingRegistryNotSet();\n\n /// @notice Invalid ticket number\n error InvalidTicketNumber();\n\n /// @notice Submission window not closed yet\n error SubmissionWindowNotClosed();\n\n /// @notice Threshold not met for this E3\n error ThresholdNotMet();\n\n /// @notice Caller is not authorized\n error Unauthorized();\n\n ////////////////////////////////////////////////////////////\n // //\n // Modifiers //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @dev Restricts function access to only the Enclave contract\n modifier onlyEnclave() {\n require(msg.sender == enclave, OnlyEnclave());\n _;\n }\n\n /// @dev Restricts function access to only the bonding registry\n modifier onlyBondingRegistry() {\n require(msg.sender == bondingRegistry, OnlyBondingRegistry());\n _;\n }\n\n /// @dev Restricts function access to owner or bonding registry\n modifier onlyOwnerOrBondingVault() {\n require(\n msg.sender == owner() || msg.sender == bondingRegistry,\n NotOwnerOrBondingRegistry()\n );\n _;\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Initialization //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Constructor that disables initializers.\n /// @dev Prevents the implementation contract from being initialized. Initialization is performed\n /// via the initialize() function when deployed behind a proxy.\n constructor() {\n _disableInitializers();\n }\n\n /// @notice Initializes the registry contract\n /// @dev Can only be called once due to initializer modifier\n /// @param _owner Address that will own the contract\n /// @param _enclave Address of the Enclave contract\n /// @param _submissionWindow The submission window for the E3 sortition in seconds\n function initialize(\n address _owner,\n address _enclave,\n uint256 _submissionWindow\n ) public initializer {\n require(_owner != address(0), ZeroAddress());\n require(_enclave != address(0), ZeroAddress());\n\n __Ownable_init(msg.sender);\n setEnclave(_enclave);\n setSortitionSubmissionWindow(_submissionWindow);\n if (_owner != owner()) transferOwnership(_owner);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Core Entrypoints //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @inheritdoc ICiphernodeRegistry\n function requestCommittee(\n uint256 e3Id,\n uint256 seed,\n uint32[2] calldata threshold\n ) external onlyEnclave returns (bool success) {\n Committee storage c = committees[e3Id];\n require(!c.initialized, CommitteeAlreadyRequested());\n\n c.initialized = true;\n c.finalized = false;\n c.seed = seed;\n c.requestBlock = block.number;\n c.submissionDeadline = block.timestamp + sortitionSubmissionWindow;\n c.threshold = threshold;\n roots[e3Id] = root();\n\n emit CommitteeRequested(\n e3Id,\n seed,\n threshold,\n c.requestBlock,\n c.submissionDeadline\n );\n success = true;\n }\n\n /// @notice Publishes a committee for an E3 computation\n /// @dev Only callable by owner. Verifies committee is finalized and matches provided nodes.\n /// @param e3Id ID of the E3 computation\n /// @param nodes Array of ciphernode addresses selected for the committee\n /// @param publicKey Aggregated public key of the committee\n function publishCommittee(\n uint256 e3Id,\n address[] calldata nodes,\n bytes calldata publicKey\n ) external onlyOwner {\n Committee storage c = committees[e3Id];\n\n require(c.initialized, CommitteeNotRequested());\n require(c.finalized, CommitteeNotFinalized());\n require(c.publicKey == bytes32(0), CommitteeAlreadyPublished());\n require(nodes.length == c.committee.length, \"Node count mismatch\");\n\n // TODO: Currently we trust the owner to publish the correct committee.\n // TODO: Need a Proof that the public key is generated from the committee\n bytes32 publicKeyHash = keccak256(publicKey);\n c.publicKey = publicKeyHash;\n publicKeyHashes[e3Id] = publicKeyHash;\n emit CommitteePublished(e3Id, nodes, publicKey);\n }\n\n /// @inheritdoc ICiphernodeRegistry\n function addCiphernode(address node) external onlyOwnerOrBondingVault {\n if (isEnabled(node)) {\n return;\n }\n\n uint160 ciphernode = uint160(node);\n ciphernodes._insert(ciphernode);\n numCiphernodes++;\n emit CiphernodeAdded(\n node,\n ciphernodes._indexOf(ciphernode),\n numCiphernodes,\n ciphernodes.size\n );\n }\n\n /// @inheritdoc ICiphernodeRegistry\n function removeCiphernode(\n address node,\n uint256[] calldata siblingNodes\n ) external onlyOwnerOrBondingVault {\n require(isEnabled(node), CiphernodeNotEnabled(node));\n\n uint160 ciphernode = uint160(node);\n uint256 index = ciphernodes._indexOf(ciphernode);\n ciphernodes._remove(ciphernode, siblingNodes);\n numCiphernodes--;\n emit CiphernodeRemoved(node, index, numCiphernodes, ciphernodes.size);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Sortition Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Submit a ticket for sortition\n /// @dev Validates ticket against node's balance at request block and inserts into top-N\n /// @param e3Id ID of the E3 computation\n /// @param ticketNumber The ticket number to submit (1 to available tickets at snapshot)\n function submitTicket(uint256 e3Id, uint256 ticketNumber) external {\n Committee storage c = committees[e3Id];\n require(c.initialized, CommitteeNotRequested());\n require(!c.finalized, CommitteeAlreadyFinalized());\n require(\n block.timestamp <= c.submissionDeadline,\n SubmissionDeadlineReached()\n );\n require(!c.submitted[msg.sender], NodeAlreadySubmitted());\n require(isCiphernodeEligible(msg.sender), NodeNotEligible());\n\n // Validate node eligibility and ticket number\n _validateNodeEligibility(msg.sender, ticketNumber, e3Id);\n\n // Compute score\n uint256 score = _computeTicketScore(\n msg.sender,\n ticketNumber,\n e3Id,\n c.seed\n );\n\n // Store submission\n c.submitted[msg.sender] = true;\n\n // Insert into top-N (ascending score)\n _insertTopN(c, msg.sender, score);\n\n emit TicketSubmitted(e3Id, msg.sender, ticketNumber, score);\n }\n\n /// @notice Finalize the committee after submission window closes\n /// @dev Can be called by anyone after the deadline. Reverts if not enough nodes submitted.\n /// @param e3Id ID of the E3 computation\n function finalizeCommittee(uint256 e3Id) external {\n Committee storage c = committees[e3Id];\n require(c.initialized, CommitteeNotRequested());\n require(!c.finalized, CommitteeAlreadyFinalized());\n require(\n block.timestamp >= c.submissionDeadline,\n SubmissionWindowNotClosed()\n );\n // TODO: Handle what happens if the threshold is not met.\n require(c.topNodes.length >= c.threshold[0], ThresholdNotMet());\n\n c.finalized = true;\n c.committee = c.topNodes;\n\n emit CommitteeFinalized(e3Id, c.topNodes);\n }\n\n /// @notice Check if submission window is still open for an E3\n /// @param e3Id ID of the E3 computation\n /// @return Whether the submission window is open\n function isOpen(uint256 e3Id) public view returns (bool) {\n Committee storage c = committees[e3Id];\n if (!c.initialized || c.finalized) return false;\n return block.timestamp <= c.submissionDeadline;\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Set Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Sets the Enclave contract address\n /// @dev Only callable by owner\n /// @param _enclave Address of the Enclave contract\n function setEnclave(address _enclave) public onlyOwner {\n require(_enclave != address(0), ZeroAddress());\n enclave = _enclave;\n emit EnclaveSet(_enclave);\n }\n\n /// @notice Sets the bonding registry contract address\n /// @dev Only callable by owner\n /// @param _bondingRegistry Address of the bonding registry contract\n function setBondingRegistry(address _bondingRegistry) public onlyOwner {\n require(_bondingRegistry != address(0), ZeroAddress());\n bondingRegistry = _bondingRegistry;\n emit BondingRegistrySet(_bondingRegistry);\n }\n\n /// @inheritdoc ICiphernodeRegistry\n function setSortitionSubmissionWindow(\n uint256 _sortitionSubmissionWindow\n ) public onlyOwner {\n sortitionSubmissionWindow = _sortitionSubmissionWindow;\n emit SortitionSubmissionWindowSet(_sortitionSubmissionWindow);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Get Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @inheritdoc ICiphernodeRegistry\n function committeePublicKey(\n uint256 e3Id\n ) external view returns (bytes32 publicKeyHash) {\n publicKeyHash = publicKeyHashes[e3Id];\n require(publicKeyHash != bytes32(0), CommitteeNotPublished());\n }\n\n /// @inheritdoc ICiphernodeRegistry\n function isCiphernodeEligible(address node) public view returns (bool) {\n if (!isEnabled(node)) return false;\n\n require(bondingRegistry != address(0), BondingRegistryNotSet());\n return IBondingRegistry(bondingRegistry).isActive(node);\n }\n\n /// @inheritdoc ICiphernodeRegistry\n function isEnabled(address node) public view returns (bool) {\n return ciphernodes._has(uint160(node));\n }\n\n /// @notice Returns the current root of the ciphernode IMT\n /// @return Current IMT root\n function root() public view returns (uint256) {\n return (ciphernodes._root());\n }\n\n /// @notice Returns the IMT root at the time a committee was requested\n /// @param e3Id ID of the E3\n /// @return IMT root at time of committee request\n function rootAt(uint256 e3Id) public view returns (uint256) {\n return roots[e3Id];\n }\n\n /// @inheritdoc ICiphernodeRegistry\n function getCommitteeNodes(\n uint256 e3Id\n ) public view returns (address[] memory nodes) {\n Committee storage c = committees[e3Id];\n require(c.publicKey != bytes32(0), CommitteeNotPublished());\n nodes = c.committee;\n }\n\n /// @notice Returns the current size of the ciphernode IMT\n /// @return Size of the IMT\n function treeSize() public view returns (uint256) {\n return ciphernodes.size;\n }\n\n /// @notice Returns the address of the bonding registry\n /// @return Address of the bonding registry contract\n function getBondingRegistry() external view returns (address) {\n return bondingRegistry;\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Internal Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Computes ticket score as keccak256(node || ticketNumber || e3Id || seed)\n /// @param node Address of the ciphernode\n /// @param ticketNumber The ticket number\n /// @param e3Id ID of the E3 computation\n /// @param seed Random seed for the E3\n /// @return score The computed score\n function _computeTicketScore(\n address node,\n uint256 ticketNumber,\n uint256 e3Id,\n uint256 seed\n ) internal pure returns (uint256) {\n bytes32 hash = keccak256(\n abi.encodePacked(node, ticketNumber, e3Id, seed)\n );\n return uint256(hash);\n }\n\n /// @notice Validates that a node is eligible to submit a ticket\n /// @dev Uses snapshot of ticket balance at E3 request block for deterministic validation\n /// @param node Address of the ciphernode\n /// @param ticketNumber The ticket number being submitted\n /// @param e3Id ID of the E3 computation\n function _validateNodeEligibility(\n address node,\n uint256 ticketNumber,\n uint256 e3Id\n ) internal view {\n require(ticketNumber > 0, InvalidTicketNumber());\n require(bondingRegistry != address(0), BondingRegistryNotSet());\n\n Committee storage c = committees[e3Id];\n\n // @todo Ensure we check everywhere that we use the block before the request block\n // to ensure cases where everything is done in the same block are handled correctly.\n uint256 ticketBalance = IBondingRegistry(bondingRegistry)\n .getTicketBalanceAtBlock(node, c.requestBlock - 1);\n uint256 ticketPrice = IBondingRegistry(bondingRegistry).ticketPrice();\n\n require(ticketPrice > 0, InvalidTicketNumber());\n uint256 availableTickets = ticketBalance / ticketPrice;\n\n require(availableTickets > 0, NodeNotEligible());\n require(ticketNumber <= availableTickets, InvalidTicketNumber());\n }\n\n /// @notice Inserts a node into the top-N list - Smallest scores\n /// @dev If the node is not in the top-N, it is added to the top-N.\n /// @param c Committee storage reference\n /// @param node Address of the node\n /// @param score Score of the node\n /// @return entered Whether the node was inserted into the top-N\n function _insertTopN(\n Committee storage c,\n address node,\n uint256 score\n ) internal returns (bool entered) {\n address[] storage top = c.topNodes;\n uint256 cap = c.threshold[1];\n\n if (top.length < cap) {\n top.push(node);\n c.scoreOf[node] = score;\n return true;\n }\n\n uint256 worstIdx = 0;\n uint256 worstScore = c.scoreOf[top[0]];\n unchecked {\n for (uint256 i = 1; i < top.length; ++i) {\n uint256 s = c.scoreOf[top[i]];\n if (s > worstScore) {\n worstScore = s;\n worstIdx = i;\n }\n }\n }\n\n if (score >= worstScore) return false;\n\n top[worstIdx] = node;\n c.scoreOf[node] = score;\n\n return true;\n }\n}\n"
|
|
280
|
+
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\npragma solidity >=0.8.27;\n\nimport { ICiphernodeRegistry } from \"../interfaces/ICiphernodeRegistry.sol\";\nimport { IBondingRegistry } from \"../interfaces/IBondingRegistry.sol\";\nimport {\n OwnableUpgradeable\n} from \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport {\n InternalLeanIMT,\n LeanIMTData\n} from \"@zk-kit/lean-imt.sol/InternalLeanIMT.sol\";\n\n/**\n * @title CiphernodeRegistryOwnable\n * @notice Ownable implementation of the ciphernode registry with IMT-based membership tracking\n * @dev Manages ciphernode registration, committee selection, and integrates with bonding registry\n */\ncontract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable {\n using InternalLeanIMT for LeanIMTData;\n\n ////////////////////////////////////////////////////////////\n // //\n // Events //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Emitted when the bonding registry address is set\n /// @param bondingRegistry Address of the bonding registry contract\n event BondingRegistrySet(address indexed bondingRegistry);\n\n ////////////////////////////////////////////////////////////\n // //\n // Storage Variables //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Address of the Enclave contract authorized to request committees\n address public enclave;\n\n /// @notice Address of the bonding registry for checking node eligibility\n address public bondingRegistry;\n\n /// @notice Current number of registered ciphernodes\n uint256 public numCiphernodes;\n\n /// @notice Submission Window for an E3 Sortition.\n /// @dev The submission window is the time period during which the ciphernodes can submit\n /// their tickets to be a part of the committee.\n uint256 public sortitionSubmissionWindow;\n\n /// @notice Incremental Merkle Tree (IMT) containing all registered ciphernodes\n LeanIMTData public ciphernodes;\n\n /// @notice Maps E3 ID to the IMT root at the time of committee request\n mapping(uint256 e3Id => uint256 root) public roots;\n\n /// @notice Maps E3 ID to the hash of the committee's public key\n mapping(uint256 e3Id => bytes32 publicKeyHash) public publicKeyHashes;\n\n /// @notice Maps E3 ID to its committee data\n mapping(uint256 e3Id => Committee committee) internal committees;\n\n ////////////////////////////////////////////////////////////\n // //\n // Errors //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Committee has already been requested for this E3\n error CommitteeAlreadyRequested();\n\n /// @notice Committee has already been published for this E3\n error CommitteeAlreadyPublished();\n\n /// @notice Committee has not been published yet for this E3\n error CommitteeNotPublished();\n\n /// @notice Committee has not been requested yet for this E3\n error CommitteeNotRequested();\n\n /// @notice Committee Not Initialized or Finalized\n error CommitteeNotInitializedOrFinalized();\n\n /// @notice Submission Window has been closed for this E3\n error SubmissionWindowClosed();\n\n /// @notice Submission deadline has been reached for this E3\n error SubmissionDeadlineReached();\n\n /// @notice Committee has already been finalized for this E3\n error CommitteeAlreadyFinalized();\n\n /// @notice Committee has not been finalized yet for this E3\n error CommitteeNotFinalized();\n\n /// @notice Node has already submitted a ticket for this E3\n error NodeAlreadySubmitted();\n\n /// @notice Node has not submitted a ticket for this E3\n error NodeNotSubmitted();\n\n /// @notice Node is not eligible for this E3\n error NodeNotEligible();\n\n /// @notice Ciphernode is not enabled in the registry\n /// @param node Address of the ciphernode\n error CiphernodeNotEnabled(address node);\n\n /// @notice Caller is not the Enclave contract\n error OnlyEnclave();\n\n /// @notice Caller is not the bonding registry\n error OnlyBondingRegistry();\n\n /// @notice Caller is neither owner nor bonding registry\n error NotOwnerOrBondingRegistry();\n\n /// @notice Node is not bonded\n /// @param node Address of the node\n error NodeNotBonded(address node);\n\n /// @notice Address cannot be zero\n error ZeroAddress();\n\n /// @notice Bonding registry has not been set\n error BondingRegistryNotSet();\n\n /// @notice Invalid ticket number\n error InvalidTicketNumber();\n\n /// @notice Submission window not closed yet\n error SubmissionWindowNotClosed();\n\n /// @notice Threshold not met for this E3\n error ThresholdNotMet();\n\n /// @notice Caller is not authorized\n error Unauthorized();\n\n ////////////////////////////////////////////////////////////\n // //\n // Modifiers //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @dev Restricts function access to only the Enclave contract\n modifier onlyEnclave() {\n require(msg.sender == enclave, OnlyEnclave());\n _;\n }\n\n /// @dev Restricts function access to only the bonding registry\n modifier onlyBondingRegistry() {\n require(msg.sender == bondingRegistry, OnlyBondingRegistry());\n _;\n }\n\n /// @dev Restricts function access to owner or bonding registry\n modifier onlyOwnerOrBondingVault() {\n require(\n msg.sender == owner() || msg.sender == bondingRegistry,\n NotOwnerOrBondingRegistry()\n );\n _;\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Initialization //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Constructor that disables initializers.\n /// @dev Prevents the implementation contract from being initialized. Initialization is performed\n /// via the initialize() function when deployed behind a proxy.\n constructor() {\n _disableInitializers();\n }\n\n /// @notice Initializes the registry contract\n /// @dev Can only be called once due to initializer modifier\n /// @param _owner Address that will own the contract\n /// @param _enclave Address of the Enclave contract\n /// @param _submissionWindow The submission window for the E3 sortition in seconds\n function initialize(\n address _owner,\n address _enclave,\n uint256 _submissionWindow\n ) public initializer {\n require(_owner != address(0), ZeroAddress());\n require(_enclave != address(0), ZeroAddress());\n\n __Ownable_init(msg.sender);\n setEnclave(_enclave);\n setSortitionSubmissionWindow(_submissionWindow);\n if (_owner != owner()) transferOwnership(_owner);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Core Entrypoints //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @inheritdoc ICiphernodeRegistry\n function requestCommittee(\n uint256 e3Id,\n uint256 seed,\n uint32[2] calldata threshold\n ) external onlyEnclave returns (bool success) {\n Committee storage c = committees[e3Id];\n require(!c.initialized, CommitteeAlreadyRequested());\n\n c.initialized = true;\n c.finalized = false;\n c.seed = seed;\n c.requestBlock = block.number;\n c.submissionDeadline = block.timestamp + sortitionSubmissionWindow;\n c.threshold = threshold;\n roots[e3Id] = root();\n\n emit CommitteeRequested(\n e3Id,\n seed,\n threshold,\n c.requestBlock,\n c.submissionDeadline\n );\n success = true;\n }\n\n /// @notice Publishes a committee for an E3 computation\n /// @dev Only callable by owner. Verifies committee is finalized and matches provided nodes.\n /// @param e3Id ID of the E3 computation\n /// @param nodes Array of ciphernode addresses selected for the committee\n /// @param publicKey Aggregated public key of the committee\n /// @param publicKeyHash The hash of the public key\n function publishCommittee(\n uint256 e3Id,\n address[] calldata nodes,\n bytes calldata publicKey,\n bytes32 publicKeyHash\n ) external onlyOwner {\n Committee storage c = committees[e3Id];\n\n require(c.initialized, CommitteeNotRequested());\n require(c.finalized, CommitteeNotFinalized());\n require(c.publicKey == bytes32(0), CommitteeAlreadyPublished());\n require(nodes.length == c.committee.length, \"Node count mismatch\");\n\n // TODO: Currently we trust the owner to publish the correct committee.\n // TODO: Need a Proof that the public key is generated from the committee\n c.publicKey = publicKeyHash;\n publicKeyHashes[e3Id] = publicKeyHash;\n emit CommitteePublished(e3Id, nodes, publicKey);\n }\n\n /// @inheritdoc ICiphernodeRegistry\n function addCiphernode(address node) external onlyOwnerOrBondingVault {\n if (isEnabled(node)) {\n return;\n }\n\n uint160 ciphernode = uint160(node);\n ciphernodes._insert(ciphernode);\n numCiphernodes++;\n emit CiphernodeAdded(\n node,\n ciphernodes._indexOf(ciphernode),\n numCiphernodes,\n ciphernodes.size\n );\n }\n\n /// @inheritdoc ICiphernodeRegistry\n function removeCiphernode(\n address node,\n uint256[] calldata siblingNodes\n ) external onlyOwnerOrBondingVault {\n require(isEnabled(node), CiphernodeNotEnabled(node));\n\n uint160 ciphernode = uint160(node);\n uint256 index = ciphernodes._indexOf(ciphernode);\n ciphernodes._remove(ciphernode, siblingNodes);\n numCiphernodes--;\n emit CiphernodeRemoved(node, index, numCiphernodes, ciphernodes.size);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Sortition Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Submit a ticket for sortition\n /// @dev Validates ticket against node's balance at request block and inserts into top-N\n /// @param e3Id ID of the E3 computation\n /// @param ticketNumber The ticket number to submit (1 to available tickets at snapshot)\n function submitTicket(uint256 e3Id, uint256 ticketNumber) external {\n Committee storage c = committees[e3Id];\n require(c.initialized, CommitteeNotRequested());\n require(!c.finalized, CommitteeAlreadyFinalized());\n require(\n block.timestamp <= c.submissionDeadline,\n SubmissionDeadlineReached()\n );\n require(!c.submitted[msg.sender], NodeAlreadySubmitted());\n require(isCiphernodeEligible(msg.sender), NodeNotEligible());\n\n // Validate node eligibility and ticket number\n _validateNodeEligibility(msg.sender, ticketNumber, e3Id);\n\n // Compute score\n uint256 score = _computeTicketScore(\n msg.sender,\n ticketNumber,\n e3Id,\n c.seed\n );\n\n // Store submission\n c.submitted[msg.sender] = true;\n\n // Insert into top-N (ascending score)\n _insertTopN(c, msg.sender, score);\n\n emit TicketSubmitted(e3Id, msg.sender, ticketNumber, score);\n }\n\n /// @notice Finalize the committee after submission window closes\n /// @dev Can be called by anyone after the deadline. Reverts if not enough nodes submitted.\n /// @param e3Id ID of the E3 computation\n function finalizeCommittee(uint256 e3Id) external {\n Committee storage c = committees[e3Id];\n require(c.initialized, CommitteeNotRequested());\n require(!c.finalized, CommitteeAlreadyFinalized());\n require(\n block.timestamp >= c.submissionDeadline,\n SubmissionWindowNotClosed()\n );\n // TODO: Handle what happens if the threshold is not met.\n require(c.topNodes.length >= c.threshold[1], ThresholdNotMet());\n\n c.finalized = true;\n c.committee = c.topNodes;\n\n emit CommitteeFinalized(e3Id, c.topNodes);\n }\n\n /// @notice Check if submission window is still open for an E3\n /// @param e3Id ID of the E3 computation\n /// @return Whether the submission window is open\n function isOpen(uint256 e3Id) public view returns (bool) {\n Committee storage c = committees[e3Id];\n if (!c.initialized || c.finalized) return false;\n return block.timestamp <= c.submissionDeadline;\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Set Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Sets the Enclave contract address\n /// @dev Only callable by owner\n /// @param _enclave Address of the Enclave contract\n function setEnclave(address _enclave) public onlyOwner {\n require(_enclave != address(0), ZeroAddress());\n enclave = _enclave;\n emit EnclaveSet(_enclave);\n }\n\n /// @notice Sets the bonding registry contract address\n /// @dev Only callable by owner\n /// @param _bondingRegistry Address of the bonding registry contract\n function setBondingRegistry(address _bondingRegistry) public onlyOwner {\n require(_bondingRegistry != address(0), ZeroAddress());\n bondingRegistry = _bondingRegistry;\n emit BondingRegistrySet(_bondingRegistry);\n }\n\n /// @inheritdoc ICiphernodeRegistry\n function setSortitionSubmissionWindow(\n uint256 _sortitionSubmissionWindow\n ) public onlyOwner {\n sortitionSubmissionWindow = _sortitionSubmissionWindow;\n emit SortitionSubmissionWindowSet(_sortitionSubmissionWindow);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Get Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @inheritdoc ICiphernodeRegistry\n function committeePublicKey(\n uint256 e3Id\n ) external view returns (bytes32 publicKeyHash) {\n publicKeyHash = publicKeyHashes[e3Id];\n require(publicKeyHash != bytes32(0), CommitteeNotPublished());\n }\n\n /// @inheritdoc ICiphernodeRegistry\n function isCiphernodeEligible(address node) public view returns (bool) {\n if (!isEnabled(node)) return false;\n\n require(bondingRegistry != address(0), BondingRegistryNotSet());\n return IBondingRegistry(bondingRegistry).isActive(node);\n }\n\n /// @inheritdoc ICiphernodeRegistry\n function isEnabled(address node) public view returns (bool) {\n return ciphernodes._has(uint160(node));\n }\n\n /// @notice Returns the current root of the ciphernode IMT\n /// @return Current IMT root\n function root() public view returns (uint256) {\n return (ciphernodes._root());\n }\n\n /// @notice Returns the IMT root at the time a committee was requested\n /// @param e3Id ID of the E3\n /// @return IMT root at time of committee request\n function rootAt(uint256 e3Id) public view returns (uint256) {\n return roots[e3Id];\n }\n\n /// @inheritdoc ICiphernodeRegistry\n function getCommitteeNodes(\n uint256 e3Id\n ) public view returns (address[] memory nodes) {\n Committee storage c = committees[e3Id];\n require(c.publicKey != bytes32(0), CommitteeNotPublished());\n nodes = c.committee;\n }\n\n /// @notice Returns the current size of the ciphernode IMT\n /// @return Size of the IMT\n function treeSize() public view returns (uint256) {\n return ciphernodes.size;\n }\n\n /// @notice Returns the address of the bonding registry\n /// @return Address of the bonding registry contract\n function getBondingRegistry() external view returns (address) {\n return bondingRegistry;\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Internal Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice Computes ticket score as keccak256(node || ticketNumber || e3Id || seed)\n /// @param node Address of the ciphernode\n /// @param ticketNumber The ticket number\n /// @param e3Id ID of the E3 computation\n /// @param seed Random seed for the E3\n /// @return score The computed score\n function _computeTicketScore(\n address node,\n uint256 ticketNumber,\n uint256 e3Id,\n uint256 seed\n ) internal pure returns (uint256) {\n bytes32 hash = keccak256(\n abi.encodePacked(node, ticketNumber, e3Id, seed)\n );\n return uint256(hash);\n }\n\n /// @notice Validates that a node is eligible to submit a ticket\n /// @dev Uses snapshot of ticket balance at E3 request block for deterministic validation\n /// @param node Address of the ciphernode\n /// @param ticketNumber The ticket number being submitted\n /// @param e3Id ID of the E3 computation\n function _validateNodeEligibility(\n address node,\n uint256 ticketNumber,\n uint256 e3Id\n ) internal view {\n require(ticketNumber > 0, InvalidTicketNumber());\n require(bondingRegistry != address(0), BondingRegistryNotSet());\n\n Committee storage c = committees[e3Id];\n\n // @todo Ensure we check everywhere that we use the block before the request block\n // to ensure cases where everything is done in the same block are handled correctly.\n uint256 ticketBalance = IBondingRegistry(bondingRegistry)\n .getTicketBalanceAtBlock(node, c.requestBlock - 1);\n uint256 ticketPrice = IBondingRegistry(bondingRegistry).ticketPrice();\n\n require(ticketPrice > 0, InvalidTicketNumber());\n uint256 availableTickets = ticketBalance / ticketPrice;\n\n require(availableTickets > 0, NodeNotEligible());\n require(ticketNumber <= availableTickets, InvalidTicketNumber());\n }\n\n /// @notice Inserts a node into the top-N list - Smallest scores\n /// @dev If the node is not in the top-N, it is added to the top-N.\n /// @param c Committee storage reference\n /// @param node Address of the node\n /// @param score Score of the node\n /// @return entered Whether the node was inserted into the top-N\n function _insertTopN(\n Committee storage c,\n address node,\n uint256 score\n ) internal returns (bool entered) {\n address[] storage top = c.topNodes;\n uint256 cap = c.threshold[1];\n\n if (top.length < cap) {\n top.push(node);\n c.scoreOf[node] = score;\n return true;\n }\n\n uint256 worstIdx = 0;\n uint256 worstScore = c.scoreOf[top[0]];\n unchecked {\n for (uint256 i = 1; i < top.length; ++i) {\n uint256 s = c.scoreOf[top[i]];\n if (s > worstScore) {\n worstScore = s;\n worstIdx = i;\n }\n }\n }\n\n if (score >= worstScore) return false;\n\n top[worstIdx] = node;\n c.scoreOf[node] = score;\n\n return true;\n }\n}\n"
|
|
281
281
|
},
|
|
282
282
|
"project/contracts/slashing/SlashingManager.sol": {
|
|
283
283
|
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\npragma solidity >=0.8.27;\n\nimport {\n AccessControl\n} from \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport { ISlashingManager } from \"../interfaces/ISlashingManager.sol\";\nimport { IBondingRegistry } from \"../interfaces/IBondingRegistry.sol\";\nimport { ISlashVerifier } from \"../interfaces/ISlashVerifier.sol\";\n\n/**\n * @title SlashingManager\n * @notice Implementation of slashing management with proposal, appeal, and execution workflows\n * @dev Role-based access control for slashers, verifiers, and governance with configurable slash policies\n */\ncontract SlashingManager is ISlashingManager, AccessControl {\n // ======================\n // Constants & Roles\n // ======================\n\n /// @notice Role identifier for accounts authorized to propose and execute slashes\n bytes32 public constant SLASHER_ROLE = keccak256(\"SLASHER_ROLE\");\n\n /// @notice Role identifier for accounts authorized to verify cryptographic proofs in slash proposals\n bytes32 public constant VERIFIER_ROLE = keccak256(\"VERIFIER_ROLE\");\n\n /// @notice Role identifier for governance accounts that can configure policies, resolve appeals, and manage bans\n bytes32 public constant GOVERNANCE_ROLE = keccak256(\"GOVERNANCE_ROLE\");\n\n // ======================\n // Storage\n // ======================\n\n /// @notice Reference to the bonding registry contract where slash penalties are executed\n /// @dev Used to call slashTicketBalance() and slashLicenseBond() when executing slashes\n IBondingRegistry public bondingRegistry;\n\n /// @notice Mapping from slash reason hash to its configured policy\n /// @dev Stores penalty amounts, proof requirements, and appeal settings for each slash type\n mapping(bytes32 reason => SlashPolicy policy) public slashPolicies;\n\n /// @notice Internal storage for all slash proposals indexed by proposal ID\n /// @dev Sequentially indexed starting from 0, accessed via getSlashProposal()\n mapping(uint256 proposalId => SlashProposal proposal) internal _proposals;\n\n /// @notice Counter for total number of slash proposals ever created\n /// @dev Also serves as the next proposal ID to be assigned\n uint256 public totalProposals;\n\n /// @notice Mapping tracking which nodes are currently banned from the network\n /// @dev Set to true when a node is banned (either via executeSlash or banNode), false when unbanned\n mapping(address node => bool banned) public banned;\n\n // ======================\n // Modifiers\n // ======================\n\n /// @notice Restricts function access to accounts with SLASHER_ROLE\n /// @dev Reverts with Unauthorized() if caller lacks the role\n modifier onlySlasher() {\n if (!hasRole(SLASHER_ROLE, msg.sender)) revert Unauthorized();\n _;\n }\n\n /// @notice Restricts function access to accounts with VERIFIER_ROLE\n /// @dev Reverts with Unauthorized() if caller lacks the role\n modifier onlyVerifier() {\n if (!hasRole(VERIFIER_ROLE, msg.sender)) revert Unauthorized();\n _;\n }\n\n /// @notice Restricts function access to accounts with GOVERNANCE_ROLE\n /// @dev Reverts with Unauthorized() if caller lacks the role\n modifier onlyGovernance() {\n if (!hasRole(GOVERNANCE_ROLE, msg.sender)) revert Unauthorized();\n _;\n }\n\n // ======================\n // Constructor\n // ======================\n\n /**\n * @notice Initializes the SlashingManager contract with admin and bonding registry\n * @dev Sets up initial role assignments and bonding registry reference\n * @param admin Address to receive DEFAULT_ADMIN_ROLE and GOVERNANCE_ROLE\n * @param _bondingRegistry Address of the bonding registry contract for executing slashes\n * Requirements:\n * - admin must not be zero address\n * - _bondingRegistry must not be zero address\n */\n constructor(address admin, address _bondingRegistry) {\n require(admin != address(0), ZeroAddress());\n require(_bondingRegistry != address(0), ZeroAddress());\n\n bondingRegistry = IBondingRegistry(_bondingRegistry);\n\n _grantRole(DEFAULT_ADMIN_ROLE, admin);\n _grantRole(GOVERNANCE_ROLE, admin);\n }\n\n // ======================\n // View Functions\n // ======================\n\n /// @inheritdoc ISlashingManager\n function getSlashPolicy(\n bytes32 reason\n ) external view returns (SlashPolicy memory) {\n return slashPolicies[reason];\n }\n\n /// @inheritdoc ISlashingManager\n function getSlashProposal(\n uint256 proposalId\n ) external view returns (SlashProposal memory) {\n require(proposalId < totalProposals, InvalidProposal());\n return _proposals[proposalId];\n }\n\n /// @inheritdoc ISlashingManager\n function isBanned(address node) external view returns (bool) {\n return banned[node];\n }\n\n // ======================\n // Admin Functions\n // ======================\n\n /// @inheritdoc ISlashingManager\n function setSlashPolicy(\n bytes32 reason,\n SlashPolicy calldata policy\n ) external onlyRole(GOVERNANCE_ROLE) {\n require(reason != bytes32(0), InvalidPolicy());\n require(policy.enabled, InvalidPolicy());\n require(\n policy.ticketPenalty > 0 || policy.licensePenalty > 0,\n InvalidPolicy()\n );\n\n if (policy.requiresProof) {\n require(policy.proofVerifier != address(0), VerifierNotSet());\n // TODO: Should we allow appeal window for proof required?\n require(policy.appealWindow == 0, InvalidPolicy());\n } else {\n require(policy.appealWindow > 0, InvalidPolicy());\n }\n\n slashPolicies[reason] = policy;\n emit SlashPolicyUpdated(reason, policy);\n }\n\n /// @inheritdoc ISlashingManager\n function setBondingRegistry(\n address newBondingRegistry\n ) external onlyRole(DEFAULT_ADMIN_ROLE) {\n require(newBondingRegistry != address(0), ZeroAddress());\n bondingRegistry = IBondingRegistry(newBondingRegistry);\n }\n\n /// @inheritdoc ISlashingManager\n function addSlasher(address slasher) external onlyRole(DEFAULT_ADMIN_ROLE) {\n require(slasher != address(0), ZeroAddress());\n _grantRole(SLASHER_ROLE, slasher);\n }\n\n /// @inheritdoc ISlashingManager\n function removeSlasher(\n address slasher\n ) external onlyRole(DEFAULT_ADMIN_ROLE) {\n _revokeRole(SLASHER_ROLE, slasher);\n }\n\n /// @inheritdoc ISlashingManager\n function addVerifier(\n address verifier\n ) external onlyRole(DEFAULT_ADMIN_ROLE) {\n require(verifier != address(0), ZeroAddress());\n _grantRole(VERIFIER_ROLE, verifier);\n }\n\n /// @inheritdoc ISlashingManager\n function removeVerifier(\n address verifier\n ) external onlyRole(DEFAULT_ADMIN_ROLE) {\n _revokeRole(VERIFIER_ROLE, verifier);\n }\n\n // ======================\n // Slashing Functions\n // ======================\n\n /// @inheritdoc ISlashingManager\n function proposeSlash(\n address operator,\n bytes32 reason,\n bytes calldata proof\n )\n external\n // TODO: Do we need an onlySlasher modifier?\n // Can anyone propose a slash?\n onlySlasher\n returns (uint256 proposalId)\n {\n require(operator != address(0), ZeroAddress());\n\n SlashPolicy memory policy = slashPolicies[reason];\n require(policy.enabled, SlashReasonDisabled());\n\n proposalId = totalProposals;\n totalProposals = proposalId + 1;\n\n uint256 executableAt = block.timestamp + policy.appealWindow;\n SlashProposal storage p = _proposals[proposalId];\n\n p.operator = operator;\n p.reason = reason;\n p.ticketAmount = policy.ticketPenalty;\n p.licenseAmount = policy.licensePenalty;\n p.proposedAt = block.timestamp;\n p.executableAt = executableAt;\n p.proposer = msg.sender;\n p.proofHash = keccak256(proof);\n\n if (policy.requiresProof) {\n require(proof.length != 0, ProofRequired());\n bool ok = ISlashVerifier(policy.proofVerifier).verify(\n proposalId,\n proof\n );\n require(ok, InvalidProof());\n p.proofVerified = true;\n }\n\n emit SlashProposed(\n proposalId,\n operator,\n reason,\n policy.ticketPenalty,\n policy.licensePenalty,\n executableAt,\n msg.sender\n );\n }\n\n /// @inheritdoc ISlashingManager\n function executeSlash(uint256 proposalId) external {\n require(proposalId < totalProposals, InvalidProposal());\n SlashProposal storage p = _proposals[proposalId];\n\n // Has already been executed?\n require(!p.executed, AlreadyExecuted());\n p.executed = true;\n\n SlashPolicy memory policy = slashPolicies[p.reason];\n\n if (policy.requiresProof) {\n // Appeal window is 0 by policy validation, so we dont check for appeal gating\n require(p.proofVerified, InvalidProof());\n } else {\n // Evidence mode with appeals\n require(block.timestamp >= p.executableAt, AppealWindowActive());\n if (p.appealed) {\n require(p.resolved, AppealPending());\n require(!p.appealUpheld, AppealUpheld()); // approved = appeal upheld => cancel slash, return?\n }\n }\n\n if (p.ticketAmount > 0) {\n bondingRegistry.slashTicketBalance(\n p.operator,\n p.ticketAmount,\n p.reason\n );\n }\n\n if (p.licenseAmount > 0) {\n bondingRegistry.slashLicenseBond(\n p.operator,\n p.licenseAmount,\n p.reason\n );\n }\n\n if (policy.banNode) {\n banned[p.operator] = true;\n emit NodeBanUpdated(p.operator, true, p.reason, msg.sender);\n }\n\n emit SlashExecuted(\n proposalId,\n p.operator,\n p.reason,\n p.ticketAmount,\n p.licenseAmount,\n p.executed\n );\n }\n\n // ======================\n // Appeal Functions\n // ======================\n\n /// @inheritdoc ISlashingManager\n function fileAppeal(uint256 proposalId, string calldata evidence) external {\n require(proposalId < totalProposals, InvalidProposal());\n // TODO: Should we reject the appeal if the proposal has a cryptographic proof?\n SlashProposal storage p = _proposals[proposalId];\n\n // Only the accused can appeal\n require(msg.sender == p.operator, Unauthorized());\n // Only in the window\n require(block.timestamp < p.executableAt, AppealWindowExpired());\n // Only once\n require(!p.appealed, AlreadyAppealed());\n\n p.appealed = true;\n\n emit AppealFiled(proposalId, p.operator, p.reason, evidence);\n }\n\n /// @inheritdoc ISlashingManager\n function resolveAppeal(\n uint256 proposalId,\n bool appealUpheld,\n string calldata resolution\n ) external onlyGovernance {\n require(proposalId < totalProposals, InvalidProposal());\n SlashProposal storage p = _proposals[proposalId];\n\n require(p.appealed, InvalidProposal());\n require(!p.resolved, AlreadyResolved());\n\n p.resolved = true;\n p.appealUpheld = appealUpheld; // true => cancel slash, false => slash stands\n\n emit AppealResolved(\n proposalId,\n p.operator,\n appealUpheld,\n msg.sender,\n resolution\n );\n }\n\n // ======================\n // Ban Management\n // ======================\n\n /// @inheritdoc ISlashingManager\n function updateBanStatus(\n address node,\n bool status,\n bytes32 reason\n ) external onlyGovernance {\n require(node != address(0), ZeroAddress());\n\n banned[node] = status;\n emit NodeBanUpdated(node, status, reason, msg.sender);\n }\n}\n"
|
|
284
284
|
},
|
|
285
285
|
"project/contracts/test/MockCiphernodeRegistry.sol": {
|
|
286
|
-
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\npragma solidity >=0.8.27;\n\nimport { ICiphernodeRegistry } from \"../interfaces/ICiphernodeRegistry.sol\";\n\ncontract MockCiphernodeRegistry is ICiphernodeRegistry {\n function requestCommittee(\n uint256,\n uint256,\n uint32[2] calldata\n ) external pure returns (bool success) {\n success = true;\n }\n\n function isEnabled(address) external pure returns (bool) {\n return true;\n }\n\n function committeePublicKey(uint256 e3Id) external pure returns (bytes32) {\n if (e3Id == type(uint256).max) {\n return bytes32(0);\n } else {\n return keccak256(abi.encode(e3Id));\n }\n }\n\n function isCiphernodeEligible(address) external pure returns (bool) {\n return false;\n }\n\n // solhint-disable-next-line no-empty-blocks\n function addCiphernode(address) external pure {}\n\n // solhint-disable-next-line no-empty-blocks\n function removeCiphernode(address, uint256[] calldata) external pure {}\n\n function publishCommittee(\n uint256,\n address[] calldata,\n bytes calldata\n ) external pure {} // solhint-disable-line no-empty-blocks\n\n function getCommitteeNodes(\n uint256\n ) external pure returns (address[] memory) {\n address[] memory nodes = new address[](0);\n return nodes;\n }\n\n function root() external pure returns (uint256) {\n return 0;\n }\n\n function rootAt(uint256) external pure returns (uint256) {\n return 0;\n }\n\n function treeSize() external pure returns (uint256) {\n return 0;\n }\n\n function getBondingRegistry() external pure returns (address) {\n return address(0);\n }\n\n // solhint-disable-next-line no-empty-blocks\n function setEnclave(address) external pure {}\n\n // solhint-disable-next-line no-empty-blocks\n function setBondingRegistry(address) external pure {}\n\n // solhint-disable-next-line no-empty-blocks\n function submitTicket(uint256, uint256) external pure {}\n\n // solhint-disable-next-line no-empty-blocks\n function finalizeCommittee(uint256) external pure {}\n\n // solhint-disable-next-line no-empty-blocks\n function setSortitionSubmissionWindow(uint256) external pure {}\n\n function isOpen(uint256) external pure returns (bool) {\n return false;\n }\n}\n\ncontract MockCiphernodeRegistryEmptyKey is ICiphernodeRegistry {\n function requestCommittee(\n uint256,\n uint256,\n uint32[2] calldata\n ) external pure returns (bool success) {\n success = true;\n }\n\n function isEnabled(address) external pure returns (bool) {\n return true;\n }\n\n function committeePublicKey(uint256) external pure returns (bytes32) {\n
|
|
286
|
+
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\npragma solidity >=0.8.27;\n\nimport { ICiphernodeRegistry } from \"../interfaces/ICiphernodeRegistry.sol\";\n\ncontract MockCiphernodeRegistry is ICiphernodeRegistry {\n function requestCommittee(\n uint256,\n uint256,\n uint32[2] calldata\n ) external pure returns (bool success) {\n success = true;\n }\n\n function isEnabled(address) external pure returns (bool) {\n return true;\n }\n\n function committeePublicKey(uint256 e3Id) external pure returns (bytes32) {\n if (e3Id == type(uint256).max) {\n return bytes32(0);\n } else {\n return keccak256(abi.encode(e3Id));\n }\n }\n\n function isCiphernodeEligible(address) external pure returns (bool) {\n return false;\n }\n\n // solhint-disable-next-line no-empty-blocks\n function addCiphernode(address) external pure {}\n\n // solhint-disable-next-line no-empty-blocks\n function removeCiphernode(address, uint256[] calldata) external pure {}\n\n function publishCommittee(\n uint256,\n address[] calldata,\n bytes calldata,\n bytes32\n ) external pure {} // solhint-disable-line no-empty-blocks\n\n function getCommitteeNodes(\n uint256\n ) external pure returns (address[] memory) {\n address[] memory nodes = new address[](0);\n return nodes;\n }\n\n function root() external pure returns (uint256) {\n return 0;\n }\n\n function rootAt(uint256) external pure returns (uint256) {\n return 0;\n }\n\n function treeSize() external pure returns (uint256) {\n return 0;\n }\n\n function getBondingRegistry() external pure returns (address) {\n return address(0);\n }\n\n // solhint-disable-next-line no-empty-blocks\n function setEnclave(address) external pure {}\n\n // solhint-disable-next-line no-empty-blocks\n function setBondingRegistry(address) external pure {}\n\n // solhint-disable-next-line no-empty-blocks\n function submitTicket(uint256, uint256) external pure {}\n\n // solhint-disable-next-line no-empty-blocks\n function finalizeCommittee(uint256) external pure {}\n\n // solhint-disable-next-line no-empty-blocks\n function setSortitionSubmissionWindow(uint256) external pure {}\n\n function isOpen(uint256) external pure returns (bool) {\n return false;\n }\n}\n\ncontract MockCiphernodeRegistryEmptyKey is ICiphernodeRegistry {\n error CommitteeNotPublished();\n\n function requestCommittee(\n uint256,\n uint256,\n uint32[2] calldata\n ) external pure returns (bool success) {\n success = true;\n }\n\n function isEnabled(address) external pure returns (bool) {\n return true;\n }\n\n function committeePublicKey(uint256) external pure returns (bytes32) {\n revert CommitteeNotPublished();\n }\n\n function isCiphernodeEligible(address) external pure returns (bool) {\n return false;\n }\n\n // solhint-disable-next-line no-empty-blocks\n function addCiphernode(address) external pure {}\n\n // solhint-disable-next-line no-empty-blocks\n function removeCiphernode(address, uint256[] calldata) external pure {}\n\n function publishCommittee(\n uint256,\n address[] calldata,\n bytes calldata,\n bytes32\n ) external pure {} // solhint-disable-line no-empty-blocks\n\n function getCommitteeNodes(\n uint256\n ) external pure returns (address[] memory) {\n address[] memory nodes = new address[](0);\n return nodes;\n }\n\n function root() external pure returns (uint256) {\n return 0;\n }\n\n function rootAt(uint256) external pure returns (uint256) {\n return 0;\n }\n\n function treeSize() external pure returns (uint256) {\n return 0;\n }\n\n function getBondingRegistry() external pure returns (address) {\n return address(0);\n }\n\n // solhint-disable-next-line no-empty-blocks\n function setEnclave(address) external pure {}\n\n // solhint-disable-next-line no-empty-blocks\n function setBondingRegistry(address) external pure {}\n\n // solhint-disable-next-line no-empty-blocks\n function setSortitionSubmissionWindow(uint256) external pure {}\n\n // solhint-disable-next-line no-empty-blocks\n function submitTicket(uint256, uint256) external pure {}\n\n // solhint-disable-next-line no-empty-blocks\n function finalizeCommittee(uint256) external pure {}\n\n function isOpen(uint256) external pure returns (bool) {\n return false;\n }\n}\n"
|
|
287
287
|
},
|
|
288
288
|
"project/contracts/test/MockComputeProvider.sol": {
|
|
289
289
|
"content": "// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\npragma solidity >=0.8.27;\n\nimport {\n IComputeProvider,\n IDecryptionVerifier\n} from \"../interfaces/IComputeProvider.sol\";\n\ncontract MockComputeProvider is IComputeProvider {\n error InvalidParams();\n\n function validate(\n uint256,\n uint256,\n bytes memory params\n ) external pure returns (IDecryptionVerifier decryptionVerifier) {\n require(params.length == 32, InvalidParams());\n // solhint-disable no-inline-assembly\n assembly {\n decryptionVerifier := mload(add(params, 32))\n }\n (decryptionVerifier) = abi.decode(params, (IDecryptionVerifier));\n }\n}\n"
|