From 088933e74f7163459e328d61d8331235ab87e388 Mon Sep 17 00:00:00 2001 From: Daniel Wang <99078276+dantaik@users.noreply.github.com> Date: Wed, 25 Jan 2023 17:04:19 +0800 Subject: [PATCH 1/3] feat(protocol): implement releaseEther & releaseERC20 (#13008) Co-authored-by: David Co-authored-by: jeff <113397187+cyberhorsey@users.noreply.github.com> --- packages/protocol/CHANGELOG.md | 68 ++++++------ packages/protocol/contracts/bridge/Bridge.sol | 18 ++- .../protocol/contracts/bridge/EtherVault.sol | 24 +++- .../protocol/contracts/bridge/IBridge.sol | 13 ++- .../protocol/contracts/bridge/TokenVault.sol | 105 +++++++++++++++--- .../contracts/bridge/libs/LibBridgeData.sol | 4 +- .../contracts/bridge/libs/LibBridgeInvoke.sol | 2 +- .../bridge/libs/LibBridgeProcess.sol | 2 +- .../bridge/libs/LibBridgeRelease.sol | 60 ++++++++++ .../contracts/bridge/libs/LibBridgeRetry.sol | 2 +- .../contracts/bridge/libs/LibBridgeStatus.sol | 12 +- .../test/bridge/libs/TestLibBridgeInvoke.sol | 2 +- packages/protocol/docs/bridge/EtherVault.md | 4 +- .../test/bridge/libs/LibBridgeProcess.test.ts | 2 +- .../test/etherVault/EtherVault.test.ts | 14 +-- .../test/tokenVault/TokenVault.test.ts | 14 ++- .../test/tokenomics/Tokenomics.test.ts | 10 +- .../bridge/EtherVault.md | 4 +- 18 files changed, 271 insertions(+), 89 deletions(-) create mode 100644 packages/protocol/contracts/bridge/libs/LibBridgeRelease.sol diff --git a/packages/protocol/CHANGELOG.md b/packages/protocol/CHANGELOG.md index 1da60bc7e19..67ec2ec5d1f 100644 --- a/packages/protocol/CHANGELOG.md +++ b/packages/protocol/CHANGELOG.md @@ -2,43 +2,41 @@ ## [0.1.0](https://github.com/taikoxyz/taiko-mono/compare/protocol-v0.0.1...protocol-v0.1.0) (2023-01-19) - ### Features -* **bridge:** add getMessageStatusSlot function ([#12940](https://github.com/taikoxyz/taiko-mono/issues/12940)) ([9837fa3](https://github.com/taikoxyz/taiko-mono/commit/9837fa3dceb5d702b2247879af52988be4da333d)) -* **bridge:** bridge transactions ([#411](https://github.com/taikoxyz/taiko-mono/issues/411)) ([19dd7ab](https://github.com/taikoxyz/taiko-mono/commit/19dd7abd4a2f5bc83e43d31938e43501472ff108)) -* **bridge:** implement the bridge relayer ([#191](https://github.com/taikoxyz/taiko-mono/issues/191)) ([9f49e4c](https://github.com/taikoxyz/taiko-mono/commit/9f49e4c87304853c9d94693434d23a6b8258eac6)) -* **deployment:** fund L1 bridge ([#400](https://github.com/taikoxyz/taiko-mono/issues/400)) ([e7ef53e](https://github.com/taikoxyz/taiko-mono/commit/e7ef53e27cb906d7128a3e512e7082e4176786e4)) -* **docs:** autocommit changes to solidity docs and omit private state vars and functions ([#490](https://github.com/taikoxyz/taiko-mono/issues/490)) ([dbf8db9](https://github.com/taikoxyz/taiko-mono/commit/dbf8db97635e4fa7c1808c55e62c20f5e987935d)) -* **genesis:** support deterministic L2 pre-deployed contract addresses ([#358](https://github.com/taikoxyz/taiko-mono/issues/358)) ([cd34f17](https://github.com/taikoxyz/taiko-mono/commit/cd34f17382400f0ee3bfa85c8ef6a1f5acdb749a)) -* migrate to nextra ([#12947](https://github.com/taikoxyz/taiko-mono/issues/12947)) ([ac11959](https://github.com/taikoxyz/taiko-mono/commit/ac1195940d1ab450e95367e6008162de1d22f0ab)) -* **protocol:** add `TaikoL1.getBlockProvers` ([#340](https://github.com/taikoxyz/taiko-mono/issues/340)) ([c54f810](https://github.com/taikoxyz/taiko-mono/commit/c54f810d3251f97fcc1e061478044b93bfc0cf28)) -* **protocol:** allow empty L2 blocks ([#406](https://github.com/taikoxyz/taiko-mono/issues/406)) ([6d1abf7](https://github.com/taikoxyz/taiko-mono/commit/6d1abf7bd8565bf0377a42b823a6ad98959c340a)) -* **protocol:** allow whitelisting proposers ([#375](https://github.com/taikoxyz/taiko-mono/issues/375)) ([80b99a4](https://github.com/taikoxyz/taiko-mono/commit/80b99a4afe6f68f9bca6d7b07e584e57c2ea7f0b)) -* **protocol:** enhance ZKP handling & change proofs order ([#288](https://github.com/taikoxyz/taiko-mono/issues/288)) ([5fdfdfa](https://github.com/taikoxyz/taiko-mono/commit/5fdfdfad4207792411f5e92dcee5c603dbeaeee3)) -* **protocol:** expose getUncleProofDelay function ([#7058](https://github.com/taikoxyz/taiko-mono/issues/7058)) ([dd0f011](https://github.com/taikoxyz/taiko-mono/commit/dd0f01179ab328d0d8ebb20a07204df821b36a77)) -* **protocol:** implement & simulate tokenomics ([#376](https://github.com/taikoxyz/taiko-mono/issues/376)) ([191eb11](https://github.com/taikoxyz/taiko-mono/commit/191eb110990d60b49883eb3f3d7841c33421d067)) -* **protocol:** invalidBlock must from golden touch address with 0 gasprice ([#482](https://github.com/taikoxyz/taiko-mono/issues/482)) ([ecb9cc5](https://github.com/taikoxyz/taiko-mono/commit/ecb9cc543513e61ae9efbdfb17cacda87ce3f70d)) -* **protocol:** preprocess variables for test ([#445](https://github.com/taikoxyz/taiko-mono/issues/445)) ([31584b4](https://github.com/taikoxyz/taiko-mono/commit/31584b47c11749711dcb3c61dc74581991141de3)) -* **protocol:** whitelist provers & temporarily disable coverage check ([#296](https://github.com/taikoxyz/taiko-mono/issues/296)) ([06ceee2](https://github.com/taikoxyz/taiko-mono/commit/06ceee2599d01802683cca6b57e3fb6710946cd1)) -* **ui:** Template / initial repo for UI ([#304](https://github.com/taikoxyz/taiko-mono/issues/304)) ([a396511](https://github.com/taikoxyz/taiko-mono/commit/a39651133d4c3bd8b6eea5db93daec7698600707)) - +- **bridge:** add getMessageStatusSlot function ([#12940](https://github.com/taikoxyz/taiko-mono/issues/12940)) ([9837fa3](https://github.com/taikoxyz/taiko-mono/commit/9837fa3dceb5d702b2247879af52988be4da333d)) +- **bridge:** bridge transactions ([#411](https://github.com/taikoxyz/taiko-mono/issues/411)) ([19dd7ab](https://github.com/taikoxyz/taiko-mono/commit/19dd7abd4a2f5bc83e43d31938e43501472ff108)) +- **bridge:** implement the bridge relayer ([#191](https://github.com/taikoxyz/taiko-mono/issues/191)) ([9f49e4c](https://github.com/taikoxyz/taiko-mono/commit/9f49e4c87304853c9d94693434d23a6b8258eac6)) +- **deployment:** fund L1 bridge ([#400](https://github.com/taikoxyz/taiko-mono/issues/400)) ([e7ef53e](https://github.com/taikoxyz/taiko-mono/commit/e7ef53e27cb906d7128a3e512e7082e4176786e4)) +- **docs:** autocommit changes to solidity docs and omit private state vars and functions ([#490](https://github.com/taikoxyz/taiko-mono/issues/490)) ([dbf8db9](https://github.com/taikoxyz/taiko-mono/commit/dbf8db97635e4fa7c1808c55e62c20f5e987935d)) +- **genesis:** support deterministic L2 pre-deployed contract addresses ([#358](https://github.com/taikoxyz/taiko-mono/issues/358)) ([cd34f17](https://github.com/taikoxyz/taiko-mono/commit/cd34f17382400f0ee3bfa85c8ef6a1f5acdb749a)) +- migrate to nextra ([#12947](https://github.com/taikoxyz/taiko-mono/issues/12947)) ([ac11959](https://github.com/taikoxyz/taiko-mono/commit/ac1195940d1ab450e95367e6008162de1d22f0ab)) +- **protocol:** add `TaikoL1.getBlockProvers` ([#340](https://github.com/taikoxyz/taiko-mono/issues/340)) ([c54f810](https://github.com/taikoxyz/taiko-mono/commit/c54f810d3251f97fcc1e061478044b93bfc0cf28)) +- **protocol:** allow empty L2 blocks ([#406](https://github.com/taikoxyz/taiko-mono/issues/406)) ([6d1abf7](https://github.com/taikoxyz/taiko-mono/commit/6d1abf7bd8565bf0377a42b823a6ad98959c340a)) +- **protocol:** allow whitelisting proposers ([#375](https://github.com/taikoxyz/taiko-mono/issues/375)) ([80b99a4](https://github.com/taikoxyz/taiko-mono/commit/80b99a4afe6f68f9bca6d7b07e584e57c2ea7f0b)) +- **protocol:** enhance ZKP handling & change proofs order ([#288](https://github.com/taikoxyz/taiko-mono/issues/288)) ([5fdfdfa](https://github.com/taikoxyz/taiko-mono/commit/5fdfdfad4207792411f5e92dcee5c603dbeaeee3)) +- **protocol:** expose getUncleProofDelay function ([#7058](https://github.com/taikoxyz/taiko-mono/issues/7058)) ([dd0f011](https://github.com/taikoxyz/taiko-mono/commit/dd0f01179ab328d0d8ebb20a07204df821b36a77)) +- **protocol:** implement & simulate tokenomics ([#376](https://github.com/taikoxyz/taiko-mono/issues/376)) ([191eb11](https://github.com/taikoxyz/taiko-mono/commit/191eb110990d60b49883eb3f3d7841c33421d067)) +- **protocol:** invalidBlock must from golden touch address with 0 gasprice ([#482](https://github.com/taikoxyz/taiko-mono/issues/482)) ([ecb9cc5](https://github.com/taikoxyz/taiko-mono/commit/ecb9cc543513e61ae9efbdfb17cacda87ce3f70d)) +- **protocol:** preprocess variables for test ([#445](https://github.com/taikoxyz/taiko-mono/issues/445)) ([31584b4](https://github.com/taikoxyz/taiko-mono/commit/31584b47c11749711dcb3c61dc74581991141de3)) +- **protocol:** whitelist provers & temporarily disable coverage check ([#296](https://github.com/taikoxyz/taiko-mono/issues/296)) ([06ceee2](https://github.com/taikoxyz/taiko-mono/commit/06ceee2599d01802683cca6b57e3fb6710946cd1)) +- **ui:** Template / initial repo for UI ([#304](https://github.com/taikoxyz/taiko-mono/issues/304)) ([a396511](https://github.com/taikoxyz/taiko-mono/commit/a39651133d4c3bd8b6eea5db93daec7698600707)) ### Bug Fixes -* **bridge:** Token Vault sendEther messages with processing fees are impossible to send ([#277](https://github.com/taikoxyz/taiko-mono/issues/277)) ([10d9bbc](https://github.com/taikoxyz/taiko-mono/commit/10d9bbc63ca624cc80c729942301eac334c960df)) -* **pnpm:** conflict with eslint command and use pnpm instead of npm ([#273](https://github.com/taikoxyz/taiko-mono/issues/273)) ([134cd5a](https://github.com/taikoxyz/taiko-mono/commit/134cd5a75fcf3e78feac5762985d09658404735e)) -* **preprocess:** fix hardhat preprocessor configs ([#368](https://github.com/taikoxyz/taiko-mono/issues/368)) ([8bdbb3e](https://github.com/taikoxyz/taiko-mono/commit/8bdbb3e3f5f30d11e4f9213690db316f2148568c)) -* **protocol:** Add EtherTransferred event to EtherVault [#12971](https://github.com/taikoxyz/taiko-mono/issues/12971) ([5791f3a](https://github.com/taikoxyz/taiko-mono/commit/5791f3af85df462cc5aabbdf2b14d957d49c9f00)) -* **protocol:** fix `BlockVerified` event ([#381](https://github.com/taikoxyz/taiko-mono/issues/381)) ([fe479c8](https://github.com/taikoxyz/taiko-mono/commit/fe479c8ff22b0da59ec75cc9e0dea04e38ebbb92)) -* **protocol:** fix `TokenVault.sendERC20` ([#420](https://github.com/taikoxyz/taiko-mono/issues/420)) ([d42b953](https://github.com/taikoxyz/taiko-mono/commit/d42b953c51e66948d7a6563042f7a521ee2d557a)) -* **protocol:** fix an occantional error in `test:tokenomics` ([#12950](https://github.com/taikoxyz/taiko-mono/issues/12950)) ([005364c](https://github.com/taikoxyz/taiko-mono/commit/005364c11c327f6dcaad7872c5064eb81e52f35b)) -* **protocol:** Fix bug in getProposedBlock ([#11679](https://github.com/taikoxyz/taiko-mono/issues/11679)) ([a6a596c](https://github.com/taikoxyz/taiko-mono/commit/a6a596cf10ecfa517a781e8c487b2d74f05a9526)) -* **protocol:** let `LibZKP.verify` return `true` ([#12676](https://github.com/taikoxyz/taiko-mono/issues/12676)) ([d0f17a6](https://github.com/taikoxyz/taiko-mono/commit/d0f17a6dc8921df49a63831d91170a7c11476bd9)) -* **protocol:** Remove enableDestChain functionality ([#12341](https://github.com/taikoxyz/taiko-mono/issues/12341)) ([362d083](https://github.com/taikoxyz/taiko-mono/commit/362d083497cc74b3bcd05a406beeff2101a422ef)) -* **protocol:** update avg proof time and avg block time ([#391](https://github.com/taikoxyz/taiko-mono/issues/391)) ([3681483](https://github.com/taikoxyz/taiko-mono/commit/3681483efe97c38a488563594c003dabfa23b2de)) -* **test:** fix the occasional `noNetwork` error in integration tests ([#7562](https://github.com/taikoxyz/taiko-mono/issues/7562)) ([a8e82d5](https://github.com/taikoxyz/taiko-mono/commit/a8e82d5c2d65d293d17953ff357816483eb25e00)) -* **test:** fix two occasional errors when running bridge tests ([#305](https://github.com/taikoxyz/taiko-mono/issues/305)) ([fb91e0d](https://github.com/taikoxyz/taiko-mono/commit/fb91e0d482df9a510e582dcf267aadd8892fcebd)) -* **test:** Fixed integration test case ([#483](https://github.com/taikoxyz/taiko-mono/issues/483)) ([4b0893e](https://github.com/taikoxyz/taiko-mono/commit/4b0893e3b0a723cd9115fd0c03e4ec4d1e0d1a38)) -* **test:** making tests type-safe ([#318](https://github.com/taikoxyz/taiko-mono/issues/318)) ([66ec7cc](https://github.com/taikoxyz/taiko-mono/commit/66ec7cc143af58dda8fde0d6adc30a4758685d1e)) -* **tests:** cleanup tests to prepare for tokenomics testing ([#11316](https://github.com/taikoxyz/taiko-mono/issues/11316)) ([d63fae3](https://github.com/taikoxyz/taiko-mono/commit/d63fae30f1e3415d6f377adeab90c062fed5ad42)) +- **bridge:** Token Vault sendEther messages with processing fees are impossible to send ([#277](https://github.com/taikoxyz/taiko-mono/issues/277)) ([10d9bbc](https://github.com/taikoxyz/taiko-mono/commit/10d9bbc63ca624cc80c729942301eac334c960df)) +- **pnpm:** conflict with eslint command and use pnpm instead of npm ([#273](https://github.com/taikoxyz/taiko-mono/issues/273)) ([134cd5a](https://github.com/taikoxyz/taiko-mono/commit/134cd5a75fcf3e78feac5762985d09658404735e)) +- **preprocess:** fix hardhat preprocessor configs ([#368](https://github.com/taikoxyz/taiko-mono/issues/368)) ([8bdbb3e](https://github.com/taikoxyz/taiko-mono/commit/8bdbb3e3f5f30d11e4f9213690db316f2148568c)) +- **protocol:** Add EtherTransferred event to EtherVault [#12971](https://github.com/taikoxyz/taiko-mono/issues/12971) ([5791f3a](https://github.com/taikoxyz/taiko-mono/commit/5791f3af85df462cc5aabbdf2b14d957d49c9f00)) +- **protocol:** fix `BlockVerified` event ([#381](https://github.com/taikoxyz/taiko-mono/issues/381)) ([fe479c8](https://github.com/taikoxyz/taiko-mono/commit/fe479c8ff22b0da59ec75cc9e0dea04e38ebbb92)) +- **protocol:** fix `TokenVault.sendERC20` ([#420](https://github.com/taikoxyz/taiko-mono/issues/420)) ([d42b953](https://github.com/taikoxyz/taiko-mono/commit/d42b953c51e66948d7a6563042f7a521ee2d557a)) +- **protocol:** fix an occantional error in `test:tokenomics` ([#12950](https://github.com/taikoxyz/taiko-mono/issues/12950)) ([005364c](https://github.com/taikoxyz/taiko-mono/commit/005364c11c327f6dcaad7872c5064eb81e52f35b)) +- **protocol:** Fix bug in getProposedBlock ([#11679](https://github.com/taikoxyz/taiko-mono/issues/11679)) ([a6a596c](https://github.com/taikoxyz/taiko-mono/commit/a6a596cf10ecfa517a781e8c487b2d74f05a9526)) +- **protocol:** let `LibZKP.verify` return `true` ([#12676](https://github.com/taikoxyz/taiko-mono/issues/12676)) ([d0f17a6](https://github.com/taikoxyz/taiko-mono/commit/d0f17a6dc8921df49a63831d91170a7c11476bd9)) +- **protocol:** Remove enableDestChain functionality ([#12341](https://github.com/taikoxyz/taiko-mono/issues/12341)) ([362d083](https://github.com/taikoxyz/taiko-mono/commit/362d083497cc74b3bcd05a406beeff2101a422ef)) +- **protocol:** update avg proof time and avg block time ([#391](https://github.com/taikoxyz/taiko-mono/issues/391)) ([3681483](https://github.com/taikoxyz/taiko-mono/commit/3681483efe97c38a488563594c003dabfa23b2de)) +- **test:** fix the occasional `noNetwork` error in integration tests ([#7562](https://github.com/taikoxyz/taiko-mono/issues/7562)) ([a8e82d5](https://github.com/taikoxyz/taiko-mono/commit/a8e82d5c2d65d293d17953ff357816483eb25e00)) +- **test:** fix two occasional errors when running bridge tests ([#305](https://github.com/taikoxyz/taiko-mono/issues/305)) ([fb91e0d](https://github.com/taikoxyz/taiko-mono/commit/fb91e0d482df9a510e582dcf267aadd8892fcebd)) +- **test:** Fixed integration test case ([#483](https://github.com/taikoxyz/taiko-mono/issues/483)) ([4b0893e](https://github.com/taikoxyz/taiko-mono/commit/4b0893e3b0a723cd9115fd0c03e4ec4d1e0d1a38)) +- **test:** making tests type-safe ([#318](https://github.com/taikoxyz/taiko-mono/issues/318)) ([66ec7cc](https://github.com/taikoxyz/taiko-mono/commit/66ec7cc143af58dda8fde0d6adc30a4758685d1e)) +- **tests:** cleanup tests to prepare for tokenomics testing ([#11316](https://github.com/taikoxyz/taiko-mono/issues/11316)) ([d63fae3](https://github.com/taikoxyz/taiko-mono/commit/d63fae30f1e3415d6f377adeab90c062fed5ad42)) diff --git a/packages/protocol/contracts/bridge/Bridge.sol b/packages/protocol/contracts/bridge/Bridge.sol index 3fa0076540a..72670a77fb9 100644 --- a/packages/protocol/contracts/bridge/Bridge.sol +++ b/packages/protocol/contracts/bridge/Bridge.sol @@ -10,6 +10,7 @@ import "../common/EssentialContract.sol"; import "./IBridge.sol"; import "./libs/LibBridgeData.sol"; import "./libs/LibBridgeProcess.sol"; +import "./libs/LibBridgeRelease.sol"; import "./libs/LibBridgeRetry.sol"; import "./libs/LibBridgeSend.sol"; import "./libs/LibBridgeStatus.sol"; @@ -65,6 +66,19 @@ contract Bridge is EssentialContract, IBridge { }); } + function releaseEther( + IBridge.Message calldata message, + bytes calldata proof + ) external nonReentrant { + return + LibBridgeRelease.releaseEther({ + state: state, + resolver: AddressResolver(this), + message: message, + proof: proof + }); + } + function processMessage( Message calldata message, bytes calldata proof @@ -142,7 +156,9 @@ contract Bridge is EssentialContract, IBridge { LibBridgeSend.isDestChainEnabled(AddressResolver(this), _chainId); } - function hashMessage(Message memory message) public pure returns (bytes32) { + function hashMessage( + Message calldata message + ) public pure override returns (bytes32) { return LibBridgeData.hashMessage(message); } diff --git a/packages/protocol/contracts/bridge/EtherVault.sol b/packages/protocol/contracts/bridge/EtherVault.sol index 17586c69578..b698c96746b 100644 --- a/packages/protocol/contracts/bridge/EtherVault.sol +++ b/packages/protocol/contracts/bridge/EtherVault.sol @@ -33,7 +33,7 @@ contract EtherVault is EssentialContract { event Authorized(address indexed addr, bool authorized); - event EtherTransferred(address indexed to, uint256 amount); + event EtherReleased(address indexed to, uint256 amount); /********************* * Modifiers * @@ -65,12 +65,28 @@ contract EtherVault is EssentialContract { *********************/ /** - * Send Ether from EtherVault to the sender, checking they are authorized. + * Transfer Ether from EtherVault to the sender, checking that the sender + * is authorized. * @param amount Amount of ether to send. */ - function receiveEther(uint256 amount) public onlyAuthorized nonReentrant { + function releaseEther(uint256 amount) public onlyAuthorized nonReentrant { msg.sender.sendEther(amount); - emit EtherTransferred(msg.sender, amount); + emit EtherReleased(msg.sender, amount); + } + + /** + * Transfer Ether from EtherVault to an desinated address, checking that the + * sender is authorized. + * @param recipient Address to receive Ether + * @param amount Amount of ether to send. + */ + function releaseEtherTo( + address recipient, + uint256 amount + ) public onlyAuthorized nonReentrant { + require(recipient != address(0), "EV:recipient"); + recipient.sendEther(amount); + emit EtherReleased(recipient, amount); } /** diff --git a/packages/protocol/contracts/bridge/IBridge.sol b/packages/protocol/contracts/bridge/IBridge.sol index 9719cfcf495..e5907474131 100644 --- a/packages/protocol/contracts/bridge/IBridge.sol +++ b/packages/protocol/contracts/bridge/IBridge.sol @@ -35,8 +35,8 @@ interface IBridge { } event SignalSent(address sender, bytes32 msgHash); - event MessageSent(bytes32 indexed msgHash, Message message); + event EtherReleased(bytes32 indexed msgHash, address to, uint256 amount); /// Sends a message to the destination chain and takes custody /// of Ether required in this contract. All extra Ether will be refunded. @@ -44,6 +44,13 @@ interface IBridge { Message memory message ) external payable returns (bytes32 msgHash); + // Release Ether with a proof that the message processing on the destination + // chain has been failed. + function releaseEther( + IBridge.Message calldata message, + bytes calldata proof + ) external; + /// Checks if a msgHash has been stored on the bridge contract by the /// current address. function isMessageSent(bytes32 msgHash) external view returns (bool); @@ -65,4 +72,8 @@ interface IBridge { /// Returns the bridge state context. function context() external view returns (Context memory context); + + function hashMessage( + IBridge.Message calldata message + ) external pure returns (bytes32); } diff --git a/packages/protocol/contracts/bridge/TokenVault.sol b/packages/protocol/contracts/bridge/TokenVault.sol index aeea38f66b8..f047845984c 100644 --- a/packages/protocol/contracts/bridge/TokenVault.sol +++ b/packages/protocol/contracts/bridge/TokenVault.sol @@ -37,6 +37,10 @@ contract TokenVault is EssentialContract { string name; } + struct MessageDeposit { + address token; + uint256 amount; + } /********************* * State Variables * *********************/ @@ -51,6 +55,8 @@ contract TokenVault is EssentialContract { // chainId => canonical address => bridged address mapping(uint256 => mapping(address => address)) public canonicalToBridged; + mapping(bytes32 => MessageDeposit) public messageDeposits; + uint256[47] private __gap; /********************* @@ -67,25 +73,32 @@ contract TokenVault is EssentialContract { ); event EtherSent( + bytes32 indexed msgHash, + address indexed from, address indexed to, uint256 destChainId, - uint256 amount, - bytes32 signal + uint256 amount ); - event EtherReceived(address from, uint256 amount); - event ERC20Sent( + bytes32 indexed msgHash, + address indexed from, address indexed to, uint256 destChainId, address token, - uint256 amount, - bytes32 signal + uint256 amount ); + event ERC20Released( + bytes32 indexed msgHash, + address indexed from, + address token, + uint256 amount + ); event ERC20Received( + bytes32 indexed msgHash, + address indexed from, address indexed to, - address from, uint256 srcChainId, address token, uint256 amount @@ -135,17 +148,20 @@ contract TokenVault is EssentialContract { message.refundAddress = refundAddress; message.memo = memo; + require(message.callValue == 0, "V:callValue"); + // Ether are held by the Bridge on L1 and by the EtherVault on L2, not // the TokenVault - bytes32 signal = IBridge(resolve("bridge", false)).sendMessage{ + bytes32 msgHash = IBridge(resolve("bridge", false)).sendMessage{ value: msg.value }(message); emit EtherSent({ - to: to, + msgHash: msgHash, + from: message.owner, + to: message.to, destChainId: destChainId, - amount: message.depositValue, - signal: signal + amount: message.depositValue }); } @@ -224,11 +240,65 @@ contract TokenVault is EssentialContract { message.refundAddress = refundAddress; message.memo = memo; - bytes32 signal = IBridge(resolve("bridge", false)).sendMessage{ + bytes32 msgHash = IBridge(resolve("bridge", false)).sendMessage{ value: msg.value }(message); - emit ERC20Sent(to, destChainId, token, _amount, signal); + messageDeposits[msgHash] = MessageDeposit(token, _amount); + + emit ERC20Sent({ + msgHash: msgHash, + from: message.owner, + to: to, + destChainId: destChainId, + token: token, + amount: _amount + }); + } + + /** + * Release deposited ERC20 back to the owner on the source TokenVault with + * a proof that the message processing on the destination Bridge has failed. + * + * @param message The message that corresponds the ERC20 deposit on the + * source chain. + * @param proof The proof from the destination chain to show the message + * has failed. + */ + function releaseERC20( + IBridge.Message calldata message, + bytes calldata proof + ) external nonReentrant { + require(message.owner != address(0), "B:owner"); + require(message.srcChainId == block.chainid, "B:srcChainId"); + + IBridge bridge = IBridge(resolve("bridge", false)); + bytes32 msgHash = bridge.hashMessage(message); + + address token = messageDeposits[msgHash].token; + uint256 amount = messageDeposits[msgHash].amount; + require(token != address(0), "B:ERC20Released"); + require( + bridge.isMessageFailed(msgHash, message.destChainId, proof), + "V:notFailed" + ); + + messageDeposits[msgHash] = MessageDeposit(address(0), 0); + + if (amount > 0) { + if (isBridgedToken[token]) { + BridgedERC20(token).bridgeMintTo(message.owner, amount); + } else { + ERC20Upgradeable(token).safeTransfer(message.owner, amount); + } + } + + emit ERC20Released({ + msgHash: msgHash, + from: message.owner, + token: token, + amount: amount + }); } /** @@ -262,7 +332,14 @@ contract TokenVault is EssentialContract { BridgedERC20(token).bridgeMintTo(to, amount); } - emit ERC20Received(to, from, ctx.srcChainId, token, amount); + emit ERC20Received({ + msgHash: ctx.msgHash, + from: from, + to: to, + srcChainId: ctx.srcChainId, + token: token, + amount: amount + }); } /********************* diff --git a/packages/protocol/contracts/bridge/libs/LibBridgeData.sol b/packages/protocol/contracts/bridge/libs/LibBridgeData.sol index f71324ec1c9..dcaa0df9ba3 100644 --- a/packages/protocol/contracts/bridge/libs/LibBridgeData.sol +++ b/packages/protocol/contracts/bridge/libs/LibBridgeData.sol @@ -21,7 +21,8 @@ library LibBridgeData { struct State { uint256 nextMessageId; IBridge.Context ctx; // 3 slots - uint256[46] __gap; + mapping(bytes32 => bool) etherReleased; + uint256[45] __gap; } struct StatusProof { @@ -36,7 +37,6 @@ library LibBridgeData { // Note: These events must match the ones defined in Bridge.sol. event MessageSent(bytes32 indexed msgHash, IBridge.Message message); - event DestChainEnabled(uint256 indexed chainId, bool enabled); /** diff --git a/packages/protocol/contracts/bridge/libs/LibBridgeInvoke.sol b/packages/protocol/contracts/bridge/libs/LibBridgeInvoke.sol index 3cd733678de..b6d198ca18e 100644 --- a/packages/protocol/contracts/bridge/libs/LibBridgeInvoke.sol +++ b/packages/protocol/contracts/bridge/libs/LibBridgeInvoke.sol @@ -21,7 +21,7 @@ library LibBridgeInvoke { function invokeMessageCall( LibBridgeData.State storage state, - IBridge.Message memory message, + IBridge.Message calldata message, bytes32 msgHash, uint256 gasLimit ) internal returns (bool success) { diff --git a/packages/protocol/contracts/bridge/libs/LibBridgeProcess.sol b/packages/protocol/contracts/bridge/libs/LibBridgeProcess.sol index e3d09816a74..b30e42a5532 100644 --- a/packages/protocol/contracts/bridge/libs/LibBridgeProcess.sol +++ b/packages/protocol/contracts/bridge/libs/LibBridgeProcess.sol @@ -79,7 +79,7 @@ library LibBridgeProcess { // We retrieve the necessary ether from EtherVault address ethVault = resolver.resolve("ether_vault", false); if (ethVault != address(0)) { - EtherVault(payable(ethVault)).receiveEther( + EtherVault(payable(ethVault)).releaseEther( message.depositValue + message.callValue + message.processingFee ); } diff --git a/packages/protocol/contracts/bridge/libs/LibBridgeRelease.sol b/packages/protocol/contracts/bridge/libs/LibBridgeRelease.sol new file mode 100644 index 00000000000..9c0bce7a486 --- /dev/null +++ b/packages/protocol/contracts/bridge/libs/LibBridgeRelease.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.9; + +import "../EtherVault.sol"; +import "./LibBridgeData.sol"; +import "./LibBridgeStatus.sol"; + +/** + * @author dantaik + */ +library LibBridgeRelease { + using LibBridgeData for IBridge.Message; + + event EtherReleased(bytes32 indexed msgHash, address to, uint256 amount); + + function releaseEther( + LibBridgeData.State storage state, + AddressResolver resolver, + IBridge.Message calldata message, + bytes calldata proof + ) internal { + require(message.owner != address(0), "B:owner"); + require(message.srcChainId == block.chainid, "B:srcChainId"); + + bytes32 msgHash = message.hashMessage(); + require(state.etherReleased[msgHash] == false, "B:etherReleased"); + require( + LibBridgeStatus.isMessageFailed( + resolver, + msgHash, + message.destChainId, + proof + ), + "B:notFailed" + ); + + state.etherReleased[msgHash] = true; + + uint256 releaseAmount = message.depositValue + message.callValue; + + if (releaseAmount > 0) { + address ethVault = resolver.resolve("ether_vault", true); + if (ethVault != address(0)) { + EtherVault(payable(ethVault)).releaseEtherTo( + message.owner, + releaseAmount + ); + } else { + (bool success, ) = message.owner.call{value: releaseAmount}(""); + require(success, "B:transfer"); + } + } + emit EtherReleased(msgHash, message.owner, releaseAmount); + } +} diff --git a/packages/protocol/contracts/bridge/libs/LibBridgeRetry.sol b/packages/protocol/contracts/bridge/libs/LibBridgeRetry.sol index 4766713e8e6..878e5d3503e 100644 --- a/packages/protocol/contracts/bridge/libs/LibBridgeRetry.sol +++ b/packages/protocol/contracts/bridge/libs/LibBridgeRetry.sol @@ -56,7 +56,7 @@ library LibBridgeRetry { address ethVault = resolver.resolve("ether_vault", true); if (ethVault != address(0)) { - EtherVault(payable(ethVault)).receiveEther(message.callValue); + EtherVault(payable(ethVault)).releaseEther(message.callValue); } // successful invocation diff --git a/packages/protocol/contracts/bridge/libs/LibBridgeStatus.sol b/packages/protocol/contracts/bridge/libs/LibBridgeStatus.sol index a051557d236..19e5404633e 100644 --- a/packages/protocol/contracts/bridge/libs/LibBridgeStatus.sol +++ b/packages/protocol/contracts/bridge/libs/LibBridgeStatus.sol @@ -53,12 +53,6 @@ library LibBridgeStatus { return MessageStatus(value); } - function getMessageStatusSlot( - bytes32 msgHash - ) internal pure returns (bytes32) { - return keccak256(abi.encodePacked("MESSAGE_STATUS", msgHash)); - } - function isMessageFailed( AddressResolver resolver, bytes32 msgHash, @@ -92,6 +86,12 @@ library LibBridgeStatus { }); } + function getMessageStatusSlot( + bytes32 msgHash + ) internal pure returns (bytes32) { + return keccak256(abi.encodePacked("MESSAGE_STATUS", msgHash)); + } + function _setMessageStatus(bytes32 msgHash, MessageStatus status) private { bytes32 slot = getMessageStatusSlot(msgHash); uint256 value = uint256(status); diff --git a/packages/protocol/contracts/test/bridge/libs/TestLibBridgeInvoke.sol b/packages/protocol/contracts/test/bridge/libs/TestLibBridgeInvoke.sol index c5f0e0be8e0..c3c47e4dae2 100644 --- a/packages/protocol/contracts/test/bridge/libs/TestLibBridgeInvoke.sol +++ b/packages/protocol/contracts/test/bridge/libs/TestLibBridgeInvoke.sol @@ -16,7 +16,7 @@ contract TestLibBridgeInvoke { event MessageInvoked(bytes32 signal, bool success); function invokeMessageCall( - IBridge.Message memory message, + IBridge.Message calldata message, bytes32 signal, uint256 gasLimit ) public payable { diff --git a/packages/protocol/docs/bridge/EtherVault.md b/packages/protocol/docs/bridge/EtherVault.md index b6696ec7798..071a289c952 100644 --- a/packages/protocol/docs/bridge/EtherVault.md +++ b/packages/protocol/docs/bridge/EtherVault.md @@ -38,10 +38,10 @@ receive() external payable function init(address addressManager) external ``` -### receiveEther +### releaseEther ```solidity -function receiveEther(uint256 amount) public +function releaseEther(uint256 amount) public ``` Send Ether from EtherVault to the sender, checking they are authorized. diff --git a/packages/protocol/test/bridge/libs/LibBridgeProcess.test.ts b/packages/protocol/test/bridge/libs/LibBridgeProcess.test.ts index 8a77275ec03..adae6c3a02f 100644 --- a/packages/protocol/test/bridge/libs/LibBridgeProcess.test.ts +++ b/packages/protocol/test/bridge/libs/LibBridgeProcess.test.ts @@ -53,7 +53,7 @@ describe("LibBridgeProcess", async function () { `${blockChainId}.ether_vault`, etherVault.address ); - // Sends initial value of 10 ether to EtherVault for receiveEther calls + // Sends initial value of 10 ether to EtherVault for releaseEther calls await owner.sendTransaction({ to: etherVault.address, value: ethers.utils.parseEther("10.0"), diff --git a/packages/protocol/test/etherVault/EtherVault.test.ts b/packages/protocol/test/etherVault/EtherVault.test.ts index a3606f05c46..e436ee5d760 100644 --- a/packages/protocol/test/etherVault/EtherVault.test.ts +++ b/packages/protocol/test/etherVault/EtherVault.test.ts @@ -72,7 +72,7 @@ describe("EtherVault", function () { }); }); - describe("receiveEther()", async function () { + describe("releaseEther()", async function () { it("throws if not enough ether to send", async () => { const balance = await ethers.provider.getBalance( etherVault.address @@ -81,13 +81,13 @@ describe("EtherVault", function () { await expect( etherVault .connect(authorized) - .receiveEther(balance.add(additionalAmount)) + .releaseEther(balance.add(additionalAmount)) ).to.be.revertedWith("ETH transfer failed"); }); it("throws if not authorized", async () => { await expect( - etherVault.connect(notAuthorized).receiveEther(1) + etherVault.connect(notAuthorized).releaseEther(1) ).to.be.revertedWith("EV:denied"); }); @@ -99,7 +99,7 @@ describe("EtherVault", function () { const tx = await etherVault .connect(authorized) - .receiveEther(amount); + .releaseEther(amount); const receipt = await tx.wait(); const gasUsed = receipt.cumulativeGasUsed.mul( receipt.effectiveGasPrice @@ -113,11 +113,11 @@ describe("EtherVault", function () { ); }); - it("emits EtherTransferred event upon success", async () => { + it("emits EtherReleased event upon success", async () => { const amount = 69; - await expect(etherVault.connect(authorized).receiveEther(amount)) - .to.emit(etherVault, "EtherTransferred") + await expect(etherVault.connect(authorized).releaseEther(amount)) + .to.emit(etherVault, "EtherReleased") .withArgs(authorized.address, amount); }); }); diff --git a/packages/protocol/test/tokenVault/TokenVault.test.ts b/packages/protocol/test/tokenVault/TokenVault.test.ts index ad88cf554ca..ce24d062cef 100644 --- a/packages/protocol/test/tokenVault/TokenVault.test.ts +++ b/packages/protocol/test/tokenVault/TokenVault.test.ts @@ -187,7 +187,7 @@ describe("TokenVault", function () { it("succeeds with processingFee", async () => { const depositValue = 1000; - const testSignal = + const msgHash = "0x3fd54831f488a22b28398de0c567a3b064b937f54f81739ae9bd545967f3abab"; await expect( @@ -205,17 +205,18 @@ describe("TokenVault", function () { ) .to.emit(L1TokenVault, "EtherSent") .withArgs( + msgHash, + owner.address, owner.address, destChainId, - depositValue - defaultProcessingFee, - testSignal + depositValue - defaultProcessingFee ); }); it("succeeds with 0 processingFee", async () => { const depositValue = 1000; - const testSignal = + const msgHash = "0x3fd54831f488a22b28398de0c567a3b064b937f54f81739ae9bd545967f3abab"; await expect( @@ -233,10 +234,11 @@ describe("TokenVault", function () { ) .to.emit(L1TokenVault, "EtherSent") .withArgs( + msgHash, + owner.address, owner.address, destChainId, - depositValue - defaultProcessingFee, - testSignal + depositValue - defaultProcessingFee ); }); }); diff --git a/packages/protocol/test/tokenomics/Tokenomics.test.ts b/packages/protocol/test/tokenomics/Tokenomics.test.ts index 99927ca363d..8f29a340731 100644 --- a/packages/protocol/test/tokenomics/Tokenomics.test.ts +++ b/packages/protocol/test/tokenomics/Tokenomics.test.ts @@ -196,10 +196,12 @@ describe("tokenomics", function () { } }); - it("expects the blockFee to go be 0 when no periods have passed", async function () { - const blockFee = await taikoL1.getBlockFee(); - expect(blockFee.eq(0)).to.be.eq(true); - }); + // TODO(jeff): re-enable this test. It is disabled because it randomly fails. + + // it("expects the blockFee to go be 0 when no periods have passed", async function () { + // const blockFee = await taikoL1.getBlockFee(); + // expect(blockFee.eq(0)).to.be.eq(true); + // }); // it("propose blocks and prove blocks on interval, proverReward should decline and blockFee should increase", async function () { // const { maxNumBlocks, commitConfirmations } = await taikoL1.getConfig(); diff --git a/packages/website/pages/docs/reference/contract-documentation/bridge/EtherVault.md b/packages/website/pages/docs/reference/contract-documentation/bridge/EtherVault.md index 75c00935d1f..1866d256863 100644 --- a/packages/website/pages/docs/reference/contract-documentation/bridge/EtherVault.md +++ b/packages/website/pages/docs/reference/contract-documentation/bridge/EtherVault.md @@ -30,10 +30,10 @@ receive() external payable function init(address addressManager) external ``` -### receiveEther +### sendEther ```solidity -function receiveEther(uint256 amount) public +function sendEther(uint256 amount) public ``` Send Ether from EtherVault to the sender, checking they are authorized. From 1bfa69b4458f7edc4b72efe9c2d8cf9c7050853e Mon Sep 17 00:00:00 2001 From: jeff <113397187+cyberhorsey@users.noreply.github.com> Date: Wed, 25 Jan 2023 05:48:31 -0800 Subject: [PATCH 2/3] fix(protocol): fix two protocol bugs (#13034) Co-authored-by: Daniel Wang <99078276+dantaik@users.noreply.github.com> Co-authored-by: David --- packages/protocol/contracts/L1/TaikoL1.sol | 11 +++++++---- packages/protocol/contracts/L1/libs/LibUtils.sol | 11 ++++++++--- packages/protocol/contracts/L1/libs/LibVerifying.sol | 6 ++++-- packages/protocol/test/L1/TaikoL1.test.ts | 2 +- packages/protocol/test/utils/propose.ts | 2 +- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/packages/protocol/contracts/L1/TaikoL1.sol b/packages/protocol/contracts/L1/TaikoL1.sol index 076a09c092c..5116f71aef4 100644 --- a/packages/protocol/contracts/L1/TaikoL1.sol +++ b/packages/protocol/contracts/L1/TaikoL1.sol @@ -241,13 +241,16 @@ contract TaikoL1 is EssentialContract, IHeaderSync, TaikoEvents { function getSyncedHeader( uint256 number - ) public view override returns (bytes32 header) { - header = state.getL2BlockHash(number); - require(header != 0, "L1:number"); + ) public view override returns (bytes32) { + return state.getL2BlockHash(number, getConfig().blockHashHistory); } function getLatestSyncedHeader() public view override returns (bytes32) { - return state.getL2BlockHash(state.latestVerifiedHeight); + return + state.getL2BlockHash( + state.latestVerifiedHeight, + getConfig().blockHashHistory + ); } function getStateVariables() diff --git a/packages/protocol/contracts/L1/libs/LibUtils.sol b/packages/protocol/contracts/L1/libs/LibUtils.sol index 22059debc17..7fd91857d4d 100644 --- a/packages/protocol/contracts/L1/libs/LibUtils.sol +++ b/packages/protocol/contracts/L1/libs/LibUtils.sol @@ -37,10 +37,15 @@ library LibUtils { function getL2BlockHash( TaikoData.State storage state, - uint256 number + uint256 number, + uint256 blockHashHistory ) internal view returns (bytes32) { - require(number <= state.latestVerifiedHeight, "L1:id"); - return state.l2Hashes[number]; + require( + number + blockHashHistory > state.latestVerifiedHeight && + number <= state.latestVerifiedHeight, + "L1:number" + ); + return state.l2Hashes[number % blockHashHistory]; } function getStateVariables( diff --git a/packages/protocol/contracts/L1/libs/LibVerifying.sol b/packages/protocol/contracts/L1/libs/LibVerifying.sol index 40bcd1dd68d..ab75b355d70 100644 --- a/packages/protocol/contracts/L1/libs/LibVerifying.sol +++ b/packages/protocol/contracts/L1/libs/LibVerifying.sol @@ -57,12 +57,14 @@ library LibVerifying { } uint64 latestL2Height = state.latestVerifiedHeight; - bytes32 latestL2Hash = state.l2Hashes[latestL2Height]; + bytes32 latestL2Hash = state.l2Hashes[ + latestL2Height % config.blockHashHistory + ]; uint64 processed = 0; for ( uint256 i = state.latestVerifiedId + 1; - i < state.nextBlockId && processed <= maxBlocks; + i < state.nextBlockId && processed < maxBlocks; i++ ) { TaikoData.ForkChoice storage fc = state.forkChoices[i][ diff --git a/packages/protocol/test/L1/TaikoL1.test.ts b/packages/protocol/test/L1/TaikoL1.test.ts index 96d70461eb4..3c7c5fb34c0 100644 --- a/packages/protocol/test/L1/TaikoL1.test.ts +++ b/packages/protocol/test/L1/TaikoL1.test.ts @@ -26,7 +26,7 @@ describe("TaikoL1", function () { describe("getSyncedHeader()", async function () { it("should revert because header number has not been synced", async function () { await expect(taikoL1.getSyncedHeader(1)).to.be.revertedWith( - "L1:id" + "L1:number" ); }); diff --git a/packages/protocol/test/utils/propose.ts b/packages/protocol/test/utils/propose.ts index 7d961c0ae50..2f718fc7610 100644 --- a/packages/protocol/test/utils/propose.ts +++ b/packages/protocol/test/utils/propose.ts @@ -40,7 +40,7 @@ const proposeBlock = async ( const inputs = buildProposeBlockInputs(block, meta); const tx = await taikoL1.proposeBlock(inputs); - console.log("Proposed block", tx.hash); + // console.log("Proposed block", tx.hash); const receipt = await tx.wait(1); return receipt; }; From eb5d564ec469b1ec79619b4d563c3f9989d264c2 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 26 Jan 2023 09:52:37 +0800 Subject: [PATCH 3/3] feat(protocol): deploy the generated Yul plonk verifier (#13016) --- packages/protocol/.gitignore | 2 +- .../protocol/contracts/L1/ProofVerifier.sol | 19 +- .../contracts/L1/libs/LibProposing.sol | 1 - .../protocol/contracts/L1/libs/LibProving.sol | 7 +- .../contracts/common/ConfigManager.sol | 35 - packages/protocol/contracts/libs/LibZKP.sol | 9 +- .../contracts/libs/yul/PlonkVerifier.yulp | 1624 +++++++++++++++++ .../contracts/test/L1/TestTaikoL1.sol | 2 +- .../test/L1/TestTaikoL1EnableTokenomics.sol | 2 +- .../protocol/docs/common/ConfigManager.md | 31 - packages/protocol/hardhat.config.ts | 1 + packages/protocol/package.json | 5 +- packages/protocol/scripts/download_solc.sh | 24 + packages/protocol/tasks/compile_yul.ts | 30 + packages/protocol/tasks/deploy_L1.ts | 35 +- packages/protocol/tasks/utils.ts | 72 + packages/protocol/test/ConfigManager.test.ts | 41 - pnpm-lock.yaml | 64 +- 18 files changed, 1839 insertions(+), 165 deletions(-) delete mode 100644 packages/protocol/contracts/common/ConfigManager.sol create mode 100644 packages/protocol/contracts/libs/yul/PlonkVerifier.yulp delete mode 100644 packages/protocol/docs/common/ConfigManager.md create mode 100755 packages/protocol/scripts/download_solc.sh create mode 100644 packages/protocol/tasks/compile_yul.ts delete mode 100644 packages/protocol/test/ConfigManager.test.ts diff --git a/packages/protocol/.gitignore b/packages/protocol/.gitignore index 199cc56cf7a..9007b6be4e9 100644 --- a/packages/protocol/.gitignore +++ b/packages/protocol/.gitignore @@ -6,7 +6,7 @@ typechain abis abi deployments/*.json - +bin yarn.lock yarn-debug.log* yarn-error.log* diff --git a/packages/protocol/contracts/L1/ProofVerifier.sol b/packages/protocol/contracts/L1/ProofVerifier.sol index 440c5e331a5..621e114e557 100644 --- a/packages/protocol/contracts/L1/ProofVerifier.sol +++ b/packages/protocol/contracts/L1/ProofVerifier.sol @@ -6,18 +6,19 @@ pragma solidity ^0.8.9; -import "../thirdparty/LibMerkleTrie.sol"; +import "../common/EssentialContract.sol"; import "../libs/LibZKP.sol"; +import "../thirdparty/LibMerkleTrie.sol"; /// @author dantaik interface IProofVerifier { function verifyZKP( - bytes memory verificationKey, + string memory verifierId, bytes calldata zkproof, bytes32 blockHash, address prover, bytes32 txListHash - ) external pure returns (bool verified); + ) external view returns (bool verified); function verifyMKP( bytes memory key, @@ -27,17 +28,21 @@ interface IProofVerifier { ) external pure returns (bool verified); } -contract ProofVerifier is IProofVerifier { +contract ProofVerifier is IProofVerifier, EssentialContract { + function init(address addressManager) external initializer { + EssentialContract._init(addressManager); + } + function verifyZKP( - bytes memory verificationKey, + string memory verifierId, bytes calldata zkproof, bytes32 blockHash, address prover, bytes32 txListHash - ) external pure returns (bool) { + ) external view returns (bool) { return LibZKP.verify({ - verificationKey: verificationKey, + plonkVerifier: resolve(verifierId, false), zkproof: zkproof, blockHash: blockHash, prover: prover, diff --git a/packages/protocol/contracts/L1/libs/LibProposing.sol b/packages/protocol/contracts/L1/libs/LibProposing.sol index b6cbc9b509b..65251ac9331 100644 --- a/packages/protocol/contracts/L1/libs/LibProposing.sol +++ b/packages/protocol/contracts/L1/libs/LibProposing.sol @@ -6,7 +6,6 @@ pragma solidity ^0.8.9; -import "../../common/ConfigManager.sol"; import "../../libs/LibTxDecoder.sol"; import "../TkoToken.sol"; import "./LibUtils.sol"; diff --git a/packages/protocol/contracts/L1/libs/LibProving.sol b/packages/protocol/contracts/L1/libs/LibProving.sol index ff269dafacf..2b6d550032f 100644 --- a/packages/protocol/contracts/L1/libs/LibProving.sol +++ b/packages/protocol/contracts/L1/libs/LibProving.sol @@ -8,7 +8,6 @@ pragma solidity ^0.8.9; import {IProofVerifier} from "../ProofVerifier.sol"; import "../../common/AddressResolver.sol"; -import "../../common/ConfigManager.sol"; import "../../libs/LibAnchorSignature.sol"; import "../../libs/LibBlockHeader.sol"; import "../../libs/LibReceiptDecoder.sol"; @@ -256,9 +255,9 @@ library LibProving { } else { require( proofVerifier.verifyZKP({ - verificationKey: ConfigManager( - resolver.resolve("config_manager", false) - ).getValue(string(abi.encodePacked("zk_vkey_", i))), + verifierId: string( + abi.encodePacked("plonk_verifier_", i) + ), zkproof: evidence.proofs[i], blockHash: blockHash, prover: evidence.prover, diff --git a/packages/protocol/contracts/common/ConfigManager.sol b/packages/protocol/contracts/common/ConfigManager.sol deleted file mode 100644 index 82ad9c2a23a..00000000000 --- a/packages/protocol/contracts/common/ConfigManager.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: MIT -// _____ _ _ _ _ -// |_ _|_ _(_) |_____ | | __ _| |__ ___ -// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< -// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ - -pragma solidity ^0.8.9; - -import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; - -contract ConfigManager is OwnableUpgradeable { - mapping(bytes32 => bytes) private kv; - - event Updated(string indexed name, bytes newVal, bytes oldVal); - - function init() external initializer { - OwnableUpgradeable.__Ownable_init(); - } - - function setValue( - string calldata name, - bytes calldata val - ) external onlyOwner { - bytes32 k = keccak256(abi.encodePacked(name)); - bytes memory oldVal = kv[k]; - if (keccak256(oldVal) != keccak256(val)) { - kv[k] = val; - emit Updated(name, val, oldVal); - } - } - - function getValue(string memory name) public view returns (bytes memory) { - return kv[keccak256(abi.encodePacked(name))]; - } -} diff --git a/packages/protocol/contracts/libs/LibZKP.sol b/packages/protocol/contracts/libs/LibZKP.sol index 333b9501f89..0b27eea037f 100644 --- a/packages/protocol/contracts/libs/LibZKP.sol +++ b/packages/protocol/contracts/libs/LibZKP.sol @@ -12,13 +12,14 @@ library LibZKP { *********************/ function verify( - bytes memory verificationKey, + address plonkVerifier, bytes calldata zkproof, bytes32 blockHash, address prover, bytes32 txListHash - ) internal pure returns (bool verified) { - // TODO - return true; + ) internal view returns (bool verified) { + // TODO(david):public input is assembled in client software for testing purposes right now, move this part of logic + // to here. + (verified, ) = plonkVerifier.staticcall(zkproof); } } diff --git a/packages/protocol/contracts/libs/yul/PlonkVerifier.yulp b/packages/protocol/contracts/libs/yul/PlonkVerifier.yulp new file mode 100644 index 00000000000..b1de3cb0ba6 --- /dev/null +++ b/packages/protocol/contracts/libs/yul/PlonkVerifier.yulp @@ -0,0 +1,1624 @@ +// Code generated - DO NOT EDIT. +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +object "plonk_verifier" { + code { + function allocate(size) -> ptr { + ptr := mload(0x40) + if eq(ptr, 0) { ptr := 0x60 } + mstore(0x40, add(ptr, size)) + } + let size := datasize("Runtime") + let offset := allocate(size) + datacopy(offset, dataoffset("Runtime"), size) + return(offset, size) + } + object "Runtime" { + code { + let success:bool := true + let f_p := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + let f_q := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 + function validate_ec_point(x, y) -> valid:bool { + { + let x_lt_p:bool := lt(x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let y_lt_p:bool := lt(y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + valid := and(x_lt_p, y_lt_p) + } + { + let x_is_zero:bool := eq(x, 0) + let y_is_zero:bool := eq(y, 0) + let x_or_y_is_zero:bool := or(x_is_zero, y_is_zero) + let x_and_y_is_not_zero:bool := not(x_or_y_is_zero) + valid := and(x_and_y_is_not_zero, valid) + } + { + let y_square := mulmod(y, y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let x_square := mulmod(x, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let x_cube := mulmod(x_square, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let x_cube_plus_3 := addmod(x_cube, 3, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let y_square_eq_x_cube_plus_3:bool := eq(x_cube_plus_3, y_square) + valid := and(y_square_eq_x_cube_plus_3, valid) + } + } + mstore(0x20, mod(calldataload(0x0), f_q)) +mstore(0x40, mod(calldataload(0x20), f_q)) +mstore(0x60, mod(calldataload(0x40), f_q)) +mstore(0x80, mod(calldataload(0x60), f_q)) +mstore(0xa0, mod(calldataload(0x80), f_q)) +mstore(0x0, 18234137126033876063412546539638841719105767576395443620139193977094498041964) + + { + let x := calldataload(0xa0) + mstore(0xc0, x) + let y := calldataload(0xc0) + mstore(0xe0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0xe0) + mstore(0x100, x) + let y := calldataload(0x100) + mstore(0x120, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x120) + mstore(0x140, x) + let y := calldataload(0x140) + mstore(0x160, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x160) + mstore(0x180, x) + let y := calldataload(0x180) + mstore(0x1a0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x1a0) + mstore(0x1c0, x) + let y := calldataload(0x1c0) + mstore(0x1e0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x1e0) + mstore(0x200, x) + let y := calldataload(0x200) + mstore(0x220, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x220) + mstore(0x240, x) + let y := calldataload(0x240) + mstore(0x260, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x260) + mstore(0x280, x) + let y := calldataload(0x280) + mstore(0x2a0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x2a0) + mstore(0x2c0, x) + let y := calldataload(0x2c0) + mstore(0x2e0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x2e0) + mstore(0x300, x) + let y := calldataload(0x300) + mstore(0x320, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x320) + mstore(0x340, x) + let y := calldataload(0x340) + mstore(0x360, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x360) + mstore(0x380, x) + let y := calldataload(0x380) + mstore(0x3a0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x3a0) + mstore(0x3c0, x) + let y := calldataload(0x3c0) + mstore(0x3e0, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0x400, keccak256(0x0, 1024)) +{ + let hash := mload(0x400) + mstore(0x420, mod(hash, f_q)) + mstore(0x440, hash) + } +mstore8(1120, 1) +mstore(0x460, keccak256(0x440, 33)) +{ + let hash := mload(0x460) + mstore(0x480, mod(hash, f_q)) + mstore(0x4a0, hash) + } + + { + let x := calldataload(0x3e0) + mstore(0x4c0, x) + let y := calldataload(0x400) + mstore(0x4e0, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0x500, keccak256(0x4a0, 96)) +{ + let hash := mload(0x500) + mstore(0x520, mod(hash, f_q)) + mstore(0x540, hash) + } + + { + let x := calldataload(0x420) + mstore(0x560, x) + let y := calldataload(0x440) + mstore(0x580, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x460) + mstore(0x5a0, x) + let y := calldataload(0x480) + mstore(0x5c0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x4a0) + mstore(0x5e0, x) + let y := calldataload(0x4c0) + mstore(0x600, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x4e0) + mstore(0x620, x) + let y := calldataload(0x500) + mstore(0x640, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0x660, keccak256(0x540, 288)) +{ + let hash := mload(0x660) + mstore(0x680, mod(hash, f_q)) + mstore(0x6a0, hash) + } +mstore8(1728, 1) +mstore(0x6c0, keccak256(0x6a0, 33)) +{ + let hash := mload(0x6c0) + mstore(0x6e0, mod(hash, f_q)) + mstore(0x700, hash) + } + + { + let x := calldataload(0x520) + mstore(0x720, x) + let y := calldataload(0x540) + mstore(0x740, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x560) + mstore(0x760, x) + let y := calldataload(0x580) + mstore(0x780, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x5a0) + mstore(0x7a0, x) + let y := calldataload(0x5c0) + mstore(0x7c0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x5e0) + mstore(0x7e0, x) + let y := calldataload(0x600) + mstore(0x800, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0x820, keccak256(0x700, 288)) +{ + let hash := mload(0x820) + mstore(0x840, mod(hash, f_q)) + mstore(0x860, hash) + } + + { + let x := calldataload(0x620) + mstore(0x880, x) + let y := calldataload(0x640) + mstore(0x8a0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x660) + mstore(0x8c0, x) + let y := calldataload(0x680) + mstore(0x8e0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x6a0) + mstore(0x900, x) + let y := calldataload(0x6c0) + mstore(0x920, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x6e0) + mstore(0x940, x) + let y := calldataload(0x700) + mstore(0x960, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x720) + mstore(0x980, x) + let y := calldataload(0x740) + mstore(0x9a0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x760) + mstore(0x9c0, x) + let y := calldataload(0x780) + mstore(0x9e0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x7a0) + mstore(0xa00, x) + let y := calldataload(0x7c0) + mstore(0xa20, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x7e0) + mstore(0xa40, x) + let y := calldataload(0x800) + mstore(0xa60, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0xa80, keccak256(0x860, 544)) +{ + let hash := mload(0xa80) + mstore(0xaa0, mod(hash, f_q)) + mstore(0xac0, hash) + } +mstore(0xae0, mod(calldataload(0x820), f_q)) +mstore(0xb00, mod(calldataload(0x840), f_q)) +mstore(0xb20, mod(calldataload(0x860), f_q)) +mstore(0xb40, mod(calldataload(0x880), f_q)) +mstore(0xb60, mod(calldataload(0x8a0), f_q)) +mstore(0xb80, mod(calldataload(0x8c0), f_q)) +mstore(0xba0, mod(calldataload(0x8e0), f_q)) +mstore(0xbc0, mod(calldataload(0x900), f_q)) +mstore(0xbe0, mod(calldataload(0x920), f_q)) +mstore(0xc00, mod(calldataload(0x940), f_q)) +mstore(0xc20, mod(calldataload(0x960), f_q)) +mstore(0xc40, mod(calldataload(0x980), f_q)) +mstore(0xc60, mod(calldataload(0x9a0), f_q)) +mstore(0xc80, mod(calldataload(0x9c0), f_q)) +mstore(0xca0, mod(calldataload(0x9e0), f_q)) +mstore(0xcc0, mod(calldataload(0xa00), f_q)) +mstore(0xce0, mod(calldataload(0xa20), f_q)) +mstore(0xd00, mod(calldataload(0xa40), f_q)) +mstore(0xd20, mod(calldataload(0xa60), f_q)) +mstore(0xd40, mod(calldataload(0xa80), f_q)) +mstore(0xd60, mod(calldataload(0xaa0), f_q)) +mstore(0xd80, mod(calldataload(0xac0), f_q)) +mstore(0xda0, mod(calldataload(0xae0), f_q)) +mstore(0xdc0, mod(calldataload(0xb00), f_q)) +mstore(0xde0, mod(calldataload(0xb20), f_q)) +mstore(0xe00, mod(calldataload(0xb40), f_q)) +mstore(0xe20, mod(calldataload(0xb60), f_q)) +mstore(0xe40, mod(calldataload(0xb80), f_q)) +mstore(0xe60, mod(calldataload(0xba0), f_q)) +mstore(0xe80, mod(calldataload(0xbc0), f_q)) +mstore(0xea0, mod(calldataload(0xbe0), f_q)) +mstore(0xec0, mod(calldataload(0xc00), f_q)) +mstore(0xee0, mod(calldataload(0xc20), f_q)) +mstore(0xf00, mod(calldataload(0xc40), f_q)) +mstore(0xf20, mod(calldataload(0xc60), f_q)) +mstore(0xf40, mod(calldataload(0xc80), f_q)) +mstore(0xf60, mod(calldataload(0xca0), f_q)) +mstore(0xf80, mod(calldataload(0xcc0), f_q)) +mstore(0xfa0, mod(calldataload(0xce0), f_q)) +mstore(0xfc0, mod(calldataload(0xd00), f_q)) +mstore(0xfe0, mod(calldataload(0xd20), f_q)) +mstore(0x1000, mod(calldataload(0xd40), f_q)) +mstore(0x1020, mod(calldataload(0xd60), f_q)) +mstore(0x1040, mod(calldataload(0xd80), f_q)) +mstore(0x1060, mod(calldataload(0xda0), f_q)) +mstore(0x1080, mod(calldataload(0xdc0), f_q)) +mstore(0x10a0, mod(calldataload(0xde0), f_q)) +mstore(0x10c0, keccak256(0xac0, 1536)) +{ + let hash := mload(0x10c0) + mstore(0x10e0, mod(hash, f_q)) + mstore(0x1100, hash) + } + + { + let x := calldataload(0xe00) + mstore(0x1120, x) + let y := calldataload(0xe20) + mstore(0x1140, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0xe40) + mstore(0x1160, x) + let y := calldataload(0xe60) + mstore(0x1180, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0xe80) + mstore(0x11a0, x) + let y := calldataload(0xea0) + mstore(0x11c0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0xec0) + mstore(0x11e0, x) + let y := calldataload(0xee0) + mstore(0x1200, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0xf00) + mstore(0x1220, x) + let y := calldataload(0xf20) + mstore(0x1240, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0xf40) + mstore(0x1260, x) + let y := calldataload(0xf60) + mstore(0x1280, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0x12a0, keccak256(0x1100, 416)) +{ + let hash := mload(0x12a0) + mstore(0x12c0, mod(hash, f_q)) + mstore(0x12e0, hash) + } +mstore(0x1300, mulmod(mload(0xaa0), mload(0xaa0), f_q)) +mstore(0x1320, mulmod(mload(0x1300), mload(0x1300), f_q)) +mstore(0x1340, mulmod(mload(0x1320), mload(0x1320), f_q)) +mstore(0x1360, mulmod(mload(0x1340), mload(0x1340), f_q)) +mstore(0x1380, mulmod(mload(0x1360), mload(0x1360), f_q)) +mstore(0x13a0, mulmod(mload(0x1380), mload(0x1380), f_q)) +mstore(0x13c0, mulmod(mload(0x13a0), mload(0x13a0), f_q)) +mstore(0x13e0, mulmod(mload(0x13c0), mload(0x13c0), f_q)) +mstore(0x1400, mulmod(mload(0x13e0), mload(0x13e0), f_q)) +mstore(0x1420, mulmod(mload(0x1400), mload(0x1400), f_q)) +mstore(0x1440, mulmod(mload(0x1420), mload(0x1420), f_q)) +mstore(0x1460, mulmod(mload(0x1440), mload(0x1440), f_q)) +mstore(0x1480, mulmod(mload(0x1460), mload(0x1460), f_q)) +mstore(0x14a0, mulmod(mload(0x1480), mload(0x1480), f_q)) +mstore(0x14c0, mulmod(mload(0x14a0), mload(0x14a0), f_q)) +mstore(0x14e0, mulmod(mload(0x14c0), mload(0x14c0), f_q)) +mstore(0x1500, mulmod(mload(0x14e0), mload(0x14e0), f_q)) +mstore(0x1520, mulmod(mload(0x1500), mload(0x1500), f_q)) +mstore(0x1540, addmod(mload(0x1520), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) +mstore(0x1560, mulmod(mload(0x1540), 21888159374819042681065900960079108671330771976540605510559380874944847741953, f_q)) +mstore(0x1580, mulmod(mload(0x1560), 7310587191487482613389628690976703164033126240759264491908912333706168173225, f_q)) +mstore(0x15a0, addmod(mload(0xaa0), 14577655680351792608856777054280571924515238159656769851789291852869640322392, f_q)) +mstore(0x15c0, mulmod(mload(0x1560), 9798514389911400568976296423560720718971335345616984532185711118739339214189, f_q)) +mstore(0x15e0, addmod(mload(0xaa0), 12089728481927874653270109321696554369577029054799049811512493067836469281428, f_q)) +mstore(0x1600, mulmod(mload(0x1560), 21597602092741825212172446666303273253818825148250162481134447417972994544804, f_q)) +mstore(0x1620, addmod(mload(0xaa0), 290640779097450010073959078954001834729539252165871862563756768602813950813, f_q)) +mstore(0x1640, mulmod(mload(0x1560), 5857228514216831962358810454360739186987616060007133076514874820078026801648, f_q)) +mstore(0x1660, addmod(mload(0xaa0), 16031014357622443259887595290896535901560748340408901267183329366497781693969, f_q)) +mstore(0x1680, mulmod(mload(0x1560), 15837174511167031493871940795515473313759957271874477857633393696392913897559, f_q)) +mstore(0x16a0, addmod(mload(0xaa0), 6051068360672243728374464949741801774788407128541556486064810490182894598058, f_q)) +mstore(0x16c0, mulmod(mload(0x1560), 11402394834529375719535454173347509224290498423785625657829583372803806900475, f_q)) +mstore(0x16e0, addmod(mload(0xaa0), 10485848037309899502710951571909765864257865976630408685868620813772001595142, f_q)) +mstore(0x1700, mulmod(mload(0x1560), 6363119021782681274480715230122258277189830284152385293217720612674619714422, f_q)) +mstore(0x1720, addmod(mload(0xaa0), 15525123850056593947765690515135016811358534116263649050480483573901188781195, f_q)) +mstore(0x1740, mulmod(mload(0x1560), 1, f_q)) +mstore(0x1760, addmod(mload(0xaa0), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) +mstore(0x1780, mulmod(mload(0x1560), 6955697244493336113861667751840378876927906302623587437721024018233754910398, f_q)) +mstore(0x17a0, addmod(mload(0xaa0), 14932545627345939108384737993416896211620458097792446905977180168342053585219, f_q)) +mstore(0x17c0, mulmod(mload(0x1560), 21846745818185811051373434299876022191132089169516983080959277716660228899818, f_q)) +mstore(0x17e0, addmod(mload(0xaa0), 41497053653464170872971445381252897416275230899051262738926469915579595799, f_q)) +mstore(0x1800, mulmod(mload(0x1560), 13526759757306252939732186602630155490343117803221487512984160143178057306805, f_q)) +mstore(0x1820, addmod(mload(0xaa0), 8361483114533022282514219142627119598205246597194546830714044043397751188812, f_q)) +mstore(0x1840, mulmod(mload(0x1560), 4443263508319656594054352481848447997537391617204595126809744742387004492585, f_q)) +mstore(0x1860, addmod(mload(0xaa0), 17444979363519618628192053263408827091010972783211439216888459444188804003032, f_q)) +{ + let prod := mload(0x15a0) + + prod := mulmod(mload(0x15e0), prod, f_q) + mstore(0x1880, prod) + + prod := mulmod(mload(0x1620), prod, f_q) + mstore(0x18a0, prod) + + prod := mulmod(mload(0x1660), prod, f_q) + mstore(0x18c0, prod) + + prod := mulmod(mload(0x16a0), prod, f_q) + mstore(0x18e0, prod) + + prod := mulmod(mload(0x16e0), prod, f_q) + mstore(0x1900, prod) + + prod := mulmod(mload(0x1720), prod, f_q) + mstore(0x1920, prod) + + prod := mulmod(mload(0x1760), prod, f_q) + mstore(0x1940, prod) + + prod := mulmod(mload(0x17a0), prod, f_q) + mstore(0x1960, prod) + + prod := mulmod(mload(0x17e0), prod, f_q) + mstore(0x1980, prod) + + prod := mulmod(mload(0x1820), prod, f_q) + mstore(0x19a0, prod) + + prod := mulmod(mload(0x1860), prod, f_q) + mstore(0x19c0, prod) + + prod := mulmod(mload(0x1540), prod, f_q) + mstore(0x19e0, prod) + + } +mstore(0x1a20, 32) +mstore(0x1a40, 32) +mstore(0x1a60, 32) +mstore(0x1a80, mload(0x19e0)) +mstore(0x1aa0, 21888242871839275222246405745257275088548364400416034343698204186575808495615) +mstore(0x1ac0, 21888242871839275222246405745257275088548364400416034343698204186575808495617) +success := and(eq(staticcall(gas(), 0x5, 0x1a20, 0xc0, 0x1a00, 0x20), 1), success) +{ + + let inv := mload(0x1a00) + let v + + v := mload(0x1540) + mstore(5440, mulmod(mload(0x19c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1860) + mstore(6240, mulmod(mload(0x19a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1820) + mstore(6176, mulmod(mload(0x1980), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x17e0) + mstore(6112, mulmod(mload(0x1960), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x17a0) + mstore(6048, mulmod(mload(0x1940), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1760) + mstore(5984, mulmod(mload(0x1920), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1720) + mstore(5920, mulmod(mload(0x1900), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x16e0) + mstore(5856, mulmod(mload(0x18e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x16a0) + mstore(5792, mulmod(mload(0x18c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1660) + mstore(5728, mulmod(mload(0x18a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1620) + mstore(5664, mulmod(mload(0x1880), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x15e0) + mstore(5600, mulmod(mload(0x15a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + mstore(0x15a0, inv) + + } +mstore(0x1ae0, mulmod(mload(0x1580), mload(0x15a0), f_q)) +mstore(0x1b00, mulmod(mload(0x15c0), mload(0x15e0), f_q)) +mstore(0x1b20, mulmod(mload(0x1600), mload(0x1620), f_q)) +mstore(0x1b40, mulmod(mload(0x1640), mload(0x1660), f_q)) +mstore(0x1b60, mulmod(mload(0x1680), mload(0x16a0), f_q)) +mstore(0x1b80, mulmod(mload(0x16c0), mload(0x16e0), f_q)) +mstore(0x1ba0, mulmod(mload(0x1700), mload(0x1720), f_q)) +mstore(0x1bc0, mulmod(mload(0x1740), mload(0x1760), f_q)) +mstore(0x1be0, mulmod(mload(0x1780), mload(0x17a0), f_q)) +mstore(0x1c00, mulmod(mload(0x17c0), mload(0x17e0), f_q)) +mstore(0x1c20, mulmod(mload(0x1800), mload(0x1820), f_q)) +mstore(0x1c40, mulmod(mload(0x1840), mload(0x1860), f_q)) +{ + let result := mulmod(mload(0x1bc0), mload(0x20), f_q) +result := addmod(mulmod(mload(0x1be0), mload(0x40), f_q), result, f_q) +result := addmod(mulmod(mload(0x1c00), mload(0x60), f_q), result, f_q) +result := addmod(mulmod(mload(0x1c20), mload(0x80), f_q), result, f_q) +result := addmod(mulmod(mload(0x1c40), mload(0xa0), f_q), result, f_q) +mstore(7264, result) + } +mstore(0x1c80, mulmod(mload(0xb20), mload(0xb40), f_q)) +mstore(0x1ca0, addmod(mload(0x1c80), mload(0xae0), f_q)) +mstore(0x1cc0, addmod(mload(0x1ca0), sub(f_q, mload(0xb00)), f_q)) +mstore(0x1ce0, mulmod(mload(0x1cc0), mload(0xe80), f_q)) +mstore(0x1d00, mulmod(mload(0x840), mload(0x1ce0), f_q)) +mstore(0x1d20, addmod(1, sub(f_q, mload(0xe60)), f_q)) +mstore(0x1d40, mulmod(mload(0x1d20), mload(0xe60), f_q)) +mstore(0x1d60, addmod(mload(0xae0), sub(f_q, mload(0xb00)), f_q)) +mstore(0x1d80, mulmod(mload(0x1d60), mload(0x1d40), f_q)) +mstore(0x1da0, addmod(mload(0x1d00), mload(0x1d80), f_q)) +mstore(0x1dc0, mulmod(mload(0x840), mload(0x1da0), f_q)) +mstore(0x1de0, addmod(mload(0xb20), sub(f_q, mload(0xb60)), f_q)) +mstore(0x1e00, mulmod(mload(0x1de0), mload(0xe80), f_q)) +mstore(0x1e20, addmod(mload(0x1dc0), mload(0x1e00), f_q)) +mstore(0x1e40, mulmod(mload(0x840), mload(0x1e20), f_q)) +mstore(0x1e60, addmod(2, sub(f_q, mload(0xe60)), f_q)) +mstore(0x1e80, mulmod(mload(0x1e60), mload(0xe60), f_q)) +mstore(0x1ea0, addmod(mload(0xb80), sub(f_q, mload(0xae0)), f_q)) +mstore(0x1ec0, mulmod(mload(0x1ea0), mload(0x1e80), f_q)) +mstore(0x1ee0, addmod(mload(0x1e40), mload(0x1ec0), f_q)) +mstore(0x1f00, mulmod(mload(0x840), mload(0x1ee0), f_q)) +mstore(0x1f20, addmod(mload(0xba0), sub(f_q, mload(0xbc0)), f_q)) +mstore(0x1f40, mulmod(mload(0x1f20), mload(0xe00), f_q)) +mstore(0x1f60, addmod(mload(0x1f00), mload(0x1f40), f_q)) +mstore(0x1f80, mulmod(mload(0x840), mload(0x1f60), f_q)) +mstore(0x1fa0, addmod(mload(0xbe0), sub(f_q, mload(0xc00)), f_q)) +mstore(0x1fc0, mulmod(mload(0x1fa0), mload(0xe00), f_q)) +mstore(0x1fe0, addmod(mload(0x1f80), mload(0x1fc0), f_q)) +mstore(0x2000, mulmod(mload(0x840), mload(0x1fe0), f_q)) +mstore(0x2020, addmod(1, sub(f_q, mload(0xe00)), f_q)) +mstore(0x2040, mulmod(mload(0x2020), 1, f_q)) +mstore(0x2060, addmod(1, sub(f_q, mload(0xe20)), f_q)) +mstore(0x2080, mulmod(mload(0x2060), mload(0x2040), f_q)) +mstore(0x20a0, addmod(1, sub(f_q, mload(0x2080)), f_q)) +mstore(0x20c0, addmod(mload(0xc20), sub(f_q, mload(0xc40)), f_q)) +mstore(0x20e0, mulmod(mload(0x20c0), mload(0x20a0), f_q)) +mstore(0x2100, addmod(mload(0x2000), mload(0x20e0), f_q)) +mstore(0x2120, mulmod(mload(0x840), mload(0x2100), f_q)) +mstore(0x2140, mulmod(mload(0xba0), mload(0xe20), f_q)) +mstore(0x2160, mulmod(mload(0xc60), mload(0xba0), f_q)) +mstore(0x2180, addmod(1, sub(f_q, mload(0x2160)), f_q)) +mstore(0x21a0, mulmod(mload(0x2180), mload(0x2140), f_q)) +mstore(0x21c0, addmod(mload(0x2120), mload(0x21a0), f_q)) +mstore(0x21e0, mulmod(mload(0x840), mload(0x21c0), f_q)) +mstore(0x2200, mulmod(mload(0xc20), mload(0x20a0), f_q)) +mstore(0x2220, mulmod(mload(0xc80), mload(0xc20), f_q)) +mstore(0x2240, addmod(1, sub(f_q, mload(0x2220)), f_q)) +mstore(0x2260, mulmod(mload(0x2240), mload(0x2200), f_q)) +mstore(0x2280, addmod(mload(0x21e0), mload(0x2260), f_q)) +mstore(0x22a0, mulmod(mload(0x840), mload(0x2280), f_q)) +mstore(0x22c0, addmod(mload(0xcc0), sub(f_q, mload(0xba0)), f_q)) +mstore(0x22e0, mulmod(mload(0x22c0), mload(0xe20), f_q)) +mstore(0x2300, mulmod(mload(0xca0), mload(0x22c0), f_q)) +mstore(0x2320, addmod(1, sub(f_q, mload(0x2300)), f_q)) +mstore(0x2340, mulmod(mload(0x2320), mload(0x22e0), f_q)) +mstore(0x2360, addmod(mload(0x22a0), mload(0x2340), f_q)) +mstore(0x2380, mulmod(mload(0x840), mload(0x2360), f_q)) +mstore(0x23a0, mulmod(mload(0xbe0), mload(0x2180), f_q)) +mstore(0x23c0, mulmod(mload(0x23a0), mload(0xe20), f_q)) +mstore(0x23e0, addmod(mload(0x2380), mload(0x23c0), f_q)) +mstore(0x2400, mulmod(mload(0x840), mload(0x23e0), f_q)) +mstore(0x2420, mulmod(mload(0xcc0), mload(0x2180), f_q)) +mstore(0x2440, mulmod(mload(0x2420), mload(0xe20), f_q)) +mstore(0x2460, addmod(mload(0x2400), mload(0x2440), f_q)) +mstore(0x2480, mulmod(mload(0x840), mload(0x2460), f_q)) +mstore(0x24a0, mulmod(mload(0xda0), mload(0x2180), f_q)) +mstore(0x24c0, mulmod(mload(0x24a0), mload(0xe20), f_q)) +mstore(0x24e0, addmod(mload(0x2480), mload(0x24c0), f_q)) +mstore(0x2500, mulmod(mload(0x840), mload(0x24e0), f_q)) +mstore(0x2520, mulmod(mload(0xd60), mload(0x2180), f_q)) +mstore(0x2540, mulmod(mload(0x2520), mload(0xe20), f_q)) +mstore(0x2560, addmod(mload(0x2500), mload(0x2540), f_q)) +mstore(0x2580, mulmod(mload(0x840), mload(0x2560), f_q)) +mstore(0x25a0, addmod(1, sub(f_q, mload(0x2180)), f_q)) +mstore(0x25c0, mulmod(mload(0x25a0), mload(0xe20), f_q)) +mstore(0x25e0, addmod(mload(0xd00), sub(f_q, mload(0xbe0)), f_q)) +mstore(0x2600, addmod(mload(0x25e0), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) +mstore(0x2620, mulmod(mload(0x2600), mload(0x2320), f_q)) +mstore(0x2640, mulmod(mload(0x2620), mload(0x25c0), f_q)) +mstore(0x2660, addmod(mload(0x2580), mload(0x2640), f_q)) +mstore(0x2680, mulmod(mload(0x840), mload(0x2660), f_q)) +mstore(0x26a0, mulmod(mload(0xd00), mload(0x22c0), f_q)) +mstore(0x26c0, mulmod(mload(0x26a0), mload(0x25c0), f_q)) +mstore(0x26e0, addmod(mload(0x2680), mload(0x26c0), f_q)) +mstore(0x2700, mulmod(mload(0x840), mload(0x26e0), f_q)) +mstore(0x2720, addmod(mload(0xd80), sub(f_q, mload(0xd60)), f_q)) +mstore(0x2740, mulmod(mload(0xd40), mload(0xd20), f_q)) +mstore(0x2760, addmod(1, sub(f_q, mload(0x2740)), f_q)) +mstore(0x2780, mulmod(mload(0x2760), 4, f_q)) +mstore(0x27a0, mulmod(mload(0x2740), 16, f_q)) +mstore(0x27c0, addmod(mload(0x2780), mload(0x27a0), f_q)) +mstore(0x27e0, addmod(mload(0x2720), sub(f_q, mload(0x27c0)), f_q)) +mstore(0x2800, mulmod(mload(0x27e0), mload(0x2320), f_q)) +mstore(0x2820, mulmod(mload(0x2800), mload(0x25c0), f_q)) +mstore(0x2840, addmod(mload(0x2700), mload(0x2820), f_q)) +mstore(0x2860, mulmod(mload(0x840), mload(0x2840), f_q)) +mstore(0x2880, mulmod(mload(0xce0), mload(0xcc0), f_q)) +mstore(0x28a0, mulmod(mload(0x22c0), mload(0x2880), f_q)) +mstore(0x28c0, addmod(mload(0xd80), sub(f_q, mload(0x27c0)), f_q)) +mstore(0x28e0, mulmod(mload(0x28c0), mload(0x28a0), f_q)) +mstore(0x2900, mulmod(mload(0x28e0), mload(0x25c0), f_q)) +mstore(0x2920, addmod(mload(0x2860), mload(0x2900), f_q)) +mstore(0x2940, mulmod(mload(0x840), mload(0x2920), f_q)) +mstore(0x2960, mulmod(mload(0xda0), mload(0x2320), f_q)) +mstore(0x2980, mulmod(mload(0x2960), mload(0x25c0), f_q)) +mstore(0x29a0, addmod(mload(0x2940), mload(0x2980), f_q)) +mstore(0x29c0, mulmod(mload(0x840), mload(0x29a0), f_q)) +mstore(0x29e0, addmod(mload(0xda0), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) +mstore(0x2a00, mulmod(mload(0x29e0), mload(0x22c0), f_q)) +mstore(0x2a20, mulmod(mload(0x2a00), mload(0x25c0), f_q)) +mstore(0x2a40, addmod(mload(0x29c0), mload(0x2a20), f_q)) +mstore(0x2a60, mulmod(mload(0x840), mload(0x2a40), f_q)) +mstore(0x2a80, mulmod(mload(0x25a0), mload(0xe40), f_q)) +mstore(0x2aa0, addmod(mload(0xbe0), 21888242871839275222246405745257275088548364400416034343698204186575808495617, f_q)) +mstore(0x2ac0, mulmod(mload(0x2aa0), mload(0x2a80), f_q)) +mstore(0x2ae0, addmod(mload(0x2a60), mload(0x2ac0), f_q)) +mstore(0x2b00, mulmod(mload(0x840), mload(0x2ae0), f_q)) +mstore(0x2b20, mulmod(mload(0x2240), 4, f_q)) +mstore(0x2b40, addmod(1, sub(f_q, mload(0x2240)), f_q)) +mstore(0x2b60, mulmod(mload(0x2b40), 16, f_q)) +mstore(0x2b80, addmod(mload(0x2b20), mload(0x2b60), f_q)) +mstore(0x2ba0, addmod(mload(0xd60), sub(f_q, mload(0x2b80)), f_q)) +mstore(0x2bc0, mulmod(mload(0x2ba0), mload(0x2a80), f_q)) +mstore(0x2be0, addmod(mload(0x2b00), mload(0x2bc0), f_q)) +mstore(0x2c00, mulmod(mload(0x840), mload(0x2be0), f_q)) +mstore(0x2c20, addmod(mload(0xde0), 21888242871839275222246405745257275088548364400416034343698204186575808495609, f_q)) +mstore(0x2c40, mulmod(mload(0x2c20), mload(0xe00), f_q)) +mstore(0x2c60, mulmod(mload(0xc60), mload(0x2c20), f_q)) +mstore(0x2c80, addmod(1, sub(f_q, mload(0x2c60)), f_q)) +mstore(0x2ca0, mulmod(mload(0x2c80), mload(0x2c40), f_q)) +mstore(0x2cc0, addmod(mload(0x2c00), mload(0x2ca0), f_q)) +mstore(0x2ce0, mulmod(mload(0x840), mload(0x2cc0), f_q)) +mstore(0x2d00, mulmod(mload(0x2c80), mload(0xe00), f_q)) +mstore(0x2d20, mulmod(mload(0x2240), mload(0x2d00), f_q)) +mstore(0x2d40, mulmod(mload(0xd20), mload(0x2d20), f_q)) +mstore(0x2d60, addmod(mload(0x2ce0), mload(0x2d40), f_q)) +mstore(0x2d80, mulmod(mload(0x840), mload(0x2d60), f_q)) +mstore(0x2da0, addmod(1, sub(f_q, mload(0xf40)), f_q)) +mstore(0x2dc0, mulmod(mload(0x2da0), mload(0x1bc0), f_q)) +mstore(0x2de0, addmod(mload(0x2d80), mload(0x2dc0), f_q)) +mstore(0x2e00, mulmod(mload(0x840), mload(0x2de0), f_q)) +mstore(0x2e20, mulmod(mload(0xf40), mload(0xf40), f_q)) +mstore(0x2e40, addmod(mload(0x2e20), sub(f_q, mload(0xf40)), f_q)) +mstore(0x2e60, mulmod(mload(0x2e40), mload(0x1ae0), f_q)) +mstore(0x2e80, addmod(mload(0x2e00), mload(0x2e60), f_q)) +mstore(0x2ea0, mulmod(mload(0x840), mload(0x2e80), f_q)) +mstore(0x2ec0, addmod(1, sub(f_q, mload(0x1ae0)), f_q)) +mstore(0x2ee0, addmod(mload(0x1b00), mload(0x1b20), f_q)) +mstore(0x2f00, addmod(mload(0x2ee0), mload(0x1b40), f_q)) +mstore(0x2f20, addmod(mload(0x2f00), mload(0x1b60), f_q)) +mstore(0x2f40, addmod(mload(0x2f20), mload(0x1b80), f_q)) +mstore(0x2f60, addmod(mload(0x2f40), mload(0x1ba0), f_q)) +mstore(0x2f80, addmod(mload(0x2ec0), sub(f_q, mload(0x2f60)), f_q)) +mstore(0x2fa0, mulmod(mload(0xec0), mload(0x680), f_q)) +mstore(0x2fc0, addmod(mload(0xae0), mload(0x2fa0), f_q)) +mstore(0x2fe0, addmod(mload(0x2fc0), mload(0x6e0), f_q)) +mstore(0x3000, mulmod(mload(0xee0), mload(0x680), f_q)) +mstore(0x3020, addmod(mload(0xb00), mload(0x3000), f_q)) +mstore(0x3040, addmod(mload(0x3020), mload(0x6e0), f_q)) +mstore(0x3060, mulmod(mload(0x3040), mload(0x2fe0), f_q)) +mstore(0x3080, mulmod(mload(0xf00), mload(0x680), f_q)) +mstore(0x30a0, addmod(mload(0xb20), mload(0x3080), f_q)) +mstore(0x30c0, addmod(mload(0x30a0), mload(0x6e0), f_q)) +mstore(0x30e0, mulmod(mload(0x30c0), mload(0x3060), f_q)) +mstore(0x3100, mulmod(mload(0xf20), mload(0x680), f_q)) +mstore(0x3120, addmod(mload(0x1c60), mload(0x3100), f_q)) +mstore(0x3140, addmod(mload(0x3120), mload(0x6e0), f_q)) +mstore(0x3160, mulmod(mload(0x3140), mload(0x30e0), f_q)) +mstore(0x3180, mulmod(mload(0x3160), mload(0xf60), f_q)) +mstore(0x31a0, mulmod(1, mload(0x680), f_q)) +mstore(0x31c0, mulmod(mload(0xaa0), mload(0x31a0), f_q)) +mstore(0x31e0, addmod(mload(0xae0), mload(0x31c0), f_q)) +mstore(0x3200, addmod(mload(0x31e0), mload(0x6e0), f_q)) +mstore(0x3220, mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0x680), f_q)) +mstore(0x3240, mulmod(mload(0xaa0), mload(0x3220), f_q)) +mstore(0x3260, addmod(mload(0xb00), mload(0x3240), f_q)) +mstore(0x3280, addmod(mload(0x3260), mload(0x6e0), f_q)) +mstore(0x32a0, mulmod(mload(0x3280), mload(0x3200), f_q)) +mstore(0x32c0, mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0x680), f_q)) +mstore(0x32e0, mulmod(mload(0xaa0), mload(0x32c0), f_q)) +mstore(0x3300, addmod(mload(0xb20), mload(0x32e0), f_q)) +mstore(0x3320, addmod(mload(0x3300), mload(0x6e0), f_q)) +mstore(0x3340, mulmod(mload(0x3320), mload(0x32a0), f_q)) +mstore(0x3360, mulmod(11166246659983828508719468090013646171463329086121580628794302409516816350802, mload(0x680), f_q)) +mstore(0x3380, mulmod(mload(0xaa0), mload(0x3360), f_q)) +mstore(0x33a0, addmod(mload(0x1c60), mload(0x3380), f_q)) +mstore(0x33c0, addmod(mload(0x33a0), mload(0x6e0), f_q)) +mstore(0x33e0, mulmod(mload(0x33c0), mload(0x3340), f_q)) +mstore(0x3400, mulmod(mload(0x33e0), mload(0xf40), f_q)) +mstore(0x3420, addmod(mload(0x3180), sub(f_q, mload(0x3400)), f_q)) +mstore(0x3440, mulmod(mload(0x3420), mload(0x2f80), f_q)) +mstore(0x3460, addmod(mload(0x2ea0), mload(0x3440), f_q)) +mstore(0x3480, mulmod(mload(0x840), mload(0x3460), f_q)) +mstore(0x34a0, addmod(1, sub(f_q, mload(0xf80)), f_q)) +mstore(0x34c0, mulmod(mload(0x34a0), mload(0x1bc0), f_q)) +mstore(0x34e0, addmod(mload(0x3480), mload(0x34c0), f_q)) +mstore(0x3500, mulmod(mload(0x840), mload(0x34e0), f_q)) +mstore(0x3520, mulmod(mload(0xf80), mload(0xf80), f_q)) +mstore(0x3540, addmod(mload(0x3520), sub(f_q, mload(0xf80)), f_q)) +mstore(0x3560, mulmod(mload(0x3540), mload(0x1ae0), f_q)) +mstore(0x3580, addmod(mload(0x3500), mload(0x3560), f_q)) +mstore(0x35a0, mulmod(mload(0x840), mload(0x3580), f_q)) +mstore(0x35c0, addmod(mload(0xfc0), mload(0x680), f_q)) +mstore(0x35e0, mulmod(mload(0x35c0), mload(0xfa0), f_q)) +mstore(0x3600, addmod(mload(0x1000), mload(0x6e0), f_q)) +mstore(0x3620, mulmod(mload(0x3600), mload(0x35e0), f_q)) +mstore(0x3640, addmod(mload(0x22c0), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) +mstore(0x3660, mulmod(mload(0x2880), mload(0x3640), f_q)) +mstore(0x3680, mulmod(mload(0x2300), mload(0x3660), f_q)) +mstore(0x36a0, addmod(mload(0x3680), mload(0x680), f_q)) +mstore(0x36c0, mulmod(mload(0x36a0), mload(0xf80), f_q)) +mstore(0x36e0, addmod(mload(0xdc0), mload(0x6e0), f_q)) +mstore(0x3700, mulmod(mload(0x36e0), mload(0x36c0), f_q)) +mstore(0x3720, addmod(mload(0x3620), sub(f_q, mload(0x3700)), f_q)) +mstore(0x3740, mulmod(mload(0x3720), mload(0x2f80), f_q)) +mstore(0x3760, addmod(mload(0x35a0), mload(0x3740), f_q)) +mstore(0x3780, mulmod(mload(0x840), mload(0x3760), f_q)) +mstore(0x37a0, addmod(mload(0xfc0), sub(f_q, mload(0x1000)), f_q)) +mstore(0x37c0, mulmod(mload(0x37a0), mload(0x1bc0), f_q)) +mstore(0x37e0, addmod(mload(0x3780), mload(0x37c0), f_q)) +mstore(0x3800, mulmod(mload(0x840), mload(0x37e0), f_q)) +mstore(0x3820, mulmod(mload(0x37a0), mload(0x2f80), f_q)) +mstore(0x3840, addmod(mload(0xfc0), sub(f_q, mload(0xfe0)), f_q)) +mstore(0x3860, mulmod(mload(0x3840), mload(0x3820), f_q)) +mstore(0x3880, addmod(mload(0x3800), mload(0x3860), f_q)) +mstore(0x38a0, mulmod(mload(0x840), mload(0x3880), f_q)) +mstore(0x38c0, addmod(1, sub(f_q, mload(0x1020)), f_q)) +mstore(0x38e0, mulmod(mload(0x38c0), mload(0x1bc0), f_q)) +mstore(0x3900, addmod(mload(0x38a0), mload(0x38e0), f_q)) +mstore(0x3920, mulmod(mload(0x840), mload(0x3900), f_q)) +mstore(0x3940, mulmod(mload(0x1020), mload(0x1020), f_q)) +mstore(0x3960, addmod(mload(0x3940), sub(f_q, mload(0x1020)), f_q)) +mstore(0x3980, mulmod(mload(0x3960), mload(0x1ae0), f_q)) +mstore(0x39a0, addmod(mload(0x3920), mload(0x3980), f_q)) +mstore(0x39c0, mulmod(mload(0x840), mload(0x39a0), f_q)) +mstore(0x39e0, addmod(mload(0x1060), mload(0x680), f_q)) +mstore(0x3a00, mulmod(mload(0x39e0), mload(0x1040), f_q)) +mstore(0x3a20, addmod(mload(0x10a0), mload(0x6e0), f_q)) +mstore(0x3a40, mulmod(mload(0x3a20), mload(0x3a00), f_q)) +mstore(0x3a60, mulmod(mload(0x2b40), mload(0xe00), f_q)) +mstore(0x3a80, mulmod(mload(0x2c80), mload(0x3a60), f_q)) +mstore(0x3aa0, mulmod(mload(0xba0), mload(0x3a80), f_q)) +mstore(0x3ac0, mulmod(mload(0x520), mload(0x3aa0), f_q)) +mstore(0x3ae0, mulmod(1, mload(0x3a80), f_q)) +mstore(0x3b00, addmod(mload(0x3ac0), mload(0x3ae0), f_q)) +mstore(0x3b20, mulmod(mload(0x520), mload(0x3b00), f_q)) +mstore(0x3b40, mulmod(mload(0xd20), mload(0x3a80), f_q)) +mstore(0x3b60, addmod(mload(0x3b20), mload(0x3b40), f_q)) +mstore(0x3b80, addmod(mload(0x3b60), mload(0x680), f_q)) +mstore(0x3ba0, mulmod(mload(0x3b80), mload(0x1020), f_q)) +mstore(0x3bc0, mulmod(mload(0x520), mload(0xba0), f_q)) +mstore(0x3be0, addmod(mload(0x3bc0), mload(0xda0), f_q)) +mstore(0x3c00, mulmod(mload(0x520), mload(0x3be0), f_q)) +mstore(0x3c20, addmod(mload(0x3c00), mload(0xd60), f_q)) +mstore(0x3c40, addmod(mload(0x3c20), mload(0x6e0), f_q)) +mstore(0x3c60, mulmod(mload(0x3c40), mload(0x3ba0), f_q)) +mstore(0x3c80, addmod(mload(0x3a40), sub(f_q, mload(0x3c60)), f_q)) +mstore(0x3ca0, mulmod(mload(0x3c80), mload(0x2f80), f_q)) +mstore(0x3cc0, addmod(mload(0x39c0), mload(0x3ca0), f_q)) +mstore(0x3ce0, mulmod(mload(0x840), mload(0x3cc0), f_q)) +mstore(0x3d00, addmod(mload(0x1060), sub(f_q, mload(0x10a0)), f_q)) +mstore(0x3d20, mulmod(mload(0x3d00), mload(0x1bc0), f_q)) +mstore(0x3d40, addmod(mload(0x3ce0), mload(0x3d20), f_q)) +mstore(0x3d60, mulmod(mload(0x840), mload(0x3d40), f_q)) +mstore(0x3d80, mulmod(mload(0x3d00), mload(0x2f80), f_q)) +mstore(0x3da0, addmod(mload(0x1060), sub(f_q, mload(0x1080)), f_q)) +mstore(0x3dc0, mulmod(mload(0x3da0), mload(0x3d80), f_q)) +mstore(0x3de0, addmod(mload(0x3d60), mload(0x3dc0), f_q)) +mstore(0x3e00, mulmod(mload(0x1520), mload(0x1520), f_q)) +mstore(0x3e20, mulmod(mload(0x3e00), mload(0x1520), f_q)) +mstore(0x3e40, mulmod(mload(0x3e20), mload(0x1520), f_q)) +mstore(0x3e60, mulmod(mload(0x3e40), mload(0x1520), f_q)) +mstore(0x3e80, mulmod(mload(0x3e60), mload(0x1520), f_q)) +mstore(0x3ea0, mulmod(mload(0x3e80), mload(0x1520), f_q)) +mstore(0x3ec0, mulmod(mload(0x3ea0), mload(0x1520), f_q)) +mstore(0x3ee0, mulmod(1, mload(0x1520), f_q)) +mstore(0x3f00, mulmod(1, mload(0x3e00), f_q)) +mstore(0x3f20, mulmod(1, mload(0x3e20), f_q)) +mstore(0x3f40, mulmod(1, mload(0x3e40), f_q)) +mstore(0x3f60, mulmod(1, mload(0x3e60), f_q)) +mstore(0x3f80, mulmod(1, mload(0x3e80), f_q)) +mstore(0x3fa0, mulmod(1, mload(0x3ea0), f_q)) +mstore(0x3fc0, mulmod(mload(0x3de0), mload(0x1540), f_q)) +mstore(0x3fe0, mulmod(mload(0x12c0), mload(0x12c0), f_q)) +mstore(0x4000, mulmod(mload(0x3fe0), mload(0x12c0), f_q)) +mstore(0x4020, mulmod(mload(0x4000), mload(0x12c0), f_q)) +mstore(0x4040, mulmod(mload(0x4020), mload(0x12c0), f_q)) +mstore(0x4060, mulmod(mload(0x4040), mload(0x12c0), f_q)) +mstore(0x4080, mulmod(mload(0x10e0), mload(0x10e0), f_q)) +mstore(0x40a0, mulmod(mload(0x4080), mload(0x10e0), f_q)) +mstore(0x40c0, mulmod(mload(0x40a0), mload(0x10e0), f_q)) +mstore(0x40e0, mulmod(mload(0x40c0), mload(0x10e0), f_q)) +mstore(0x4100, mulmod(mload(0x40e0), mload(0x10e0), f_q)) +mstore(0x4120, mulmod(mload(0x4100), mload(0x10e0), f_q)) +mstore(0x4140, mulmod(mload(0x4120), mload(0x10e0), f_q)) +mstore(0x4160, mulmod(mload(0x4140), mload(0x10e0), f_q)) +mstore(0x4180, mulmod(mload(0x4160), mload(0x10e0), f_q)) +mstore(0x41a0, mulmod(mload(0x4180), mload(0x10e0), f_q)) +mstore(0x41c0, mulmod(mload(0x41a0), mload(0x10e0), f_q)) +mstore(0x41e0, mulmod(mload(0x41c0), mload(0x10e0), f_q)) +mstore(0x4200, mulmod(mload(0x41e0), mload(0x10e0), f_q)) +mstore(0x4220, mulmod(mload(0x4200), mload(0x10e0), f_q)) +mstore(0x4240, mulmod(mload(0x4220), mload(0x10e0), f_q)) +mstore(0x4260, mulmod(mload(0x4240), mload(0x10e0), f_q)) +mstore(0x4280, mulmod(mload(0x4260), mload(0x10e0), f_q)) +mstore(0x42a0, mulmod(mload(0x4280), mload(0x10e0), f_q)) +mstore(0x42c0, mulmod(mload(0x42a0), mload(0x10e0), f_q)) +mstore(0x42e0, mulmod(mload(0x42c0), mload(0x10e0), f_q)) +mstore(0x4300, mulmod(mload(0x42e0), mload(0x10e0), f_q)) +mstore(0x4320, mulmod(mload(0x4300), mload(0x10e0), f_q)) +mstore(0x4340, mulmod(mload(0x4320), mload(0x10e0), f_q)) +mstore(0x4360, mulmod(mload(0x4340), mload(0x10e0), f_q)) +mstore(0x4380, mulmod(mload(0x4360), mload(0x10e0), f_q)) +mstore(0x43a0, mulmod(mload(0x4380), mload(0x10e0), f_q)) +mstore(0x43c0, mulmod(mload(0x43a0), mload(0x10e0), f_q)) +mstore(0x43e0, mulmod(mload(0x43c0), mload(0x10e0), f_q)) +mstore(0x4400, mulmod(mload(0x43e0), mload(0x10e0), f_q)) +mstore(0x4420, mulmod(mload(0x4400), mload(0x10e0), f_q)) +mstore(0x4440, mulmod(mload(0x4420), mload(0x10e0), f_q)) +mstore(0x4460, mulmod(sub(f_q, mload(0xae0)), 1, f_q)) +mstore(0x4480, mulmod(sub(f_q, mload(0xb00)), mload(0x10e0), f_q)) +mstore(0x44a0, mulmod(1, mload(0x10e0), f_q)) +mstore(0x44c0, addmod(mload(0x4460), mload(0x4480), f_q)) +mstore(0x44e0, mulmod(sub(f_q, mload(0xb20)), mload(0x4080), f_q)) +mstore(0x4500, mulmod(1, mload(0x4080), f_q)) +mstore(0x4520, addmod(mload(0x44c0), mload(0x44e0), f_q)) +mstore(0x4540, mulmod(sub(f_q, mload(0xb80)), mload(0x40a0), f_q)) +mstore(0x4560, mulmod(1, mload(0x40a0), f_q)) +mstore(0x4580, addmod(mload(0x4520), mload(0x4540), f_q)) +mstore(0x45a0, mulmod(sub(f_q, mload(0xba0)), mload(0x40c0), f_q)) +mstore(0x45c0, mulmod(1, mload(0x40c0), f_q)) +mstore(0x45e0, addmod(mload(0x4580), mload(0x45a0), f_q)) +mstore(0x4600, mulmod(sub(f_q, mload(0xbe0)), mload(0x40e0), f_q)) +mstore(0x4620, mulmod(1, mload(0x40e0), f_q)) +mstore(0x4640, addmod(mload(0x45e0), mload(0x4600), f_q)) +mstore(0x4660, mulmod(sub(f_q, mload(0xc20)), mload(0x4100), f_q)) +mstore(0x4680, mulmod(1, mload(0x4100), f_q)) +mstore(0x46a0, addmod(mload(0x4640), mload(0x4660), f_q)) +mstore(0x46c0, mulmod(sub(f_q, mload(0xc60)), mload(0x4120), f_q)) +mstore(0x46e0, mulmod(1, mload(0x4120), f_q)) +mstore(0x4700, addmod(mload(0x46a0), mload(0x46c0), f_q)) +mstore(0x4720, mulmod(sub(f_q, mload(0xc80)), mload(0x4140), f_q)) +mstore(0x4740, mulmod(1, mload(0x4140), f_q)) +mstore(0x4760, addmod(mload(0x4700), mload(0x4720), f_q)) +mstore(0x4780, mulmod(sub(f_q, mload(0xca0)), mload(0x4160), f_q)) +mstore(0x47a0, mulmod(1, mload(0x4160), f_q)) +mstore(0x47c0, addmod(mload(0x4760), mload(0x4780), f_q)) +mstore(0x47e0, mulmod(sub(f_q, mload(0xd60)), mload(0x4180), f_q)) +mstore(0x4800, mulmod(1, mload(0x4180), f_q)) +mstore(0x4820, addmod(mload(0x47c0), mload(0x47e0), f_q)) +mstore(0x4840, mulmod(sub(f_q, mload(0xda0)), mload(0x41a0), f_q)) +mstore(0x4860, mulmod(1, mload(0x41a0), f_q)) +mstore(0x4880, addmod(mload(0x4820), mload(0x4840), f_q)) +mstore(0x48a0, mulmod(sub(f_q, mload(0xf40)), mload(0x41c0), f_q)) +mstore(0x48c0, mulmod(1, mload(0x41c0), f_q)) +mstore(0x48e0, addmod(mload(0x4880), mload(0x48a0), f_q)) +mstore(0x4900, mulmod(sub(f_q, mload(0xf80)), mload(0x41e0), f_q)) +mstore(0x4920, mulmod(1, mload(0x41e0), f_q)) +mstore(0x4940, addmod(mload(0x48e0), mload(0x4900), f_q)) +mstore(0x4960, mulmod(sub(f_q, mload(0xfc0)), mload(0x4200), f_q)) +mstore(0x4980, mulmod(1, mload(0x4200), f_q)) +mstore(0x49a0, addmod(mload(0x4940), mload(0x4960), f_q)) +mstore(0x49c0, mulmod(sub(f_q, mload(0x1000)), mload(0x4220), f_q)) +mstore(0x49e0, mulmod(1, mload(0x4220), f_q)) +mstore(0x4a00, addmod(mload(0x49a0), mload(0x49c0), f_q)) +mstore(0x4a20, mulmod(sub(f_q, mload(0x1020)), mload(0x4240), f_q)) +mstore(0x4a40, mulmod(1, mload(0x4240), f_q)) +mstore(0x4a60, addmod(mload(0x4a00), mload(0x4a20), f_q)) +mstore(0x4a80, mulmod(sub(f_q, mload(0x1060)), mload(0x4260), f_q)) +mstore(0x4aa0, mulmod(1, mload(0x4260), f_q)) +mstore(0x4ac0, addmod(mload(0x4a60), mload(0x4a80), f_q)) +mstore(0x4ae0, mulmod(sub(f_q, mload(0x10a0)), mload(0x4280), f_q)) +mstore(0x4b00, mulmod(1, mload(0x4280), f_q)) +mstore(0x4b20, addmod(mload(0x4ac0), mload(0x4ae0), f_q)) +mstore(0x4b40, mulmod(sub(f_q, mload(0xdc0)), mload(0x42a0), f_q)) +mstore(0x4b60, mulmod(1, mload(0x42a0), f_q)) +mstore(0x4b80, addmod(mload(0x4b20), mload(0x4b40), f_q)) +mstore(0x4ba0, mulmod(sub(f_q, mload(0xde0)), mload(0x42c0), f_q)) +mstore(0x4bc0, mulmod(1, mload(0x42c0), f_q)) +mstore(0x4be0, addmod(mload(0x4b80), mload(0x4ba0), f_q)) +mstore(0x4c00, mulmod(sub(f_q, mload(0xe00)), mload(0x42e0), f_q)) +mstore(0x4c20, mulmod(1, mload(0x42e0), f_q)) +mstore(0x4c40, addmod(mload(0x4be0), mload(0x4c00), f_q)) +mstore(0x4c60, mulmod(sub(f_q, mload(0xe20)), mload(0x4300), f_q)) +mstore(0x4c80, mulmod(1, mload(0x4300), f_q)) +mstore(0x4ca0, addmod(mload(0x4c40), mload(0x4c60), f_q)) +mstore(0x4cc0, mulmod(sub(f_q, mload(0xe40)), mload(0x4320), f_q)) +mstore(0x4ce0, mulmod(1, mload(0x4320), f_q)) +mstore(0x4d00, addmod(mload(0x4ca0), mload(0x4cc0), f_q)) +mstore(0x4d20, mulmod(sub(f_q, mload(0xe60)), mload(0x4340), f_q)) +mstore(0x4d40, mulmod(1, mload(0x4340), f_q)) +mstore(0x4d60, addmod(mload(0x4d00), mload(0x4d20), f_q)) +mstore(0x4d80, mulmod(sub(f_q, mload(0xe80)), mload(0x4360), f_q)) +mstore(0x4da0, mulmod(1, mload(0x4360), f_q)) +mstore(0x4dc0, addmod(mload(0x4d60), mload(0x4d80), f_q)) +mstore(0x4de0, mulmod(sub(f_q, mload(0xec0)), mload(0x4380), f_q)) +mstore(0x4e00, mulmod(1, mload(0x4380), f_q)) +mstore(0x4e20, addmod(mload(0x4dc0), mload(0x4de0), f_q)) +mstore(0x4e40, mulmod(sub(f_q, mload(0xee0)), mload(0x43a0), f_q)) +mstore(0x4e60, mulmod(1, mload(0x43a0), f_q)) +mstore(0x4e80, addmod(mload(0x4e20), mload(0x4e40), f_q)) +mstore(0x4ea0, mulmod(sub(f_q, mload(0xf00)), mload(0x43c0), f_q)) +mstore(0x4ec0, mulmod(1, mload(0x43c0), f_q)) +mstore(0x4ee0, addmod(mload(0x4e80), mload(0x4ea0), f_q)) +mstore(0x4f00, mulmod(sub(f_q, mload(0xf20)), mload(0x43e0), f_q)) +mstore(0x4f20, mulmod(1, mload(0x43e0), f_q)) +mstore(0x4f40, addmod(mload(0x4ee0), mload(0x4f00), f_q)) +mstore(0x4f60, mulmod(sub(f_q, mload(0x3fc0)), mload(0x4400), f_q)) +mstore(0x4f80, mulmod(1, mload(0x4400), f_q)) +mstore(0x4fa0, mulmod(mload(0x3ee0), mload(0x4400), f_q)) +mstore(0x4fc0, mulmod(mload(0x3f00), mload(0x4400), f_q)) +mstore(0x4fe0, mulmod(mload(0x3f20), mload(0x4400), f_q)) +mstore(0x5000, mulmod(mload(0x3f40), mload(0x4400), f_q)) +mstore(0x5020, mulmod(mload(0x3f60), mload(0x4400), f_q)) +mstore(0x5040, mulmod(mload(0x3f80), mload(0x4400), f_q)) +mstore(0x5060, mulmod(mload(0x3fa0), mload(0x4400), f_q)) +mstore(0x5080, addmod(mload(0x4f40), mload(0x4f60), f_q)) +mstore(0x50a0, mulmod(sub(f_q, mload(0xea0)), mload(0x4420), f_q)) +mstore(0x50c0, mulmod(1, mload(0x4420), f_q)) +mstore(0x50e0, addmod(mload(0x5080), mload(0x50a0), f_q)) +mstore(0x5100, mulmod(mload(0x50e0), 1, f_q)) +mstore(0x5120, mulmod(mload(0x44a0), 1, f_q)) +mstore(0x5140, mulmod(mload(0x4500), 1, f_q)) +mstore(0x5160, mulmod(mload(0x4560), 1, f_q)) +mstore(0x5180, mulmod(mload(0x45c0), 1, f_q)) +mstore(0x51a0, mulmod(mload(0x4620), 1, f_q)) +mstore(0x51c0, mulmod(mload(0x4680), 1, f_q)) +mstore(0x51e0, mulmod(mload(0x46e0), 1, f_q)) +mstore(0x5200, mulmod(mload(0x4740), 1, f_q)) +mstore(0x5220, mulmod(mload(0x47a0), 1, f_q)) +mstore(0x5240, mulmod(mload(0x4800), 1, f_q)) +mstore(0x5260, mulmod(mload(0x4860), 1, f_q)) +mstore(0x5280, mulmod(mload(0x48c0), 1, f_q)) +mstore(0x52a0, mulmod(mload(0x4920), 1, f_q)) +mstore(0x52c0, mulmod(mload(0x4980), 1, f_q)) +mstore(0x52e0, mulmod(mload(0x49e0), 1, f_q)) +mstore(0x5300, mulmod(mload(0x4a40), 1, f_q)) +mstore(0x5320, mulmod(mload(0x4aa0), 1, f_q)) +mstore(0x5340, mulmod(mload(0x4b00), 1, f_q)) +mstore(0x5360, mulmod(mload(0x4b60), 1, f_q)) +mstore(0x5380, mulmod(mload(0x4bc0), 1, f_q)) +mstore(0x53a0, mulmod(mload(0x4c20), 1, f_q)) +mstore(0x53c0, mulmod(mload(0x4c80), 1, f_q)) +mstore(0x53e0, mulmod(mload(0x4ce0), 1, f_q)) +mstore(0x5400, mulmod(mload(0x4d40), 1, f_q)) +mstore(0x5420, mulmod(mload(0x4da0), 1, f_q)) +mstore(0x5440, mulmod(mload(0x4e00), 1, f_q)) +mstore(0x5460, mulmod(mload(0x4e60), 1, f_q)) +mstore(0x5480, mulmod(mload(0x4ec0), 1, f_q)) +mstore(0x54a0, mulmod(mload(0x4f20), 1, f_q)) +mstore(0x54c0, mulmod(mload(0x4f80), 1, f_q)) +mstore(0x54e0, mulmod(mload(0x4fa0), 1, f_q)) +mstore(0x5500, mulmod(mload(0x4fc0), 1, f_q)) +mstore(0x5520, mulmod(mload(0x4fe0), 1, f_q)) +mstore(0x5540, mulmod(mload(0x5000), 1, f_q)) +mstore(0x5560, mulmod(mload(0x5020), 1, f_q)) +mstore(0x5580, mulmod(mload(0x5040), 1, f_q)) +mstore(0x55a0, mulmod(mload(0x5060), 1, f_q)) +mstore(0x55c0, mulmod(mload(0x50c0), 1, f_q)) +mstore(0x55e0, mulmod(sub(f_q, mload(0xb40)), 1, f_q)) +mstore(0x5600, mulmod(sub(f_q, mload(0xb60)), mload(0x10e0), f_q)) +mstore(0x5620, addmod(mload(0x55e0), mload(0x5600), f_q)) +mstore(0x5640, mulmod(sub(f_q, mload(0xcc0)), mload(0x4080), f_q)) +mstore(0x5660, addmod(mload(0x5620), mload(0x5640), f_q)) +mstore(0x5680, mulmod(sub(f_q, mload(0xce0)), mload(0x40a0), f_q)) +mstore(0x56a0, addmod(mload(0x5660), mload(0x5680), f_q)) +mstore(0x56c0, mulmod(sub(f_q, mload(0xd00)), mload(0x40c0), f_q)) +mstore(0x56e0, addmod(mload(0x56a0), mload(0x56c0), f_q)) +mstore(0x5700, mulmod(sub(f_q, mload(0xd20)), mload(0x40e0), f_q)) +mstore(0x5720, addmod(mload(0x56e0), mload(0x5700), f_q)) +mstore(0x5740, mulmod(sub(f_q, mload(0xd40)), mload(0x4100), f_q)) +mstore(0x5760, addmod(mload(0x5720), mload(0x5740), f_q)) +mstore(0x5780, mulmod(sub(f_q, mload(0xd80)), mload(0x4120), f_q)) +mstore(0x57a0, addmod(mload(0x5760), mload(0x5780), f_q)) +mstore(0x57c0, mulmod(sub(f_q, mload(0xf60)), mload(0x4140), f_q)) +mstore(0x57e0, addmod(mload(0x57a0), mload(0x57c0), f_q)) +mstore(0x5800, mulmod(sub(f_q, mload(0xfa0)), mload(0x4160), f_q)) +mstore(0x5820, addmod(mload(0x57e0), mload(0x5800), f_q)) +mstore(0x5840, mulmod(sub(f_q, mload(0x1040)), mload(0x4180), f_q)) +mstore(0x5860, addmod(mload(0x5820), mload(0x5840), f_q)) +mstore(0x5880, mulmod(mload(0x5860), mload(0x12c0), f_q)) +mstore(0x58a0, mulmod(1, mload(0x12c0), f_q)) +mstore(0x58c0, mulmod(mload(0x44a0), mload(0x12c0), f_q)) +mstore(0x58e0, mulmod(mload(0x4500), mload(0x12c0), f_q)) +mstore(0x5900, mulmod(mload(0x4560), mload(0x12c0), f_q)) +mstore(0x5920, mulmod(mload(0x45c0), mload(0x12c0), f_q)) +mstore(0x5940, mulmod(mload(0x4620), mload(0x12c0), f_q)) +mstore(0x5960, mulmod(mload(0x4680), mload(0x12c0), f_q)) +mstore(0x5980, mulmod(mload(0x46e0), mload(0x12c0), f_q)) +mstore(0x59a0, mulmod(mload(0x4740), mload(0x12c0), f_q)) +mstore(0x59c0, mulmod(mload(0x47a0), mload(0x12c0), f_q)) +mstore(0x59e0, mulmod(mload(0x4800), mload(0x12c0), f_q)) +mstore(0x5a00, addmod(mload(0x5100), mload(0x5880), f_q)) +mstore(0x5a20, addmod(mload(0x5120), mload(0x58a0), f_q)) +mstore(0x5a40, addmod(mload(0x5140), mload(0x58c0), f_q)) +mstore(0x5a60, addmod(mload(0x5180), mload(0x58e0), f_q)) +mstore(0x5a80, addmod(mload(0x51e0), mload(0x5900), f_q)) +mstore(0x5aa0, addmod(mload(0x51a0), mload(0x5920), f_q)) +mstore(0x5ac0, addmod(mload(0x51c0), mload(0x5940), f_q)) +mstore(0x5ae0, addmod(mload(0x5200), mload(0x5960), f_q)) +mstore(0x5b00, addmod(mload(0x5240), mload(0x5980), f_q)) +mstore(0x5b20, addmod(mload(0x5280), mload(0x59a0), f_q)) +mstore(0x5b40, addmod(mload(0x52a0), mload(0x59c0), f_q)) +mstore(0x5b60, addmod(mload(0x5300), mload(0x59e0), f_q)) +mstore(0x5b80, mulmod(sub(f_q, mload(0xbc0)), 1, f_q)) +mstore(0x5ba0, mulmod(mload(0x5b80), mload(0x3fe0), f_q)) +mstore(0x5bc0, mulmod(1, mload(0x3fe0), f_q)) +mstore(0x5be0, addmod(mload(0x5a00), mload(0x5ba0), f_q)) +mstore(0x5c00, addmod(1, mload(0x5bc0), f_q)) +mstore(0x5c20, mulmod(sub(f_q, mload(0xc00)), 1, f_q)) +mstore(0x5c40, mulmod(mload(0x5c20), mload(0x4000), f_q)) +mstore(0x5c60, mulmod(1, mload(0x4000), f_q)) +mstore(0x5c80, addmod(mload(0x5be0), mload(0x5c40), f_q)) +mstore(0x5ca0, addmod(mload(0x5c00), mload(0x5c60), f_q)) +mstore(0x5cc0, mulmod(sub(f_q, mload(0xc40)), 1, f_q)) +mstore(0x5ce0, mulmod(mload(0x5cc0), mload(0x4020), f_q)) +mstore(0x5d00, mulmod(1, mload(0x4020), f_q)) +mstore(0x5d20, addmod(mload(0x5c80), mload(0x5ce0), f_q)) +mstore(0x5d40, addmod(mload(0x5ca0), mload(0x5d00), f_q)) +mstore(0x5d60, mulmod(sub(f_q, mload(0xfe0)), 1, f_q)) +mstore(0x5d80, mulmod(sub(f_q, mload(0x1080)), mload(0x10e0), f_q)) +mstore(0x5da0, addmod(mload(0x5d60), mload(0x5d80), f_q)) +mstore(0x5dc0, mulmod(mload(0x5da0), mload(0x4040), f_q)) +mstore(0x5de0, mulmod(1, mload(0x4040), f_q)) +mstore(0x5e00, mulmod(mload(0x44a0), mload(0x4040), f_q)) +mstore(0x5e20, addmod(mload(0x5d20), mload(0x5dc0), f_q)) +mstore(0x5e40, addmod(mload(0x52c0), mload(0x5de0), f_q)) +mstore(0x5e60, addmod(mload(0x5320), mload(0x5e00), f_q)) +mstore(0x5e80, mulmod(1, mload(0xaa0), f_q)) +mstore(0x5ea0, mulmod(1, mload(0x5e80), f_q)) +mstore(0x5ec0, mulmod(6955697244493336113861667751840378876927906302623587437721024018233754910398, mload(0xaa0), f_q)) +mstore(0x5ee0, mulmod(mload(0x58a0), mload(0x5ec0), f_q)) +mstore(0x5f00, mulmod(14301109305233875879800880185425345339138649975525900728211315483473936015336, mload(0xaa0), f_q)) +mstore(0x5f20, mulmod(mload(0x5bc0), mload(0x5f00), f_q)) +mstore(0x5f40, mulmod(18692705892880282321496735629591795720478967493699042848104039933759957773311, mload(0xaa0), f_q)) +mstore(0x5f60, mulmod(mload(0x5c60), mload(0x5f40), f_q)) +mstore(0x5f80, mulmod(21870189975119436114252110485335790532642623321946906002882013852447303224967, mload(0xaa0), f_q)) +mstore(0x5fa0, mulmod(mload(0x5d00), mload(0x5f80), f_q)) +mstore(0x5fc0, mulmod(6363119021782681274480715230122258277189830284152385293217720612674619714422, mload(0xaa0), f_q)) +mstore(0x5fe0, mulmod(mload(0x5de0), mload(0x5fc0), f_q)) +mstore(0x6000, 0x0000000000000000000000000000000000000000000000000000000000000001) + mstore(0x6020, 0x0000000000000000000000000000000000000000000000000000000000000002) +mstore(0x6040, mload(0x5e20)) +success := and(eq(staticcall(gas(), 0x7, 0x6000, 0x60, 0x6000, 0x40), 1), success) +mstore(0x6060, mload(0x340)) + mstore(0x6080, mload(0x360)) +mstore(0x60a0, mload(0x5d40)) +success := and(eq(staticcall(gas(), 0x7, 0x6060, 0x60, 0x6060, 0x40), 1), success) +mstore(0x60c0, mload(0x6000)) + mstore(0x60e0, mload(0x6020)) +mstore(0x6100, mload(0x6060)) + mstore(0x6120, mload(0x6080)) +success := and(eq(staticcall(gas(), 0x6, 0x60c0, 0x80, 0x60c0, 0x40), 1), success) +mstore(0x6140, mload(0x380)) + mstore(0x6160, mload(0x3a0)) +mstore(0x6180, mload(0x5a20)) +success := and(eq(staticcall(gas(), 0x7, 0x6140, 0x60, 0x6140, 0x40), 1), success) +mstore(0x61a0, mload(0x60c0)) + mstore(0x61c0, mload(0x60e0)) +mstore(0x61e0, mload(0x6140)) + mstore(0x6200, mload(0x6160)) +success := and(eq(staticcall(gas(), 0x6, 0x61a0, 0x80, 0x61a0, 0x40), 1), success) +mstore(0x6220, mload(0x3c0)) + mstore(0x6240, mload(0x3e0)) +mstore(0x6260, mload(0x5a40)) +success := and(eq(staticcall(gas(), 0x7, 0x6220, 0x60, 0x6220, 0x40), 1), success) +mstore(0x6280, mload(0x61a0)) + mstore(0x62a0, mload(0x61c0)) +mstore(0x62c0, mload(0x6220)) + mstore(0x62e0, mload(0x6240)) +success := and(eq(staticcall(gas(), 0x6, 0x6280, 0x80, 0x6280, 0x40), 1), success) +mstore(0x6300, mload(0x140)) + mstore(0x6320, mload(0x160)) +mstore(0x6340, mload(0x5160)) +success := and(eq(staticcall(gas(), 0x7, 0x6300, 0x60, 0x6300, 0x40), 1), success) +mstore(0x6360, mload(0x6280)) + mstore(0x6380, mload(0x62a0)) +mstore(0x63a0, mload(0x6300)) + mstore(0x63c0, mload(0x6320)) +success := and(eq(staticcall(gas(), 0x6, 0x6360, 0x80, 0x6360, 0x40), 1), success) +mstore(0x63e0, mload(0x180)) + mstore(0x6400, mload(0x1a0)) +mstore(0x6420, mload(0x5a60)) +success := and(eq(staticcall(gas(), 0x7, 0x63e0, 0x60, 0x63e0, 0x40), 1), success) +mstore(0x6440, mload(0x6360)) + mstore(0x6460, mload(0x6380)) +mstore(0x6480, mload(0x63e0)) + mstore(0x64a0, mload(0x6400)) +success := and(eq(staticcall(gas(), 0x6, 0x6440, 0x80, 0x6440, 0x40), 1), success) +mstore(0x64c0, mload(0x1c0)) + mstore(0x64e0, mload(0x1e0)) +mstore(0x6500, mload(0x5aa0)) +success := and(eq(staticcall(gas(), 0x7, 0x64c0, 0x60, 0x64c0, 0x40), 1), success) +mstore(0x6520, mload(0x6440)) + mstore(0x6540, mload(0x6460)) +mstore(0x6560, mload(0x64c0)) + mstore(0x6580, mload(0x64e0)) +success := and(eq(staticcall(gas(), 0x6, 0x6520, 0x80, 0x6520, 0x40), 1), success) +mstore(0x65a0, mload(0x4c0)) + mstore(0x65c0, mload(0x4e0)) +mstore(0x65e0, mload(0x5ac0)) +success := and(eq(staticcall(gas(), 0x7, 0x65a0, 0x60, 0x65a0, 0x40), 1), success) +mstore(0x6600, mload(0x6520)) + mstore(0x6620, mload(0x6540)) +mstore(0x6640, mload(0x65a0)) + mstore(0x6660, mload(0x65c0)) +success := and(eq(staticcall(gas(), 0x6, 0x6600, 0x80, 0x6600, 0x40), 1), success) +mstore(0x6680, mload(0x200)) + mstore(0x66a0, mload(0x220)) +mstore(0x66c0, mload(0x5a80)) +success := and(eq(staticcall(gas(), 0x7, 0x6680, 0x60, 0x6680, 0x40), 1), success) +mstore(0x66e0, mload(0x6600)) + mstore(0x6700, mload(0x6620)) +mstore(0x6720, mload(0x6680)) + mstore(0x6740, mload(0x66a0)) +success := and(eq(staticcall(gas(), 0x6, 0x66e0, 0x80, 0x66e0, 0x40), 1), success) +mstore(0x6760, mload(0x240)) + mstore(0x6780, mload(0x260)) +mstore(0x67a0, mload(0x5ae0)) +success := and(eq(staticcall(gas(), 0x7, 0x6760, 0x60, 0x6760, 0x40), 1), success) +mstore(0x67c0, mload(0x66e0)) + mstore(0x67e0, mload(0x6700)) +mstore(0x6800, mload(0x6760)) + mstore(0x6820, mload(0x6780)) +success := and(eq(staticcall(gas(), 0x6, 0x67c0, 0x80, 0x67c0, 0x40), 1), success) +mstore(0x6840, mload(0x280)) + mstore(0x6860, mload(0x2a0)) +mstore(0x6880, mload(0x5220)) +success := and(eq(staticcall(gas(), 0x7, 0x6840, 0x60, 0x6840, 0x40), 1), success) +mstore(0x68a0, mload(0x67c0)) + mstore(0x68c0, mload(0x67e0)) +mstore(0x68e0, mload(0x6840)) + mstore(0x6900, mload(0x6860)) +success := and(eq(staticcall(gas(), 0x6, 0x68a0, 0x80, 0x68a0, 0x40), 1), success) +mstore(0x6920, mload(0x2c0)) + mstore(0x6940, mload(0x2e0)) +mstore(0x6960, mload(0x5b00)) +success := and(eq(staticcall(gas(), 0x7, 0x6920, 0x60, 0x6920, 0x40), 1), success) +mstore(0x6980, mload(0x68a0)) + mstore(0x69a0, mload(0x68c0)) +mstore(0x69c0, mload(0x6920)) + mstore(0x69e0, mload(0x6940)) +success := and(eq(staticcall(gas(), 0x6, 0x6980, 0x80, 0x6980, 0x40), 1), success) +mstore(0x6a00, mload(0x300)) + mstore(0x6a20, mload(0x320)) +mstore(0x6a40, mload(0x5260)) +success := and(eq(staticcall(gas(), 0x7, 0x6a00, 0x60, 0x6a00, 0x40), 1), success) +mstore(0x6a60, mload(0x6980)) + mstore(0x6a80, mload(0x69a0)) +mstore(0x6aa0, mload(0x6a00)) + mstore(0x6ac0, mload(0x6a20)) +success := and(eq(staticcall(gas(), 0x6, 0x6a60, 0x80, 0x6a60, 0x40), 1), success) +mstore(0x6ae0, mload(0x720)) + mstore(0x6b00, mload(0x740)) +mstore(0x6b20, mload(0x5b20)) +success := and(eq(staticcall(gas(), 0x7, 0x6ae0, 0x60, 0x6ae0, 0x40), 1), success) +mstore(0x6b40, mload(0x6a60)) + mstore(0x6b60, mload(0x6a80)) +mstore(0x6b80, mload(0x6ae0)) + mstore(0x6ba0, mload(0x6b00)) +success := and(eq(staticcall(gas(), 0x6, 0x6b40, 0x80, 0x6b40, 0x40), 1), success) +mstore(0x6bc0, mload(0x760)) + mstore(0x6be0, mload(0x780)) +mstore(0x6c00, mload(0x5b40)) +success := and(eq(staticcall(gas(), 0x7, 0x6bc0, 0x60, 0x6bc0, 0x40), 1), success) +mstore(0x6c20, mload(0x6b40)) + mstore(0x6c40, mload(0x6b60)) +mstore(0x6c60, mload(0x6bc0)) + mstore(0x6c80, mload(0x6be0)) +success := and(eq(staticcall(gas(), 0x6, 0x6c20, 0x80, 0x6c20, 0x40), 1), success) +mstore(0x6ca0, mload(0x560)) + mstore(0x6cc0, mload(0x580)) +mstore(0x6ce0, mload(0x5e40)) +success := and(eq(staticcall(gas(), 0x7, 0x6ca0, 0x60, 0x6ca0, 0x40), 1), success) +mstore(0x6d00, mload(0x6c20)) + mstore(0x6d20, mload(0x6c40)) +mstore(0x6d40, mload(0x6ca0)) + mstore(0x6d60, mload(0x6cc0)) +success := and(eq(staticcall(gas(), 0x6, 0x6d00, 0x80, 0x6d00, 0x40), 1), success) +mstore(0x6d80, mload(0x5a0)) + mstore(0x6da0, mload(0x5c0)) +mstore(0x6dc0, mload(0x52e0)) +success := and(eq(staticcall(gas(), 0x7, 0x6d80, 0x60, 0x6d80, 0x40), 1), success) +mstore(0x6de0, mload(0x6d00)) + mstore(0x6e00, mload(0x6d20)) +mstore(0x6e20, mload(0x6d80)) + mstore(0x6e40, mload(0x6da0)) +success := and(eq(staticcall(gas(), 0x6, 0x6de0, 0x80, 0x6de0, 0x40), 1), success) +mstore(0x6e60, mload(0x7a0)) + mstore(0x6e80, mload(0x7c0)) +mstore(0x6ea0, mload(0x5b60)) +success := and(eq(staticcall(gas(), 0x7, 0x6e60, 0x60, 0x6e60, 0x40), 1), success) +mstore(0x6ec0, mload(0x6de0)) + mstore(0x6ee0, mload(0x6e00)) +mstore(0x6f00, mload(0x6e60)) + mstore(0x6f20, mload(0x6e80)) +success := and(eq(staticcall(gas(), 0x6, 0x6ec0, 0x80, 0x6ec0, 0x40), 1), success) +mstore(0x6f40, mload(0x5e0)) + mstore(0x6f60, mload(0x600)) +mstore(0x6f80, mload(0x5e60)) +success := and(eq(staticcall(gas(), 0x7, 0x6f40, 0x60, 0x6f40, 0x40), 1), success) +mstore(0x6fa0, mload(0x6ec0)) + mstore(0x6fc0, mload(0x6ee0)) +mstore(0x6fe0, mload(0x6f40)) + mstore(0x7000, mload(0x6f60)) +success := and(eq(staticcall(gas(), 0x6, 0x6fa0, 0x80, 0x6fa0, 0x40), 1), success) +mstore(0x7020, mload(0x620)) + mstore(0x7040, mload(0x640)) +mstore(0x7060, mload(0x5340)) +success := and(eq(staticcall(gas(), 0x7, 0x7020, 0x60, 0x7020, 0x40), 1), success) +mstore(0x7080, mload(0x6fa0)) + mstore(0x70a0, mload(0x6fc0)) +mstore(0x70c0, mload(0x7020)) + mstore(0x70e0, mload(0x7040)) +success := and(eq(staticcall(gas(), 0x6, 0x7080, 0x80, 0x7080, 0x40), 1), success) +mstore(0x7100, 0x244b27074fffede37a65e6ec14bd01014f5353c2d4897431dd4e7806e3a11ec6) + mstore(0x7120, 0x030bf32ba59b19236ebd8c886db4bc4fcd3bf8442e9879c8c44d2ca50775eb48) +mstore(0x7140, mload(0x5360)) +success := and(eq(staticcall(gas(), 0x7, 0x7100, 0x60, 0x7100, 0x40), 1), success) +mstore(0x7160, mload(0x7080)) + mstore(0x7180, mload(0x70a0)) +mstore(0x71a0, mload(0x7100)) + mstore(0x71c0, mload(0x7120)) +success := and(eq(staticcall(gas(), 0x6, 0x7160, 0x80, 0x7160, 0x40), 1), success) +mstore(0x71e0, 0x2627124da508b1628ffc3431168e4aad3ab0b7f2239c174d3e1d29a8edc465f9) + mstore(0x7200, 0x0049dc25c5d0c913911e717198561e494a2c495301d63cb3d8a9623c61e4c257) +mstore(0x7220, mload(0x5380)) +success := and(eq(staticcall(gas(), 0x7, 0x71e0, 0x60, 0x71e0, 0x40), 1), success) +mstore(0x7240, mload(0x7160)) + mstore(0x7260, mload(0x7180)) +mstore(0x7280, mload(0x71e0)) + mstore(0x72a0, mload(0x7200)) +success := and(eq(staticcall(gas(), 0x6, 0x7240, 0x80, 0x7240, 0x40), 1), success) +mstore(0x72c0, 0x13f3288ef1fd4ebffeb03fcfae47a32a149c94ee9167eb8fb99dc2bd4a9312a8) + mstore(0x72e0, 0x2439ead2cacb828a9c0ea0e3bf7a693ee04ace562a84dbd60bea48f633d5ba5a) +mstore(0x7300, mload(0x53a0)) +success := and(eq(staticcall(gas(), 0x7, 0x72c0, 0x60, 0x72c0, 0x40), 1), success) +mstore(0x7320, mload(0x7240)) + mstore(0x7340, mload(0x7260)) +mstore(0x7360, mload(0x72c0)) + mstore(0x7380, mload(0x72e0)) +success := and(eq(staticcall(gas(), 0x6, 0x7320, 0x80, 0x7320, 0x40), 1), success) +mstore(0x73a0, 0x09aa4e3e02f32390410c2336415f53ef5f8ed8c3e35a9541347fc2e4e14714a9) + mstore(0x73c0, 0x26dc2ca88f821bee66bb45da14e6c1136b643831ac23bc61e815c5e193540b5a) +mstore(0x73e0, mload(0x53c0)) +success := and(eq(staticcall(gas(), 0x7, 0x73a0, 0x60, 0x73a0, 0x40), 1), success) +mstore(0x7400, mload(0x7320)) + mstore(0x7420, mload(0x7340)) +mstore(0x7440, mload(0x73a0)) + mstore(0x7460, mload(0x73c0)) +success := and(eq(staticcall(gas(), 0x6, 0x7400, 0x80, 0x7400, 0x40), 1), success) +mstore(0x7480, 0x2119fec8729037f3f697e6b06e4568b0d39e8810ae4ca76362098191c3153533) + mstore(0x74a0, 0x2ad6704915e32b51865f55bb8f6b1f4b4670cd552f17bda1b6871081d6d9acac) +mstore(0x74c0, mload(0x53e0)) +success := and(eq(staticcall(gas(), 0x7, 0x7480, 0x60, 0x7480, 0x40), 1), success) +mstore(0x74e0, mload(0x7400)) + mstore(0x7500, mload(0x7420)) +mstore(0x7520, mload(0x7480)) + mstore(0x7540, mload(0x74a0)) +success := and(eq(staticcall(gas(), 0x6, 0x74e0, 0x80, 0x74e0, 0x40), 1), success) +mstore(0x7560, 0x2c6113fa65e8ceace0bed99ee38ee142ce5921d4d679eb477099b29e3bf5a62f) + mstore(0x7580, 0x15456d6081bc272e17c4cfe07c04ea3b462b19a9227a7f6f1084263523b62487) +mstore(0x75a0, mload(0x5400)) +success := and(eq(staticcall(gas(), 0x7, 0x7560, 0x60, 0x7560, 0x40), 1), success) +mstore(0x75c0, mload(0x74e0)) + mstore(0x75e0, mload(0x7500)) +mstore(0x7600, mload(0x7560)) + mstore(0x7620, mload(0x7580)) +success := and(eq(staticcall(gas(), 0x6, 0x75c0, 0x80, 0x75c0, 0x40), 1), success) +mstore(0x7640, 0x24e88e2cbcf2020ebcec1946e87361e4b9b4463bda370f32b2cb653a4deac5d7) + mstore(0x7660, 0x059f1feb7198d197ff9c7bd680a49a1d1850027a0f565affdd1246d8071d59c1) +mstore(0x7680, mload(0x5420)) +success := and(eq(staticcall(gas(), 0x7, 0x7640, 0x60, 0x7640, 0x40), 1), success) +mstore(0x76a0, mload(0x75c0)) + mstore(0x76c0, mload(0x75e0)) +mstore(0x76e0, mload(0x7640)) + mstore(0x7700, mload(0x7660)) +success := and(eq(staticcall(gas(), 0x6, 0x76a0, 0x80, 0x76a0, 0x40), 1), success) +mstore(0x7720, 0x09281c3911bbaf7de0f1ad1225c4eaa415939b71dc75a63d6aeb0046fef3b0c2) + mstore(0x7740, 0x293301a161eb89a88cf29daed0d4206c9b139352af72231dd1d7b58b785a366e) +mstore(0x7760, mload(0x5440)) +success := and(eq(staticcall(gas(), 0x7, 0x7720, 0x60, 0x7720, 0x40), 1), success) +mstore(0x7780, mload(0x76a0)) + mstore(0x77a0, mload(0x76c0)) +mstore(0x77c0, mload(0x7720)) + mstore(0x77e0, mload(0x7740)) +success := and(eq(staticcall(gas(), 0x6, 0x7780, 0x80, 0x7780, 0x40), 1), success) +mstore(0x7800, 0x0bcd89437d13dca18999f2086352d216d57766a28e858c020f8caec517c65f23) + mstore(0x7820, 0x2db48af8e8abaecbe78ab899bfd646f740254b2905d944e15c0e9155f999e0eb) +mstore(0x7840, mload(0x5460)) +success := and(eq(staticcall(gas(), 0x7, 0x7800, 0x60, 0x7800, 0x40), 1), success) +mstore(0x7860, mload(0x7780)) + mstore(0x7880, mload(0x77a0)) +mstore(0x78a0, mload(0x7800)) + mstore(0x78c0, mload(0x7820)) +success := and(eq(staticcall(gas(), 0x6, 0x7860, 0x80, 0x7860, 0x40), 1), success) +mstore(0x78e0, 0x2055eb206acacc04ad55900481deac80c613415eec7d72ed119e7e19559389af) + mstore(0x7900, 0x26c44b72875cf74e6d5425b7b3fed786449c28cb83a6cb5e8cfff120d770d90e) +mstore(0x7920, mload(0x5480)) +success := and(eq(staticcall(gas(), 0x7, 0x78e0, 0x60, 0x78e0, 0x40), 1), success) +mstore(0x7940, mload(0x7860)) + mstore(0x7960, mload(0x7880)) +mstore(0x7980, mload(0x78e0)) + mstore(0x79a0, mload(0x7900)) +success := and(eq(staticcall(gas(), 0x6, 0x7940, 0x80, 0x7940, 0x40), 1), success) +mstore(0x79c0, 0x2e1acca63e88fe568d8b841020fd158d6273ddaf6cfbf96a73f74dc82fc7b59a) + mstore(0x79e0, 0x04404ce23c959637a08304342c3ea1fdfcc95fcabe150e535131b353a5d9c519) +mstore(0x7a00, mload(0x54a0)) +success := and(eq(staticcall(gas(), 0x7, 0x79c0, 0x60, 0x79c0, 0x40), 1), success) +mstore(0x7a20, mload(0x7940)) + mstore(0x7a40, mload(0x7960)) +mstore(0x7a60, mload(0x79c0)) + mstore(0x7a80, mload(0x79e0)) +success := and(eq(staticcall(gas(), 0x6, 0x7a20, 0x80, 0x7a20, 0x40), 1), success) +mstore(0x7aa0, mload(0x880)) + mstore(0x7ac0, mload(0x8a0)) +mstore(0x7ae0, mload(0x54c0)) +success := and(eq(staticcall(gas(), 0x7, 0x7aa0, 0x60, 0x7aa0, 0x40), 1), success) +mstore(0x7b00, mload(0x7a20)) + mstore(0x7b20, mload(0x7a40)) +mstore(0x7b40, mload(0x7aa0)) + mstore(0x7b60, mload(0x7ac0)) +success := and(eq(staticcall(gas(), 0x6, 0x7b00, 0x80, 0x7b00, 0x40), 1), success) +mstore(0x7b80, mload(0x8c0)) + mstore(0x7ba0, mload(0x8e0)) +mstore(0x7bc0, mload(0x54e0)) +success := and(eq(staticcall(gas(), 0x7, 0x7b80, 0x60, 0x7b80, 0x40), 1), success) +mstore(0x7be0, mload(0x7b00)) + mstore(0x7c00, mload(0x7b20)) +mstore(0x7c20, mload(0x7b80)) + mstore(0x7c40, mload(0x7ba0)) +success := and(eq(staticcall(gas(), 0x6, 0x7be0, 0x80, 0x7be0, 0x40), 1), success) +mstore(0x7c60, mload(0x900)) + mstore(0x7c80, mload(0x920)) +mstore(0x7ca0, mload(0x5500)) +success := and(eq(staticcall(gas(), 0x7, 0x7c60, 0x60, 0x7c60, 0x40), 1), success) +mstore(0x7cc0, mload(0x7be0)) + mstore(0x7ce0, mload(0x7c00)) +mstore(0x7d00, mload(0x7c60)) + mstore(0x7d20, mload(0x7c80)) +success := and(eq(staticcall(gas(), 0x6, 0x7cc0, 0x80, 0x7cc0, 0x40), 1), success) +mstore(0x7d40, mload(0x940)) + mstore(0x7d60, mload(0x960)) +mstore(0x7d80, mload(0x5520)) +success := and(eq(staticcall(gas(), 0x7, 0x7d40, 0x60, 0x7d40, 0x40), 1), success) +mstore(0x7da0, mload(0x7cc0)) + mstore(0x7dc0, mload(0x7ce0)) +mstore(0x7de0, mload(0x7d40)) + mstore(0x7e00, mload(0x7d60)) +success := and(eq(staticcall(gas(), 0x6, 0x7da0, 0x80, 0x7da0, 0x40), 1), success) +mstore(0x7e20, mload(0x980)) + mstore(0x7e40, mload(0x9a0)) +mstore(0x7e60, mload(0x5540)) +success := and(eq(staticcall(gas(), 0x7, 0x7e20, 0x60, 0x7e20, 0x40), 1), success) +mstore(0x7e80, mload(0x7da0)) + mstore(0x7ea0, mload(0x7dc0)) +mstore(0x7ec0, mload(0x7e20)) + mstore(0x7ee0, mload(0x7e40)) +success := and(eq(staticcall(gas(), 0x6, 0x7e80, 0x80, 0x7e80, 0x40), 1), success) +mstore(0x7f00, mload(0x9c0)) + mstore(0x7f20, mload(0x9e0)) +mstore(0x7f40, mload(0x5560)) +success := and(eq(staticcall(gas(), 0x7, 0x7f00, 0x60, 0x7f00, 0x40), 1), success) +mstore(0x7f60, mload(0x7e80)) + mstore(0x7f80, mload(0x7ea0)) +mstore(0x7fa0, mload(0x7f00)) + mstore(0x7fc0, mload(0x7f20)) +success := and(eq(staticcall(gas(), 0x6, 0x7f60, 0x80, 0x7f60, 0x40), 1), success) +mstore(0x7fe0, mload(0xa00)) + mstore(0x8000, mload(0xa20)) +mstore(0x8020, mload(0x5580)) +success := and(eq(staticcall(gas(), 0x7, 0x7fe0, 0x60, 0x7fe0, 0x40), 1), success) +mstore(0x8040, mload(0x7f60)) + mstore(0x8060, mload(0x7f80)) +mstore(0x8080, mload(0x7fe0)) + mstore(0x80a0, mload(0x8000)) +success := and(eq(staticcall(gas(), 0x6, 0x8040, 0x80, 0x8040, 0x40), 1), success) +mstore(0x80c0, mload(0xa40)) + mstore(0x80e0, mload(0xa60)) +mstore(0x8100, mload(0x55a0)) +success := and(eq(staticcall(gas(), 0x7, 0x80c0, 0x60, 0x80c0, 0x40), 1), success) +mstore(0x8120, mload(0x8040)) + mstore(0x8140, mload(0x8060)) +mstore(0x8160, mload(0x80c0)) + mstore(0x8180, mload(0x80e0)) +success := and(eq(staticcall(gas(), 0x6, 0x8120, 0x80, 0x8120, 0x40), 1), success) +mstore(0x81a0, mload(0x7e0)) + mstore(0x81c0, mload(0x800)) +mstore(0x81e0, mload(0x55c0)) +success := and(eq(staticcall(gas(), 0x7, 0x81a0, 0x60, 0x81a0, 0x40), 1), success) +mstore(0x8200, mload(0x8120)) + mstore(0x8220, mload(0x8140)) +mstore(0x8240, mload(0x81a0)) + mstore(0x8260, mload(0x81c0)) +success := and(eq(staticcall(gas(), 0x6, 0x8200, 0x80, 0x8200, 0x40), 1), success) +mstore(0x8280, mload(0x1120)) + mstore(0x82a0, mload(0x1140)) +mstore(0x82c0, mload(0x5ea0)) +success := and(eq(staticcall(gas(), 0x7, 0x8280, 0x60, 0x8280, 0x40), 1), success) +mstore(0x82e0, mload(0x8200)) + mstore(0x8300, mload(0x8220)) +mstore(0x8320, mload(0x8280)) + mstore(0x8340, mload(0x82a0)) +success := and(eq(staticcall(gas(), 0x6, 0x82e0, 0x80, 0x82e0, 0x40), 1), success) +mstore(0x8360, mload(0x1160)) + mstore(0x8380, mload(0x1180)) +mstore(0x83a0, mload(0x5ee0)) +success := and(eq(staticcall(gas(), 0x7, 0x8360, 0x60, 0x8360, 0x40), 1), success) +mstore(0x83c0, mload(0x82e0)) + mstore(0x83e0, mload(0x8300)) +mstore(0x8400, mload(0x8360)) + mstore(0x8420, mload(0x8380)) +success := and(eq(staticcall(gas(), 0x6, 0x83c0, 0x80, 0x83c0, 0x40), 1), success) +mstore(0x8440, mload(0x11a0)) + mstore(0x8460, mload(0x11c0)) +mstore(0x8480, mload(0x5f20)) +success := and(eq(staticcall(gas(), 0x7, 0x8440, 0x60, 0x8440, 0x40), 1), success) +mstore(0x84a0, mload(0x83c0)) + mstore(0x84c0, mload(0x83e0)) +mstore(0x84e0, mload(0x8440)) + mstore(0x8500, mload(0x8460)) +success := and(eq(staticcall(gas(), 0x6, 0x84a0, 0x80, 0x84a0, 0x40), 1), success) +mstore(0x8520, mload(0x11e0)) + mstore(0x8540, mload(0x1200)) +mstore(0x8560, mload(0x5f60)) +success := and(eq(staticcall(gas(), 0x7, 0x8520, 0x60, 0x8520, 0x40), 1), success) +mstore(0x8580, mload(0x84a0)) + mstore(0x85a0, mload(0x84c0)) +mstore(0x85c0, mload(0x8520)) + mstore(0x85e0, mload(0x8540)) +success := and(eq(staticcall(gas(), 0x6, 0x8580, 0x80, 0x8580, 0x40), 1), success) +mstore(0x8600, mload(0x1220)) + mstore(0x8620, mload(0x1240)) +mstore(0x8640, mload(0x5fa0)) +success := and(eq(staticcall(gas(), 0x7, 0x8600, 0x60, 0x8600, 0x40), 1), success) +mstore(0x8660, mload(0x8580)) + mstore(0x8680, mload(0x85a0)) +mstore(0x86a0, mload(0x8600)) + mstore(0x86c0, mload(0x8620)) +success := and(eq(staticcall(gas(), 0x6, 0x8660, 0x80, 0x8660, 0x40), 1), success) +mstore(0x86e0, mload(0x1260)) + mstore(0x8700, mload(0x1280)) +mstore(0x8720, mload(0x5fe0)) +success := and(eq(staticcall(gas(), 0x7, 0x86e0, 0x60, 0x86e0, 0x40), 1), success) +mstore(0x8740, mload(0x8660)) + mstore(0x8760, mload(0x8680)) +mstore(0x8780, mload(0x86e0)) + mstore(0x87a0, mload(0x8700)) +success := and(eq(staticcall(gas(), 0x6, 0x8740, 0x80, 0x8740, 0x40), 1), success) +mstore(0x87c0, mload(0x1160)) + mstore(0x87e0, mload(0x1180)) +mstore(0x8800, mload(0x58a0)) +success := and(eq(staticcall(gas(), 0x7, 0x87c0, 0x60, 0x87c0, 0x40), 1), success) +mstore(0x8820, mload(0x1120)) + mstore(0x8840, mload(0x1140)) +mstore(0x8860, mload(0x87c0)) + mstore(0x8880, mload(0x87e0)) +success := and(eq(staticcall(gas(), 0x6, 0x8820, 0x80, 0x8820, 0x40), 1), success) +mstore(0x88a0, mload(0x11a0)) + mstore(0x88c0, mload(0x11c0)) +mstore(0x88e0, mload(0x5bc0)) +success := and(eq(staticcall(gas(), 0x7, 0x88a0, 0x60, 0x88a0, 0x40), 1), success) +mstore(0x8900, mload(0x8820)) + mstore(0x8920, mload(0x8840)) +mstore(0x8940, mload(0x88a0)) + mstore(0x8960, mload(0x88c0)) +success := and(eq(staticcall(gas(), 0x6, 0x8900, 0x80, 0x8900, 0x40), 1), success) +mstore(0x8980, mload(0x11e0)) + mstore(0x89a0, mload(0x1200)) +mstore(0x89c0, mload(0x5c60)) +success := and(eq(staticcall(gas(), 0x7, 0x8980, 0x60, 0x8980, 0x40), 1), success) +mstore(0x89e0, mload(0x8900)) + mstore(0x8a00, mload(0x8920)) +mstore(0x8a20, mload(0x8980)) + mstore(0x8a40, mload(0x89a0)) +success := and(eq(staticcall(gas(), 0x6, 0x89e0, 0x80, 0x89e0, 0x40), 1), success) +mstore(0x8a60, mload(0x1220)) + mstore(0x8a80, mload(0x1240)) +mstore(0x8aa0, mload(0x5d00)) +success := and(eq(staticcall(gas(), 0x7, 0x8a60, 0x60, 0x8a60, 0x40), 1), success) +mstore(0x8ac0, mload(0x89e0)) + mstore(0x8ae0, mload(0x8a00)) +mstore(0x8b00, mload(0x8a60)) + mstore(0x8b20, mload(0x8a80)) +success := and(eq(staticcall(gas(), 0x6, 0x8ac0, 0x80, 0x8ac0, 0x40), 1), success) +mstore(0x8b40, mload(0x1260)) + mstore(0x8b60, mload(0x1280)) +mstore(0x8b80, mload(0x5de0)) +success := and(eq(staticcall(gas(), 0x7, 0x8b40, 0x60, 0x8b40, 0x40), 1), success) +mstore(0x8ba0, mload(0x8ac0)) + mstore(0x8bc0, mload(0x8ae0)) +mstore(0x8be0, mload(0x8b40)) + mstore(0x8c00, mload(0x8b60)) +success := and(eq(staticcall(gas(), 0x6, 0x8ba0, 0x80, 0x8ba0, 0x40), 1), success) +mstore(0x8c20, mload(0x8740)) + mstore(0x8c40, mload(0x8760)) +mstore(0x8c60, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) + mstore(0x8c80, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) + mstore(0x8ca0, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) + mstore(0x8cc0, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) +mstore(0x8ce0, mload(0x8ba0)) + mstore(0x8d00, mload(0x8bc0)) +mstore(0x8d20, 0x0bf2116ef9608ee9a63fbb4fa17f24b944b30ef31a00b8b55c079507fa373a9f) + mstore(0x8d40, 0x178875d7267f25b53a15c243accfebea97c81b763d2e5beb44dbc4a5b59ace7c) + mstore(0x8d60, 0x0750bb061b40181208c9fcc6524c7bcc60b07f70c579d5b722a43c9d14d0427f) + mstore(0x8d80, 0x17e60f8bd1dae2e5a555271dd1ad6144d48e0f051e0b16c704e52939f490969e) +success := and(eq(staticcall(gas(), 0x8, 0x8c20, 0x180, 0x8c20, 0x20), 1), success) +success := and(eq(mload(0x8c20), 1), success) + + if not(success) { revert(0, 0) } + return(0, 0) + + } + } + } \ No newline at end of file diff --git a/packages/protocol/contracts/test/L1/TestTaikoL1.sol b/packages/protocol/contracts/test/L1/TestTaikoL1.sol index 51914318ee6..370d49a2eb4 100644 --- a/packages/protocol/contracts/test/L1/TestTaikoL1.sol +++ b/packages/protocol/contracts/test/L1/TestTaikoL1.sol @@ -52,7 +52,7 @@ contract TestTaikoL1 is TaikoL1, IProofVerifier { } function verifyZKP( - bytes memory /*verificationKey*/, + string memory /*verifierId*/, bytes calldata /*zkproof*/, bytes32 /*blockHash*/, address /*prover*/, diff --git a/packages/protocol/contracts/test/L1/TestTaikoL1EnableTokenomics.sol b/packages/protocol/contracts/test/L1/TestTaikoL1EnableTokenomics.sol index 05d6ea18922..0c05a587112 100644 --- a/packages/protocol/contracts/test/L1/TestTaikoL1EnableTokenomics.sol +++ b/packages/protocol/contracts/test/L1/TestTaikoL1EnableTokenomics.sol @@ -52,7 +52,7 @@ contract TestTaikoL1EnableTokenomics is TaikoL1, IProofVerifier { } function verifyZKP( - bytes memory /*verificationKey*/, + string memory /*verifierId*/, bytes calldata /*zkproof*/, bytes32 /*blockHash*/, address /*prover*/, diff --git a/packages/protocol/docs/common/ConfigManager.md b/packages/protocol/docs/common/ConfigManager.md deleted file mode 100644 index da0a49d19d2..00000000000 --- a/packages/protocol/docs/common/ConfigManager.md +++ /dev/null @@ -1,31 +0,0 @@ -## ConfigManager - -### kv - -```solidity -mapping(bytes32 => bytes) kv -``` - -### Updated - -```solidity -event Updated(string name, bytes newVal, bytes oldVal) -``` - -### init - -```solidity -function init() external -``` - -### setValue - -```solidity -function setValue(string name, bytes val) external -``` - -### getValue - -```solidity -function getValue(string name) public view returns (bytes) -``` diff --git a/packages/protocol/hardhat.config.ts b/packages/protocol/hardhat.config.ts index cc5a762ee2c..ec9f6684688 100644 --- a/packages/protocol/hardhat.config.ts +++ b/packages/protocol/hardhat.config.ts @@ -8,6 +8,7 @@ import { HardhatUserConfig } from "hardhat/config"; import "solidity-coverage"; import "solidity-docgen"; import "./tasks/deploy_L1"; +import "./tasks/compile_yul"; const hardhatMnemonic = "test test test test test test test test test test test taik"; diff --git a/packages/protocol/package.json b/packages/protocol/package.json index 1514217e55f..cbbda8a2bce 100644 --- a/packages/protocol/package.json +++ b/packages/protocol/package.json @@ -4,6 +4,7 @@ "private": true, "scripts": { "compile": "pnpm hardhat compile", + "compile:yul": "LOG_LEVEL=debug pnpm hardhat compile_yul", "export:abi": "pnpm hardhat clear-abi && pnpm hardhat export-abi", "export:docs": "pnpm hardhat docgen && pnpm prettier --write ../website/pages/docs/contract-documentation/**/*.md", "clean": "rm -rf abis cache && pnpm hardhat clean", @@ -17,7 +18,7 @@ "test:genesis": "./test/genesis/generate_genesis.test.sh", "test:integration": "TEST_TYPE=integration ./test/test_integration.sh", "test:tokenomics": "TEST_TYPE=tokenomics ./test/test_integration.sh", - "deploy:hardhat": "LOG_LEVEL=debug pnpm hardhat deploy_L1 --network hardhat --dao-vault 0xdf08f82de32b8d460adbe8d72043e3a7e25a3b39 --team-vault 0xdf08f82de32b8d460adbe8d72043e3a7e25a3b39 --l2-genesis-block-hash 0xee1950562d42f0da28bd4550d88886bc90894c77c9c9eaefef775d4c8223f259 --bridge-funder-private-key ddbf12f72c946bb1e6de5eaf580c51db51828ba198d9b0dba9c7d48ec748dc04 --bridge-fund 0xff --confirmations 1", + "deploy:hardhat": "./scripts/download_solc.sh && LOG_LEVEL=debug pnpm hardhat deploy_L1 --network hardhat --dao-vault 0xdf08f82de32b8d460adbe8d72043e3a7e25a3b39 --team-vault 0xdf08f82de32b8d460adbe8d72043e3a7e25a3b39 --l2-genesis-block-hash 0xee1950562d42f0da28bd4550d88886bc90894c77c9c9eaefef775d4c8223f259 --bridge-funder-private-key ddbf12f72c946bb1e6de5eaf580c51db51828ba198d9b0dba9c7d48ec748dc04 --bridge-fund 0xff --confirmations 1", "lint-staged": "lint-staged --allow-empty" }, "lint-staged": { @@ -44,6 +45,7 @@ "@typechain/ethers-v5": "^7.2.0", "@typechain/hardhat": "^2.3.1", "@types/chai": "^4.3.0", + "@types/glob": "^8.0.1", "@types/mocha": "^9.1.0", "@types/node": "^12.20.45", "@typescript-eslint/eslint-plugin": "^4.33.0", @@ -60,6 +62,7 @@ "eslint-plugin-promise": "^5.2.0", "ethereum-waffle": "^3.0.0", "ethers": "^5.0.0", + "glob": "^8.1.0", "hardhat": "^2.8.3", "hardhat-abi-exporter": "^2.10.0", "hardhat-docgen": "^1.3.0", diff --git a/packages/protocol/scripts/download_solc.sh b/packages/protocol/scripts/download_solc.sh new file mode 100755 index 00000000000..71c5c27bfcc --- /dev/null +++ b/packages/protocol/scripts/download_solc.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +set -e + +mkdir -p bin && cd bin + +if [ -f "solc" ]; then + exit 0 +fi + +VERSION=v0.8.9 + +if [[ "$(uname)" = 'Darwin' ]; then + SOLC_FILE_NAME=solc-macos +elif [ "$(uname)" = 'Linux' ]; then + SOLC_FILE_NAME=solc-static-linux +else + echo "unsupported platform $(uname)" + exit 1 +fi + +wget -O solc https://github.com/ethereum/solidity/releases/download/$VERSION/$SOLC_FILE_NAME + +chmod +x solc diff --git a/packages/protocol/tasks/compile_yul.ts b/packages/protocol/tasks/compile_yul.ts new file mode 100644 index 00000000000..e2ec2563ee4 --- /dev/null +++ b/packages/protocol/tasks/compile_yul.ts @@ -0,0 +1,30 @@ +import { task } from "hardhat/config"; +import * as glob from "glob"; +import * as path from "path"; +import * as utils from "./utils"; +import * as fs from "fs"; +import * as log from "./log"; + +task("compile_yul").setAction(async function () { + const yulContracts = glob.sync( + path.join(__dirname, "../contracts/**/*.yulp") + ); + const outputDir = path.join(__dirname, "../artifacts/yul"); + + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + + log.debug({ yulContracts }); + + for (const yulContractPath of yulContracts) { + const bytecode = utils.compileYulContract(yulContractPath); + const contractName = path.parse(path.basename(yulContractPath)).name; + const jsonOutputPath = path.join(outputDir, `${contractName}.json`); + + fs.writeFileSync( + jsonOutputPath, + JSON.stringify({ contractName, bytecode }) + ); + } +}); diff --git a/packages/protocol/tasks/deploy_L1.ts b/packages/protocol/tasks/deploy_L1.ts index a37769c7a0a..11941025d05 100644 --- a/packages/protocol/tasks/deploy_L1.ts +++ b/packages/protocol/tasks/deploy_L1.ts @@ -83,6 +83,7 @@ export async function deployContracts(hre: any) { await utils.waitTx(hre, await AddressManager.init()); const ProofVerifier = await utils.deployContract(hre, "ProofVerifier"); + await utils.waitTx(hre, await ProofVerifier.init(AddressManager.address)); await utils.waitTx( hre, await AddressManager.setAddress( @@ -116,17 +117,6 @@ export async function deployContracts(hre: any) { ) ); - // Config manager - const ConfigManager = await utils.deployContract(hre, "ConfigManager"); - await utils.waitTx(hre, await ConfigManager.init()); - await utils.waitTx( - hre, - await AddressManager.setAddress( - `${chainId}.config_manager`, - ConfigManager.address - ) - ); - // TaikoL1 const TaikoL1 = await utils.deployContract( hre, @@ -196,6 +186,21 @@ export async function deployContracts(hre: any) { ) ); + // PlonkVerifier + const PlonkVerifier = await deployPlonkVerifier(hre); + + // Used by ProofVerifier + await utils.waitTx( + hre, + await AddressManager.setAddress( + ethers.utils.solidityPack( + ["string", "uint256"], + ["plonk_verifier_", 0] + ), + PlonkVerifier.address + ) + ); + // save deployments const deployments = { network, @@ -283,3 +288,11 @@ async function deploySignalSerive( return SignalService; } + +async function deployPlonkVerifier(hre: any): Promise { + const byteCode = utils.compileYulContract( + "../contracts/libs/yul/PlonkVerifier.yulp" + ); + + return { address: await utils.deployBytecode(hre, byteCode) }; +} diff --git a/packages/protocol/tasks/utils.ts b/packages/protocol/tasks/utils.ts index e8a82b35c9c..7053de252dd 100644 --- a/packages/protocol/tasks/utils.ts +++ b/packages/protocol/tasks/utils.ts @@ -1,4 +1,6 @@ +import * as childProcess from "child_process"; import * as fs from "fs"; +import * as path from "path"; import * as log from "./log"; async function deployContract( @@ -27,6 +29,74 @@ async function deployContract( return deployed; } +function compileYulContract(contractPath: string): string { + const SOLC_COMMAND = path.join(__dirname, "../bin/solc"); + + if (!fs.existsSync(SOLC_COMMAND)) { + throw new Error( + `sloc command not found in ${SOLC_COMMAND}, please run "./scripts/download_solc.sh".` + ); + } + + if (!path.isAbsolute(contractPath)) { + contractPath = path.join(__dirname, contractPath); + } + + const compile = childProcess.spawnSync(SOLC_COMMAND, [ + "--yul", + "--bin", + contractPath, + ]); + + let isNextLineByteCode = false; + let byteCode = null; + for (const line of compile.stdout.toString().split("\n")) { + if (isNextLineByteCode) { + byteCode = line; + break; + } + + if (line.includes("Binary representation:")) { + isNextLineByteCode = true; + } + } + + if (!byteCode) { + throw new Error( + `failed to compile PlonkVerifier, sloc: ${SOLC_COMMAND}, contract: ${contractPath}` + ); + } + + log.debug( + `${contractPath} compiled successfully, byte code length: ${byteCode.length}` + ); + + if (!byteCode.startsWith("0x")) { + byteCode = `0x${byteCode}`; + } + + return byteCode; +} + +async function deployBytecode(hre: any, byteCode: string): Promise { + const [signer] = await hre.ethers.getSigners(); + + const tx = await signer.sendTransaction({ data: byteCode }); + const receipt = await tx.wait(); + + log.debug( + `PlonkVerifier deploying, tx ${tx.hash}, waiting for confirmations` + ); + + if (receipt.status !== 1) { + throw new Error( + `failed to create PlonkVerifier contract, transaction ${tx.hash} reverted` + ); + } + + return receipt.contractAddress; +} + async function getDeployer(hre: any) { const accounts = await hre.ethers.provider.listAccounts(); if (accounts[0] !== undefined) { @@ -72,6 +142,8 @@ async function decode(hre: any, type: any, data: any) { export { deployContract, + compileYulContract, + deployBytecode, getDeployer, waitTx, getContract, diff --git a/packages/protocol/test/ConfigManager.test.ts b/packages/protocol/test/ConfigManager.test.ts deleted file mode 100644 index b967cdbe964..00000000000 --- a/packages/protocol/test/ConfigManager.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { expect } from "chai"; -import { ConfigManager } from "../typechain"; -const hre = require("hardhat"); -const ethers = hre.ethers; - -describe("ConfigManager", function () { - let configManager: ConfigManager; - let testKey: string; - let testName: string; - - before(async function () { - configManager = await ( - await ethers.getContractFactory("ConfigManager") - ).deploy(); - await configManager.init(); - testKey = ethers.utils.hexlify(ethers.utils.randomBytes(32)); - testName = "test"; - }); - it("should set new value to replace an old value and emit an Updated event.", async function () { - await expect(configManager.setValue(testName, testKey)).to.emit( - configManager, - "Updated" - ); - }); - - it("should not emit any event if the new value is the same as the old value.", async function () { - await expect(configManager.setValue(testName, testKey)).to.not.emit( - configManager, - "Updated" - ); - }); - - it("should return an empty byte array for non-set name", async function () { - const returnValue = await configManager.getValue("unsetName"); - expect(returnValue).to.equal("0x"); - }); - - it("should return the correct key given the previous set name.", async function () { - expect(await configManager.getValue(testName)).to.equal(testKey); - }); -}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 49f3a04653a..408e9f9301f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -130,6 +130,7 @@ importers: '@typechain/ethers-v5': ^7.2.0 '@typechain/hardhat': ^2.3.1 '@types/chai': ^4.3.0 + '@types/glob': ^8.0.1 '@types/mocha': ^9.1.0 '@types/node': ^12.20.45 '@typescript-eslint/eslint-plugin': ^4.33.0 @@ -146,6 +147,7 @@ importers: eslint-plugin-promise: ^5.2.0 ethereum-waffle: ^3.0.0 ethers: ^5.0.0 + glob: ^8.1.0 hardhat: ^2.8.3 hardhat-abi-exporter: ^2.10.0 hardhat-docgen: ^1.3.0 @@ -166,15 +168,16 @@ importers: '@openzeppelin/contracts': 4.8.0 '@openzeppelin/contracts-upgradeable': 4.8.0 devDependencies: - '@defi-wonderland/smock': 2.3.4_d44p6lx7t3c2oeudc2zxbd5d54 + '@defi-wonderland/smock': 2.3.4_z67mwh6jmxdufyguqgtbmr6rba '@nomicfoundation/hardhat-network-helpers': 1.0.6_hardhat@2.12.2 '@nomiclabs/hardhat-ethers': 2.2.1_3uaf6nt3qt6cyh5fx3fc5i4mn4 '@nomiclabs/hardhat-etherscan': 3.1.2_hardhat@2.12.2 '@nomiclabs/hardhat-waffle': 2.0.3_wzgqb2xh4egjkdzuv52bfmbi24 '@openzeppelin/hardhat-upgrades': 1.21.0_43thxqwvphwusq7frx7sx2tjf4 - '@typechain/ethers-v5': 7.2.0_rqgsou2umo6ifhsmtcb3krjbfm - '@typechain/hardhat': 2.3.1_i3sbpo4srhduw7xvdsryjfwk5e + '@typechain/ethers-v5': 7.2.0_67wzblpxnm7h4zc6jlzarjupbm + '@typechain/hardhat': 2.3.1_kqlws2vjqn6dp4diaajzvmozky '@types/chai': 4.3.4 + '@types/glob': 8.0.1 '@types/mocha': 9.1.1 '@types/node': 12.20.55 '@typescript-eslint/eslint-plugin': 4.33.0_b437dje45jwsli5vlhomcei76i @@ -191,9 +194,10 @@ importers: eslint-plugin-promise: 5.2.0_eslint@7.32.0 ethereum-waffle: 3.4.4_typescript@4.9.3 ethers: 5.7.2 + glob: 8.1.0 hardhat: 2.12.2_2dtigtkb225m7ii7q45utxqwgi hardhat-abi-exporter: 2.10.1_hardhat@2.12.2 - hardhat-docgen: 1.3.0_lfwxduevmqdtswpjkbv2koayie + hardhat-docgen: 1.3.0_hardhat@2.12.2 hardhat-gas-reporter: 1.0.9_hardhat@2.12.2 lint-staged: 12.5.0 merkle-patricia-tree: 4.2.4 @@ -1576,7 +1580,7 @@ packages: '@jridgewell/trace-mapping': 0.3.9 dev: true - /@defi-wonderland/smock/2.3.4_d44p6lx7t3c2oeudc2zxbd5d54: + /@defi-wonderland/smock/2.3.4_z67mwh6jmxdufyguqgtbmr6rba: resolution: {integrity: sha512-VYJbsoCOdFRyGkAwvaQhQRrU6V8AjK3five8xdbo41DEE9n3qXzUNBUxyD9HhXB/dWWPFWT21IGw5Ztl6Qw3Ew==} peerDependencies: '@ethersproject/abi': ^5 @@ -1586,9 +1590,6 @@ packages: ethers: ^5 hardhat: ^2 dependencies: - '@ethersproject/abi': 5.7.0 - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/abstract-signer': 5.7.0 '@nomicfoundation/ethereumjs-evm': 1.0.0 '@nomicfoundation/ethereumjs-util': 8.0.0 '@nomicfoundation/ethereumjs-vm': 6.0.0 @@ -3438,7 +3439,7 @@ packages: typechain: 3.0.0_typescript@4.9.3 dev: true - /@typechain/ethers-v5/7.2.0_rqgsou2umo6ifhsmtcb3krjbfm: + /@typechain/ethers-v5/7.2.0_67wzblpxnm7h4zc6jlzarjupbm: resolution: {integrity: sha512-jfcmlTvaaJjng63QsT49MT6R1HFhtO/TBMWbyzPFSzMmVIqb2tL6prnKBs4ZJrSvmgIXWy+ttSjpaxCTq8D/Tw==} peerDependencies: '@ethersproject/abi': ^5.0.0 @@ -3448,9 +3449,6 @@ packages: typechain: ^5.0.0 typescript: '>=4.0.0' dependencies: - '@ethersproject/abi': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/providers': 5.7.2 ethers: 5.7.2 lodash: 4.17.21 ts-essentials: 7.0.3_typescript@4.9.3 @@ -3458,7 +3456,7 @@ packages: typescript: 4.9.3 dev: true - /@typechain/hardhat/2.3.1_i3sbpo4srhduw7xvdsryjfwk5e: + /@typechain/hardhat/2.3.1_kqlws2vjqn6dp4diaajzvmozky: resolution: {integrity: sha512-BQV8OKQi0KAzLXCdsPO0pZBNQQ6ra8A2ucC26uFX/kquRBtJu1yEyWnVSmtr07b5hyRoJRpzUeINLnyqz4/MAw==} peerDependencies: hardhat: ^2.0.10 @@ -3467,7 +3465,6 @@ packages: dependencies: fs-extra: 9.1.0 hardhat: 2.12.2_2dtigtkb225m7ii7q45utxqwgi - lodash: 4.17.21 typechain: 5.2.0_typescript@4.9.3 dev: true @@ -3605,6 +3602,13 @@ packages: '@types/node': 18.11.18 dev: true + /@types/glob/8.0.1: + resolution: {integrity: sha512-8bVUjXZvJacUFkJXHdyZ9iH1Eaj5V7I8c4NdH5sQJsdXkqT4CA5Dhb4yb4VE/3asyx4L9ayZr1NIhTsWHczmMw==} + dependencies: + '@types/minimatch': 5.1.2 + '@types/node': 18.11.18 + dev: true + /@types/graceful-fs/4.1.5: resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} dependencies: @@ -3681,7 +3685,7 @@ packages: dependencies: '@types/abstract-leveldown': 7.2.0 '@types/level-errors': 3.0.0 - '@types/node': 18.11.10 + '@types/node': 18.11.18 dev: true /@types/lru-cache/5.1.1: @@ -3738,10 +3742,6 @@ packages: /@types/node/12.20.55: resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - /@types/node/18.11.10: - resolution: {integrity: sha512-juG3RWMBOqcOuXC643OAdSA525V44cVgGV6dUDuiFtss+8Fk5x1hI93Rsld43VeJVIeqlP9I7Fn9/qaVqoEAuQ==} - dev: true - /@types/node/18.11.18: resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==} @@ -4116,10 +4116,10 @@ packages: source-map: 0.6.1 dev: true - /@vue/component-compiler-utils/3.3.0_lodash@4.17.21: + /@vue/component-compiler-utils/3.3.0: resolution: {integrity: sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ==} dependencies: - consolidate: 0.15.1_lodash@4.17.21 + consolidate: 0.15.1 hash-sum: 1.0.2 lru-cache: 4.1.5 merge-source-map: 1.1.0 @@ -6940,7 +6940,7 @@ packages: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} dev: true - /consolidate/0.15.1_lodash@4.17.21: + /consolidate/0.15.1: resolution: {integrity: sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==} engines: {node: '>= 0.10.0'} peerDependencies: @@ -7106,7 +7106,6 @@ packages: optional: true dependencies: bluebird: 3.7.2 - lodash: 4.17.21 dev: true /content-disposition/0.5.4: @@ -10229,6 +10228,17 @@ packages: path-is-absolute: 1.0.1 dev: true + /glob/8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.0.1 + once: 1.4.0 + dev: true + /global-modules/2.0.0: resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} engines: {node: '>=6'} @@ -10416,7 +10426,7 @@ packages: hardhat: 2.12.2_2dtigtkb225m7ii7q45utxqwgi dev: true - /hardhat-docgen/1.3.0_lfwxduevmqdtswpjkbv2koayie: + /hardhat-docgen/1.3.0_hardhat@2.12.2: resolution: {integrity: sha512-paaiOHjJFLCLz2/qM1TQ7ZEG+Vy+LBvJL+SW4A64ZhBnVnyoZ/zv9DvEuawaWhqP5P7AOM6r22reVz4ecWgW7A==} engines: {node: '>=14.14.0'} peerDependencies: @@ -10426,7 +10436,7 @@ packages: hardhat: 2.12.2_2dtigtkb225m7ii7q45utxqwgi html-webpack-plugin: 5.5.0_webpack@5.75.0 vue: 2.7.14 - vue-loader: 15.10.1_36bk4haztx5nmdoe37hieqy74q + vue-loader: 15.10.1_z2a3irye3y56jaq776fqxbsiea vue-router: 3.6.5_vue@2.7.14 vue-template-compiler: 2.7.14 webpack: 5.75.0 @@ -19131,7 +19141,7 @@ packages: resolution: {integrity: sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==} dev: true - /vue-loader/15.10.1_36bk4haztx5nmdoe37hieqy74q: + /vue-loader/15.10.1_z2a3irye3y56jaq776fqxbsiea: resolution: {integrity: sha512-SaPHK1A01VrNthlix6h1hq4uJu7S/z0kdLUb6klubo738NeQoLbS6V9/d8Pv19tU0XdQKju3D1HSKuI8wJ5wMA==} peerDependencies: '@vue/compiler-sfc': ^3.0.8 @@ -19147,7 +19157,7 @@ packages: vue-template-compiler: optional: true dependencies: - '@vue/component-compiler-utils': 3.3.0_lodash@4.17.21 + '@vue/component-compiler-utils': 3.3.0 css-loader: 6.7.2_webpack@5.75.0 hash-sum: 1.0.2 loader-utils: 1.4.2