diff --git a/.openzeppelin/unknown-6913.json b/.openzeppelin/unknown-6913.json new file mode 100644 index 000000000..61704e705 --- /dev/null +++ b/.openzeppelin/unknown-6913.json @@ -0,0 +1,460 @@ +{ + "manifestVersion": "3.2", + "proxies": [ + { + "address": "0x3C9acB2205Aa72A05F6D77d708b5Cf85FCa3a896", + "kind": "transparent" + } + ], + "impls": { + "ac0db523ddc3e330f735df7b3b0b24460531c71290a891170e840f8f67d5ff6b": { + "address": "0x56fF81aBB5cdaC478bF236db717e4976b2ff841e", + "layout": { + "solcVersion": "0.8.27", + "storage": [], + "types": {}, + "namespaces": {} + } + }, + "d4588bc192b3eb54c8b0c5781f8194a6152fd1b1edd4e712a681370fa4e7a3a0": { + "address": "0x946d3D28f19702904CAb34c1391AEd9609D86C57", + "txHash": "0x95e639e652829c8b465902a1e5dc002af2ae804b671dc0ffa06829016445c631", + "layout": { + "solcVersion": "0.8.27", + "storage": [ + { + "label": "__gap", + "offset": 0, + "slot": "0", + "type": "t_array(t_uint256)651_storage", + "contract": "State", + "src": "contracts/state/State.sol:56" + }, + { + "label": "verifier", + "offset": 0, + "slot": "651", + "type": "t_contract(IStateTransitionVerifier)934", + "contract": "State", + "src": "contracts/state/State.sol:61" + }, + { + "label": "_stateData", + "offset": 0, + "slot": "652", + "type": "t_struct(Data)3699_storage", + "contract": "State", + "src": "contracts/state/State.sol:66" + }, + { + "label": "_gistData", + "offset": 0, + "slot": "702", + "type": "t_struct(Data)1961_storage", + "contract": "State", + "src": "contracts/state/State.sol:71" + }, + { + "label": "_defaultIdType", + "offset": 0, + "slot": "752", + "type": "t_bytes2", + "contract": "State", + "src": "contracts/state/State.sol:76" + }, + { + "label": "_defaultIdTypeInitialized", + "offset": 2, + "slot": "752", + "type": "t_bool", + "contract": "State", + "src": "contracts/state/State.sol:81" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes2": { + "label": "bytes2", + "numberOfBytes": "2" + }, + "t_contract(ICrossChainProofValidator)253": { + "label": "contract ICrossChainProofValidator", + "numberOfBytes": "20" + }, + "t_mapping(t_bytes2,t_mapping(t_uint256,t_uint256))": { + "label": "mapping(bytes2 => mapping(uint256 => uint256))", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_mapping(t_uint256,t_uint256))": { + "label": "mapping(uint256 => mapping(uint256 => uint256))", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_uint256)": { + "label": "mapping(uint256 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(InitializableStorage)146_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Ownable2StepStorage)14_storage": { + "label": "struct Ownable2StepUpgradeable.Ownable2StepStorage", + "members": [ + { + "label": "_pendingOwner", + "type": "t_address", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OwnableStorage)74_storage": { + "label": "struct OwnableUpgradeable.OwnableStorage", + "members": [ + { + "label": "_owner", + "type": "t_address", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(StateCrossChainStorage)1733_storage": { + "label": "struct State.StateCrossChainStorage", + "members": [ + { + "label": "_idToStateReplacedAt", + "type": "t_mapping(t_uint256,t_mapping(t_uint256,t_uint256))", + "offset": 0, + "slot": "0" + }, + { + "label": "_rootToGistRootReplacedAt", + "type": "t_mapping(t_bytes2,t_mapping(t_uint256,t_uint256))", + "offset": 0, + "slot": "1" + }, + { + "label": "_crossChainProofValidator", + "type": "t_contract(ICrossChainProofValidator)253", + "offset": 0, + "slot": "2" + } + ], + "numberOfBytes": "96" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_array(t_struct(Entry)3676_storage)dyn_storage": { + "label": "struct StateLib.Entry[]", + "numberOfBytes": "32" + }, + "t_array(t_struct(RootEntry)1988_storage)dyn_storage": { + "label": "struct SmtLib.RootEntry[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)45_storage": { + "label": "uint256[45]", + "numberOfBytes": "1440" + }, + "t_array(t_uint256)47_storage": { + "label": "uint256[47]", + "numberOfBytes": "1504" + }, + "t_array(t_uint256)651_storage": { + "label": "uint256[651]", + "numberOfBytes": "20832" + }, + "t_array(t_uint256)dyn_storage": { + "label": "uint256[]", + "numberOfBytes": "32" + }, + "t_contract(IStateTransitionVerifier)934": { + "label": "contract IStateTransitionVerifier", + "numberOfBytes": "20" + }, + "t_enum(NodeType)1937": { + "label": "enum SmtLib.NodeType", + "members": [ + "EMPTY", + "LEAF", + "MIDDLE" + ], + "numberOfBytes": "1" + }, + "t_mapping(t_bytes2,t_bool)": { + "label": "mapping(bytes2 => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_array(t_struct(Entry)3676_storage)dyn_storage)": { + "label": "mapping(uint256 => struct StateLib.Entry[])", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_array(t_uint256)dyn_storage)": { + "label": "mapping(uint256 => uint256[])", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_mapping(t_uint256,t_array(t_uint256)dyn_storage))": { + "label": "mapping(uint256 => mapping(uint256 => uint256[]))", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_struct(Node)2015_storage)": { + "label": "mapping(uint256 => struct SmtLib.Node)", + "numberOfBytes": "32" + }, + "t_struct(Data)1961_storage": { + "label": "struct SmtLib.Data", + "members": [ + { + "label": "nodes", + "type": "t_mapping(t_uint256,t_struct(Node)2015_storage)", + "offset": 0, + "slot": "0" + }, + { + "label": "rootEntries", + "type": "t_array(t_struct(RootEntry)1988_storage)dyn_storage", + "offset": 0, + "slot": "1" + }, + { + "label": "rootIndexes", + "type": "t_mapping(t_uint256,t_array(t_uint256)dyn_storage)", + "offset": 0, + "slot": "2" + }, + { + "label": "maxDepth", + "type": "t_uint256", + "offset": 0, + "slot": "3" + }, + { + "label": "initialized", + "type": "t_bool", + "offset": 0, + "slot": "4" + }, + { + "label": "__gap", + "type": "t_array(t_uint256)45_storage", + "offset": 0, + "slot": "5" + } + ], + "numberOfBytes": "1600" + }, + "t_struct(Data)3699_storage": { + "label": "struct StateLib.Data", + "members": [ + { + "label": "stateEntries", + "type": "t_mapping(t_uint256,t_array(t_struct(Entry)3676_storage)dyn_storage)", + "offset": 0, + "slot": "0" + }, + { + "label": "stateIndexes", + "type": "t_mapping(t_uint256,t_mapping(t_uint256,t_array(t_uint256)dyn_storage))", + "offset": 0, + "slot": "1" + }, + { + "label": "isIdTypeSupported", + "type": "t_mapping(t_bytes2,t_bool)", + "offset": 0, + "slot": "2" + }, + { + "label": "__gap", + "type": "t_array(t_uint256)47_storage", + "offset": 0, + "slot": "3" + } + ], + "numberOfBytes": "1600" + }, + "t_struct(Entry)3676_storage": { + "label": "struct StateLib.Entry", + "members": [ + { + "label": "state", + "type": "t_uint256", + "offset": 0, + "slot": "0" + }, + { + "label": "timestamp", + "type": "t_uint256", + "offset": 0, + "slot": "1" + }, + { + "label": "block", + "type": "t_uint256", + "offset": 0, + "slot": "2" + } + ], + "numberOfBytes": "96" + }, + "t_struct(Node)2015_storage": { + "label": "struct SmtLib.Node", + "members": [ + { + "label": "nodeType", + "type": "t_enum(NodeType)1937", + "offset": 0, + "slot": "0" + }, + { + "label": "childLeft", + "type": "t_uint256", + "offset": 0, + "slot": "1" + }, + { + "label": "childRight", + "type": "t_uint256", + "offset": 0, + "slot": "2" + }, + { + "label": "index", + "type": "t_uint256", + "offset": 0, + "slot": "3" + }, + { + "label": "value", + "type": "t_uint256", + "offset": 0, + "slot": "4" + } + ], + "numberOfBytes": "160" + }, + "t_struct(RootEntry)1988_storage": { + "label": "struct SmtLib.RootEntry", + "members": [ + { + "label": "root", + "type": "t_uint256", + "offset": 0, + "slot": "0" + }, + { + "label": "createdAtTimestamp", + "type": "t_uint256", + "offset": 0, + "slot": "1" + }, + { + "label": "createdAtBlock", + "type": "t_uint256", + "offset": 0, + "slot": "2" + } + ], + "numberOfBytes": "96" + } + }, + "namespaces": { + "erc7201:iden3.storage.StateCrossChain": [ + { + "contract": "State", + "label": "_idToStateReplacedAt", + "type": "t_mapping(t_uint256,t_mapping(t_uint256,t_uint256))", + "src": "contracts/state/State.sol:85", + "offset": 0, + "slot": "0" + }, + { + "contract": "State", + "label": "_rootToGistRootReplacedAt", + "type": "t_mapping(t_bytes2,t_mapping(t_uint256,t_uint256))", + "src": "contracts/state/State.sol:86", + "offset": 0, + "slot": "1" + }, + { + "contract": "State", + "label": "_crossChainProofValidator", + "type": "t_contract(ICrossChainProofValidator)253", + "src": "contracts/state/State.sol:87", + "offset": 0, + "slot": "2" + } + ], + "erc7201:openzeppelin.storage.Ownable2Step": [ + { + "contract": "Ownable2StepUpgradeable", + "label": "_pendingOwner", + "type": "t_address", + "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:29", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Ownable": [ + { + "contract": "OwnableUpgradeable", + "label": "_owner", + "type": "t_address", + "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:24", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + } + } +} diff --git a/.solhintignore b/.solhintignore index 821516fc3..7c569c837 100644 --- a/.solhintignore +++ b/.solhintignore @@ -7,11 +7,6 @@ **/lib/VerifierStateTransition.sol **/lib/VerifierV3.sol **/lib/VerifierV3Wrapper.sol -**/lib/groth16-verifiers/Groth16VerifierMTP.sol -**/lib/groth16-verifiers/Groth16VerifierMTPWrapper.sol -**/lib/groth16-verifiers/Groth16VerifierSig.sol -**/lib/groth16-verifiers/Groth16VerifierSigWrapper.sol -**/lib/groth16-verifiers/Groth16VerifierStateTransition.sol -**/lib/groth16-verifiers/Groth16VerifierV3.sol -**/lib/groth16-verifiers/Groth16VerifierV3Wrapper.sol +**/lib/groth16-verifiers **/node_modules + diff --git a/README.md b/README.md index a6b3e0380..24121ce0d 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,9 @@ We have deployed contracts across the following mainnets and testnets so far (** 2. [Nethermind](https://www.nethermind.io/smart-contract-audits) has performed a second security audit of our core smart contracts (State, IdentityBase, GenesisUtils, OnChainIdentity) and compiled a report on Sep 13, 2023: [NM0113-FINAL-POLYGONID.pdf](https://iden3-circuits-bucket.s3.eu-west-1.amazonaws.com/audit_reports/NM0113-FINAL-POLYGONID.pdf) +3. [Nethermind](https://www.nethermind.io/smart-contract-audits) has performed a third security audit of our core smart contracts (all contracts in cross-chain/*, payment/*, verifiers/* and validators/* folders) and compiled a report on Apr 4, 2025: + [NM_0379_Final_PRIVADO_iD.pdf](https://iden3-circuits-bucket.s3.eu-west-1.amazonaws.com/audit_reports/NM_0379_Final_PRIVADO_iD.pdf) + ## Deployment methodology with CREATE2 and ledger Note, that this methodology is not what expected to be used by the repository users as its purpose is mainly for our team to deploy and maintain the contracts across many networks in a unified way. However, it can be used as a reference for the deployment process. diff --git a/contracts/AlwaysRevert.sol b/contracts/AlwaysRevert.sol index 7f9bf9437..93c57422b 100644 --- a/contracts/AlwaysRevert.sol +++ b/contracts/AlwaysRevert.sol @@ -1,10 +1,12 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.27; +error TheContractIsDisabled(); + /// @title This contract as a dummy implementation for Proxy contract if we need to revert all calls // This can be applied to disable all methods of a proxy contract with explicit error message contract AlwaysRevert { fallback() external payable { - revert("The contract is disabled"); + revert TheContractIsDisabled(); } } diff --git a/contracts/Create2AddressAnchor.sol b/contracts/Create2AddressAnchor.sol index 4913ffc17..e43d8108e 100644 --- a/contracts/Create2AddressAnchor.sol +++ b/contracts/Create2AddressAnchor.sol @@ -1,4 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.27; +/* solhint-disable no-empty-blocks */ contract Create2AddressAnchor {} +/* solhint-enable no-empty-blocks */ diff --git a/contracts/cross-chain/CrossChainProofValidator.sol b/contracts/cross-chain/CrossChainProofValidator.sol index 163c3ce8e..c6f495346 100644 --- a/contracts/cross-chain/CrossChainProofValidator.sol +++ b/contracts/cross-chain/CrossChainProofValidator.sol @@ -6,6 +6,13 @@ import {ICrossChainProofValidator} from "../interfaces/ICrossChainProofValidator import {IState} from "../interfaces/IState.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +error IdentityStateProofInvalid(); +error GlobalStateProofInvalid(); +error GlobalStateProofSigningAddressInvalid(address recovered); +error IdentityStateProofSigningAddressInvalid(address recovered); +error OracleTimestampCannotBeInThePast(); +error OracleReplacedAtTimestampCannotBeInTheFuture(); + /** * @dev Contract which provides proof validation from identity state * and global state proofs from trusted oracle with signature from any network. @@ -93,11 +100,12 @@ contract CrossChainProofValidator is Ownable, EIP712, ICrossChainProofValidator gsu.globalStateMsg, gsu.signature ); - require(isValid, "Global state proof is not valid"); - require( - recovered == _oracleSigningAddress, - "Global state proof signing address is not valid" - ); + if (!isValid) { + revert GlobalStateProofInvalid(); + } + if (recovered != _oracleSigningAddress) { + revert GlobalStateProofSigningAddressInvalid(recovered); + } return IState.GlobalStateProcessResult({ @@ -127,11 +135,12 @@ contract CrossChainProofValidator is Ownable, EIP712, ICrossChainProofValidator isu.idStateMsg, isu.signature ); - require(isValid, "Identity state proof is not valid"); - require( - recovered == _oracleSigningAddress, - "Identity state proof signing address is not valid" - ); + if (!isValid) { + revert IdentityStateProofInvalid(); + } + if (recovered != _oracleSigningAddress) { + revert IdentityStateProofSigningAddressInvalid(recovered); + } return IState.IdentityStateProcessResult({ @@ -223,13 +232,13 @@ contract CrossChainProofValidator is Ownable, EIP712, ICrossChainProofValidator uint256 replacedAtTimestamp ) internal view returns (uint256 replacedAt) { if (oracleTimestamp < block.timestamp - MAX_TIMESTAMP_LAG) { - revert("Oracle timestamp cannot be in the past"); + revert OracleTimestampCannotBeInThePast(); } replacedAt = replacedAtTimestamp == 0 ? oracleTimestamp : replacedAtTimestamp; if (replacedAt > block.timestamp + MAX_REPLACED_AT_AHEAD_OF_TIME) { - revert("Oracle replacedAtTimestamp or oracle timestamp cannot be in the future"); + revert OracleReplacedAtTimestampCannotBeInTheFuture(); } // this should never happen as block.timestamp is always greater than 0 diff --git a/contracts/identitytreestore/IdentityTreeStore.sol b/contracts/identitytreestore/IdentityTreeStore.sol index fa636c7d9..a2a4eaefe 100644 --- a/contracts/identitytreestore/IdentityTreeStore.sol +++ b/contracts/identitytreestore/IdentityTreeStore.sol @@ -8,6 +8,11 @@ import {IOnchainCredentialStatusResolver} from "../interfaces/IOnchainCredential import {IRHSStorage} from "../interfaces/IRHSStorage.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +error NodeNotFound(); +error InvalidStateNode(); +error InvalidNodeType(); +error UnsupportedLength(); + /** * @dev Contract which provides onchain Reverse Hash Service (RHS) * for checking revocation status of claims. @@ -40,10 +45,12 @@ contract IdentityTreeStore is Initializable, IOnchainCredentialStatusResolver, I // keccak256(abi.encode(uint256(keccak256("iden3.storage.IdentityTreeStore.ReverseHashLibData")) - 1)) & // ~bytes32(uint256(0xff)); + // solhint-disable-next-line const-name-snakecase bytes32 private constant ReverseHashLibDataStorageLocation = 0x0f7e3bdc6cc0e880d509aa1f6b8d1a88e5fcb7274e18dfba772424a36fe9b400; function _getReverseHashLibDataStorage() private pure returns (ReverseHashLib.Data storage $) { + // solhint-disable-next-line no-inline-assembly assembly { $.slot := ReverseHashLibDataStorageLocation } @@ -55,6 +62,7 @@ contract IdentityTreeStore is Initializable, IOnchainCredentialStatusResolver, I } // keccak256(abi.encode(uint256(keccak256("iden3.storage.IdentityTreeStore.Main")) - 1)) & ~bytes32(uint256(0xff)); + // solhint-disable-next-line const-name-snakecase bytes32 private constant IdentityTreeStoreMainStorageLocation = 0x95ca427007e091a13a7ccfcb233b8a2ed19d987330a248c445b1b483a35bb800; @@ -64,6 +72,7 @@ contract IdentityTreeStore is Initializable, IOnchainCredentialStatusResolver, I pure returns (IdentityTreeStoreMainStorage storage $) { + // solhint-disable-next-line no-inline-assembly assembly { $.slot := IdentityTreeStoreMainStorageLocation } @@ -96,7 +105,9 @@ contract IdentityTreeStore is Initializable, IOnchainCredentialStatusResolver, I */ function getNode(uint256 key) public view returns (uint256[] memory) { uint256[] memory preim = _getReverseHashLibDataStorage().getPreimage(key); - require(preim.length > 0, "Node not found"); + if (preim.length == 0) { + revert NodeNotFound(); + } return preim; } @@ -122,6 +133,7 @@ contract IdentityTreeStore is Initializable, IOnchainCredentialStatusResolver, I * @return CredentialStatus */ function getRevocationStatusByIdAndState( + // solhint-disable-next-line no-unused-vars uint256 id, uint256 state, uint64 nonce @@ -134,7 +146,9 @@ contract IdentityTreeStore is Initializable, IOnchainCredentialStatusResolver, I uint64 nonce ) internal view returns (CredentialStatus memory) { uint256[] memory roots = getNode(state); - require(_nodeType(roots) == NodeType.State, "Invalid state node"); + if (_nodeType(roots) != NodeType.State) { + revert InvalidStateNode(); + } CredentialStatus memory status = CredentialStatus({ issuer: IdentityStateRoots({ @@ -200,7 +214,7 @@ contract IdentityTreeStore is Initializable, IOnchainCredentialStatusResolver, I proof.siblings[i] = children[1]; } } else { - revert("Invalid node type"); + revert InvalidNodeType(); } } @@ -234,6 +248,6 @@ contract IdentityTreeStore is Initializable, IOnchainCredentialStatusResolver, I if (preimage.length == 3) { return PoseidonUnit3L.poseidon([preimage[0], preimage[1], preimage[2]]); } - revert("Unsupported length"); + revert UnsupportedLength(); } } diff --git a/contracts/imports.sol b/contracts/imports.sol index 4cdc83cfb..61554a969 100644 --- a/contracts/imports.sol +++ b/contracts/imports.sol @@ -1,7 +1,9 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.27; // We import these here to force Hardhat to compile them. // This ensures that their artifacts are available for Hardhat Ignition to use. +/* solhint-disable no-unused-import */ import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +/* solhint-enable no-unused-import */ diff --git a/contracts/interfaces/IAuthValidator.sol b/contracts/interfaces/IAuthValidator.sol new file mode 100644 index 000000000..564137873 --- /dev/null +++ b/contracts/interfaces/IAuthValidator.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.27; + +/** + * @dev IAuthValidator. Interface for verification of auth data. + */ +interface IAuthValidator { + /** + * @dev AuthResponseField. Information about response fields from verification. Used in verify function. + * @param name Name of the response field + * @param value Value of the response field + */ + struct AuthResponseField { + string name; + uint256 value; + } + + /** + * @dev Get version of the contract + */ + function version() external view returns (string memory); + + /** + * @dev Verify the proof with the supported method informed in the auth query data + * packed as bytes and that the proof was generated by the sender. + * @param sender Sender of the proof. + * @param proof Proof packed as bytes to verify. + * @param params Request query data of the credential to verify. + * @return userID User Id for the auth proof verified and response fields. + * @return authResponseFields Additional response fields. + */ + function verify( + address sender, + bytes calldata proof, + bytes calldata params + ) external returns (uint256 userID, AuthResponseField[] memory authResponseFields); +} diff --git a/contracts/interfaces/ICircuitValidator.sol b/contracts/interfaces/ICircuitValidator.sol deleted file mode 100644 index 273172afa..000000000 --- a/contracts/interfaces/ICircuitValidator.sol +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; - -import {IState} from "./IState.sol"; - -/** - * @dev ICircuitValidator. Interface for circuit verification. - */ -interface ICircuitValidator { - /** - * @dev KeyToInputIndex. Information about public inputs of the circuit verification. Used in verify function. - * @param key Name of the public input - * @param inputIndex Index of the public input - * - * Note: Kept for backward compatibility. Now it's replaced by Signal struct for verifyV2 function. - */ - struct KeyToInputIndex { - string key; - uint256 inputIndex; - } - - /** - * @dev Signal. Information about public signals of the circuit verification. Used in verifyV2 function. - * @param name Name of the public signal - * @param value Value of the public signal - */ - struct Signal { - string name; - uint256 value; - } - - /** - * @dev Get version of the contract - */ - function version() external view returns (string memory); - - /** - * @dev Verify with the supported circuit informed in the request query data the groth16 proof - * π=([πa]1,[πb]2,[πc]1) and that the proof was generated by the sender. - * @param inputs Public inputs of the circuit. - * @param a πa element of the groth16 proof. - * @param b πb element of the groth16 proof. - * @param c πc element of the groth16 proof. - * @param data Request query data of the credential to verify. - * @param sender Sender of the proof. - * @return Array of key to public input index as result. - */ - function verify( - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c, - bytes calldata data, - address sender - ) external returns (ICircuitValidator.KeyToInputIndex[] memory); - - /** - * @dev Verify with the supported circuit informed in the request query data the groth16 proof - * packed as bytes and that the proof was generated by the sender. - * @param zkProof Proof packed as bytes to verify. - * @param data Request query data of the credential to verify. - * @param sender Sender of the proof. - * @param state State contract to get identities and gist states to check. - * @return Array of public signals as result. - */ - function verifyV2( - bytes calldata zkProof, - bytes calldata data, - address sender, - IState state - ) external returns (ICircuitValidator.Signal[] memory); - - /** - * @dev Get supported circuit ids. - * @return ids Array of circuit ids supported. - */ - function getSupportedCircuitIds() external view returns (string[] memory ids); - - /** - * @dev Get the index of the public input of the circuit by name. - * @param name Name of the public input. - * @return Index of the public input. - */ - function inputIndexOf(string memory name) external view returns (uint256); -} diff --git a/contracts/interfaces/IGroth16Verifier.sol b/contracts/interfaces/IGroth16Verifier.sol new file mode 100644 index 000000000..e41c41962 --- /dev/null +++ b/contracts/interfaces/IGroth16Verifier.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.27; + +/** + * @dev IGroth16Verifier. Interface for verification of groth16 proofs. + */ +interface IGroth16Verifier { + /** + * @dev Verify the circuit with the groth16 proof π=([πa]1,[πb]2,[πc]1). + * @param a πa element of the groth16 proof. + * @param b πb element of the groth16 proof. + * @param c πc element of the groth16 proof. + * @param signals Public inputs and outputs of the circuit. + * @return r true if the proof is verified. + */ + function verify( + uint256[2] calldata a, + uint256[2][2] calldata b, + uint256[2] calldata c, + uint256[] calldata signals + ) external view returns (bool r); +} diff --git a/contracts/interfaces/IRequestValidator.sol b/contracts/interfaces/IRequestValidator.sol new file mode 100644 index 000000000..ec988c669 --- /dev/null +++ b/contracts/interfaces/IRequestValidator.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.27; + +/** + * @dev IRequestValidator. Interface for verification of request query data. + */ +interface IRequestValidator { + error RequestParamNameNotFound(); + error InputNameNotFound(); + /** + * @dev ResponseField. Information about response fields from verification. Used in verify function. + * @param name Name of the response field + * @param value Value of the response field + * @param rawValue Raw value of the response field + */ + struct ResponseField { + string name; + uint256 value; + bytes rawValue; + } + + /** + * @dev RequestParam. Information about request param from request query data. + * @param name Name of the request query param + * @param value Value of the request query param + */ + struct RequestParam { + string name; + uint256 value; + } + + /** + * @dev Get version of the contract + */ + function version() external view returns (string memory); + + /** + * @dev Verify the proof with the supported method informed in the request query data + * packed as bytes and that the proof was generated by the sender. + * @param sender Sender of the proof. + * @param proof Proof packed as bytes to verify. + * @param requestParams Request query data of the credential to verify. + * @param responseMetadata Metadata from the response. + * @return Array of response fields as result. + */ + function verify( + address sender, + bytes calldata proof, + bytes calldata requestParams, + bytes calldata responseMetadata + ) external returns (ResponseField[] memory); + + /** + * @dev Get the request param from params of the request query data. + * @param params Request query data of the credential to verify. + * @param paramName Request query param name to retrieve of the credential to verify. + * @return RequestParam for the param name of the request query data. + */ + function getRequestParam( + bytes calldata params, + string memory paramName + ) external view returns (RequestParam memory); + + /** + * @dev Get the index of the public input of the circuit by name + * @param name Name of the public input + * @return Index of the public input + */ + function inputIndexOf(string memory name) external view returns (uint256); +} diff --git a/contracts/interfaces/IVerifier.sol b/contracts/interfaces/IVerifier.sol index b7ba452f0..d0e269d2e 100644 --- a/contracts/interfaces/IVerifier.sol +++ b/contracts/interfaces/IVerifier.sol @@ -1,22 +1,267 @@ // SPDX-License-Identifier: GPL-3.0 + pragma solidity 0.8.27; +import {IAuthValidator} from "./IAuthValidator.sol"; +import {IRequestValidator} from "./IRequestValidator.sol"; + /** - * @dev IVerifier. Interface for verification of groth16 proofs. + * @dev IVerifier. Interface for creating requests and verifying request responses through validators circuits. */ interface IVerifier { /** - * @dev Verify the circuit with the groth16 proof π=([πa]1,[πb]2,[πc]1). - * @param a πa element of the groth16 proof. - * @param b πb element of the groth16 proof. - * @param c πc element of the groth16 proof. - * @param input Public inputs of the circuit. - * @return r true if the proof is verified. - */ - function verify( - uint256[2] calldata a, - uint256[2][2] calldata b, - uint256[2] calldata c, - uint256[] calldata input - ) external view returns (bool r); + * @dev Request. Structure for request. + * @param requestId Request id. + * @param metadata Metadata of the request. + * @param validator Validator to verify the response. + * @param params Parameters data of the request. + */ + struct Request { + uint256 requestId; + string metadata; + IRequestValidator validator; + bytes params; + address owner; + } + + /** + * @dev Request. Structure for request for storage. + * @param metadata Metadata of the request. + * @param validator Validator circuit. + * @param params Params of the request. Proof parameters could be ZK groth16, plonk, ESDSA, EIP712, etc. + */ + struct RequestData { + string metadata; + IRequestValidator validator; + bytes params; + address creator; + } + + /** + * @dev RequestInfo. Structure for request info. + * @param requestId Request id. + * @param metadata Metadata of the request. + * @param validator Validator to verify the response. + * @param params Parameters data of the request. + * @param creator Creator of the request. + * @param verifierId Verifier id. + */ + struct RequestInfo { + uint256 requestId; + string metadata; + IRequestValidator validator; + bytes params; + address creator; + } + + /** + * @dev Response. Structure for response. + * @param requestId Request id of the request. + * @param proof proof to verify. + * @param metadata Metadata of the request. + */ + struct Response { + uint256 requestId; + bytes proof; + bytes metadata; + } + + /** + * @dev AuthResponse. Structure for auth response. + * @param authMethod Auth type of the proof response. + * @param proof proof to verify. + */ + struct AuthResponse { + string authMethod; + bytes proof; + } + + /** + * @dev RequestProofStatus. Structure for request proof status. + * @param requestId Request id of the proof. + * @param isVerified True if the proof is verified. + * @param validatorVersion Version of the validator. + * @param timestamp Timestamp of the proof. + */ + struct RequestProofStatus { + uint256 requestId; + bool isVerified; + string validatorVersion; + uint256 timestamp; + } + + /** + * @dev AuthMethod. Structure for auth type for auth proofs. + * @param authMethod Auth type of the auth proof. + * @param validator Validator to verify the auth. + * @param params Parameters data of the auth. + */ + struct AuthMethod { + string authMethod; + IAuthValidator validator; + bytes params; + } + + /** + * @dev MultiRequest. Structure for multiRequest. + * @param multiRequestId MultiRequest id. + * @param requestIds Request ids for this multi multiRequest (without groupId. Single requests). + * @param groupIds Group ids for this multi multiRequest (all the requests included in the group. Grouped requests). + * @param metadata Metadata for the multiRequest. Empty in first version. + */ + struct MultiRequest { + uint256 multiRequestId; + uint256[] requestIds; + uint256[] groupIds; + bytes metadata; + } + + /** + * @dev Submits an array of responses and updates proofs status + * @param authResponse Auth response including auth type and proof + * @param responses The list of responses including request ID, proof and metadata for requests + * @param crossChainProofs The list of cross chain proofs from universal resolver (oracle). This + * includes identities and global states. + */ + function submitResponse( + AuthResponse memory authResponse, + Response[] memory responses, + bytes memory crossChainProofs + ) external; + + /** + * @dev Sets different requests + * @param requests List of requests + */ + function setRequests(Request[] calldata requests) external; + + /** + * @dev Gets a specific request by ID + * @param requestId The ID of the request + * @return request The request info + */ + function getRequest(uint256 requestId) external view returns (RequestInfo memory request); + + /** + * @dev Get the requests count. + * @return Requests count. + */ + function getRequestsCount() external view returns (uint256); + + /** + * @dev Get the group of requests count. + * @return Group of requests count. + */ + function getGroupsCount() external view returns (uint256); + + /** + * @dev Get the group of requests. + * @return Group of requests. + */ + function getGroupedRequests(uint256 groupID) external view returns (RequestInfo[] memory); + + /** + * @dev Checks if a request ID exists + * @param requestId The ID of the request + * @return Whether the request ID exists + */ + function requestIdExists(uint256 requestId) external view returns (bool); + + /** + * @dev Checks if a group ID exists + * @param groupId The ID of the group + * @return Whether the group ID exists + */ + function groupIdExists(uint256 groupId) external view returns (bool); + + /** + * @dev Checks if a multiRequest ID exists + * @param multiRequestId The ID of the multiRequest + * @return Whether the multiRequest ID exists + */ + function multiRequestIdExists(uint256 multiRequestId) external view returns (bool); + + /** + * @dev Gets the status of the multiRequest verification + * @param multiRequestId The ID of the MultiRequest + * @param userAddress The address of the user + * @return status The status of the MultiRequest. "True" if all requests are verified, "false" otherwise + */ + function getMultiRequestProofsStatus( + uint256 multiRequestId, + address userAddress + ) external view returns (RequestProofStatus[] memory); + + /** + * @dev Checks if the proofs from a Multirequest submitted for a given sender and request ID are verified + * @param multiRequestId The ID of the MultiRequest + * @param userAddress The address of the user + * @return Wether the multiRequest is verified. + */ + function areMultiRequestProofsVerified( + uint256 multiRequestId, + address userAddress + ) external view returns (bool); + + /** + * @dev Gets proof storage response field value + * @param requestId Id of the request + * @param sender Address of the user + * @param responseFieldName Name of the proof storage response field to get + */ + function getResponseFieldValue( + uint256 requestId, + address sender, + string memory responseFieldName + ) external view returns (uint256); + + /** + * @dev Gets proof storage response fields + * @param requestId Id of the request + * @param sender Address of the user + */ + function getResponseFields( + uint256 requestId, + address sender + ) external view returns (IRequestValidator.ResponseField[] memory); + + /** + * @dev Checks if a proof from a request submitted for a given sender and request ID is verified + * @param sender Sender of the proof. + * @param requestId Request id of the Request to verify. + * @return True if proof is verified for the sender and request id. + */ + function isRequestProofVerified(address sender, uint256 requestId) external view returns (bool); + + /** + * @dev Sets an auth method + * @param authMethod The auth method to add + */ + function setAuthMethod(AuthMethod calldata authMethod) external; + + /** + * @dev Sets a multiRequest + * @param multiRequest The multiRequest data + */ + function setMultiRequest(MultiRequest calldata multiRequest) external; + + /** + * @dev Gets a specific multiRequest by ID + * @param multiRequestId The ID of the multiRequest + * @return multiRequest The multiRequest data + */ + function getMultiRequest( + uint256 multiRequestId + ) external view returns (MultiRequest memory multiRequest); + + /** + * @dev Get the proof status for the sender and request with requestId. + * @param sender Sender of the proof. + * @param requestId Request id of the proof. + * @return Proof status. + */ + function getRequestProofStatus( + address sender, + uint256 requestId + ) external view returns (RequestProofStatus memory); } diff --git a/contracts/interfaces/IZKPVerifier.sol b/contracts/interfaces/IZKPVerifier.sol deleted file mode 100644 index 585dd43ce..000000000 --- a/contracts/interfaces/IZKPVerifier.sol +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.27; - -import {ICircuitValidator} from "./ICircuitValidator.sol"; - -/** - * @dev IZKPVerifier. Interface for verification of groth16 proofs for validators circuits. - */ -interface IZKPVerifier { - /** - * @dev ZKPRequest. Structure for ZKP request. - * @param metadata Metadata of the request. - * @param validator Validator circuit. - * @param data Data of the request. - */ - struct ZKPRequest { - string metadata; - ICircuitValidator validator; - bytes data; - } - /** - * @dev ProofStatus. Structure for proof status. - * @param isVerified True if the proof is verified. - * @param validatorVersion Version of the validator. - * @param blockNumber Block number of the proof. - * @param blockTimestamp Block timestamp of the proof. - */ - struct ProofStatus { - bool isVerified; - string validatorVersion; - uint256 blockNumber; - uint256 blockTimestamp; - } - - /** - * @dev ZKPResponse. Structure for ZKP response. - * @param requestId Request id of the ZKP request. - * @param zkProof ZKP proof to verify. - * @param data Metadata of the request. - */ - struct ZKPResponse { - uint64 requestId; - bytes zkProof; - bytes data; - } - - /** - * @dev Submit the groth16 proof π=([πa]1,[πb]2,[πc]1) for the ZKP request requestId. - * @param requestId Request id of the ZKP request. - * @param inputs Public inputs of the circuit. - * @param a πa element of the groth16 proof. - * @param b πb element of the groth16 proof. - * @param c πc element of the groth16 proof. - */ - function submitZKPResponse( - uint64 requestId, - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c - ) external; - - /** - * @dev Submit the groth16 proof π=([πa]1,[πb]2,[πc]1) for the ZKP request requestId. - * @param responses The list of responses including ZKP request ID, ZK proof and metadata. - * @param crossChainProofs The list of cross chain proofs from universal resolver (oracle). - */ - function submitZKPResponseV2( - ZKPResponse[] memory responses, - bytes memory crossChainProofs - ) external; - - /** - * @dev Set the ZKP request for the requestId. - * @param requestId Request id of the ZKP request. - * @param request ZKP request to set. - */ - function setZKPRequest(uint64 requestId, ZKPRequest calldata request) external; - - /** - * @dev Get the ZKP request for the requestId. - * @param requestId Request id of the ZKP request. - * @return ZKP request. - */ - function getZKPRequest(uint64 requestId) external view returns (ZKPRequest memory); - - /** - * @dev Get the ZKP request count. - * @return ZKP request count. - */ - function getZKPRequestsCount() external view returns (uint256); - - /** - * @dev Check if the requestId exists. - * @param requestId Request id of the ZKP request. - * @return True if the requestId exists. - */ - function requestIdExists(uint64 requestId) external view returns (bool); - - /** - * @dev Get the ZKP requests. - * @param startIndex Start index of the ZKP requests. - * @param length Length of the ZKP requests. - * @return Array of the ZKP requests. - */ - function getZKPRequests( - uint256 startIndex, - uint256 length - ) external view returns (ZKPRequest[] memory); - - /** - * @dev Get if proof is verified for the sender and ZKP request with requestId. - * @param sender Sender of the proof. - * @param requestId Request id of the ZKP Request to verify. - * @return True if proof is verified for the sender and request id. - */ - function isProofVerified(address sender, uint64 requestId) external view returns (bool); - - /** - * @dev Get the proof status for the sender and ZKP request with requestId. - * @param sender Sender of the proof. - * @param requestId Request id of the proof. - * @return Proof status. - */ - function getProofStatus( - address sender, - uint64 requestId - ) external view returns (ProofStatus memory); - - /** - * @dev Get the proof storage field for the user, requestId and key. - * @param user User address. - * @param requestId Request id of the proof. - * @param key Key of the proof storage field. - * @return Proof storage field. - */ - function getProofStorageField( - address user, - uint64 requestId, - string memory key - ) external view returns (uint256); -} diff --git a/contracts/lib/ClaimBuilder.sol b/contracts/lib/ClaimBuilder.sol index bf8f5d317..bbb42773f 100644 --- a/contracts/lib/ClaimBuilder.sol +++ b/contracts/lib/ClaimBuilder.sol @@ -3,6 +3,15 @@ pragma solidity 0.8.27; import {PrimitiveTypeUtils} from "../lib/PrimitiveTypeUtils.sol"; +error IdShouldBeEmpty(); +error IdShouldBeNotEmpty(); +error InvalidIdPosition(); +error RevocationNonceShouldBeZeroForNonExpirableClaim(); +error ExpirationDateShouldBeZeroForNonExpirableClaim(); +error VersionShouldBeZeroForNonUpdatableClaim(); +error DataSlotsShouldBeEmpty(); +error MerklizedRootShouldBeZeroForNonMerklizedClaim(); + library ClaimBuilder { // ID_POSITION_NONE means ID value not located in claim. uint8 public constant ID_POSITION_NONE = 0; @@ -50,6 +59,8 @@ library ClaimBuilder { uint256 valueDataSlotB; } + /* solhint-disable code-complexity */ + // RULE: each uint we convert to bytes has to be reversed (in go Little ending, solidity - big ending). // // Final result reverted bytes to get valid uint256 @@ -72,56 +83,64 @@ library ClaimBuilder { // ID if (c.idPosition == ID_POSITION_NONE) { - require(c.id == 0, "id should be empty"); + if (c.id != 0) { + revert IdShouldBeEmpty(); + } } else if (c.idPosition == ID_POSITION_INDEX) { - require(c.id != 0, "id should be not empty"); + if (c.id == 0) { + revert IdShouldBeNotEmpty(); + } flags |= SUBJECT_FLAG_OTHER_IDEN_INDEX; claim[1] = c.id; } else if (c.idPosition == ID_POSITION_VALUE) { - require(c.id != 0, "id should be not empty"); + if (c.id == 0) { + revert IdShouldBeNotEmpty(); + } flags |= SUBJECT_FLAG_OTHER_IDEN_VALUE; claim[5] = c.id; } else { - require(false, "invalid id position"); + revert InvalidIdPosition(); } // Expirable if (c.expirable) { flags |= EXPIRABLE_FLAG_YES; - } else { - require(c.expirationDate == 0, "expirationDate should be 0 for non expirable claim"); + } else if (c.expirationDate != 0) { + revert ExpirationDateShouldBeZeroForNonExpirableClaim(); } // Updatable if (c.updatable) { flags |= UPDATABLE_FLAG_YES; - } else { - require(c.version == 0, "version should be 0 for non updatable claim"); + } else if (c.version != 0) { + revert VersionShouldBeZeroForNonUpdatableClaim(); } // Merklized Root if (c.merklizedRootPosition == MERKLIZED_ROOT_POSITION_INDEX) { - require( - c.indexDataSlotA == 0 && - c.indexDataSlotB == 0 && - c.valueDataSlotA == 0 && - c.indexDataSlotB == 0, - "data slots should be empty" - ); + if ( + c.indexDataSlotA != 0 || + c.indexDataSlotB != 0 || + c.valueDataSlotA != 0 || + c.valueDataSlotB != 0 + ) { + revert DataSlotsShouldBeEmpty(); + } flags |= MERKLIZED_FLAG_INDEX; claim[2] = c.merklizedRoot; } else if (c.merklizedRootPosition == MERKLIZED_ROOT_POSITION_VALUE) { - require( - c.indexDataSlotA == 0 && - c.indexDataSlotB == 0 && - c.valueDataSlotA == 0 && - c.indexDataSlotB == 0, - "data slots should be empty" - ); + if ( + c.indexDataSlotA != 0 || + c.indexDataSlotB != 0 || + c.valueDataSlotA != 0 || + c.valueDataSlotB != 0 + ) { + revert DataSlotsShouldBeEmpty(); + } flags |= MERKLIZED_FLAG_VALUE; claim[6] = c.merklizedRoot; - } else { - require(c.merklizedRoot == 0, "merklizedRoot should be 0 for non merklized claim"); + } else if (c.merklizedRoot != 0) { + revert MerklizedRootShouldBeZeroForNonMerklizedClaim(); } bytes memory claim0 = PrimitiveTypeUtils.concat( @@ -153,4 +172,5 @@ library ClaimBuilder { return claim; } + /* solhint-enable code-complexity */ } diff --git a/contracts/lib/GenesisUtils.sol b/contracts/lib/GenesisUtils.sol index 8be58af78..888dc0f71 100644 --- a/contracts/lib/GenesisUtils.sol +++ b/contracts/lib/GenesisUtils.sol @@ -3,12 +3,15 @@ pragma solidity 0.8.27; import {PrimitiveTypeUtils} from "./PrimitiveTypeUtils.sol"; +error ChecksumLengthRequired(uint256 length); +error IdBytesLengthRequired(uint256 length); + library GenesisUtils { /** * @dev sum */ function sum(bytes memory array) internal pure returns (uint16 s) { - require(array.length == 29, "Checksum requires 29 length array"); + if (array.length != 29) revert ChecksumLengthRequired(29); for (uint256 i = 0; i < array.length; ++i) { s += uint16(uint8(array[i])); @@ -49,7 +52,7 @@ library GenesisUtils { bytes memory checkSumBytes = abi.encodePacked(checksum); bytes memory idBytes = PrimitiveTypeUtils.concat(beforeChecksum, checkSumBytes); - require(idBytes.length == 31, "idBytes requires 31 length array"); + if (idBytes.length != 31) revert IdBytesLengthRequired(31); return PrimitiveTypeUtils.reverseUint256(PrimitiveTypeUtils.padRightToUint256(idBytes)); } diff --git a/contracts/lib/IdentityBase.sol b/contracts/lib/IdentityBase.sol index 0ba9527fe..3c5c88879 100644 --- a/contracts/lib/IdentityBase.sol +++ b/contracts/lib/IdentityBase.sol @@ -7,6 +7,8 @@ import {IdentityLib} from "../lib/IdentityLib.sol"; import {SmtLib} from "../lib/SmtLib.sol"; import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +error IdentityIdMismatch(); + // /** // * @dev Contract managing onchain identity // */ @@ -20,11 +22,13 @@ abstract contract IdentityBase is IIdentifiable, IOnchainCredentialStatusResolve // keccak256(abi.encode(uint256(keccak256("iden3.storage.IdentityBase")) - 1)) // & ~bytes32(uint256(0xff)); + // solhint-disable-next-line const-name-snakecase bytes32 private constant IdentityBaseStorageLocation = 0x3018a310c36c4f8228f09bf3b1822685cf0971daa8265a58ca807c4a4daba400; /// @dev Get the main storage using assembly to ensure specific storage location function _getIdentityBaseStorage() internal pure returns (IdentityBaseStorage storage $) { + // solhint-disable-next-line no-inline-assembly assembly { $.slot := IdentityBaseStorageLocation } @@ -262,7 +266,9 @@ abstract contract IdentityBase is IIdentifiable, IOnchainCredentialStatusResolve uint256 state, uint64 nonce ) public view returns (CredentialStatus memory) { - require(id == _getIdentityBaseStorage().identity.id, "Identity id mismatch"); + if (id != _getIdentityBaseStorage().identity.id) { + revert IdentityIdMismatch(); + } IdentityLib.Roots memory historicalStates = _getIdentityBaseStorage() .identity .getRootsByState(state); diff --git a/contracts/lib/IdentityLib.sol b/contracts/lib/IdentityLib.sol index 3ce4260ed..330fb63c2 100644 --- a/contracts/lib/IdentityLib.sol +++ b/contracts/lib/IdentityLib.sol @@ -6,6 +6,11 @@ import {SmtLib} from "../lib/SmtLib.sol"; import {PoseidonUnit3L, PoseidonUnit4L} from "../lib/Poseidon.sol"; import {GenesisUtils} from "../lib/GenesisUtils.sol"; +error SMTDepthIsGreaterThanMaxAllowed(); +error IdTypeNotSupported(); +error IdentityTreesHaventChanged(); +error RootsForThisStateDoesntExist(); +error RootsForThisStateAlreadyExist(); error ClaimAlreadyExists(uint256 hashIndex); // /** @@ -83,9 +88,13 @@ library IdentityLib { uint256 depth, bytes2 idType ) external { - require(depth <= IDENTITY_MAX_SMT_DEPTH, "SMT depth is greater than max allowed depth"); + if (depth > IDENTITY_MAX_SMT_DEPTH) { + revert SMTDepthIsGreaterThanMaxAllowed(); + } self.stateContract = IState(_stateContractAddr); - require(self.stateContract.isIdTypeSupported(idType), "id type is not supported"); + if (!self.stateContract.isIdTypeSupported(idType)) { + revert IdTypeNotSupported(); + } self.isOldStateGenesis = true; self.trees.claimsTree.initialize(depth); self.trees.revocationsTree.initialize(depth); @@ -137,12 +146,13 @@ library IdentityLib { uint256 currentRevocationsTreeRoot = self.trees.revocationsTree.getRoot(); uint256 currentRootsTreeRoot = self.trees.rootsTree.getRoot(); - require( - (self.latestPublishedTreeRoots.claimsRoot != currentClaimsTreeRoot) || - (self.latestPublishedTreeRoots.revocationsRoot != currentRevocationsTreeRoot) || - (self.latestPublishedTreeRoots.rootsRoot != currentRootsTreeRoot), - "Identity trees haven't changed" - ); + if ( + (self.latestPublishedTreeRoots.claimsRoot == currentClaimsTreeRoot) && + (self.latestPublishedTreeRoots.revocationsRoot == currentRevocationsTreeRoot) && + (self.latestPublishedTreeRoots.rootsRoot == currentRootsTreeRoot) + ) { + revert IdentityTreesHaventChanged(); + } // if claimsTreeRoot changed, then add it to rootsTree if (self.latestPublishedTreeRoots.claimsRoot != currentClaimsTreeRoot) { @@ -388,22 +398,6 @@ library IdentityLib { return self.trees.rootsTree.getRoot(); } - /** - * @dev write roots to history by state - * @param self identity - * @param state identity state - * @param roots set of roots - */ - function writeHistory(Data storage self, uint256 state, Roots memory roots) internal { - require( - self.rootsByState[state].claimsRoot == 0 && - self.rootsByState[state].revocationsRoot == 0 && - self.rootsByState[state].rootsRoot == 0, - "Roots for this state already exist" - ); - self.rootsByState[state] = roots; - } - /** * @dev returns historical claimsTree roots, revocationsTree roots, rootsTree roots * by state @@ -414,15 +408,33 @@ library IdentityLib { Data storage self, uint256 state ) external view returns (Roots memory) { - require( - self.rootsByState[state].claimsRoot != 0 || - self.rootsByState[state].revocationsRoot != 0 || - self.rootsByState[state].rootsRoot != 0, - "Roots for this state doesn't exist" - ); + if ( + self.rootsByState[state].claimsRoot == 0 && + self.rootsByState[state].revocationsRoot == 0 && + self.rootsByState[state].rootsRoot == 0 + ) { + revert RootsForThisStateDoesntExist(); + } return self.rootsByState[state]; } + /** + * @dev write roots to history by state + * @param self identity + * @param state identity state + * @param roots set of roots + */ + function writeHistory(Data storage self, uint256 state, Roots memory roots) internal { + if ( + self.rootsByState[state].claimsRoot != 0 || + self.rootsByState[state].revocationsRoot != 0 || + self.rootsByState[state].rootsRoot != 0 + ) { + revert RootsForThisStateAlreadyExist(); + } + self.rootsByState[state] = roots; + } + function _checkClaimExistence(Data storage self, uint256 hashIndex) internal view { uint256 currentRoot = self.trees.claimsTree.getRoot(); SmtLib.Proof memory proof = self.trees.claimsTree.getProofByRoot(hashIndex, currentRoot); diff --git a/contracts/lib/PrimitiveTypeUtils.sol b/contracts/lib/PrimitiveTypeUtils.sol index 929077b91..f5c543a4e 100644 --- a/contracts/lib/PrimitiveTypeUtils.sol +++ b/contracts/lib/PrimitiveTypeUtils.sol @@ -3,12 +3,15 @@ pragma solidity 0.8.27; import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol"; +error GivenInputNotAnAddressRepresentation(uint256 input); + library PrimitiveTypeUtils { /** * @dev uint256ToBytes */ function uint256ToBytes(uint256 x) internal pure returns (bytes memory b) { b = new bytes(32); + // solhint-disable-next-line no-inline-assembly assembly { mstore(add(b, 32), x) } @@ -90,6 +93,7 @@ library PrimitiveTypeUtils { * @dev bytesToAddress */ function bytesToAddress(bytes memory bys) internal pure returns (address addr) { + // solhint-disable-next-line no-inline-assembly assembly { addr := mload(add(bys, 20)) } @@ -135,10 +139,9 @@ library PrimitiveTypeUtils { * @return address representation of uint256 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 */ function uint256ToAddress(uint256 input) internal pure returns (address) { - require( - input == uint256(uint160(input)), - "given input is not a representation of address, 12 most significant bytes should be zero" - ); + if (input != uint256(uint160(input))) { + revert GivenInputNotAnAddressRepresentation(input); + } return address(uint160(input)); } @@ -166,10 +169,9 @@ library PrimitiveTypeUtils { * @return address - 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 */ function uint256LEToAddress(uint256 input) internal pure returns (address) { - require( - input == uint256(uint160(input)), - "given uint256 is not a representation of an address, 12 most significant bytes should be zero" - ); + if (input != uint256(uint160(input))) { + revert GivenInputNotAnAddressRepresentation(input); + } return bytesToAddress(uint256ToBytes(reverseUint256(input))); } diff --git a/contracts/lib/StateCrossChainLib.sol b/contracts/lib/StateCrossChainLib.sol deleted file mode 100644 index 4292ab0f6..000000000 --- a/contracts/lib/StateCrossChainLib.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; - -import {IState} from "../interfaces/IState.sol"; -import {State} from "../state/State.sol"; - -/** - * @title StateCrossChainLib - * @dev The library provides functions to process cross chain proofs. - */ -library StateCrossChainLib { - bytes32 private constant GLOBAL_STATE_PROOF_TYPE = keccak256(bytes("globalStateProof")); - - bytes32 private constant STATE_PROOF_TYPE = keccak256(bytes("stateProof")); - - /** - * @dev Processes cross chain proofs. - * @param self The StateCrossChainStorage storage pointer. - * @param crossChainProofs The cross chain proofs. - */ - function processCrossChainProofs( - State.StateCrossChainStorage storage self, - bytes calldata crossChainProofs - ) public { - if (crossChainProofs.length == 0) { - return; - } - - IState.CrossChainProof[] memory proofs = abi.decode( - crossChainProofs, - (IState.CrossChainProof[]) - ); - - for (uint256 i = 0; i < proofs.length; i++) { - if (keccak256(bytes(proofs[i].proofType)) == GLOBAL_STATE_PROOF_TYPE) { - IState.GlobalStateProcessResult memory gsp = self - ._crossChainProofValidator - .processGlobalStateProof(proofs[i].proof); - self._rootToGistRootReplacedAt[gsp.idType][gsp.root] = gsp.replacedAtTimestamp; - } else if (keccak256(bytes(proofs[i].proofType)) == STATE_PROOF_TYPE) { - IState.IdentityStateProcessResult memory isu = self - ._crossChainProofValidator - .processIdentityStateProof(proofs[i].proof); - self._idToStateReplacedAt[isu.id][isu.state] = isu.replacedAtTimestamp; - } else { - revert("Unknown proof type"); - } - } - } -} diff --git a/contracts/lib/StateLib.sol b/contracts/lib/StateLib.sol index cf64be95f..6434df993 100644 --- a/contracts/lib/StateLib.sol +++ b/contracts/lib/StateLib.sol @@ -3,6 +3,10 @@ pragma solidity 0.8.27; import {ArrayUtils} from "../lib/ArrayUtils.sol"; +error IdentityDoesNotExist(); +error StateDoesNotExist(); +error IdentityAlreadyExists(); + /// @title Library for state data management. // It's purpose is to keep records of identity states along with their metadata and history. library StateLib { @@ -91,7 +95,9 @@ library StateLib { * @param id Identity */ modifier onlyExistingId(Data storage self, uint256 id) { - require(idExists(self, id), "Identity does not exist"); + if (!idExists(self, id)) { + revert IdentityDoesNotExist(); + } _; } @@ -101,7 +107,9 @@ library StateLib { * @param state State */ modifier onlyExistingState(Data storage self, uint256 id, uint256 state) { - require(stateExists(self, id, state), "State does not exist"); + if (!stateExists(self, id, state)) { + revert StateDoesNotExist(); + } _; } @@ -120,10 +128,9 @@ library StateLib { * @param state State */ function addGenesisState(Data storage self, uint256 id, uint256 state) external { - require( - !idExists(self, id), - "Zero timestamp and block should be only in the first identity state" - ); + if (idExists(self, id)) { + revert IdentityAlreadyExists(); + } _addState(self, id, state, 0, 0); } diff --git a/contracts/lib/VerifierLib.sol b/contracts/lib/VerifierLib.sol deleted file mode 100644 index a47ad53d7..000000000 --- a/contracts/lib/VerifierLib.sol +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; - -import {ZKPVerifierBase} from "../verifiers/ZKPVerifierBase.sol"; -import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol"; - -/** - * @title VerifierLib - * @dev A library for writing proof results. - */ -library VerifierLib { - /// @dev Struct to store ZKP proof and associated data - struct Proof { - bool isVerified; - mapping(string key => uint256 inputValue) storageFields; - string validatorVersion; - uint256 blockNumber; - uint256 blockTimestamp; - mapping(string key => bytes) metadata; - } - - /** - * @dev Writes proof results. - * @param self The ZKPVerifierStorage storage pointer - * @param sender The sender of the proof - * @param requestId The request ID - * @param keyToInpIdxs The array of key to public inputs index mapping - * @param inputs The array of public inputs - */ - function writeProofResults( - ZKPVerifierBase.ZKPVerifierStorage storage self, - address sender, - uint64 requestId, - ICircuitValidator.KeyToInputIndex[] memory keyToInpIdxs, - uint256[] memory inputs - ) public { - Proof storage proof = self._proofs[sender][requestId]; - for (uint256 i = 0; i < keyToInpIdxs.length; i++) { - proof.storageFields[keyToInpIdxs[i].key] = inputs[keyToInpIdxs[i].inputIndex]; - } - - proof.isVerified = true; - proof.validatorVersion = self._requests[requestId].validator.version(); - proof.blockNumber = block.number; - proof.blockTimestamp = block.timestamp; - } - - /** - * @dev Writes proof results. - * @param self The ZKPVerifierStorage storage pointer - * @param sender The sender of the proof - * @param requestId The request ID of the proof - * @param signals The array of public signals of the proof - */ - function writeProofResultsV2( - ZKPVerifierBase.ZKPVerifierStorage storage self, - address sender, - uint64 requestId, - ICircuitValidator.Signal[] memory signals - ) public { - Proof storage proof = self._proofs[sender][requestId]; - for (uint256 i = 0; i < signals.length; i++) { - proof.storageFields[signals[i].name] = signals[i].value; - } - - proof.isVerified = true; - proof.validatorVersion = self._requests[requestId].validator.version(); - proof.blockNumber = block.number; - proof.blockTimestamp = block.timestamp; - } -} diff --git a/contracts/lib/VerifierMTP.sol b/contracts/lib/VerifierMTP.sol deleted file mode 100644 index 5f31cc998..000000000 --- a/contracts/lib/VerifierMTP.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -/* - Copyright 2021 0KIMS association. - - This file is generated with [snarkJS](https://github.com/iden3/snarkjs). - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -pragma solidity >=0.7.0 <0.9.0; - -import "./groth16-verifiers/Groth16VerifierMTP.sol"; - -/** - * @dev The VerifierMTP is deprecated and will be removed in the future major versions - * Please use Groth16VerifierMTP instead - */ -contract VerifierMTP is Groth16VerifierMTP {} diff --git a/contracts/lib/VerifierMTPWrapper.sol b/contracts/lib/VerifierMTPWrapper.sol deleted file mode 100644 index 8ec5bd718..000000000 --- a/contracts/lib/VerifierMTPWrapper.sol +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright 2017 Christian Reitwiessner -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// 2019 OKIMS -// ported to solidity 0.6 -// fixed linter warnings -// added require error messages -// -// -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; - -import "./groth16-verifiers/Groth16VerifierMTPWrapper.sol"; - -/** - * @dev The VerifierMTPWrapper is deprecated and will be removed in the future major versions - * Please use Groth16VerifierMTPWrapper instead - */ -contract VerifierMTPWrapper is Groth16VerifierMTPWrapper {} diff --git a/contracts/lib/VerifierSig.sol b/contracts/lib/VerifierSig.sol deleted file mode 100644 index d93e4c4ea..000000000 --- a/contracts/lib/VerifierSig.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -/* - Copyright 2021 0KIMS association. - - This file is generated with [snarkJS](https://github.com/iden3/snarkjs). - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -pragma solidity >=0.7.0 <0.9.0; - -import "./groth16-verifiers/Groth16VerifierSig.sol"; - -/** - * @dev The VerifierSig is deprecated and will be removed in the future major versions - * Please use Groth16VerifierSig instead - */ -contract VerifierSig is Groth16VerifierSig {} diff --git a/contracts/lib/VerifierSigWrapper.sol b/contracts/lib/VerifierSigWrapper.sol deleted file mode 100644 index cff0e64d6..000000000 --- a/contracts/lib/VerifierSigWrapper.sol +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright 2017 Christian Reitwiessner -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// 2019 OKIMS -// ported to solidity 0.6 -// fixed linter warnings -// added require error messages -// -// -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; - -import "./groth16-verifiers/Groth16VerifierSigWrapper.sol"; - -/** - * @dev The VerifierSigWrapper is deprecated and will be removed in the future major versions - * Please use Groth16VerifierSigWrapper instead - */ -contract VerifierSigWrapper is Groth16VerifierSigWrapper {} diff --git a/contracts/lib/VerifierStateTransition.sol b/contracts/lib/VerifierStateTransition.sol deleted file mode 100644 index 0d884b1d2..000000000 --- a/contracts/lib/VerifierStateTransition.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -/* - Copyright 2021 0KIMS association. - - This file is generated with [snarkJS](https://github.com/iden3/snarkjs). - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -pragma solidity >=0.7.0 <0.9.0; - -import "./groth16-verifiers/Groth16VerifierStateTransition.sol"; - -/** - * @dev The VerifierStateTransition is deprecated and will be removed in the future major versions - * Please use Groth16VerifierStateTransition instead - */ -contract VerifierStateTransition is Groth16VerifierStateTransition {} diff --git a/contracts/lib/VerifierV3.sol b/contracts/lib/VerifierV3.sol deleted file mode 100644 index 3dbfe69c9..000000000 --- a/contracts/lib/VerifierV3.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -/* - Copyright 2021 0KIMS association. - - This file is generated with [snarkJS](https://github.com/iden3/snarkjs). - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -pragma solidity >=0.7.0 <0.9.0; - -import "./groth16-verifiers/Groth16VerifierV3.sol"; - -/** - * @dev The VerifierV3 is deprecated and will be removed in the future major versions - * Please use Groth16VerifierV3 instead - */ -contract VerifierV3 is Groth16VerifierV3 {} diff --git a/contracts/lib/VerifierV3Wrapper.sol b/contracts/lib/VerifierV3Wrapper.sol deleted file mode 100644 index 18d9a39e7..000000000 --- a/contracts/lib/VerifierV3Wrapper.sol +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright 2017 Christian Reitwiessner -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// 2019 OKIMS -// ported to solidity 0.6 -// fixed linter warnings -// added require error messages -// -// -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; - -import "./groth16-verifiers/Groth16VerifierV3Wrapper.sol"; - -/** - * @dev The VerifierV3Wrapper is deprecated and will be removed in the future major versions - * Please use Groth16VerifierV3Wrapper instead - */ -contract VerifierV3Wrapper is Groth16VerifierV3Wrapper {} diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierAuthV2Wrapper.sol b/contracts/lib/groth16-verifiers/Groth16VerifierAuthV2Wrapper.sol index 356ead470..89d092f84 100644 --- a/contracts/lib/groth16-verifiers/Groth16VerifierAuthV2Wrapper.sol +++ b/contracts/lib/groth16-verifiers/Groth16VerifierAuthV2Wrapper.sol @@ -1,32 +1,12 @@ -// -// Copyright 2017 Christian Reitwiessner -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom -// the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// 2019 OKIMS -// ported to solidity 0.6 -// fixed linter warnings -// added require error messages -// -// // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.27; import {Groth16VerifierAuthV2} from "./Groth16VerifierAuthV2.sol"; -import {IVerifier} from "../../interfaces/IVerifier.sol"; +import {IGroth16Verifier} from "../../interfaces/IGroth16Verifier.sol"; -contract Groth16VerifierAuthV2Wrapper is Groth16VerifierAuthV2, IVerifier { +error ExpectedArrayLenght(uint256 expected, uint256 actual); + +contract Groth16VerifierAuthV2Wrapper is Groth16VerifierAuthV2, IGroth16Verifier { /** * @dev Number of public signals for atomic mtp circuit */ @@ -37,21 +17,23 @@ contract Groth16VerifierAuthV2Wrapper is Groth16VerifierAuthV2, IVerifier { * @param a πa element of the groth16 proof. * @param b πb element of the groth16 proof. * @param c πc element of the groth16 proof. - * @param input Public inputs of the circuit. + * @param signals Public inputs and outputs of the circuit. * @return r true if the proof is valid. */ function verify( uint256[2] calldata a, uint256[2][2] calldata b, uint256[2] calldata c, - uint256[] calldata input + uint256[] calldata signals ) public view returns (bool r) { uint[PUBSIGNALS_LENGTH] memory pubSignals; - require(input.length == PUBSIGNALS_LENGTH, "expected array length is 3"); + if (signals.length != PUBSIGNALS_LENGTH) { + revert ExpectedArrayLenght(PUBSIGNALS_LENGTH, signals.length); + } for (uint256 i = 0; i < PUBSIGNALS_LENGTH; i++) { - pubSignals[i] = input[i]; + pubSignals[i] = signals[i]; } return this.verifyProof(a, b, c, pubSignals); diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierLinkedMultiQuery10.sol b/contracts/lib/groth16-verifiers/Groth16VerifierLinkedMultiQuery10.sol new file mode 100644 index 000000000..e2dba6a76 --- /dev/null +++ b/contracts/lib/groth16-verifiers/Groth16VerifierLinkedMultiQuery10.sol @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: GPL-3.0 +/* + Copyright 2021 0KIMS association. + + This file is generated with [snarkJS](https://github.com/iden3/snarkjs). + + snarkJS is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + snarkJS is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with snarkJS. If not, see . +*/ + +pragma solidity >=0.8.4 <0.9.0; + +contract Groth16VerifierLinkedMultiQuery10 { + // Scalar field size + uint256 constant r = + 21888242871839275222246405745257275088548364400416034343698204186575808495617; + // Base field size + uint256 constant q = + 21888242871839275222246405745257275088696311157297823662689037894645226208583; + + // Verification Key data + uint256 constant alphax = + 20491192805390485299153009773594534940189261866228447918068658471970481763042; + uint256 constant alphay = + 9383485363053290200918347156157836566562967994039712273449902621266178545958; + uint256 constant betax1 = + 4252822878758300859123897981450591353533073413197771768651442665752259397132; + uint256 constant betax2 = + 6375614351688725206403948262868962793625744043794305715222011528459656738731; + uint256 constant betay1 = + 21847035105528745403288232691147584728191162732299865338377159692350059136679; + uint256 constant betay2 = + 10505242626370262277552901082094356697409835680220590971873171140371331206856; + uint256 constant gammax1 = + 11559732032986387107991004021392285783925812861821192530917403151452391805634; + uint256 constant gammax2 = + 10857046999023057135944570762232829481370756359578518086990519993285655852781; + uint256 constant gammay1 = + 4082367875863433681332203403145435568316851327593401208105741076214120093531; + uint256 constant gammay2 = + 8495653923123431417604973247489272438418190587263600148770280649306958101930; + uint256 constant deltax1 = + 4767756989901781990548811495555254021246964220885607355087778530306964004185; + uint256 constant deltax2 = + 13574129252125202270158307841999632289188481698271261939235393046564697547323; + uint256 constant deltay1 = + 11765493019200775638510616767809212227835759957683292721283970143875449362878; + uint256 constant deltay2 = + 20994491963918641855107870498261517959074286551785099903933200630273567734342; + + uint256 constant IC0x = + 12449886944142661472251059230965936349361235560943050777171852750972268056009; + uint256 constant IC0y = + 5508789765348348011558576931625983265119736287691184278767289209256184182152; + + uint256 constant IC1x = + 11354840822823409678846005531170154810223893374328536931571598076429246168962; + uint256 constant IC1y = + 10243618321308788660349859395450060514823490518996600371300209313988271557806; + + uint256 constant IC2x = + 7688841796121824588147585218713985820690021917094358723669767856390683928034; + uint256 constant IC2y = + 15304029843415543132293541704424359450862448668530347048215672038580045683481; + + uint256 constant IC3x = + 15990615657429515286876718277658019436828926204319889565777537283744068146700; + uint256 constant IC3y = + 20265128390631794181627612941990068143695235211256419586038084564697570772459; + + uint256 constant IC4x = + 16744634382041772612761056860980716914432614100602561913600347639646803828867; + uint256 constant IC4y = + 9587909504738762931618416803620503763808524690654300610728307244650105345649; + + uint256 constant IC5x = + 14498281259442737211687928465501452644380043044531604747511002130574576040500; + uint256 constant IC5y = + 15178480169883279183083105005735414370343021495727319036601387862295433592890; + + uint256 constant IC6x = + 181238700928172282344680236185737466543303371505875966182504955165221550787; + uint256 constant IC6y = + 21622111637396317730948136644302630767714713068723532481132071344883159478317; + + uint256 constant IC7x = + 8334117149439267478794081283986502998659211363774660979410854038645857015106; + uint256 constant IC7y = + 3525586056545466424550069059261704178677653029630068235241952571550605630653; + + uint256 constant IC8x = + 16676389244152071637547895889424069474191043909363062157910970100503924284824; + uint256 constant IC8y = + 6293986690744783536251466348123663316687870380690807594123241364218706730246; + + uint256 constant IC9x = + 12745671365224662776594194440156600675329812876347548121369698185420569095439; + uint256 constant IC9y = + 11273088596548493444123027464142605382437970433270231501917065525393005894036; + + uint256 constant IC10x = + 7732485931307476787148144929824683305147104743163709148772223736952704050567; + uint256 constant IC10y = + 14991775678419768558530779568394256066852823412993601432448554479361118463299; + + uint256 constant IC11x = + 13954475229491875183185146721491133006576631796979640931033593718558384269206; + uint256 constant IC11y = + 20143678799568261548345812147552378448221261337943896478291695109662795302646; + + uint256 constant IC12x = + 1588536655220107824895151554872386730171641945783207210783928981583577082720; + uint256 constant IC12y = + 13908530648827733472139197820866316501402019214593222521521102979981263265396; + + uint256 constant IC13x = + 12678767645933368864421466910761496605084347784517452696623065956846509548782; + uint256 constant IC13y = + 21381570127686765465000169852593021495333227087229864265691446720659272361152; + + uint256 constant IC14x = + 17922265673268483320025865036589139344955822363275373430719168065953761526520; + uint256 constant IC14y = + 9242324301503892823219332201525279187476010610994752688104429744801597668285; + + uint256 constant IC15x = + 19367539127735956732148435844861647320899694335953718141209016532640873590140; + uint256 constant IC15y = + 12701104584447112200166345844417732176637947754547635778619790266357846083284; + + uint256 constant IC16x = + 14931750548482966130586321361300230947899794584196248761236252137274123990811; + uint256 constant IC16y = + 18907870831743031028168656813690968152456035625888662633278498386598866738708; + + uint256 constant IC17x = + 21078326524345796712273699205406122410330437647297400186087773951320605894880; + uint256 constant IC17y = + 6471701510558433137588469036231611931381433511837825536013781894924055589201; + + uint256 constant IC18x = + 11616604898621091236885062107603844843578912315924240360909152763967953411071; + uint256 constant IC18y = + 15567597962932438133376009485279673723080736998791665521084155531250437535832; + + uint256 constant IC19x = + 16814378820042549514945932350142180953549065761435730844701764513083012014298; + uint256 constant IC19y = + 9577851565990440995137571478255586121135591079059958395444685890902579770570; + + uint256 constant IC20x = + 1093702848180480792269642835164492672016092778979951861285096707497432193760; + uint256 constant IC20y = + 4063334433551442475817332481927046015343707417264061346417488535608502495218; + + uint256 constant IC21x = + 7214731470556020664921656204545020072837783006969685612760693537299230135333; + uint256 constant IC21y = + 8891562787830667150144624187125115054175583159717508708300614390764766181778; + + uint256 constant IC22x = + 4041991063957841891847968885939221032895793579852508335899469034278358488695; + uint256 constant IC22y = + 12929528695870206289536816082066059156374288392417066761527212742555189041207; + + // Memory data + uint16 constant pVk = 0; + uint16 constant pPairing = 128; + + uint16 constant pLastMem = 896; + + function verifyProof( + uint[2] calldata _pA, + uint[2][2] calldata _pB, + uint[2] calldata _pC, + uint[22] calldata _pubSignals + ) public view returns (bool) { + assembly { + function checkField(v) { + if iszero(lt(v, r)) { + mstore(0, 0) + return(0, 0x20) + } + } + + // G1 function to multiply a G1 value(x,y) to value in an address + function g1_mulAccC(pR, x, y, s) { + let success + let mIn := mload(0x40) + mstore(mIn, x) + mstore(add(mIn, 32), y) + mstore(add(mIn, 64), s) + + success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + + mstore(add(mIn, 64), mload(pR)) + mstore(add(mIn, 96), mload(add(pR, 32))) + + success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + } + + function checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk { + let _pPairing := add(pMem, pPairing) + let _pVk := add(pMem, pVk) + + mstore(_pVk, IC0x) + mstore(add(_pVk, 32), IC0y) + + // Compute the linear combination vk_x + + g1_mulAccC(_pVk, IC1x, IC1y, calldataload(add(pubSignals, 0))) + + g1_mulAccC(_pVk, IC2x, IC2y, calldataload(add(pubSignals, 32))) + + g1_mulAccC(_pVk, IC3x, IC3y, calldataload(add(pubSignals, 64))) + + g1_mulAccC(_pVk, IC4x, IC4y, calldataload(add(pubSignals, 96))) + + g1_mulAccC(_pVk, IC5x, IC5y, calldataload(add(pubSignals, 128))) + + g1_mulAccC(_pVk, IC6x, IC6y, calldataload(add(pubSignals, 160))) + + g1_mulAccC(_pVk, IC7x, IC7y, calldataload(add(pubSignals, 192))) + + g1_mulAccC(_pVk, IC8x, IC8y, calldataload(add(pubSignals, 224))) + + g1_mulAccC(_pVk, IC9x, IC9y, calldataload(add(pubSignals, 256))) + + g1_mulAccC(_pVk, IC10x, IC10y, calldataload(add(pubSignals, 288))) + + g1_mulAccC(_pVk, IC11x, IC11y, calldataload(add(pubSignals, 320))) + + g1_mulAccC(_pVk, IC12x, IC12y, calldataload(add(pubSignals, 352))) + + g1_mulAccC(_pVk, IC13x, IC13y, calldataload(add(pubSignals, 384))) + + g1_mulAccC(_pVk, IC14x, IC14y, calldataload(add(pubSignals, 416))) + + g1_mulAccC(_pVk, IC15x, IC15y, calldataload(add(pubSignals, 448))) + + g1_mulAccC(_pVk, IC16x, IC16y, calldataload(add(pubSignals, 480))) + + g1_mulAccC(_pVk, IC17x, IC17y, calldataload(add(pubSignals, 512))) + + g1_mulAccC(_pVk, IC18x, IC18y, calldataload(add(pubSignals, 544))) + + g1_mulAccC(_pVk, IC19x, IC19y, calldataload(add(pubSignals, 576))) + + g1_mulAccC(_pVk, IC20x, IC20y, calldataload(add(pubSignals, 608))) + + g1_mulAccC(_pVk, IC21x, IC21y, calldataload(add(pubSignals, 640))) + + g1_mulAccC(_pVk, IC22x, IC22y, calldataload(add(pubSignals, 672))) + + // -A + mstore(_pPairing, calldataload(pA)) + mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q)) + + // B + mstore(add(_pPairing, 64), calldataload(pB)) + mstore(add(_pPairing, 96), calldataload(add(pB, 32))) + mstore(add(_pPairing, 128), calldataload(add(pB, 64))) + mstore(add(_pPairing, 160), calldataload(add(pB, 96))) + + // alpha1 + mstore(add(_pPairing, 192), alphax) + mstore(add(_pPairing, 224), alphay) + + // beta2 + mstore(add(_pPairing, 256), betax1) + mstore(add(_pPairing, 288), betax2) + mstore(add(_pPairing, 320), betay1) + mstore(add(_pPairing, 352), betay2) + + // vk_x + mstore(add(_pPairing, 384), mload(add(pMem, pVk))) + mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32)))) + + // gamma2 + mstore(add(_pPairing, 448), gammax1) + mstore(add(_pPairing, 480), gammax2) + mstore(add(_pPairing, 512), gammay1) + mstore(add(_pPairing, 544), gammay2) + + // C + mstore(add(_pPairing, 576), calldataload(pC)) + mstore(add(_pPairing, 608), calldataload(add(pC, 32))) + + // delta2 + mstore(add(_pPairing, 640), deltax1) + mstore(add(_pPairing, 672), deltax2) + mstore(add(_pPairing, 704), deltay1) + mstore(add(_pPairing, 736), deltay2) + + let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20) + + isOk := and(success, mload(_pPairing)) + } + + let pMem := mload(0x40) + mstore(0x40, add(pMem, pLastMem)) + + // Validate that all evaluations ∈ F + + checkField(calldataload(add(_pubSignals, 0))) + + checkField(calldataload(add(_pubSignals, 32))) + + checkField(calldataload(add(_pubSignals, 64))) + + checkField(calldataload(add(_pubSignals, 96))) + + checkField(calldataload(add(_pubSignals, 128))) + + checkField(calldataload(add(_pubSignals, 160))) + + checkField(calldataload(add(_pubSignals, 192))) + + checkField(calldataload(add(_pubSignals, 224))) + + checkField(calldataload(add(_pubSignals, 256))) + + checkField(calldataload(add(_pubSignals, 288))) + + checkField(calldataload(add(_pubSignals, 320))) + + checkField(calldataload(add(_pubSignals, 352))) + + checkField(calldataload(add(_pubSignals, 384))) + + checkField(calldataload(add(_pubSignals, 416))) + + checkField(calldataload(add(_pubSignals, 448))) + + checkField(calldataload(add(_pubSignals, 480))) + + checkField(calldataload(add(_pubSignals, 512))) + + checkField(calldataload(add(_pubSignals, 544))) + + checkField(calldataload(add(_pubSignals, 576))) + + checkField(calldataload(add(_pubSignals, 608))) + + checkField(calldataload(add(_pubSignals, 640))) + + checkField(calldataload(add(_pubSignals, 672))) + + // Validate all evaluations + let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem) + + mstore(0, isValid) + return(0, 0x20) + } + } +} diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierLinkedMultiQuery10Wrapper.sol b/contracts/lib/groth16-verifiers/Groth16VerifierLinkedMultiQuery10Wrapper.sol new file mode 100644 index 000000000..0c6116388 --- /dev/null +++ b/contracts/lib/groth16-verifiers/Groth16VerifierLinkedMultiQuery10Wrapper.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.10; + +import {IGroth16Verifier} from "../../interfaces/IGroth16Verifier.sol"; +import {Groth16VerifierLinkedMultiQuery10} from "./Groth16VerifierLinkedMultiQuery10.sol"; + +error ExpectedArrayLenght(uint256 expected, uint256 actual); + +contract Groth16VerifierLinkedMultiQuery10Wrapper is + Groth16VerifierLinkedMultiQuery10, + IGroth16Verifier +{ + /** + * @dev Number of public signals for atomic mtp circuit + */ + uint256 constant PUBSIGNALS_LENGTH = 22; + + /** + * @dev Verify the circuit with the groth16 proof π=([πa]1,[πb]2,[πc]1). + * @param a πa element of the groth16 proof. + * @param b πb element of the groth16 proof. + * @param c πc element of the groth16 proof. + * @param signals Public inputs and outputs of the circuit. + * @return r true if the proof is valid. + */ + function verify( + uint256[2] calldata a, + uint256[2][2] calldata b, + uint256[2] calldata c, + uint256[] calldata signals + ) public view returns (bool r) { + uint[PUBSIGNALS_LENGTH] memory pubSignals; + + if (signals.length != PUBSIGNALS_LENGTH) { + revert ExpectedArrayLenght(PUBSIGNALS_LENGTH, signals.length); + } + + for (uint256 i = 0; i < PUBSIGNALS_LENGTH; i++) { + pubSignals[i] = signals[i]; + } + + return this.verifyProof(a, b, c, pubSignals); + } +} diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierMTP.sol b/contracts/lib/groth16-verifiers/Groth16VerifierMTP.sol index de520abfe..5c3568f07 100644 --- a/contracts/lib/groth16-verifiers/Groth16VerifierMTP.sol +++ b/contracts/lib/groth16-verifiers/Groth16VerifierMTP.sol @@ -18,7 +18,7 @@ along with snarkJS. If not, see . */ -pragma solidity >=0.7.0 <0.9.0; +pragma solidity >=0.8.4 <0.9.0; contract Groth16VerifierMTP { // Scalar field size diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierMTPWrapper.sol b/contracts/lib/groth16-verifiers/Groth16VerifierMTPWrapper.sol index 2e1680c26..9d22a7cd9 100644 --- a/contracts/lib/groth16-verifiers/Groth16VerifierMTPWrapper.sol +++ b/contracts/lib/groth16-verifiers/Groth16VerifierMTPWrapper.sol @@ -14,34 +14,38 @@ pragma solidity 0.8.27; import "./Groth16VerifierMTP.sol"; -import "../../interfaces/IVerifier.sol"; +import "../../interfaces/IGroth16Verifier.sol"; -contract Groth16VerifierMTPWrapper is Groth16VerifierMTP, IVerifier { +error ExpectedArrayLenght(uint256 expected, uint256 actual); + +contract Groth16VerifierMTPWrapper is Groth16VerifierMTP, IGroth16Verifier { /** * @dev Number of public signals for atomic mtp circuit */ - uint constant PUBSIGNALS_LENGTH = 11; + uint256 constant PUBSIGNALS_LENGTH = 11; /** * @dev Verify the circuit with the groth16 proof π=([πa]1,[πb]2,[πc]1). * @param a πa element of the groth16 proof. * @param b πb element of the groth16 proof. * @param c πc element of the groth16 proof. - * @param input Public inputs of the circuit. + * @param signals Public inputs and outputs of the circuit. * @return r true if the proof is valid. */ function verify( uint256[2] calldata a, uint256[2][2] calldata b, uint256[2] calldata c, - uint256[] calldata input + uint256[] calldata signals ) public view returns (bool r) { uint[PUBSIGNALS_LENGTH] memory pubSignals; - require(input.length == PUBSIGNALS_LENGTH, "expected array length is 11"); + if (signals.length != PUBSIGNALS_LENGTH) { + revert ExpectedArrayLenght(PUBSIGNALS_LENGTH, signals.length); + } for (uint256 i = 0; i < PUBSIGNALS_LENGTH; i++) { - pubSignals[i] = input[i]; + pubSignals[i] = signals[i]; } return this.verifyProof(a, b, c, pubSignals); diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierSig.sol b/contracts/lib/groth16-verifiers/Groth16VerifierSig.sol index 36aea4241..da97c6eb4 100644 --- a/contracts/lib/groth16-verifiers/Groth16VerifierSig.sol +++ b/contracts/lib/groth16-verifiers/Groth16VerifierSig.sol @@ -18,7 +18,7 @@ along with snarkJS. If not, see . */ -pragma solidity >=0.7.0 <0.9.0; +pragma solidity >=0.8.4 <0.9.0; contract Groth16VerifierSig { // Scalar field size diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierSigWrapper.sol b/contracts/lib/groth16-verifiers/Groth16VerifierSigWrapper.sol index d52183d2f..a6295c376 100644 --- a/contracts/lib/groth16-verifiers/Groth16VerifierSigWrapper.sol +++ b/contracts/lib/groth16-verifiers/Groth16VerifierSigWrapper.sol @@ -14,35 +14,39 @@ pragma solidity 0.8.27; import "./Groth16VerifierSig.sol"; -import "../../interfaces/IVerifier.sol"; +import "../../interfaces/IGroth16Verifier.sol"; -contract Groth16VerifierSigWrapper is Groth16VerifierSig, IVerifier { +error ExpectedArrayLenght(uint256 expected, uint256 actual); + +contract Groth16VerifierSigWrapper is Groth16VerifierSig, IGroth16Verifier { /** * @dev Number of public signals for atomic sig circuit */ - uint constant PUBSIGNALS_LENGTH = 11; + uint256 constant PUBSIGNALS_LENGTH = 11; /** * @dev Verify the circuit with the groth16 proof π=([πa]1,[πb]2,[πc]1). * @param a πa element of the groth16 proof. * @param b πb element of the groth16 proof. * @param c πc element of the groth16 proof. - * @param input Public inputs of the circuit. + * @param signals Public inputs and outputs of the circuit. * @return r true if the proof is valid. */ function verify( uint256[2] calldata a, uint256[2][2] calldata b, uint256[2] calldata c, - uint256[] calldata input + uint256[] calldata signals ) public view returns (bool r) { // slither-disable-next-line uninitialized-local uint[PUBSIGNALS_LENGTH] memory pubSignals; - require(input.length == PUBSIGNALS_LENGTH, "expected array length is 11"); + if (signals.length != PUBSIGNALS_LENGTH) { + revert ExpectedArrayLenght(PUBSIGNALS_LENGTH, signals.length); + } for (uint256 i = 0; i < PUBSIGNALS_LENGTH; i++) { - pubSignals[i] = input[i]; + pubSignals[i] = signals[i]; } return this.verifyProof(a, b, c, pubSignals); } diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierStateTransition.sol b/contracts/lib/groth16-verifiers/Groth16VerifierStateTransition.sol index 6bfdd28ad..52d567b65 100644 --- a/contracts/lib/groth16-verifiers/Groth16VerifierStateTransition.sol +++ b/contracts/lib/groth16-verifiers/Groth16VerifierStateTransition.sol @@ -18,7 +18,7 @@ along with snarkJS. If not, see . */ -pragma solidity >=0.7.0 <0.9.0; +pragma solidity >=0.8.4 <0.9.0; import "../../interfaces/IStateTransitionVerifier.sol"; diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierV3.sol b/contracts/lib/groth16-verifiers/Groth16VerifierV3.sol index 1b6d8b6f8..48a9571f2 100644 --- a/contracts/lib/groth16-verifiers/Groth16VerifierV3.sol +++ b/contracts/lib/groth16-verifiers/Groth16VerifierV3.sol @@ -18,7 +18,7 @@ along with snarkJS. If not, see . */ -pragma solidity >=0.7.0 <0.9.0; +pragma solidity >=0.8.4 <0.9.0; contract Groth16VerifierV3 { // Scalar field size diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierV3Wrapper.sol b/contracts/lib/groth16-verifiers/Groth16VerifierV3Wrapper.sol index 476c86813..00b7d8ae6 100644 --- a/contracts/lib/groth16-verifiers/Groth16VerifierV3Wrapper.sol +++ b/contracts/lib/groth16-verifiers/Groth16VerifierV3Wrapper.sol @@ -14,35 +14,39 @@ pragma solidity 0.8.27; import "./Groth16VerifierV3.sol"; -import "../../interfaces/IVerifier.sol"; +import "../../interfaces/IGroth16Verifier.sol"; -contract Groth16VerifierV3Wrapper is Groth16VerifierV3, IVerifier { +error ExpectedArrayLenght(uint256 expected, uint256 actual); + +contract Groth16VerifierV3Wrapper is Groth16VerifierV3, IGroth16Verifier { /** * @dev Number of public signals for atomic V3 circuit */ - uint constant PUBSIGNALS_LENGTH = 14; + uint256 constant PUBSIGNALS_LENGTH = 14; /** * @dev Verify the circuit with the groth16 proof π=([πa]1,[πb]2,[πc]1). * @param a πa element of the groth16 proof. * @param b πb element of the groth16 proof. * @param c πc element of the groth16 proof. - * @param input Public inputs of the circuit. + * @param signals Public inputs and outputs of the circuit. * @return r true if the proof is valid. */ function verify( uint256[2] calldata a, uint256[2][2] calldata b, uint256[2] calldata c, - uint256[] calldata input + uint256[] calldata signals ) public view returns (bool r) { // slither-disable-next-line uninitialized-local uint[PUBSIGNALS_LENGTH] memory pubSignals; - require(input.length == PUBSIGNALS_LENGTH, "expected array length is 14"); + if (signals.length != PUBSIGNALS_LENGTH) { + revert ExpectedArrayLenght(PUBSIGNALS_LENGTH, signals.length); + } for (uint256 i = 0; i < PUBSIGNALS_LENGTH; i++) { - pubSignals[i] = input[i]; + pubSignals[i] = signals[i]; } return this.verifyProof(a, b, c, pubSignals); } diff --git a/contracts/package.json b/contracts/package.json index a3810ac9a..25fb01563 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -1,7 +1,7 @@ { "name": "@iden3/contracts", "description": "Smart Contract library for Solidity", - "version": "2.5.11", + "version": "3.0.0", "files": [ "**/*.sol", "/build/contracts/*.json", diff --git a/contracts/payment/MCPayment.sol b/contracts/payment/MCPayment.sol index 957d300f3..618032feb 100644 --- a/contracts/payment/MCPayment.sol +++ b/contracts/payment/MCPayment.sol @@ -72,10 +72,12 @@ contract MCPayment is Ownable2StepUpgradeable, EIP712Upgradeable, ReentrancyGuar // keccak256(abi.encode(uint256(keccak256("iden3.storage.MCPayment")) - 1)) & // ~bytes32(uint256(0xff)); + // solhint-disable-next-line const-name-snakecase bytes32 private constant MCPaymentStorageLocation = 0x843c93f996398391e581389b674681e6ea27a4f9a96390a9d8ecb41cf0226300; function _getMCPaymentStorage() private pure returns (MCPaymentStorage storage $) { + // solhint-disable-next-line no-inline-assembly assembly { $.slot := MCPaymentStorageLocation } @@ -232,6 +234,7 @@ contract MCPayment is Ownable2StepUpgradeable, EIP712Upgradeable, ReentrancyGuar // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly + // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(permitSignature, 0x20)) s := mload(add(permitSignature, 0x40)) @@ -377,7 +380,7 @@ contract MCPayment is Ownable2StepUpgradeable, EIP712Upgradeable, ReentrancyGuar * @dev Withdraw ERC-20 balance to owner */ function ownerERC20Withdraw(address token) public onlyOwner nonReentrant { - uint amount = IERC20(token).balanceOf(address(this)); + uint256 amount = IERC20(token).balanceOf(address(this)); if (amount == 0) { revert WithdrawErrorNoBalance(); } @@ -407,7 +410,7 @@ contract MCPayment is Ownable2StepUpgradeable, EIP712Upgradeable, ReentrancyGuar address signer ) internal { IERC20 token = IERC20(paymentData.tokenAddress); - // todo repace with `trySafeTransferFrom` function after oppenzeppelin release + // todo replace with `trySafeTransferFrom` function after oppenzeppelin release token.safeTransferFrom(msg.sender, address(this), paymentData.amount); MCPaymentStorage storage $ = _getMCPaymentStorage(); uint256 ownerPart = (paymentData.amount * $.ownerPercentage) / 100; @@ -437,7 +440,7 @@ contract MCPayment is Ownable2StepUpgradeable, EIP712Upgradeable, ReentrancyGuar _withdraw(amount, issuer); } - function _withdraw(uint amount, address to) internal { + function _withdraw(uint256 amount, address to) internal { if (to == address(0)) { revert WithdrawErrorInvalidAddress(); } diff --git a/contracts/payment/VCPayment.sol b/contracts/payment/VCPayment.sol index cf6e178ea..907c0026f 100644 --- a/contracts/payment/VCPayment.sol +++ b/contracts/payment/VCPayment.sol @@ -48,10 +48,12 @@ contract VCPayment is Ownable2StepUpgradeable, ReentrancyGuardUpgradeable { // keccak256(abi.encode(uint256(keccak256("iden3.storage.VCPayment")) - 1)) & // ~bytes32(uint256(0xff)); + // solhint-disable-next-line const-name-snakecase bytes32 private constant VCPaymentStorageLocation = 0xbb49acb92ce91902600caabfefad66ed7ac2a150edbd631ab48a5501402b3300; function _getVCPaymentStorage() private pure returns (VCPaymentStorage storage $) { + // solhint-disable-next-line no-inline-assembly assembly { $.slot := VCPaymentStorageLocation } @@ -274,7 +276,7 @@ contract VCPayment is Ownable2StepUpgradeable, ReentrancyGuardUpgradeable { return $.ownerBalance; } - function _withdraw(address to, uint amount) internal { + function _withdraw(address to, uint256 amount) internal { if (amount == 0) { revert NoBalanceToWithdraw(to); } diff --git a/contracts/state/State.sol b/contracts/state/State.sol index dbb6f6533..3017b1c96 100644 --- a/contracts/state/State.sol +++ b/contracts/state/State.sol @@ -7,16 +7,43 @@ import {IStateTransitionVerifier} from "../interfaces/IStateTransitionVerifier.s import {SmtLib} from "../lib/SmtLib.sol"; import {PoseidonUnit1L} from "../lib/Poseidon.sol"; import {StateLib} from "../lib/StateLib.sol"; -import {StateCrossChainLib} from "../lib/StateCrossChainLib.sol"; import {GenesisUtils} from "../lib/GenesisUtils.sol"; import {ICrossChainProofValidator} from "../interfaces/ICrossChainProofValidator.sol"; +error VerifierContractAddressShouldNotBeZero(); +error UnknownProofType(); +error DefaultIdTypeNotInitialized(); +error ZeroKnowledgeProofOfStateTransitionIsNotValid(); +error SenderIsNotIdentityOwner(); +error MethodParamsShouldBeEmpty(); +error OldStateShouldBeZero(); +error UnknownStateTransitionMethodId(); +error StateEntryNotFound(); +error CrossChainStateNotFound(); +error GistRootEntryNotFound(); +error CrossChainGistRootNotFound(); +error IdTypeNotSupported(); +error IdShouldNotBeZero(); +error NewStateShouldNotBeZero(); +error OldStateIsGenesisButIdentityAlreadyExists(); +error OldStateIsNotGenesisButIdentityDoesNotExist(); +error OldStateDoesNotMatchTheLatestState(); +error NewStateAlreadyExists(); + /// @title Set and get states for each identity contract State is Ownable2StepUpgradeable, IState { /** * @dev Version of contract */ - string public constant VERSION = "2.6.1"; + string public constant VERSION = "2.6.2"; + /** + * @dev Global state proof type + */ + bytes32 private constant GLOBAL_STATE_PROOF_TYPE = keccak256(bytes("globalStateProof")); + /** + * @dev State proof type + */ + bytes32 private constant STATE_PROOF_TYPE = keccak256(bytes("stateProof")); // This empty reserved space is put in place to allow future versions // of the State contract to inherit from other contracts without a risk of @@ -53,34 +80,34 @@ contract State is Ownable2StepUpgradeable, IState { */ bool internal _defaultIdTypeInitialized; - // keccak256(abi.encode(uint256(keccak256("iden3.storage.StateCrossChain")) - 1)) - // & ~bytes32(uint256(0xff)); - bytes32 private constant StateCrossChainStorageLocation = - 0xfe6de916382846695d2555237dc6c0ef6555f4c949d4ba263e03532600778100; - /// @custom:storage-location erc7201:iden3.storage.StateCrossChain struct StateCrossChainStorage { mapping(uint256 id => mapping(uint256 state => uint256 replacedAt)) _idToStateReplacedAt; mapping(bytes2 idType => mapping(uint256 root => uint256 replacedAt)) _rootToGistRootReplacedAt; ICrossChainProofValidator _crossChainProofValidator; - IState _state; + } + + // keccak256(abi.encode(uint256(keccak256("iden3.storage.StateCrossChain")) - 1)) + // & ~bytes32(uint256(0xff)); + // solhint-disable-next-line const-name-snakecase + bytes32 private constant StateCrossChainStorageLocation = + 0xfe6de916382846695d2555237dc6c0ef6555f4c949d4ba263e03532600778100; + + function _getStateCrossChainStorage() private pure returns (StateCrossChainStorage storage $) { + // solhint-disable-next-line no-inline-assembly + assembly { + $.slot := StateCrossChainStorageLocation + } } using SmtLib for SmtLib.Data; using StateLib for StateLib.Data; - using StateCrossChainLib for StateCrossChainStorage; /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } - function _getStateCrossChainStorage() private pure returns (StateCrossChainStorage storage $) { - assembly { - $.slot := StateCrossChainStorageLocation - } - } - /** * @dev Initialize the contract * @param verifierContractAddr Verifier address @@ -99,7 +126,7 @@ contract State is Ownable2StepUpgradeable, IState { } if (address(verifierContractAddr) == address(0)) { - revert("Verifier contract address should not be zero"); + revert VerifierContractAddressShouldNotBeZero(); } verifier = verifierContractAddr; @@ -119,12 +146,35 @@ contract State is Ownable2StepUpgradeable, IState { } /** - * @dev Process cross chain proofs with identity and global state proofs - * @param proofs Cross chain proofs to be processed + * @dev Processes cross chain proofs. + * @param crossChainProofs The cross chain proofs. */ - function processCrossChainProofs(bytes calldata proofs) public { + function processCrossChainProofs(bytes calldata crossChainProofs) public { + if (crossChainProofs.length == 0) { + return; + } + + IState.CrossChainProof[] memory proofs = abi.decode( + crossChainProofs, + (IState.CrossChainProof[]) + ); + StateCrossChainStorage storage $ = _getStateCrossChainStorage(); - $.processCrossChainProofs(proofs); + for (uint256 i = 0; i < proofs.length; i++) { + if (keccak256(bytes(proofs[i].proofType)) == GLOBAL_STATE_PROOF_TYPE) { + IState.GlobalStateProcessResult memory gsp = $ + ._crossChainProofValidator + .processGlobalStateProof(proofs[i].proof); + $._rootToGistRootReplacedAt[gsp.idType][gsp.root] = gsp.replacedAtTimestamp; + } else if (keccak256(bytes(proofs[i].proofType)) == STATE_PROOF_TYPE) { + IState.IdentityStateProcessResult memory isu = $ + ._crossChainProofValidator + .processIdentityStateProof(proofs[i].proof); + $._idToStateReplacedAt[isu.id][isu.state] = isu.replacedAtTimestamp; + } else { + revert UnknownProofType(); + } + } } /** @@ -140,7 +190,9 @@ contract State is Ownable2StepUpgradeable, IState { * @return defaultIdType */ function getDefaultIdType() public view returns (bytes2) { - require(_defaultIdTypeInitialized, "Default Id Type is not initialized"); + if (!_defaultIdTypeInitialized) { + revert DefaultIdTypeNotInitialized(); + } return _defaultIdType; } @@ -174,10 +226,9 @@ contract State is Ownable2StepUpgradeable, IState { // Check if the id type is supported getIdTypeIfSupported(id); uint256[4] memory input = [id, oldState, newState, uint256(isOldStateGenesis ? 1 : 0)]; - require( - verifier.verifyProof(a, b, c, input), - "Zero-knowledge proof of state transition is not valid" - ); + if (!verifier.verifyProof(a, b, c, input)) { + revert ZeroKnowledgeProofOfStateTransitionIsNotValid(); + } _transitState(id, oldState, newState, isOldStateGenesis); } @@ -202,16 +253,22 @@ contract State is Ownable2StepUpgradeable, IState { bytes2 idType = getIdTypeIfSupported(id); if (methodId == 1) { uint256 calcId = GenesisUtils.calcIdFromEthAddress(idType, msg.sender); - require(calcId == id, "msg.sender is not owner of the identity"); - require(methodParams.length == 0, "methodParams should be empty"); + if (calcId != id) { + revert SenderIsNotIdentityOwner(); + } + if (methodParams.length != 0) { + revert MethodParamsShouldBeEmpty(); + } if (isOldStateGenesis) { - require(oldState == 0, "Old state should be zero"); + if (oldState != 0) { + revert OldStateShouldBeZero(); + } } _transitState(id, oldState, newState, isOldStateGenesis); } else { - revert("Unknown state transition method id"); + revert UnknownStateTransitionMethodId(); } } @@ -446,14 +503,14 @@ contract State is Ownable2StepUpgradeable, IState { } else if (GenesisUtils.isGenesisState(id, state)) { return 0; } - revert("State entry not found"); + revert StateEntryNotFound(); } else { StateCrossChainStorage storage $ = _getStateCrossChainStorage(); uint256 replacedAt = $._idToStateReplacedAt[id][state]; if (replacedAt != 0) { return replacedAt; } - revert("Cross-chain state not found"); + revert CrossChainStateNotFound(); } } @@ -468,17 +525,39 @@ contract State is Ownable2StepUpgradeable, IState { if (_gistData.rootExists(root)) { return _gistData.getRootInfo(root).replacedAtTimestamp; } - revert("GIST root entry not found"); + revert GistRootEntryNotFound(); } else { StateCrossChainStorage storage $ = _getStateCrossChainStorage(); uint256 replacedAt = $._rootToGistRootReplacedAt[idType][root]; if (replacedAt != 0) { return replacedAt; } - revert("Cross-chain GIST root not found"); + revert CrossChainGistRootNotFound(); } } + /** + * @dev Check if the id type is supported and return the id type + * @param id Identity + * trows if id type is not supported + */ + function getIdTypeIfSupported(uint256 id) public view returns (bytes2) { + bytes2 idType = GenesisUtils.getIdType(id); + if (!_stateData.isIdTypeSupported[idType]) { + revert IdTypeNotSupported(); + } + return idType; + } + + /** + * @dev Set supported IdType setter + * @param idType id type + * @param supported ability to enable or disable id type support + */ + function setSupportedIdType(bytes2 idType, bool supported) public onlyOwner { + _stateData.isIdTypeSupported[idType] = supported; + } + /** * @dev Change the state of an identity (transit to the new state) with ZKP ownership check. * @param id Identity @@ -492,23 +571,35 @@ contract State is Ownable2StepUpgradeable, IState { uint256 newState, bool isOldStateGenesis ) internal { - require(id != 0, "ID should not be zero"); - require(newState != 0, "New state should not be zero"); + if (id == 0) { + revert IdShouldNotBeZero(); + } + if (newState == 0) { + revert NewStateShouldNotBeZero(); + } if (isOldStateGenesis) { - require(!idExists(id), "Old state is genesis but identity already exists"); + if (idExists(id)) { + revert OldStateIsGenesisButIdentityAlreadyExists(); + } // Push old state to state entries, with zero timestamp and block _stateData.addGenesisState(id, oldState); } else { - require(idExists(id), "Old state is not genesis but identity does not yet exist"); + if (!idExists(id)) { + revert OldStateIsNotGenesisButIdentityDoesNotExist(); + } StateLib.EntryInfo memory prevStateInfo = _stateData.getStateInfoById(id); - require(prevStateInfo.state == oldState, "Old state does not match the latest state"); + if (prevStateInfo.state != oldState) { + revert OldStateDoesNotMatchTheLatestState(); + } } // this checks that oldState != newState as well - require(!stateExists(id, newState), "New state already exists"); + if (stateExists(id, newState)) { + revert NewStateAlreadyExists(); + } _stateData.addState(id, newState); _gistData.addLeaf(PoseidonUnit1L.poseidon([id]), newState); } @@ -574,24 +665,4 @@ contract State is Ownable2StepUpgradeable, IState { _defaultIdTypeInitialized = true; _stateData.isIdTypeSupported[defaultIdType] = true; } - - /** - * @dev Check if the id type is supported and return the id type - * @param id Identity - * trows if id type is not supported - */ - function getIdTypeIfSupported(uint256 id) public view returns (bytes2) { - bytes2 idType = GenesisUtils.getIdType(id); - require(_stateData.isIdTypeSupported[idType], "id type is not supported"); - return idType; - } - - /** - * @dev Set supported IdType setter - * @param idType id type - * @param supported ability to enable or disable id type support - */ - function setSupportedIdType(bytes2 idType, bool supported) public onlyOwner { - _stateData.isIdTypeSupported[idType] = supported; - } } diff --git a/contracts/test-helpers/AuthValidatorStub.sol b/contracts/test-helpers/AuthValidatorStub.sol new file mode 100644 index 000000000..7e89122f8 --- /dev/null +++ b/contracts/test-helpers/AuthValidatorStub.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.27; + +import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import {IAuthValidator} from "../interfaces/IAuthValidator.sol"; + +/** + * @dev AuthValidatorStub validator + */ +contract AuthValidatorStub is IAuthValidator, ERC165 { + string public constant VERSION = "1.0.0-stub"; + + uint256 private userID; + + function version() public pure override returns (string memory) { + return VERSION; + } + + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return + interfaceId == type(IAuthValidator).interfaceId || super.supportsInterface(interfaceId); + } + + function verify( + address, + bytes calldata, + bytes calldata + ) external view override returns (uint256, AuthResponseField[] memory) { + AuthResponseField[] memory authResponseFields = new AuthResponseField[](1); + authResponseFields[0] = AuthResponseField("challenge", 1); + return (userID, authResponseFields); + } + + // solhint-disable-next-line func-name-mixedcase + function stub_setVerifyResults(uint256 _userID) external { + userID = _userID; + } +} diff --git a/contracts/test-helpers/ERC20PermitToken.sol b/contracts/test-helpers/ERC20PermitToken.sol index 209de571a..a1a8395ac 100644 --- a/contracts/test-helpers/ERC20PermitToken.sol +++ b/contracts/test-helpers/ERC20PermitToken.sol @@ -1,6 +1,6 @@ pragma solidity ^0.8.27; -import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20, ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; contract ERC20PermitToken is ERC20Permit { constructor(uint256 initialSupply) ERC20Permit("TEST") ERC20("EIP-2612 TEST", "EIP2612-TST") { diff --git a/contracts/test-helpers/ERC20Token.sol b/contracts/test-helpers/ERC20Token.sol index 69028fb82..fd326c6e3 100644 --- a/contracts/test-helpers/ERC20Token.sol +++ b/contracts/test-helpers/ERC20Token.sol @@ -1,6 +1,6 @@ pragma solidity ^0.8.27; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract ERC20Token is ERC20 { constructor(uint256 initialSupply) ERC20("ERC20Token", "TST") { diff --git a/contracts/test-helpers/EmbeddedVerifierWrapper.sol b/contracts/test-helpers/EmbeddedVerifierWrapper.sol new file mode 100644 index 000000000..38c2f153d --- /dev/null +++ b/contracts/test-helpers/EmbeddedVerifierWrapper.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.27; + +import {EmbeddedVerifier} from "../verifiers/EmbeddedVerifier.sol"; +import {IState} from "../interfaces/IState.sol"; + +contract EmbeddedVerifierWrapper is EmbeddedVerifier { + event BeforeProofSubmit(AuthResponse authResponse, Response[] responses); + event AfterProofSubmit(AuthResponse authResponse, Response[] responses); + + function initialize(address initialOwner, IState state) public initializer { + super.__EmbeddedVerifier_init(initialOwner, state); + } + + function _beforeProofSubmit( + AuthResponse memory authResponse, + Response[] memory responses + ) internal override { + emit BeforeProofSubmit(authResponse, responses); + } + + function _afterProofSubmit( + AuthResponse memory authResponse, + Response[] memory responses + ) internal override { + emit AfterProofSubmit(authResponse, responses); + } +} diff --git a/contracts/test-helpers/EmbeddedZKPVerifierWrapper.sol b/contracts/test-helpers/EmbeddedZKPVerifierWrapper.sol deleted file mode 100644 index eb3ae3d4a..000000000 --- a/contracts/test-helpers/EmbeddedZKPVerifierWrapper.sol +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; - -import {EmbeddedZKPVerifier} from "../verifiers/EmbeddedZKPVerifier.sol"; -import {IState} from "../interfaces/IState.sol"; -import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol"; -import {IZKPVerifier} from "../interfaces/IZKPVerifier.sol"; - -contract EmbeddedZKPVerifierWrapper is EmbeddedZKPVerifier { - event BeforeProofSubmit(uint64 requestId, uint256[] inputs, ICircuitValidator validator); - event AfterProofSubmit(uint64 requestId, uint256[] inputs, ICircuitValidator validator); - event BeforeProofSubmitV2(IZKPVerifier.ZKPResponse[] responses); - event AfterProofSubmitV2(IZKPVerifier.ZKPResponse[] responses); - - function initialize(address initialOwner, IState state) public initializer { - super.__EmbeddedZKPVerifier_init(initialOwner, state); - } - - function _beforeProofSubmit( - uint64 requestId, - uint256[] memory inputs, - ICircuitValidator validator - ) internal override { - emit BeforeProofSubmit(requestId, inputs, validator); - } - - function _afterProofSubmit( - uint64 requestId, - uint256[] memory inputs, - ICircuitValidator validator - ) internal override { - emit AfterProofSubmit(requestId, inputs, validator); - } - - function _beforeProofSubmitV2(IZKPVerifier.ZKPResponse[] memory responses) internal override { - emit BeforeProofSubmitV2(responses); - } - - function _afterProofSubmitV2(IZKPVerifier.ZKPResponse[] memory responses) internal override { - emit AfterProofSubmitV2(responses); - } -} diff --git a/contracts/test-helpers/Groth16VerifierValidatorStub.sol b/contracts/test-helpers/Groth16VerifierValidatorStub.sol index 91f1200dc..e5c39edd5 100644 --- a/contracts/test-helpers/Groth16VerifierValidatorStub.sol +++ b/contracts/test-helpers/Groth16VerifierValidatorStub.sol @@ -1,15 +1,26 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.27; -import {IVerifier} from "../interfaces/IVerifier.sol"; +import {IGroth16Verifier} from "../interfaces/IGroth16Verifier.sol"; + +contract Groth16VerifierValidatorStub is IGroth16Verifier { + bool private verifyResult; + + constructor() { + verifyResult = true; + } -contract Groth16VerifierValidatorStub is IVerifier { function verify( uint256[2] calldata, uint256[2][2] calldata, uint256[2] calldata, uint256[] calldata - ) external pure returns (bool r) { - return true; + ) external view returns (bool r) { + return verifyResult; + } + + // solhint-disable-next-line func-name-mixedcase + function stub_setVerifyResult(bool result) external { + verifyResult = result; } } diff --git a/contracts/test-helpers/RequestDisableableTestWrapper.sol b/contracts/test-helpers/RequestDisableableTestWrapper.sol new file mode 100644 index 000000000..1fc17ec74 --- /dev/null +++ b/contracts/test-helpers/RequestDisableableTestWrapper.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.10; + +import {RequestDisableable} from "../verifiers/RequestDisableable.sol"; +import {IState} from "../interfaces/IState.sol"; +import {IVerifier} from "../interfaces/IVerifier.sol"; + +contract RequestDisableableTestWrapper is RequestDisableable { + function initialize(IState state) public initializer { + __Verifier_init(state); + } + + function disableRequest(uint256 requestId) public { + _disableRequest(requestId); + } + + function enableRequest(uint256 requestId) public { + _enableRequest(requestId); + } + + /* solhint-disable no-empty-blocks */ + function testModifier(uint256 requestId) public view onlyEnabledRequest(requestId) {} + /* solhint-enable no-empty-blocks */ + + function getRequestIfCanBeVerified( + uint256 requestId + ) public view returns (IVerifier.RequestData memory) { + return _getRequestIfCanBeVerified(requestId); + } +} diff --git a/contracts/test-helpers/RequestOwnershipTestWrapper.sol b/contracts/test-helpers/RequestOwnershipTestWrapper.sol new file mode 100644 index 000000000..36fd588b6 --- /dev/null +++ b/contracts/test-helpers/RequestOwnershipTestWrapper.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.10; + +import {RequestOwnership} from "../verifiers/RequestOwnership.sol"; +import {IState} from "../interfaces/IState.sol"; + +contract RequestOwnershipTestWrapper is RequestOwnership { + function initialize(IState state) public initializer { + __Verifier_init(state); + } + + function setRequestOwner(uint256 requestId, address requestOwner) public { + _setRequestOwner(requestId, requestOwner); + } +} diff --git a/contracts/test-helpers/RequestValidatorStub.sol b/contracts/test-helpers/RequestValidatorStub.sol new file mode 100644 index 000000000..96c8da82c --- /dev/null +++ b/contracts/test-helpers/RequestValidatorStub.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.27; + +import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import {IRequestValidator} from "../interfaces/IRequestValidator.sol"; + +/** + * @dev RequestValidatorStub validator + */ +contract RequestValidatorStub is IRequestValidator, ERC165 { + string public constant VERSION = "1.0.0-stub"; + + mapping(bytes32 hashParams => IRequestValidator.RequestParam[] requestParams) + private requestParams; + IRequestValidator.ResponseField[] private responseFields; + mapping(string => uint256) private _requestParamNameToIndex; + mapping(string => uint256) private _inputNameToIndex; + + function version() public pure override returns (string memory) { + return VERSION; + } + + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return + interfaceId == type(IRequestValidator).interfaceId || + super.supportsInterface(interfaceId); + } + + function verify( + address, + bytes calldata, + bytes calldata, + bytes calldata + ) external view returns (IRequestValidator.ResponseField[] memory) { + return responseFields; + } + + // solhint-disable-next-line func-name-mixedcase + function stub_setVerifyResults( + IRequestValidator.ResponseField[] calldata _responseFields + ) external { + delete responseFields; + for (uint256 i = 0; i < _responseFields.length; i++) { + responseFields.push(_responseFields[i]); + } + } + + function getRequestParam( + bytes calldata params, + string memory paramName + ) external view returns (RequestParam memory) { + return requestParams[keccak256(params)][requestParamIndexOf(paramName)]; + } + + function requestParamIndexOf(string memory name) public view returns (uint256) { + uint256 index = _requestParamNameToIndex[name]; + if (index == 0) revert RequestParamNameNotFound(); + return --index; // we save 1-based index, but return 0-based + } + + function inputIndexOf(string memory name) public view returns (uint256) { + uint256 index = _inputNameToIndex[name]; + if (index == 0) { + revert InputNameNotFound(); + } + return --index; // we save 1-based index, but return 0-based + } + + // solhint-disable-next-line func-name-mixedcase + function stub_setRequestParams( + bytes[] calldata _params, + IRequestValidator.RequestParam[][] calldata _requestParams + ) external { + for (uint256 i = 0; i < _params.length; i++) { + delete requestParams[keccak256(_params[i])]; + + for (uint256 j = 0; j < _requestParams[i].length; j++) { + requestParams[keccak256(_params[i])].push(_requestParams[i][j]); + _setRequestParamToIndex(_requestParams[i][j].name, j); + } + } + } + + // solhint-disable-next-line func-name-mixedcase + function stub_setInput(string memory inputName, uint256 index) external { + _setInputToIndex(inputName, index); + } + + function _setRequestParamToIndex(string memory requestParamName, uint256 index) internal { + // increment index to avoid 0 + _requestParamNameToIndex[requestParamName] = ++index; + } + + function _setInputToIndex(string memory inputName, uint256 index) internal { + // increment index to avoid 0 + _inputNameToIndex[inputName] = ++index; + } +} diff --git a/contracts/test-helpers/ReverseHashWrapper.sol b/contracts/test-helpers/ReverseHashWrapper.sol index 6e6c223fd..d4f6228b8 100644 --- a/contracts/test-helpers/ReverseHashWrapper.sol +++ b/contracts/test-helpers/ReverseHashWrapper.sol @@ -4,6 +4,8 @@ pragma solidity 0.8.27; import {ReverseHashLib} from "../lib/ReverseHashLib.sol"; import {PoseidonUnit2L, PoseidonUnit3L} from "../lib/Poseidon.sol"; +error UnsupportedLength(); + contract ReverseHashWrapper { using ReverseHashLib for ReverseHashLib.Data; @@ -28,6 +30,6 @@ contract ReverseHashWrapper { if (preimage.length == 3) { return PoseidonUnit3L.poseidon([preimage[0], preimage[1], preimage[2]]); } - revert("Unsupported length"); + revert UnsupportedLength(); } } diff --git a/contracts/test-helpers/ValidatorStub.sol b/contracts/test-helpers/ValidatorStub.sol deleted file mode 100644 index 5a4136b4a..000000000 --- a/contracts/test-helpers/ValidatorStub.sol +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; - -import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; -import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol"; -import {IState} from "../interfaces/IState.sol"; - -/** - * @dev ValidatorStub validator - */ -contract ValidatorStub is ICircuitValidator, ERC165 { - string public constant VERSION = "2.0.2-mock"; - - string internal constant CIRCUIT_ID = "mock-stub"; - - string[] circuitIds = [CIRCUIT_ID]; - - function version() public pure override returns (string memory) { - return VERSION; - } - - function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { - return - interfaceId == type(ICircuitValidator).interfaceId || - super.supportsInterface(interfaceId); - } - - function verify( - uint256[] calldata, - uint256[2] calldata, - uint256[2][2] calldata, - uint256[2] calldata, - bytes calldata, - address - ) external pure override returns (ICircuitValidator.KeyToInputIndex[] memory) { - ICircuitValidator.KeyToInputIndex[] - memory keyToInputIndexes = new ICircuitValidator.KeyToInputIndex[](2); - keyToInputIndexes[0].key = "userID"; - keyToInputIndexes[0].inputIndex = 1; - keyToInputIndexes[1].key = "issuerID"; - keyToInputIndexes[1].inputIndex = 2; - return keyToInputIndexes; - } - - function verifyV2( - bytes calldata, - bytes calldata, - address, - IState - ) external pure override returns (ICircuitValidator.Signal[] memory) { - ICircuitValidator.Signal[] memory signals = new ICircuitValidator.Signal[](2); - signals[0].name = "userID"; - signals[0].value = 1; - signals[1].name = "issuerID"; - signals[1].value = 2; - return signals; - } - - function inputIndexOf(string memory /*name*/) external pure returns (uint256) { - return 0; - } - - function getSupportedCircuitIds() external view returns (string[] memory ids) { - return circuitIds; - } -} diff --git a/contracts/test-helpers/ValidatorWhitelistTestWrapper.sol b/contracts/test-helpers/ValidatorWhitelistTestWrapper.sol new file mode 100644 index 000000000..c32d4513e --- /dev/null +++ b/contracts/test-helpers/ValidatorWhitelistTestWrapper.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.10; + +import {ValidatorWhitelist} from "../verifiers/ValidatorWhitelist.sol"; +import {IState} from "../interfaces/IState.sol"; +import {IRequestValidator} from "../interfaces/IRequestValidator.sol"; +import {IVerifier} from "../interfaces/IVerifier.sol"; + +contract ValidatorWhitelistTestWrapper is ValidatorWhitelist { + function initialize(IState state) public initializer { + __Verifier_init(state); + } + + function addValidatorToWhitelist(IRequestValidator validator) public { + _addValidatorToWhitelist(validator); + } + + function removeValidatorFromWhitelist(IRequestValidator validator) public { + _removeValidatorFromWhitelist(validator); + } + + /* solhint-disable no-empty-blocks */ + function testModifier( + IRequestValidator validator + ) public view onlyWhitelistedValidator(validator) {} + /* solhint-enable no-empty-blocks */ + + function getRequestIfCanBeVerified( + uint256 requestId + ) public view returns (IVerifier.RequestData memory) { + return _getRequestIfCanBeVerified(requestId); + } +} diff --git a/contracts/test-helpers/VerifierTestWrapper.sol b/contracts/test-helpers/VerifierTestWrapper.sol new file mode 100644 index 000000000..7509db25a --- /dev/null +++ b/contracts/test-helpers/VerifierTestWrapper.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.10; + +import {Verifier} from "../verifiers/Verifier.sol"; +import {IState} from "../interfaces/IState.sol"; + +contract VerifierTestWrapper is Verifier { + function initialize(IState state) public initializer { + __Verifier_init(state); + } + + function setVerifierID(uint256 verifierID) public { + _setVerifierID(verifierID); + } +} diff --git a/contracts/validators/AuthV2Validator.sol b/contracts/validators/AuthV2Validator.sol deleted file mode 100644 index 46ecdf0b3..000000000 --- a/contracts/validators/AuthV2Validator.sol +++ /dev/null @@ -1,138 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; - -import {CredentialAtomicQueryValidatorBase} from "./CredentialAtomicQueryValidatorBase.sol"; -import {IVerifier} from "../interfaces/IVerifier.sol"; -import {GenesisUtils} from "../lib/GenesisUtils.sol"; -import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol"; -import {IState} from "../interfaces/IState.sol"; - -/** - * @dev AuthV2Validator validator - */ -contract AuthV2Validator is CredentialAtomicQueryValidatorBase { - struct PubSignals { - uint256 userID; - uint256 challenge; - uint256 gistRoot; - } - - /** - * @dev Version of contract - */ - string public constant VERSION = "1.0.0"; - - string internal constant CIRCUIT_ID = "authV2"; - - /** - * @dev Initialize the contract - * @param _verifierContractAddr Address of the verifier contract - * @param _stateContractAddr Address of the state contract - * @param owner Owner of the contract - */ - function initialize( - address _verifierContractAddr, - address _stateContractAddr, - address owner - ) public initializer { - _setInputToIndex("userID", 0); - _setInputToIndex("challenge", 1); - _setInputToIndex("gistRoot", 2); - - _initDefaultStateVariables(_stateContractAddr, _verifierContractAddr, CIRCUIT_ID, owner); - } - - /** - * @dev Get the version of the contract - * @return Version of the contract - */ - function version() public pure override returns (string memory) { - return VERSION; - } - - /** - * @dev Parse the public signals - * @param inputs Array of public inputs - * @return Parsed public signals - */ - function parsePubSignals(uint256[] memory inputs) public pure returns (PubSignals memory) { - PubSignals memory pubSignals = PubSignals({ - userID: inputs[0], - challenge: inputs[1], - gistRoot: inputs[2] - }); - - return pubSignals; - } - - /** - * @dev Verify the groth16 proof and check the request query data - * @param inputs Public inputs of the circuit. - * @param a πa element of the groth16 proof. - * @param b πb element of the groth16 proof. - * @param c πc element of the groth16 proof. - * @param data Request query data of the credential to verify. - * @param sender Sender of the proof. - * @return Array of key to public input index as result. - */ - function verify( - // solhint-disable-next-line no-unused-vars - uint256[] memory inputs, - // solhint-disable-next-line no-unused-vars - uint256[2] memory a, - // solhint-disable-next-line no-unused-vars - uint256[2][2] memory b, - // solhint-disable-next-line no-unused-vars - uint256[2] memory c, - // solhint-disable-next-line no-unused-vars - bytes calldata data, - // solhint-disable-next-line no-unused-vars - address sender - ) public view override returns (ICircuitValidator.KeyToInputIndex[] memory) { - revert("function not supported in this contract"); - } - - /** - * @dev Verify the groth16 proof and check the request query data - * @param zkProof Proof packed as bytes to verify. - * @param data Request query data of the credential to verify. - * @param sender Sender of the proof. - * @param stateContract State contract to get identities and gist states to check. - * @return Array of public signals as result. - */ - function verifyV2( - bytes calldata zkProof, - // solhint-disable-next-line no-unused-vars - bytes calldata data, - address sender, - IState stateContract - ) public view override returns (ICircuitValidator.Signal[] memory) { - ( - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c - ) = abi.decode(zkProof, (uint256[], uint256[2], uint256[2][2], uint256[2])); - - PubSignals memory pubSignals = parsePubSignals(inputs); - _checkGistRoot(pubSignals.userID, pubSignals.gistRoot, stateContract); - _checkChallenge(pubSignals.challenge, sender); - _verifyZKP(inputs, a, b, c); - ICircuitValidator.Signal[] memory signals = new ICircuitValidator.Signal[](1); - signals[0] = ICircuitValidator.Signal({name: "userID", value: pubSignals.userID}); - return signals; - } - - function _verifyZKP( - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c - ) internal view { - IVerifier verifier = getVerifierByCircuitId(CIRCUIT_ID); - require(verifier != IVerifier(address(0)), "Verifier address should not be zero"); - - // verify that zkp is valid - require(verifier.verify(a, b, c, inputs), "Proof is not valid"); - } -} diff --git a/contracts/validators/CredentialAtomicQueryV2ValidatorBase.sol b/contracts/validators/CredentialAtomicQueryV2ValidatorBase.sol deleted file mode 100644 index a307062bf..000000000 --- a/contracts/validators/CredentialAtomicQueryV2ValidatorBase.sol +++ /dev/null @@ -1,217 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; - -import {CredentialAtomicQueryValidatorBase} from "./CredentialAtomicQueryValidatorBase.sol"; -import {IVerifier} from "../interfaces/IVerifier.sol"; -import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol"; -import {IState} from "../interfaces/IState.sol"; - -/** - * @dev Base contract for credential atomic query v2 validators circuits. - */ -abstract contract CredentialAtomicQueryV2ValidatorBase is CredentialAtomicQueryValidatorBase { - /** - * @dev Version of contract - */ - - struct CredentialAtomicQuery { - uint256 schema; - uint256 claimPathKey; - uint256 operator; - uint256 slotIndex; - uint256[] value; - uint256 queryHash; - uint256[] allowedIssuers; - string[] circuitIds; - bool skipClaimRevocationCheck; - // 0 for inclusion in merklized credentials, 1 for non-inclusion and for non-merklized credentials - uint256 claimPathNotExists; - } - - struct PubSignals { - uint256 merklized; - uint256 userID; - uint256 issuerState; - uint256 circuitQueryHash; - uint256 requestID; - uint256 challenge; - uint256 gistRoot; - uint256 issuerID; - uint256 isRevocationChecked; - uint256 issuerClaimNonRevState; - uint256 timestamp; - } - - /** - * @dev Get the version of the contract - * @return Version of the contract - */ - function version() public pure virtual override returns (string memory); - - /** - * @dev Parse the public signals - * @param inputs Array of public inputs - * @return Parsed public signals - */ - function parsePubSignals( - uint256[] memory inputs - ) public pure virtual returns (PubSignals memory); - - /** - * @dev Verify the groth16 proof and check the request query data - * @param inputs Public inputs of the circuit. - * @param a πa element of the groth16 proof. - * @param b πb element of the groth16 proof. - * @param c πc element of the groth16 proof. - * @param data Request query data of the credential to verify. - * @param sender Sender of the proof. - * @return Array of key to public input index as result. - */ - function verify( - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c, - bytes calldata data, - address sender - ) public view override returns (ICircuitValidator.KeyToInputIndex[] memory) { - _verifyMain(inputs, a, b, c, data, sender, IState(getStateAddress())); - - return _getSpecialInputIndexes(); - } - - /** - * @dev Verify the groth16 proof and check the request query data - * @param zkProof Proof packed as bytes to verify. - * @param data Request query data of the credential to verify. - * @param sender Sender of the proof. - * @param stateContract State contract to get identities and gist states to check. - * @return Array of public signals as result. - */ - function verifyV2( - bytes calldata zkProof, - bytes calldata data, - address sender, - IState stateContract - ) public view override returns (ICircuitValidator.Signal[] memory) { - ( - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c - ) = abi.decode(zkProof, (uint256[], uint256[2], uint256[2][2], uint256[2])); - - PubSignals memory pubSignals = _verifyMain(inputs, a, b, c, data, sender, stateContract); - return _getSpecialSignals(pubSignals); - } - - /** - * @dev Verify the groth16 proof and check the request query data - * @param inputs Public inputs of the circuit. - * @param a πa element of the groth16 proof. - * @param b πb element of the groth16 proof. - * @param c πc element of the groth16 proof. - * @param data Request query data of the credential to verify. - * @param sender Sender of the proof. - * @param state State contract to get identities and gist states to check. - */ - function _verifyMain( - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c, - bytes calldata data, - address sender, - IState state - ) internal view returns (PubSignals memory) { - CredentialAtomicQuery memory credAtomicQuery = abi.decode(data, (CredentialAtomicQuery)); - - require(credAtomicQuery.circuitIds.length == 1, "circuitIds length is not equal to 1"); - - IVerifier verifier = getVerifierByCircuitId(credAtomicQuery.circuitIds[0]); - - require(verifier != IVerifier(address(0)), "Verifier address should not be zero"); - - // verify that zkp is valid - require(verifier.verify(a, b, c, inputs), "Proof is not valid"); - - PubSignals memory pubSignals = parsePubSignals(inputs); - - // check circuitQueryHash - require( - pubSignals.circuitQueryHash == credAtomicQuery.queryHash, - "Query hash does not match the requested one" - ); - - // TODO: add support for query to specific userID and then verifying it - - _checkMerklized(pubSignals.merklized, credAtomicQuery.claimPathKey); - _checkAllowedIssuers(pubSignals.issuerID, credAtomicQuery.allowedIssuers); - _checkProofExpiration(pubSignals.timestamp); - _checkIsRevocationChecked( - pubSignals.isRevocationChecked, - credAtomicQuery.skipClaimRevocationCheck - ); - - // Checking challenge to prevent replay attacks from other addresses - _checkChallenge(pubSignals.challenge, sender); - - // GIST root and state checks - _checkGistRoot(pubSignals.userID, pubSignals.gistRoot, state); - _checkClaimIssuanceState(pubSignals.issuerID, pubSignals.issuerState, state); - _checkClaimNonRevState(pubSignals.issuerID, pubSignals.issuerClaimNonRevState, state); - - return pubSignals; - } - - function _checkMerklized(uint256 merklized, uint256 queryClaimPathKey) internal pure { - uint256 shouldBeMerklized = queryClaimPathKey != 0 ? 1 : 0; - require(merklized == shouldBeMerklized, "Merklized value is not correct"); - } - - function _checkIsRevocationChecked( - uint256 isRevocationChecked, - bool skipClaimRevocationCheck - ) internal pure { - uint256 expectedIsRevocationChecked = 1; - if (skipClaimRevocationCheck) { - expectedIsRevocationChecked = 0; - } - require( - isRevocationChecked == expectedIsRevocationChecked, - "Revocation check should match the query" - ); - } - - function _getSpecialSignals( - PubSignals memory pubSignals - ) internal pure returns (ICircuitValidator.Signal[] memory) { - ICircuitValidator.Signal[] memory signals = new ICircuitValidator.Signal[](3); - signals[0] = ICircuitValidator.Signal({name: "userID", value: pubSignals.userID}); - signals[1] = ICircuitValidator.Signal({name: "timestamp", value: pubSignals.timestamp}); - signals[2] = ICircuitValidator.Signal({name: "issuerID", value: pubSignals.issuerID}); - return signals; - } - - function _getSpecialInputIndexes() - internal - view - returns (ICircuitValidator.KeyToInputIndex[] memory) - { - ICircuitValidator.KeyToInputIndex[] - memory keyToInputIndexes = new ICircuitValidator.KeyToInputIndex[](3); - keyToInputIndexes[0] = ICircuitValidator.KeyToInputIndex({ - key: "userID", - inputIndex: inputIndexOf("userID") - }); - keyToInputIndexes[1] = ICircuitValidator.KeyToInputIndex({ - key: "timestamp", - inputIndex: inputIndexOf("timestamp") - }); - keyToInputIndexes[2] = ICircuitValidator.KeyToInputIndex({ - key: "issuerID", - inputIndex: inputIndexOf("issuerID") - }); - return keyToInputIndexes; - } -} diff --git a/contracts/validators/CredentialAtomicQueryV3Validator.sol b/contracts/validators/CredentialAtomicQueryV3Validator.sol deleted file mode 100644 index c704ee2b6..000000000 --- a/contracts/validators/CredentialAtomicQueryV3Validator.sol +++ /dev/null @@ -1,335 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; - -import {CredentialAtomicQueryValidatorBase} from "./CredentialAtomicQueryValidatorBase.sol"; -import {IVerifier} from "../interfaces/IVerifier.sol"; -import {GenesisUtils} from "../lib/GenesisUtils.sol"; -import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol"; -import {IState} from "../interfaces/IState.sol"; - -/** - * @dev CredentialAtomicQueryV3 validator - */ -contract CredentialAtomicQueryV3Validator is CredentialAtomicQueryValidatorBase { - struct CredentialAtomicQueryV3 { - uint256 schema; - uint256 claimPathKey; - uint256 operator; - uint256 slotIndex; - uint256[] value; - uint256 queryHash; - uint256[] allowedIssuers; - string[] circuitIds; - bool skipClaimRevocationCheck; - uint256 groupID; - uint256 nullifierSessionID; - uint256 proofType; - uint256 verifierID; - } - - struct PubSignals { - uint256 linkID; - uint256 nullifier; - uint256 operatorOutput; - uint256 proofType; - uint256 isBJJAuthEnabled; - uint256 userID; - uint256 issuerState; - uint256 circuitQueryHash; - uint256 requestID; - uint256 challenge; - uint256 gistRoot; - uint256 issuerID; - uint256 issuerClaimNonRevState; - uint256 timestamp; - } - - /** - * @dev Version of contract - */ - string public constant VERSION = "2.1.1-beta.1"; - - string internal constant CIRCUIT_ID = "credentialAtomicQueryV3OnChain-beta.1"; - - /** - * @dev Initialize the contract - * @param _verifierContractAddr Address of the verifier contract - * @param _stateContractAddr Address of the state contract - * @param owner Owner of the contract - */ - function initialize( - address _verifierContractAddr, - address _stateContractAddr, - address owner - ) public initializer { - _setInputToIndex("userID", 0); - _setInputToIndex("circuitQueryHash", 1); - _setInputToIndex("issuerState", 2); - _setInputToIndex("linkID", 3); - _setInputToIndex("nullifier", 4); - _setInputToIndex("operatorOutput", 5); - _setInputToIndex("proofType", 6); - _setInputToIndex("requestID", 7); - _setInputToIndex("challenge", 8); - _setInputToIndex("gistRoot", 9); - _setInputToIndex("issuerID", 10); - _setInputToIndex("issuerClaimNonRevState", 11); - _setInputToIndex("timestamp", 12); - _setInputToIndex("isBJJAuthEnabled", 13); - - _initDefaultStateVariables(_stateContractAddr, _verifierContractAddr, CIRCUIT_ID, owner); - } - - /** - * @dev Get the version of the contract - * @return Version of the contract - */ - function version() public pure override returns (string memory) { - return VERSION; - } - - /** - * @dev Parse the public signals - * @param inputs Array of public inputs - * @return Parsed public signals - */ - function parsePubSignals(uint256[] memory inputs) public pure returns (PubSignals memory) { - PubSignals memory pubSignals = PubSignals({ - userID: inputs[0], - circuitQueryHash: inputs[1], - issuerState: inputs[2], - linkID: inputs[3], - nullifier: inputs[4], - operatorOutput: inputs[5], - proofType: inputs[6], - requestID: inputs[7], - challenge: inputs[8], - gistRoot: inputs[9], - issuerID: inputs[10], - issuerClaimNonRevState: inputs[11], - timestamp: inputs[12], - isBJJAuthEnabled: inputs[13] - }); - - return pubSignals; - } - - /** - * @dev Verify the groth16 proof and check the request query data - * @param inputs Public inputs of the circuit. - * @param a πa element of the groth16 proof. - * @param b πb element of the groth16 proof. - * @param c πc element of the groth16 proof. - * @param data Request query data of the credential to verify. - * @param sender Sender of the proof. - * @return Array of key to public input index as result. - */ - function verify( - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c, - bytes calldata data, - address sender - ) public view override returns (ICircuitValidator.KeyToInputIndex[] memory) { - (, bool hasSD) = _verifyMain(inputs, a, b, c, data, sender, IState(getStateAddress())); - - return _getSpecialInputIndexes(hasSD); - } - - /** - * @dev Verify the groth16 proof and check the request query data - * @param zkProof Proof packed as bytes to verify. - * @param data Request query data of the credential to verify. - * @param sender Sender of the proof. - * @param stateContract State contract to get identities and gist states to check. - * @return Array of public signals as result. - */ - function verifyV2( - bytes calldata zkProof, - bytes calldata data, - address sender, - IState stateContract - ) public view override returns (ICircuitValidator.Signal[] memory) { - ( - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c - ) = abi.decode(zkProof, (uint256[], uint256[2], uint256[2][2], uint256[2])); - - (PubSignals memory pubSignals, bool hasSD) = _verifyMain( - inputs, - a, - b, - c, - data, - sender, - stateContract - ); - return _getSpecialSignals(pubSignals, hasSD); - } - - /** - * @dev Verify the groth16 proof and check the request query data - * @param inputs Public inputs of the circuit. - * @param a πa element of the groth16 proof. - * @param b πb element of the groth16 proof. - * @param c πc element of the groth16 proof. - * @param data Request query data of the credential to verify. - * @param sender Sender of the proof. - * @param state State contract to get identities and gist states to check. - */ - function _verifyMain( - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c, - bytes calldata data, - address sender, - IState state - ) internal view returns (PubSignals memory, bool) { - CredentialAtomicQueryV3 memory credAtomicQuery = abi.decode( - data, - (CredentialAtomicQueryV3) - ); - - _verifyZKP(inputs, a, b, c, credAtomicQuery); - - PubSignals memory pubSignals = parsePubSignals(inputs); - - _checkAllowedIssuers(pubSignals.issuerID, credAtomicQuery.allowedIssuers); - _checkProofExpiration(pubSignals.timestamp); - - _checkLinkID(credAtomicQuery.groupID, pubSignals.linkID); - _checkProofType(credAtomicQuery.proofType, pubSignals.proofType); - _checkNullify(pubSignals.nullifier, credAtomicQuery.nullifierSessionID); - - // GIST root and state checks - _checkClaimIssuanceState(pubSignals.issuerID, pubSignals.issuerState, state); - _checkClaimNonRevState(pubSignals.issuerID, pubSignals.issuerClaimNonRevState, state); - if (pubSignals.isBJJAuthEnabled == 1) { - _checkGistRoot(pubSignals.userID, pubSignals.gistRoot, state); - } else { - _checkAuth(pubSignals.userID, sender); - } - - // Checking challenge to prevent replay attacks from other addresses - _checkChallenge(pubSignals.challenge, sender); - - // check circuitQueryHash - require( - pubSignals.circuitQueryHash == credAtomicQuery.queryHash, - "Query hash does not match the requested one" - ); - - // if operator == 16 then we have selective disclosure - return (pubSignals, credAtomicQuery.operator == 16); - } - - function _verifyZKP( - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c, - CredentialAtomicQueryV3 memory credAtomicQuery - ) internal view { - require(credAtomicQuery.circuitIds.length == 1, "circuitIds length is not equal to 1"); - - IVerifier verifier = getVerifierByCircuitId(credAtomicQuery.circuitIds[0]); - require(verifier != IVerifier(address(0)), "Verifier address should not be zero"); - - // verify that zkp is valid - require(verifier.verify(a, b, c, inputs), "Proof is not valid"); - } - - function _checkLinkID(uint256 groupID, uint256 linkID) internal pure { - require( - (groupID == 0 && linkID == 0) || (groupID != 0 && linkID != 0), - "Invalid Link ID pub signal" - ); - } - - function _checkProofType(uint256 queryProofType, uint256 pubSignalProofType) internal pure { - require( - queryProofType == 0 || queryProofType == pubSignalProofType, - "Proof type should match the requested one in query" - ); - } - - function _checkNullify(uint256 nullifier, uint256 nullifierSessionID) internal pure { - require(nullifierSessionID == 0 || nullifier != 0, "Invalid nullify pub signal"); - } - - function _checkAuth(uint256 userID, address ethIdentityOwner) internal view { - require( - userID == - GenesisUtils.calcIdFromEthAddress( - _getState().getIdTypeIfSupported(userID), - ethIdentityOwner - ), - "UserID does not correspond to the sender" - ); - } - - function _getSpecialSignals( - PubSignals memory pubSignals, - bool hasSelectiveDisclosure - ) internal pure returns (ICircuitValidator.Signal[] memory) { - uint256 numSignals = hasSelectiveDisclosure ? 6 : 5; - ICircuitValidator.Signal[] memory signals = new ICircuitValidator.Signal[](numSignals); - - uint i = 0; - signals[i++] = ICircuitValidator.Signal({name: "userID", value: pubSignals.userID}); - signals[i++] = ICircuitValidator.Signal({name: "linkID", value: pubSignals.linkID}); - signals[i++] = ICircuitValidator.Signal({name: "nullifier", value: pubSignals.nullifier}); - if (hasSelectiveDisclosure) { - signals[i++] = ICircuitValidator.Signal({ - name: "operatorOutput", - value: pubSignals.operatorOutput - }); - } - signals[i++] = ICircuitValidator.Signal({name: "timestamp", value: pubSignals.timestamp}); - signals[i++] = ICircuitValidator.Signal({name: "issuerID", value: pubSignals.issuerID}); - - return signals; - } - - function _getSpecialInputIndexes( - bool hasSelectiveDisclosure - ) internal view returns (ICircuitValidator.KeyToInputIndex[] memory) { - uint256 numSignals = hasSelectiveDisclosure ? 6 : 5; - ICircuitValidator.KeyToInputIndex[] - memory keyToInputIndexes = new ICircuitValidator.KeyToInputIndex[](numSignals); - - uint i = 0; - keyToInputIndexes[i++] = ICircuitValidator.KeyToInputIndex({ - key: "userID", - inputIndex: inputIndexOf("userID") - }); - keyToInputIndexes[i++] = ICircuitValidator.KeyToInputIndex({ - key: "linkID", - inputIndex: inputIndexOf("linkID") - }); - keyToInputIndexes[i++] = ICircuitValidator.KeyToInputIndex({ - key: "nullifier", - inputIndex: inputIndexOf("nullifier") - }); - if (hasSelectiveDisclosure) { - keyToInputIndexes[i++] = ICircuitValidator.KeyToInputIndex({ - key: "operatorOutput", - inputIndex: inputIndexOf("operatorOutput") - }); - } - keyToInputIndexes[i++] = ICircuitValidator.KeyToInputIndex({ - key: "timestamp", - inputIndex: inputIndexOf("timestamp") - }); - keyToInputIndexes[i++] = ICircuitValidator.KeyToInputIndex({ - key: "issuerID", - inputIndex: inputIndexOf("issuerID") - }); - - return keyToInputIndexes; - } -} diff --git a/contracts/validators/auth/AuthV2Validator.sol b/contracts/validators/auth/AuthV2Validator.sol new file mode 100644 index 000000000..70c3d884f --- /dev/null +++ b/contracts/validators/auth/AuthV2Validator.sol @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.27; + +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; +import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import {IGroth16Verifier} from "../../interfaces/IGroth16Verifier.sol"; +import {GenesisUtils} from "../../lib/GenesisUtils.sol"; +import {IAuthValidator} from "../../interfaces/IAuthValidator.sol"; +import {IState} from "../../interfaces/IState.sol"; + +error VerifierAddressShouldNotBeZero(); +error ProofIsNotValid(); +error GistRootIsExpired(); + +/** + * @dev AuthV2 validator for auth + */ +contract AuthV2Validator is Ownable2StepUpgradeable, IAuthValidator, ERC165 { + struct PubSignals { + uint256 userID; + uint256 challenge; + uint256 gistRoot; + } + + /** + * @dev Version of contract + */ + string public constant VERSION = "1.0.0"; + + string internal constant CIRCUIT_ID = "authV2"; + + /// @dev Main storage structure for the contract + /// @custom:storage-location iden3.storage.AuthV2Validator + struct AuthV2ValidatorStorage { + mapping(string => IGroth16Verifier) _circuitIdToVerifier; + string[] _supportedCircuitIds; + IState state; + uint256 revocationStateExpirationTimeout; + uint256 proofExpirationTimeout; + uint256 gistRootExpirationTimeout; + mapping(string => uint256) _inputNameToIndex; + } + + // keccak256(abi.encode(uint256(keccak256("iden3.storage.AuthV2Validator")) - 1)) + // & ~bytes32(uint256(0xff)); + // solhint-disable-next-line const-name-snakecase + bytes32 private constant AuthV2ValidatorStorageLocation = + 0x5212d71c1540b1d75013e45246a2b44f2ee9363a102ea02fac1792932b691600; + + /// @dev Get the main storage using assembly to ensure specific storage location + function _getAuthV2ValidatorStorage() private pure returns (AuthV2ValidatorStorage storage $) { + // solhint-disable-next-line no-inline-assembly + assembly { + $.slot := AuthV2ValidatorStorageLocation + } + } + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /** + * @dev Initialize the contract + * @param _stateContractAddr Address of the state contract + * @param _verifierContractAddr Address of the verifier contract + * @param owner Owner of the contract + */ + function initialize( + address _stateContractAddr, + address _verifierContractAddr, + address owner + ) public initializer { + _initDefaultStateVariables(_stateContractAddr, _verifierContractAddr, CIRCUIT_ID, owner); + } + + /** + * @dev Get the version of the contract + * @return Version of the contract + */ + function version() public pure override returns (string memory) { + return VERSION; + } + + /** + * @dev Parse the public signals + * @param inputs Array of public inputs + * @return Parsed public signals + */ + function parsePubSignals(uint256[] memory inputs) public pure returns (PubSignals memory) { + PubSignals memory pubSignals = PubSignals({ + userID: inputs[0], + challenge: inputs[1], + gistRoot: inputs[2] + }); + + return pubSignals; + } + + /** + * @dev Verify the groth16 proof and check the request query data + * @param sender Sender of the proof. + * @param proof Proof packed as bytes to verify. + * @param params Request query data of the credential to verify. + * @return userID user ID of public signals as result. + */ + function verify( + // solhint-disable-next-line no-unused-vars + address sender, + bytes calldata proof, + // solhint-disable-next-line no-unused-vars + bytes calldata params + ) public view override returns (uint256 userID, AuthResponseField[] memory) { + ( + uint256[] memory inputs, + uint256[2] memory a, + uint256[2][2] memory b, + uint256[2] memory c + ) = abi.decode(proof, (uint256[], uint256[2], uint256[2][2], uint256[2])); + + PubSignals memory pubSignals = parsePubSignals(inputs); + _checkGistRoot(pubSignals.userID, pubSignals.gistRoot); + _verifyZKP(inputs, a, b, c); + + AuthResponseField[] memory authResponseFields = new AuthResponseField[](1); + authResponseFields[0] = AuthResponseField("challenge", pubSignals.challenge); + return (pubSignals.userID, authResponseFields); + } + + /** + * @dev Get the verifier by circuit id + * @param circuitId Circuit id + * @return The verifier + */ + function getVerifierByCircuitId( + string memory circuitId + ) public view virtual returns (IGroth16Verifier) { + return _getAuthV2ValidatorStorage()._circuitIdToVerifier[circuitId]; + } + + /** + * @dev Set the expiration timeout for the revocation state + * @param expirationTimeout The expiration timeout for the revocation state + */ + function setRevocationStateExpirationTimeout( + uint256 expirationTimeout + ) public virtual onlyOwner { + _getAuthV2ValidatorStorage().revocationStateExpirationTimeout = expirationTimeout; + } + + /** + * @dev Get the expiration timeout for the revocation state + * @return The expiration timeout for the revocation state + */ + function getRevocationStateExpirationTimeout() public view virtual returns (uint256) { + return _getAuthV2ValidatorStorage().revocationStateExpirationTimeout; + } + + /** + * @dev Set the expiration timeout for the proof + * @param expirationTimeout The expiration timeout for the proof + */ + function setProofExpirationTimeout(uint256 expirationTimeout) public virtual onlyOwner { + _getAuthV2ValidatorStorage().proofExpirationTimeout = expirationTimeout; + } + + /** + * @dev Get the expiration timeout for the proof + * @return The expiration timeout for the proof + */ + function getProofExpirationTimeout() public view virtual returns (uint256) { + return _getAuthV2ValidatorStorage().proofExpirationTimeout; + } + + /** + * @dev Set the expiration timeout for the gist root + * @param expirationTimeout The expiration timeout for the gist root + */ + function setGISTRootExpirationTimeout(uint256 expirationTimeout) public virtual onlyOwner { + _getAuthV2ValidatorStorage().gistRootExpirationTimeout = expirationTimeout; + } + + /** + * @dev Get the expiration timeout for the gist root + * @return The expiration timeout for the gist root + */ + function getGISTRootExpirationTimeout() public view virtual returns (uint256) { + return _getAuthV2ValidatorStorage().gistRootExpirationTimeout; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return + interfaceId == type(IAuthValidator).interfaceId || super.supportsInterface(interfaceId); + } + + function _initDefaultStateVariables( + address _stateContractAddr, + address _verifierContractAddr, + string memory circuitId, + address owner + ) internal { + AuthV2ValidatorStorage storage s = _getAuthV2ValidatorStorage(); + + s.revocationStateExpirationTimeout = 1 hours; + s.proofExpirationTimeout = 1 hours; + s.gistRootExpirationTimeout = 1 hours; + s._supportedCircuitIds = [circuitId]; + s._circuitIdToVerifier[circuitId] = IGroth16Verifier(_verifierContractAddr); + s.state = IState(_stateContractAddr); + __Ownable_init(owner); + } + + function _getState() internal view returns (IState) { + return _getAuthV2ValidatorStorage().state; + } + + function _checkGistRoot(uint256 _id, uint256 _gistRoot) internal view { + AuthV2ValidatorStorage storage $ = _getAuthV2ValidatorStorage(); + bytes2 idType = GenesisUtils.getIdType(_id); + uint256 replacedAt = _getState().getGistRootReplacedAt(idType, _gistRoot); + + if (replacedAt != 0 && block.timestamp > $.gistRootExpirationTimeout + replacedAt) { + revert GistRootIsExpired(); + } + } + + function _verifyZKP( + uint256[] memory inputs, + uint256[2] memory a, + uint256[2][2] memory b, + uint256[2] memory c + ) internal view { + IGroth16Verifier g16Verifier = getVerifierByCircuitId(CIRCUIT_ID); + if (g16Verifier == IGroth16Verifier(address(0))) { + revert VerifierAddressShouldNotBeZero(); + } + + // verify that zkp is valid + if (!g16Verifier.verify(a, b, c, inputs)) { + revert ProofIsNotValid(); + } + } +} diff --git a/contracts/validators/auth/EthIdentityValidator.sol b/contracts/validators/auth/EthIdentityValidator.sol new file mode 100644 index 000000000..b6cf49087 --- /dev/null +++ b/contracts/validators/auth/EthIdentityValidator.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.27; + +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; +import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import {GenesisUtils} from "../../lib/GenesisUtils.sol"; +import {IAuthValidator} from "../../interfaces/IAuthValidator.sol"; +import {IState} from "../../interfaces/IState.sol"; + +error SenderIsNotIdentityOwner(); + +/** + * @dev EthIdentityValidator validator + */ +contract EthIdentityValidator is Ownable2StepUpgradeable, IAuthValidator, ERC165 { + struct PubSignals { + uint256 userID; + } + + /** + * @dev Version of contract + */ + string public constant VERSION = "1.0.0"; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /** + * @dev Initialize the contract + * @param owner Owner of the contract + */ + function initialize(address owner) public initializer { + __Ownable_init(owner); + } + + /** + * @dev Get the version of the contract + * @return Version of the contract + */ + function version() public pure override returns (string memory) { + return VERSION; + } + + /** + * @dev Verify the proof and check the request query data + * @param sender Sender of the proof. + * @param proof Proof packed as bytes to verify. + * @param params Request query data of the credential to verify. + * @return Array of signals as result. + */ + function verify( + address sender, + bytes calldata proof, + // solhint-disable-next-line no-unused-vars + bytes calldata params + ) public view override returns (uint256, AuthResponseField[] memory) { + uint256 userID = abi.decode(proof, (uint256)); + + _verifyEthIdentity(userID, sender); + return (userID, new AuthResponseField[](0)); + } + + function _verifyEthIdentity(uint256 id, address sender) internal view { + bytes2 idType = GenesisUtils.getIdType(id); + uint256 calcId = GenesisUtils.calcIdFromEthAddress(idType, sender); + if (calcId != id) { + revert SenderIsNotIdentityOwner(); + } + } +} diff --git a/contracts/validators/CredentialAtomicQueryMTPV2Validator.sol b/contracts/validators/request/CredentialAtomicQueryMTPV2Validator.sol similarity index 98% rename from contracts/validators/CredentialAtomicQueryMTPV2Validator.sol rename to contracts/validators/request/CredentialAtomicQueryMTPV2Validator.sol index 03dd5334c..fd6d43267 100644 --- a/contracts/validators/CredentialAtomicQueryMTPV2Validator.sol +++ b/contracts/validators/request/CredentialAtomicQueryMTPV2Validator.sol @@ -10,19 +10,19 @@ contract CredentialAtomicQueryMTPV2Validator is CredentialAtomicQueryV2Validator /** * @dev Version of contract */ - string public constant VERSION = "2.1.1"; + string public constant VERSION = "3.0.0"; string internal constant CIRCUIT_ID = "credentialAtomicQueryMTPV2OnChain"; /** * @dev Initialize the contract - * @param _verifierContractAddr Address of the verifier contract * @param _stateContractAddr Address of the state contract + * @param _verifierContractAddr Address of the verifier contract * @param owner Owner of the contract */ function initialize( - address _verifierContractAddr, address _stateContractAddr, + address _verifierContractAddr, address owner ) public initializer { _setInputToIndex("merklized", 0); diff --git a/contracts/validators/CredentialAtomicQuerySigV2Validator.sol b/contracts/validators/request/CredentialAtomicQuerySigV2Validator.sol similarity index 89% rename from contracts/validators/CredentialAtomicQuerySigV2Validator.sol rename to contracts/validators/request/CredentialAtomicQuerySigV2Validator.sol index 97f69ba4f..84e9d892c 100644 --- a/contracts/validators/CredentialAtomicQuerySigV2Validator.sol +++ b/contracts/validators/request/CredentialAtomicQuerySigV2Validator.sol @@ -10,19 +10,19 @@ contract CredentialAtomicQuerySigV2Validator is CredentialAtomicQueryV2Validator /** * @dev Version of contract */ - string public constant VERSION = "2.1.1"; + string public constant VERSION = "3.0.0"; string internal constant CIRCUIT_ID = "credentialAtomicQuerySigV2OnChain"; /** * @dev Initialize the contract + * @param _stateContractAddress Address of the state contract * @param _verifierContractAddr Address of the verifier contract - * @param _stateContractAddr Address of the state contract * @param owner Owner of the contract */ function initialize( + address _stateContractAddress, address _verifierContractAddr, - address _stateContractAddr, address owner ) public initializer { _setInputToIndex("merklized", 0); @@ -37,7 +37,7 @@ contract CredentialAtomicQuerySigV2Validator is CredentialAtomicQueryV2Validator _setInputToIndex("issuerClaimNonRevState", 9); _setInputToIndex("timestamp", 10); - _initDefaultStateVariables(_stateContractAddr, _verifierContractAddr, CIRCUIT_ID, owner); + _initDefaultStateVariables(_stateContractAddress, _verifierContractAddr, CIRCUIT_ID, owner); } /** diff --git a/contracts/validators/request/CredentialAtomicQueryV2ValidatorBase.sol b/contracts/validators/request/CredentialAtomicQueryV2ValidatorBase.sol new file mode 100644 index 000000000..8f01a3525 --- /dev/null +++ b/contracts/validators/request/CredentialAtomicQueryV2ValidatorBase.sol @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.27; + +import {CredentialAtomicQueryValidatorBase} from "./CredentialAtomicQueryValidatorBase.sol"; +import {IGroth16Verifier} from "../../interfaces/IGroth16Verifier.sol"; +import {IRequestValidator} from "../../interfaces/IRequestValidator.sol"; + +error CircuitsLengthShouldBeOne(); +error VerifierAddressShouldNotBeZero(); +error ProofIsNotValid(); +error QueryHashDoesNotMatchTheRequestedOne(uint256 expected, uint256 actual); +error MerklizedValueIsNotCorrect(); +error RevocationCheckShouldMatchTheQuery(uint256 expected, uint256 actual); + +/** + * @dev Base contract for credential atomic query v2 validators circuits. + */ +abstract contract CredentialAtomicQueryV2ValidatorBase is CredentialAtomicQueryValidatorBase { + /** + * @dev Version of contract + */ + + struct CredentialAtomicQuery { + uint256 schema; + uint256 claimPathKey; + uint256 operator; + uint256 slotIndex; + uint256[] value; + uint256 queryHash; + uint256[] allowedIssuers; + string[] circuitIds; + bool skipClaimRevocationCheck; + // 0 for inclusion in merklized credentials, 1 for non-inclusion and for non-merklized credentials + uint256 claimPathNotExists; + } + + struct PubSignals { + uint256 merklized; + uint256 userID; + uint256 issuerState; + uint256 circuitQueryHash; + uint256 requestID; + uint256 challenge; + uint256 gistRoot; + uint256 issuerID; + uint256 isRevocationChecked; + uint256 issuerClaimNonRevState; + uint256 timestamp; + } + + // keccak256(abi.encodePacked("groupID")) + bytes32 private constant GROUPID_NAME = + 0xdab5ca4f3738dce0cd25851a4aa9160ebdfb1678ef20ca14c9a3e9217058455a; + // keccak256(abi.encodePacked("verifierID")) + bytes32 private constant VERIFIERID_NAME = + 0xa6ade9d39b76f319076fc4ad150ee37167dd21433b39e1d533a5d6b635762abe; + // keccak256(abi.encodePacked("nullifierSessionID")) + bytes32 private constant NULLIFIERSESSIONID_NAME = + 0x24cea8e4716dcdf091e4abcbd3ea617d9a5dd308b90afb5da0d75e56b3c0bc95; + + /** + * @dev Get the version of the contract + * @return Version of the contract + */ + function version() public pure virtual override returns (string memory); + + /** + * @dev Parse the public signals + * @param inputs Array of public inputs + * @return Parsed public signals + */ + function parsePubSignals( + uint256[] memory inputs + ) public pure virtual returns (PubSignals memory); + + /** + * @dev Verify the proof with the supported method informed in the request query data + * packed as bytes and that the proof was generated by the sender. + * @param sender Sender of the proof. + * @param proof Proof packed as bytes to verify. + * @param requestParams Request query data of the credential to verify. + * @param responseMetadata Metadata from the response. + * @return Array of response fields as result. + */ + function verify( + address sender, + bytes calldata proof, + bytes calldata requestParams, + bytes calldata responseMetadata + ) public view override returns (IRequestValidator.ResponseField[] memory) { + CredentialAtomicQuery memory credAtomicQuery = abi.decode( + requestParams, + (CredentialAtomicQuery) + ); + + return + _checkPubSignalsWithCredentialAtomicQuery( + credAtomicQuery, + _verifyProof(proof, credAtomicQuery), + sender + ); + } + + /** + * @dev Get the request param from params of the request query data. + * @param paramName Request query param name to retrieve of the credential to verify. + * @return RequestParam for the param name of the request query data. + */ + function getRequestParam( + bytes calldata, + string memory paramName + ) external pure returns (RequestParam memory) { + if ( + keccak256(bytes(paramName)) == GROUPID_NAME || + keccak256(bytes(paramName)) == VERIFIERID_NAME || + keccak256(bytes(paramName)) == NULLIFIERSESSIONID_NAME + ) { + return IRequestValidator.RequestParam({name: paramName, value: 0}); + } + revert RequestParamNameNotFound(); + } + + function _verifyProof( + bytes calldata proof, + CredentialAtomicQuery memory credAtomicQuery + ) internal view returns (PubSignals memory) { + if (credAtomicQuery.circuitIds.length != 1) { + revert CircuitsLengthShouldBeOne(); + } + + ( + uint256[] memory inputs, + uint256[2] memory a, + uint256[2][2] memory b, + uint256[2] memory c + ) = abi.decode(proof, (uint256[], uint256[2], uint256[2][2], uint256[2])); + + IGroth16Verifier g16Verifier = getVerifierByCircuitId(credAtomicQuery.circuitIds[0]); + + if (g16Verifier == IGroth16Verifier(address(0))) { + revert VerifierAddressShouldNotBeZero(); + } + + // verify that zkp is valid + if (!g16Verifier.verify(a, b, c, inputs)) { + revert ProofIsNotValid(); + } + + return parsePubSignals(inputs); + } + + function _checkPubSignalsWithCredentialAtomicQuery( + CredentialAtomicQuery memory credAtomicQuery, + PubSignals memory pubSignals, + address sender + ) internal view returns (IRequestValidator.ResponseField[] memory) { + // check circuitQueryHash + if (pubSignals.circuitQueryHash != credAtomicQuery.queryHash) { + revert QueryHashDoesNotMatchTheRequestedOne( + credAtomicQuery.queryHash, + pubSignals.circuitQueryHash + ); + } + + _checkMerklized(pubSignals.merklized, credAtomicQuery.claimPathKey); + _checkAllowedIssuers(pubSignals.issuerID, credAtomicQuery.allowedIssuers); + _checkProofExpiration(pubSignals.timestamp); + _checkIsRevocationChecked( + pubSignals.isRevocationChecked, + credAtomicQuery.skipClaimRevocationCheck + ); + + // Checking challenge to prevent replay attacks from other addresses + _checkChallenge(pubSignals.challenge, sender); + + // GIST root and state checks + _checkGistRoot(pubSignals.userID, pubSignals.gistRoot); + _checkClaimIssuanceState(pubSignals.issuerID, pubSignals.issuerState); + _checkClaimNonRevState(pubSignals.issuerID, pubSignals.issuerClaimNonRevState); + + return _getResponseFields(pubSignals); + } + + function _checkMerklized(uint256 merklized, uint256 queryClaimPathKey) internal pure { + uint256 shouldBeMerklized = queryClaimPathKey != 0 ? 1 : 0; + if (merklized != shouldBeMerklized) { + revert MerklizedValueIsNotCorrect(); + } + } + + function _checkIsRevocationChecked( + uint256 isRevocationChecked, + bool skipClaimRevocationCheck + ) internal pure { + uint256 expectedIsRevocationChecked = 1; + if (skipClaimRevocationCheck) { + expectedIsRevocationChecked = 0; + } + if (isRevocationChecked != expectedIsRevocationChecked) { + revert RevocationCheckShouldMatchTheQuery( + expectedIsRevocationChecked, + isRevocationChecked + ); + } + } + + function _getResponseFields( + PubSignals memory pubSignals + ) internal pure returns (IRequestValidator.ResponseField[] memory) { + IRequestValidator.ResponseField[] + memory responseFields = new IRequestValidator.ResponseField[](3); + responseFields[0] = IRequestValidator.ResponseField({ + name: "userID", + value: pubSignals.userID, + rawValue: "" + }); + responseFields[1] = IRequestValidator.ResponseField({ + name: "timestamp", + value: pubSignals.timestamp, + rawValue: "" + }); + responseFields[2] = IRequestValidator.ResponseField({ + name: "issuerID", + value: pubSignals.issuerID, + rawValue: "" + }); + return responseFields; + } +} diff --git a/contracts/validators/request/CredentialAtomicQueryV3Validator.sol b/contracts/validators/request/CredentialAtomicQueryV3Validator.sol new file mode 100644 index 000000000..371fcb8c8 --- /dev/null +++ b/contracts/validators/request/CredentialAtomicQueryV3Validator.sol @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.27; + +import {CredentialAtomicQueryValidatorBase} from "./CredentialAtomicQueryValidatorBase.sol"; +import {IGroth16Verifier} from "../../interfaces/IGroth16Verifier.sol"; +import {GenesisUtils} from "../../lib/GenesisUtils.sol"; +import {IRequestValidator} from "../../interfaces/IRequestValidator.sol"; + +error VerifierIDNotSet(); +error QueryHashDoesNotMatchTheRequestedOne(uint256 expected, uint256 actual); +error VerifierAddressShouldNotBeZero(); +error CircuitsLengthShouldBeOne(); +error ProofIsNotValid(); +error InvalidGroupIDOrLinkID(uint256 groupID, uint256 linkID); +error ProofTypeShouldMatchTheRequestedOneInQuery(); +error InvalidNullifyPubSignal(); +error UserIDDoesNotCorrespondToTheSender(); + +/** + * @dev CredentialAtomicQueryV3 validator + */ +contract CredentialAtomicQueryV3Validator is CredentialAtomicQueryValidatorBase { + struct CredentialAtomicQueryV3 { + uint256 schema; + uint256 claimPathKey; + uint256 operator; + uint256 slotIndex; + uint256[] value; + uint256 queryHash; + uint256[] allowedIssuers; + string[] circuitIds; + bool skipClaimRevocationCheck; + uint256 groupID; + uint256 nullifierSessionID; + uint256 proofType; + uint256 verifierID; + } + + struct PubSignals { + uint256 linkID; + uint256 nullifier; + uint256 operatorOutput; + uint256 proofType; + uint256 isBJJAuthEnabled; + uint256 userID; + uint256 issuerState; + uint256 circuitQueryHash; + uint256 requestID; + uint256 challenge; + uint256 gistRoot; + uint256 issuerID; + uint256 issuerClaimNonRevState; + uint256 timestamp; + } + + /** + * @dev Version of contract + */ + string public constant VERSION = "3.0.0-beta.1"; + + string internal constant CIRCUIT_ID = "credentialAtomicQueryV3OnChain-beta.1"; + + // keccak256(abi.encodePacked("groupID")) + bytes32 private constant GROUPID_NAME = + 0xdab5ca4f3738dce0cd25851a4aa9160ebdfb1678ef20ca14c9a3e9217058455a; + // keccak256(abi.encodePacked("verifierID")) + bytes32 private constant VERIFIERID_NAME = + 0xa6ade9d39b76f319076fc4ad150ee37167dd21433b39e1d533a5d6b635762abe; + // keccak256(abi.encodePacked("nullifierSessionID")) + bytes32 private constant NULLIFIERSESSIONID_NAME = + 0x24cea8e4716dcdf091e4abcbd3ea617d9a5dd308b90afb5da0d75e56b3c0bc95; + + /** + * @dev Initialize the contract + * @param _stateContractAddr Address of the state contract + * @param _verifierContractAddr Address of the verifier contract + * @param owner Owner of the contract + */ + function initialize( + address _stateContractAddr, + address _verifierContractAddr, + address owner + ) public initializer { + _setInputToIndex("userID", 0); + _setInputToIndex("circuitQueryHash", 1); + _setInputToIndex("issuerState", 2); + _setInputToIndex("linkID", 3); + _setInputToIndex("nullifier", 4); + _setInputToIndex("operatorOutput", 5); + _setInputToIndex("proofType", 6); + _setInputToIndex("requestID", 7); + _setInputToIndex("challenge", 8); + _setInputToIndex("gistRoot", 9); + _setInputToIndex("issuerID", 10); + _setInputToIndex("issuerClaimNonRevState", 11); + _setInputToIndex("timestamp", 12); + _setInputToIndex("isBJJAuthEnabled", 13); + + _initDefaultStateVariables(_stateContractAddr, _verifierContractAddr, CIRCUIT_ID, owner); + } + + /** + * @dev Get the version of the contract + * @return Version of the contract + */ + function version() public pure override returns (string memory) { + return VERSION; + } + + /** + * @dev Parse the public signals + * @param inputs Array of public inputs + * @return Parsed public signals + */ + function parsePubSignals(uint256[] memory inputs) public pure returns (PubSignals memory) { + PubSignals memory pubSignals = PubSignals({ + userID: inputs[0], + circuitQueryHash: inputs[1], + issuerState: inputs[2], + linkID: inputs[3], + nullifier: inputs[4], + operatorOutput: inputs[5], + proofType: inputs[6], + requestID: inputs[7], + challenge: inputs[8], + gistRoot: inputs[9], + issuerID: inputs[10], + issuerClaimNonRevState: inputs[11], + timestamp: inputs[12], + isBJJAuthEnabled: inputs[13] + }); + + return pubSignals; + } + + /** + * @dev Verify the proof with the supported method informed in the request query data + * packed as bytes and that the proof was generated by the sender. + * @param sender Sender of the proof. + * @param proof Proof packed as bytes to verify. + * @param requestParams Request query data of the credential to verify. + * @param responseMetadata Metadata from the response. + * @return Array of response fields as result. + */ + function verify( + address sender, + bytes calldata proof, + bytes calldata requestParams, + bytes calldata responseMetadata + ) public view override returns (IRequestValidator.ResponseField[] memory) { + CredentialAtomicQueryV3 memory credAtomicQuery = abi.decode( + requestParams, + (CredentialAtomicQueryV3) + ); + return + _checkPubSignalsWithCredentialAtomicQuery( + credAtomicQuery, + _verifyProof(proof, credAtomicQuery), + sender + ); + } + + /** + * @dev Get the request param from params of the request query data. + * @param params Request query data of the credential to verify. + * @param paramName Request query param name to retrieve of the credential to verify. + * @return RequestParam for the param name of the request query data. + */ + function getRequestParam( + bytes calldata params, + string memory paramName + ) external pure returns (RequestParam memory) { + CredentialAtomicQueryV3 memory query = abi.decode(params, (CredentialAtomicQueryV3)); + + if (keccak256(bytes(paramName)) == GROUPID_NAME) { + return IRequestValidator.RequestParam({name: paramName, value: query.groupID}); + } + if (keccak256(bytes(paramName)) == VERIFIERID_NAME) { + return IRequestValidator.RequestParam({name: paramName, value: query.verifierID}); + } + if (keccak256(bytes(paramName)) == NULLIFIERSESSIONID_NAME) { + return + IRequestValidator.RequestParam({name: paramName, value: query.nullifierSessionID}); + } + + revert RequestParamNameNotFound(); + } + + function _verifyProof( + bytes calldata proof, + CredentialAtomicQueryV3 memory credAtomicQuery + ) internal view returns (PubSignals memory) { + if (credAtomicQuery.circuitIds.length != 1) { + revert CircuitsLengthShouldBeOne(); + } + + ( + uint256[] memory inputs, + uint256[2] memory a, + uint256[2][2] memory b, + uint256[2] memory c + ) = abi.decode(proof, (uint256[], uint256[2], uint256[2][2], uint256[2])); + + IGroth16Verifier g16Verifier = getVerifierByCircuitId(credAtomicQuery.circuitIds[0]); + if (g16Verifier == IGroth16Verifier(address(0))) { + revert VerifierAddressShouldNotBeZero(); + } + + // verify that zkp is valid + if (!g16Verifier.verify(a, b, c, inputs)) { + revert ProofIsNotValid(); + } + + return parsePubSignals(inputs); + } + + function _checkPubSignalsWithCredentialAtomicQuery( + CredentialAtomicQueryV3 memory credAtomicQuery, + PubSignals memory pubSignals, + address sender + ) internal view returns (IRequestValidator.ResponseField[] memory) { + _checkAllowedIssuers(pubSignals.issuerID, credAtomicQuery.allowedIssuers); + _checkProofExpiration(pubSignals.timestamp); + + _checkGroupIDOrLinkID(credAtomicQuery.groupID, pubSignals.linkID); + _checkProofType(credAtomicQuery.proofType, pubSignals.proofType); + _checkNullify(pubSignals.nullifier, credAtomicQuery.nullifierSessionID); + + // GIST root and state checks + _checkClaimIssuanceState(pubSignals.issuerID, pubSignals.issuerState); + _checkClaimNonRevState(pubSignals.issuerID, pubSignals.issuerClaimNonRevState); + if (pubSignals.isBJJAuthEnabled == 1) { + _checkGistRoot(pubSignals.userID, pubSignals.gistRoot); + } else { + _checkAuth(pubSignals.userID, sender); + } + + // Checking challenge to prevent replay attacks from other addresses + _checkChallenge(pubSignals.challenge, sender); + + // check circuitQueryHash + if (pubSignals.circuitQueryHash != credAtomicQuery.queryHash) { + revert QueryHashDoesNotMatchTheRequestedOne( + credAtomicQuery.queryHash, + pubSignals.circuitQueryHash + ); + } + + // if operator == 16 then we have selective disclosure + return _getResponseFields(pubSignals, credAtomicQuery.operator == 16); + } + + function _checkGroupIDOrLinkID(uint256 groupID, uint256 linkID) internal pure { + if (groupID == 0 && linkID == 0) return; + if (groupID != 0 && linkID != 0) return; + revert InvalidGroupIDOrLinkID(groupID, linkID); + } + + function _checkProofType(uint256 queryProofType, uint256 pubSignalProofType) internal pure { + if (queryProofType != 0 && queryProofType != pubSignalProofType) { + revert ProofTypeShouldMatchTheRequestedOneInQuery(); + } + } + + function _checkNullify(uint256 nullifier, uint256 nullifierSessionID) internal pure { + if (nullifierSessionID != 0 && nullifier == 0) { + revert InvalidNullifyPubSignal(); + } + } + + function _checkAuth(uint256 userID, address ethIdentityOwner) internal view { + if ( + userID != + GenesisUtils.calcIdFromEthAddress(GenesisUtils.getIdType(userID), ethIdentityOwner) + ) { + revert UserIDDoesNotCorrespondToTheSender(); + } + } + + function _getResponseFields( + PubSignals memory pubSignals, + bool hasSelectiveDisclosure + ) internal pure returns (IRequestValidator.ResponseField[] memory) { + uint256 numSignals = hasSelectiveDisclosure ? 6 : 5; + IRequestValidator.ResponseField[] + memory responseFields = new IRequestValidator.ResponseField[](numSignals); + + uint256 i = 0; + responseFields[i++] = IRequestValidator.ResponseField({ + name: "userID", + value: pubSignals.userID, + rawValue: "" + }); + responseFields[i++] = IRequestValidator.ResponseField({ + name: "linkID", + value: pubSignals.linkID, + rawValue: "" + }); + responseFields[i++] = IRequestValidator.ResponseField({ + name: "nullifier", + value: pubSignals.nullifier, + rawValue: "" + }); + responseFields[i++] = IRequestValidator.ResponseField({ + name: "timestamp", + value: pubSignals.timestamp, + rawValue: "" + }); + responseFields[i++] = IRequestValidator.ResponseField({ + name: "issuerID", + value: pubSignals.issuerID, + rawValue: "" + }); + if (hasSelectiveDisclosure) { + responseFields[i++] = IRequestValidator.ResponseField({ + name: "operatorOutput", + value: pubSignals.operatorOutput, + rawValue: "" + }); + } + return responseFields; + } +} diff --git a/contracts/validators/CredentialAtomicQueryValidatorBase.sol b/contracts/validators/request/CredentialAtomicQueryValidatorBase.sol similarity index 61% rename from contracts/validators/CredentialAtomicQueryValidatorBase.sol rename to contracts/validators/request/CredentialAtomicQueryValidatorBase.sol index a972a12e8..4470d3723 100644 --- a/contracts/validators/CredentialAtomicQueryValidatorBase.sol +++ b/contracts/validators/request/CredentialAtomicQueryValidatorBase.sol @@ -3,34 +3,40 @@ pragma solidity 0.8.27; import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; -import {GenesisUtils} from "../lib/GenesisUtils.sol"; -import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol"; -import {IVerifier} from "../interfaces/IVerifier.sol"; -import {IState} from "../interfaces/IState.sol"; -import {PrimitiveTypeUtils} from "../lib/PrimitiveTypeUtils.sol"; +import {GenesisUtils} from "../../lib/GenesisUtils.sol"; +import {IRequestValidator} from "../../interfaces/IRequestValidator.sol"; +import {IGroth16Verifier} from "../../interfaces/IGroth16Verifier.sol"; +import {IState} from "../../interfaces/IState.sol"; +import {PrimitiveTypeUtils} from "../../lib/PrimitiveTypeUtils.sol"; +import {RequestValidatorBase} from "./RequestValidatorBase.sol"; + +error ChallengeShouldMatchTheSender(); +error GistRootIsExpired(); +error NonRevocationStateOfIssuerIsExpired(); +error ProofGeneratedInTheFutureIsNotValid(); +error GeneratedProofIsOutdated(); +error IssuerIsNotOnTheAllowedIssuersList(); /** * @dev Base contract for credential atomic query validators circuits. */ abstract contract CredentialAtomicQueryValidatorBase is Ownable2StepUpgradeable, - ICircuitValidator, + RequestValidatorBase, ERC165 { /// @dev Main storage structure for the contract /// @custom:storage-location iden3.storage.CredentialAtomicQueryValidator struct CredentialAtomicQueryValidatorBaseStorage { - mapping(string => IVerifier) _circuitIdToVerifier; - string[] _supportedCircuitIds; IState state; uint256 revocationStateExpirationTimeout; uint256 proofExpirationTimeout; uint256 gistRootExpirationTimeout; - mapping(string => uint256) _inputNameToIndex; } // keccak256(abi.encode(uint256(keccak256("iden3.storage.CredentialAtomicQueryValidator")) - 1)) // & ~bytes32(uint256(0xff)); + // solhint-disable-next-line const-name-snakecase bytes32 private constant CredentialAtomicQueryValidatorBaseStorageLocation = 0x28c92975a30f1f2f7970a65953987652034d896ba2d3b7a4961ada9e18287500; @@ -40,27 +46,15 @@ abstract contract CredentialAtomicQueryValidatorBase is pure returns (CredentialAtomicQueryValidatorBaseStorage storage $) { + // solhint-disable-next-line no-inline-assembly assembly { $.slot := CredentialAtomicQueryValidatorBaseStorageLocation } } - function _initDefaultStateVariables( - address _stateContractAddr, - address _verifierContractAddr, - string memory circuitId, - address owner - ) internal { - CredentialAtomicQueryValidatorBaseStorage - storage s = _getCredentialAtomicQueryValidatorBaseStorage(); - - s.revocationStateExpirationTimeout = 1 hours; - s.proofExpirationTimeout = 1 hours; - s.gistRootExpirationTimeout = 1 hours; - s._supportedCircuitIds = [circuitId]; - s._circuitIdToVerifier[circuitId] = IVerifier(_verifierContractAddr); - s.state = IState(_stateContractAddr); - __Ownable_init(owner); + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); } /** @@ -138,112 +132,74 @@ abstract contract CredentialAtomicQueryValidatorBase is } /** - * @dev Verify the groth16 proof and check the request query data - * @param inputs Public inputs of the circuit. - * @param a πa element of the groth16 proof. - * @param b πb element of the groth16 proof. - * @param c πc element of the groth16 proof. - * @param data Request query data of the credential to verify. + * @dev Verify the proof with the supported method informed in the request query data + * packed as bytes and that the proof was generated by the sender. * @param sender Sender of the proof. - * @return Array of key to public input index as result. + * @param proof Proof packed as bytes to verify. + * @param requestParams Request query data of the credential to verify. + * @param responseMetadata Metadata from the response. + * @return Array of response fields as result. */ function verify( - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c, - bytes calldata data, - address sender - ) external view virtual returns (ICircuitValidator.KeyToInputIndex[] memory); - - /** - * @dev Verify the groth16 proof and check the request query data - * @param zkProof Proof packed as bytes to verify. - * @param data Request query data of the credential to verify. - * @param sender Sender of the proof. - * @param stateContract State contract to get identities and gist states to check. - * @return Array of public signals as result. - */ - function verifyV2( - bytes calldata zkProof, - bytes calldata data, address sender, - IState stateContract - ) external view virtual returns (ICircuitValidator.Signal[] memory); - - /** - * @dev Get supported circuit ids - * @return ids Array of circuit ids supported - */ - function getSupportedCircuitIds() external view virtual returns (string[] memory ids) { - return _getCredentialAtomicQueryValidatorBaseStorage()._supportedCircuitIds; - } - - /** - * @dev Get the verifier by circuit id - * @param circuitId Circuit id - * @return The verifier - */ - function getVerifierByCircuitId( - string memory circuitId - ) public view virtual returns (IVerifier) { - return _getCredentialAtomicQueryValidatorBaseStorage()._circuitIdToVerifier[circuitId]; - } - - function _getState() internal view returns (IState) { - return _getCredentialAtomicQueryValidatorBaseStorage().state; - } - - /** - * @dev Get the index of the public input of the circuit by name - * @param name Name of the public input - * @return Index of the public input - */ - function inputIndexOf(string memory name) public view virtual returns (uint256) { - uint256 index = _getCredentialAtomicQueryValidatorBaseStorage()._inputNameToIndex[name]; - require(index != 0, "Input name not found"); - return --index; // we save 1-based index, but return 0-based - } + bytes calldata proof, + bytes calldata requestParams, + bytes calldata responseMetadata + ) external view virtual returns (ResponseField[] memory); /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return - interfaceId == type(ICircuitValidator).interfaceId || + interfaceId == type(IRequestValidator).interfaceId || super.supportsInterface(interfaceId); } - function _checkGistRoot(uint256 _id, uint256 _gistRoot, IState _stateContract) internal view { + function _initDefaultStateVariables( + address _stateContractAddr, + address _verifierContractAddr, + string memory circuitId, + address owner + ) internal { + CredentialAtomicQueryValidatorBaseStorage + storage s = _getCredentialAtomicQueryValidatorBaseStorage(); + + s.revocationStateExpirationTimeout = 1 hours; + s.proofExpirationTimeout = 1 hours; + s.gistRootExpirationTimeout = 1 hours; + s.state = IState(_stateContractAddr); + _setGroth16Verifier(circuitId, IGroth16Verifier(_verifierContractAddr)); + + __Ownable_init(owner); + } + + function _checkGistRoot(uint256 _id, uint256 _gistRoot) internal view { CredentialAtomicQueryValidatorBaseStorage storage $ = _getCredentialAtomicQueryValidatorBaseStorage(); bytes2 idType = GenesisUtils.getIdType(_id); - uint256 replacedAt = _stateContract.getGistRootReplacedAt(idType, _gistRoot); + uint256 replacedAt = $.state.getGistRootReplacedAt(idType, _gistRoot); if (replacedAt != 0 && block.timestamp > $.gistRootExpirationTimeout + replacedAt) { - revert("Gist root is expired"); + revert GistRootIsExpired(); } } - function _checkClaimIssuanceState( - uint256 _id, - uint256 _state, - IState _stateContract - ) internal view { - _stateContract.getStateReplacedAt(_id, _state); + function _getState() internal view returns (IState) { + return _getCredentialAtomicQueryValidatorBaseStorage().state; + } + + function _checkClaimIssuanceState(uint256 _id, uint256 _state) internal view { + _getState().getStateReplacedAt(_id, _state); } - function _checkClaimNonRevState( - uint256 _id, - uint256 _claimNonRevState, - IState _stateContract - ) internal view { + function _checkClaimNonRevState(uint256 _id, uint256 _claimNonRevState) internal view { CredentialAtomicQueryValidatorBaseStorage storage $ = _getCredentialAtomicQueryValidatorBaseStorage(); - uint256 replacedAt = _stateContract.getStateReplacedAt(_id, _claimNonRevState); + uint256 replacedAt = _getState().getStateReplacedAt(_id, _claimNonRevState); if (replacedAt != 0 && block.timestamp > $.revocationStateExpirationTimeout + replacedAt) { - revert("Non-Revocation state of Issuer expired"); + revert NonRevocationStateOfIssuerIsExpired(); } } @@ -254,14 +210,14 @@ abstract contract CredentialAtomicQueryValidatorBase is https://github.com/ethereum/go-ethereum/issues/24152 */ if (_proofGenerationTimestamp > (block.timestamp + 5 minutes)) { - revert("Proof generated in the future is not valid"); + revert ProofGeneratedInTheFutureIsNotValid(); } if ( block.timestamp > _getCredentialAtomicQueryValidatorBaseStorage().proofExpirationTimeout + _proofGenerationTimestamp ) { - revert("Generated proof is outdated"); + revert GeneratedProofIsOutdated(); } } @@ -271,24 +227,18 @@ abstract contract CredentialAtomicQueryValidatorBase is return; } - for (uint i = 0; i < allowedIssuers.length; i++) { + for (uint256 i = 0; i < allowedIssuers.length; i++) { if (issuerId == allowedIssuers[i]) { return; } } - revert("Issuer is not on the Allowed Issuers list"); + revert IssuerIsNotOnTheAllowedIssuersList(); } function _checkChallenge(uint256 challenge, address sender) internal pure { - require( - PrimitiveTypeUtils.uint256LEToAddress(challenge) == sender, - "Challenge should match the sender" - ); - } - - function _setInputToIndex(string memory inputName, uint256 index) internal { - // increment index to avoid 0 - _getCredentialAtomicQueryValidatorBaseStorage()._inputNameToIndex[inputName] = ++index; + if (PrimitiveTypeUtils.uint256LEToAddress(challenge) != sender) { + revert ChallengeShouldMatchTheSender(); + } } } diff --git a/contracts/validators/request/LinkedMultiQueryValidator.sol b/contracts/validators/request/LinkedMultiQueryValidator.sol new file mode 100644 index 000000000..de4293b48 --- /dev/null +++ b/contracts/validators/request/LinkedMultiQueryValidator.sol @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.10; + +import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import {IGroth16Verifier} from "../../interfaces/IGroth16Verifier.sol"; +import {IRequestValidator} from "../../interfaces/IRequestValidator.sol"; +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; +import {RequestValidatorBase} from "./RequestValidatorBase.sol"; + +error WrongCircuitID(string circuitID); +error InvalidQueryHash(uint256 expectedQueryHash, uint256 actualQueryHash); +error GroupIDCannotBeZero(); +error LinkIDCannotBeZero(); +error TooManyQueries(uint256 operatorCount); +error InvalidGroth16Proof(); + +contract LinkedMultiQueryValidator is Ownable2StepUpgradeable, RequestValidatorBase, ERC165 { + // This should be limited to the real number of queries in which operator != 0 + struct Query { + uint256[] claimPathKey; + uint256[] operator; // when checking SD take operator from here + uint256[] slotIndex; + uint256[][] value; + uint256[] queryHash; + string[] circuitIds; + uint256 groupID; + uint256 verifierID; + } + + // keccak256(abi.encodePacked("groupID")) + bytes32 private constant GROUPID_NAME = + 0xdab5ca4f3738dce0cd25851a4aa9160ebdfb1678ef20ca14c9a3e9217058455a; + // keccak256(abi.encodePacked("verifierID")) + bytes32 private constant VERIFIERID_NAME = + 0xa6ade9d39b76f319076fc4ad150ee37167dd21433b39e1d533a5d6b635762abe; + // keccak256(abi.encodePacked("nullifierSessionID")) + bytes32 private constant NULLIFIERSESSIONID_NAME = + 0x24cea8e4716dcdf091e4abcbd3ea617d9a5dd308b90afb5da0d75e56b3c0bc95; + + struct PubSignals { + uint256 linkID; + uint256 merklized; + uint256[10] operatorOutput; + uint256[10] circuitQueryHash; + } + + string public constant VERSION = "1.0.0-beta.1"; + string internal constant CIRCUIT_ID = "linkedMultiQuery10-beta.1"; + uint256 internal constant QUERIES_COUNT = 10; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /** + * @dev Returns the version of the contract + * @return The version of the contract + */ + function version() external pure override returns (string memory) { + return VERSION; + } + + /** + * @dev Initialize the contract + * @param _groth16VerifierContractAddr Address of the verifier contract + * @param owner Owner of the contract + */ + function initialize(address _groth16VerifierContractAddr, address owner) public initializer { + _setGroth16Verifier(CIRCUIT_ID, IGroth16Verifier(_groth16VerifierContractAddr)); + + _setInputToIndex("linkID", 0); + _setInputToIndex("merklized", 1); + for (uint256 i = 0; i < QUERIES_COUNT; i++) { + _setInputToIndex( + string(abi.encodePacked("operatorOutput_", Strings.toString(i))), + 2 + i + ); + _setInputToIndex( + string(abi.encodePacked("circuitQueryHash_", Strings.toString(i))), + 12 + i + ); + } + + __Ownable_init(owner); + } + + /** + * @dev Verify the proof with the supported method informed in the request query data + * packed as bytes and that the proof was generated by the sender. + * @param sender Sender of the proof. + * @param proof Proof packed as bytes to verify. + * @param requestParams Request query data of the credential to verify. + * @param responseMetadata Metadata from the response. + * @return Array of response fields as result. + */ + function verify( + // solhint-disable-next-line no-unused-vars + address sender, + bytes calldata proof, + bytes calldata requestParams, + // solhint-disable-next-line no-unused-vars + bytes calldata responseMetadata + ) external view returns (IRequestValidator.ResponseField[] memory) { + Query memory query = abi.decode(requestParams, (Query)); + ( + uint256[] memory inputs, + uint256[2] memory a, + uint256[2][2] memory b, + uint256[2] memory c + ) = abi.decode(proof, (uint256[], uint256[2], uint256[2][2], uint256[2])); + PubSignals memory pubSignals = _parsePubSignals(inputs); + + _checkQueryHash(query, pubSignals); + _checkGroupIDOrLinkID(query.groupID, pubSignals.linkID); + + if (keccak256(bytes(query.circuitIds[0])) != keccak256(bytes(CIRCUIT_ID))) { + revert WrongCircuitID(query.circuitIds[0]); + } + if (!getVerifierByCircuitId(CIRCUIT_ID).verify(a, b, c, inputs)) { + revert InvalidGroth16Proof(); + } + + return _getResponseFields(pubSignals, query); + } + + /** + * @dev Get the request param from params of the request query data. + * @param params Request query data of the credential to verify. + * @param paramName Request query param name to retrieve of the credential to verify. + * @return RequestParam for the param name of the request query data. + */ + function getRequestParam( + bytes calldata params, + string memory paramName + ) external pure returns (RequestParam memory) { + Query memory query = abi.decode(params, (Query)); + + if (keccak256(bytes(paramName)) == GROUPID_NAME) { + return IRequestValidator.RequestParam({name: paramName, value: query.groupID}); + } else if (keccak256(bytes(paramName)) == VERIFIERID_NAME) { + return IRequestValidator.RequestParam({name: paramName, value: query.verifierID}); + } else if (keccak256(bytes(paramName)) == NULLIFIERSESSIONID_NAME) { + return IRequestValidator.RequestParam({name: paramName, value: 0}); + } + revert RequestParamNameNotFound(); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return + interfaceId == type(IRequestValidator).interfaceId || + super.supportsInterface(interfaceId); + } + + function _checkGroupIDOrLinkID(uint256 groupID, uint256 linkID) internal pure { + if (groupID == 0) revert GroupIDCannotBeZero(); + if (linkID == 0) revert LinkIDCannotBeZero(); + } + + function _checkQueryHash(Query memory query, PubSignals memory pubSignals) internal pure { + if (query.queryHash.length > QUERIES_COUNT) { + revert TooManyQueries(query.queryHash.length); + } + for (uint256 i = 0; i < query.queryHash.length; i++) { + if (query.queryHash[i] != pubSignals.circuitQueryHash[i]) { + revert InvalidQueryHash(query.queryHash[i], pubSignals.circuitQueryHash[i]); + } + } + } + + function _parsePubSignals(uint256[] memory inputs) internal pure returns (PubSignals memory) { + uint256[QUERIES_COUNT] memory opsOutput; + uint256[QUERIES_COUNT] memory queryHashes; + PubSignals memory pubSignals = PubSignals({ + linkID: 0, + merklized: 0, + operatorOutput: opsOutput, + circuitQueryHash: queryHashes + }); + + pubSignals.linkID = inputs[0]; + pubSignals.merklized = inputs[1]; + for (uint256 i = 0; i < QUERIES_COUNT; i++) { + pubSignals.operatorOutput[i] = inputs[2 + i]; + pubSignals.circuitQueryHash[i] = inputs[2 + QUERIES_COUNT + i]; + } + return pubSignals; + } + + function _getResponseFields( + PubSignals memory pubSignals, + Query memory query + ) internal pure returns (ResponseField[] memory) { + uint256 operatorCount = 0; + for (uint256 i = 0; i < query.operator.length; i++) { + if (query.operator[i] == 16) { + operatorCount++; + } + } + + uint256 n = 1; + ResponseField[] memory rfs = new ResponseField[](n + operatorCount); + rfs[0] = ResponseField("linkID", pubSignals.linkID, ""); + + uint256 m = 1; + for (uint256 i = 0; i < query.operator.length; i++) { + // TODO consider if can be more gas efficient. Check via gasleft() first + if (query.operator[i] == 16) { + rfs[m++] = ResponseField( + string(abi.encodePacked("operatorOutput_", Strings.toString(i))), + pubSignals.operatorOutput[i], + "" + ); + } + } + + return rfs; + } +} diff --git a/contracts/validators/request/RequestValidatorBase.sol b/contracts/validators/request/RequestValidatorBase.sol new file mode 100644 index 000000000..07cab4a1d --- /dev/null +++ b/contracts/validators/request/RequestValidatorBase.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.10; + +import {IGroth16Verifier} from "../../interfaces/IGroth16Verifier.sol"; +import {IRequestValidator} from "../../interfaces/IRequestValidator.sol"; + +error Groth16VerifierAddressIsZero(string circuitId); +error Groth16VerifierAlreadySet(string circuitId); + +abstract contract RequestValidatorBase is IRequestValidator { + /// @dev Main storage structure for the contract + /// @custom:storage-location iden3.storage.RequestValidatorBaseStorage + struct RequestValidatorBaseStorage { + mapping(string => IGroth16Verifier) _circuitIdToGroth16Verifier; + string[] _supportedCircuitIds; + mapping(string => uint256) _inputNameToIndex; + } + + // keccak256(abi.encode(uint256(keccak256("iden3.storage.RequestValidatorBase")) - 1)) + // & ~bytes32(uint256(0xff)); + // solhint-disable-next-line const-name-snakecase + bytes32 private constant RequestValidatorBaseStorageLocation = + 0xd90b97ccc3cb854254aeec1e5c25748ff7146358b68741074181b650621e5d00; + + /// @dev Get the main storage using assembly to ensure specific storage location + function _getRequestValidatorBaseStorage() + private + pure + returns (RequestValidatorBaseStorage storage $) + { + // solhint-disable-next-line no-inline-assembly + assembly { + $.slot := RequestValidatorBaseStorageLocation + } + } + + /** + * @dev Get the index of the public input of the circuit by name + * @param name Name of the public input + * @return Index of the public input + */ + function inputIndexOf(string memory name) public view returns (uint256) { + uint256 index = _getRequestValidatorBaseStorage()._inputNameToIndex[name]; + if (index == 0) { + revert InputNameNotFound(); + } + return --index; // we save 1-based index, but return 0-based + } + + /** + * @dev Get supported circuit ids + * @return ids Array of circuit ids supported + */ + function getSupportedCircuitIds() public view returns (string[] memory ids) { + return _getRequestValidatorBaseStorage()._supportedCircuitIds; + } + + /** + * @dev Get the verifier by circuit id + * @param circuitId Circuit id + * @return The verifier + */ + function getVerifierByCircuitId( + string memory circuitId + ) public view returns (IGroth16Verifier) { + return _getRequestValidatorBaseStorage()._circuitIdToGroth16Verifier[circuitId]; + } + + function _setInputToIndex(string memory inputName, uint256 index) internal { + // increment index to avoid 0 + _getRequestValidatorBaseStorage()._inputNameToIndex[inputName] = ++index; + } + + function _setGroth16Verifier(string memory circuitId, IGroth16Verifier verifier) internal { + if (address(verifier) == address(0)) { + revert Groth16VerifierAddressIsZero(circuitId); + } + + if ( + address(_getRequestValidatorBaseStorage()._circuitIdToGroth16Verifier[circuitId]) != + address(0) + ) { + revert Groth16VerifierAlreadySet(circuitId); + } + + _getRequestValidatorBaseStorage()._supportedCircuitIds.push(circuitId); + _getRequestValidatorBaseStorage()._circuitIdToGroth16Verifier[circuitId] = verifier; + } +} diff --git a/contracts/verifiers/EmbeddedVerifier.sol b/contracts/verifiers/EmbeddedVerifier.sol new file mode 100644 index 000000000..c62d84be2 --- /dev/null +++ b/contracts/verifiers/EmbeddedVerifier.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.27; + +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; +import {Verifier} from "./Verifier.sol"; +import {IState} from "../interfaces/IState.sol"; + +abstract contract EmbeddedVerifier is Ownable2StepUpgradeable, Verifier { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @dev Sets the state contract linked to this verifier + /// @param state The state contract address + function setState(IState state) public onlyOwner { + _setState(state); + } + + /** + * @dev Submits an array of responses and updates proofs status + * @param authResponse Auth response including auth type and proof + * @param responses The list of responses including request ID, proof and metadata for requests + * @param crossChainProofs The list of cross chain proofs from universal resolver (oracle). This + * includes identities and global states. + */ + function submitResponse( + AuthResponse memory authResponse, + Response[] memory responses, + bytes memory crossChainProofs + ) public virtual override { + _beforeProofSubmit(authResponse, responses); + super.submitResponse(authResponse, responses, crossChainProofs); + _afterProofSubmit(authResponse, responses); + } + + /** + * @dev Sets the value for Owner + */ + // solhint-disable-next-line func-name-mixedcase + function __EmbeddedVerifier_init(address initialOwner, IState state) internal onlyInitializing { + __Ownable_init(initialOwner); + ___EmbeddedVerifier_init_unchained(initialOwner); + __Verifier_init(state); + } + + /* solhint-disable no-empty-blocks */ + // solhint-disable-next-line func-name-mixedcase + function ___EmbeddedVerifier_init_unchained(address initialOwner) internal onlyInitializing {} + + /** + * @dev Hook that is called before any proof response submit + * @param authResponse Auth response including auth type and proof + * @param responses The list of responses including request ID, proof and metadata for requests + */ + function _beforeProofSubmit( + AuthResponse memory authResponse, + Response[] memory responses + ) internal virtual {} + + /** + * @dev Hook that is called after any proof response submit + * @param authResponse The list of auth responses including auth type and proof + * @param responses The list of responses including request ID, proof and metadata for requests + */ + function _afterProofSubmit( + AuthResponse memory authResponse, + Response[] memory responses + ) internal virtual {} + /* solhint-enable no-empty-blocks */ +} diff --git a/contracts/verifiers/EmbeddedZKPVerifier.sol b/contracts/verifiers/EmbeddedZKPVerifier.sol deleted file mode 100644 index c122c5a67..000000000 --- a/contracts/verifiers/EmbeddedZKPVerifier.sol +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; - -import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; -import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol"; -import {IZKPVerifier} from "../interfaces/IZKPVerifier.sol"; -import {ZKPVerifierBase} from "./ZKPVerifierBase.sol"; -import {IState} from "../interfaces/IState.sol"; - -abstract contract EmbeddedZKPVerifier is Ownable2StepUpgradeable, ZKPVerifierBase { - /** - * @dev Sets the value for Owner - */ - function __EmbeddedZKPVerifier_init( - address initialOwner, - IState state - ) internal onlyInitializing { - __Ownable_init(initialOwner); - ___EmbeddedZKPVerifier_init_unchained(initialOwner); - __ZKPVerifierBase_init(state); - } - - function ___EmbeddedZKPVerifier_init_unchained( - address initialOwner - ) internal onlyInitializing {} - - /// @dev Sets the state contract linked to this verifier - /// @param state The state contract address - function setState(IState state) public onlyOwner { - _setState(state); - } - - /// @dev Sets a ZKP request - /// @param requestId The ID of the ZKP request - /// @param request The ZKP request data - function setZKPRequest( - uint64 requestId, - IZKPVerifier.ZKPRequest calldata request - ) public virtual override onlyOwner { - super.setZKPRequest(requestId, request); - } - - /// @dev Submits a ZKP response and updates proof status - /// @param requestId The ID of the ZKP request - /// @param inputs The input data for the proof - /// @param a The first component of the proof - /// @param b The second component of the proof - /// @param c The third component of the proof - function submitZKPResponse( - uint64 requestId, - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c - ) public virtual override { - IZKPVerifier.ZKPRequest memory request = getZKPRequest(requestId); - _beforeProofSubmit(requestId, inputs, request.validator); - super.submitZKPResponse(requestId, inputs, a, b, c); - _afterProofSubmit(requestId, inputs, request.validator); - } - - /** - * @dev Submits an array of ZKP responses and updates proofs status - * @param responses The list of responses including ZKP request ID, ZK proof and metadata - * @param crossChainProof The list of cross chain proofs from universal resolver (oracle). This - * includes identities and global states. - */ - function submitZKPResponseV2( - IZKPVerifier.ZKPResponse[] memory responses, - bytes memory crossChainProof - ) public override { - _beforeProofSubmitV2(responses); - super.submitZKPResponseV2(responses, crossChainProof); - _afterProofSubmitV2(responses); - } - - /** - * @dev Hook that is called before any proof response submit - */ - function _beforeProofSubmit( - uint64 requestId, - uint256[] memory inputs, - ICircuitValidator validator - ) internal virtual {} - - /** - * @dev Hook that is called after any proof response submit - */ - function _afterProofSubmit( - uint64 requestId, - uint256[] memory inputs, - ICircuitValidator validator - ) internal virtual {} - - /** - * @dev Hook that is called before any proof response submit V2 - * @param responses The list of responses including ZKP request ID, ZK proof and metadata - */ - function _beforeProofSubmitV2(IZKPVerifier.ZKPResponse[] memory responses) internal virtual {} - - /** - * @dev Hook that is called after any proof response submit V2 - * @param responses The list of responses including ZKP request ID, ZK proof and metadata - */ - function _afterProofSubmitV2(IZKPVerifier.ZKPResponse[] memory responses) internal virtual {} -} diff --git a/contracts/verifiers/RequestDisableable.sol b/contracts/verifiers/RequestDisableable.sol index 7ff1dfa0b..988a8f499 100644 --- a/contracts/verifiers/RequestDisableable.sol +++ b/contracts/verifiers/RequestDisableable.sol @@ -1,82 +1,65 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.27; -import {ZKPVerifierBase} from "./ZKPVerifierBase.sol"; -import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol"; -import {IZKPVerifier} from "../interfaces/IZKPVerifier.sol"; +import {IVerifier} from "../interfaces/IVerifier.sol"; +import {Verifier} from "./Verifier.sol"; -contract RequestDisableable is ZKPVerifierBase { +error RequestIsDisabled(uint256 requestId); + +contract RequestDisableable is Verifier { /// @custom:storage-location erc7201:iden3.storage.RequestDisableable struct RequestDisableStorage { - mapping(uint64 requestId => bool isDisabled) _requestDisabling; + mapping(uint256 requestId => bool isDisabled) _requestDisabling; } // keccak256(abi.encode(uint256(keccak256("iden3.storage.RequestDisableable")) - 1)) & ~bytes32(uint256(0xff)); + // solhint-disable-next-line const-name-snakecase bytes32 private constant RequestDisableStorageLocation = 0x70325635d67d74932012fa921ccb2f335d3b1d69e3a487f50d001cc65f531600; function _getRequestDisableStorage() private pure returns (RequestDisableStorage storage $) { + // solhint-disable-next-line no-inline-assembly assembly { $.slot := RequestDisableStorageLocation } } - /// @dev Modifier to check if the ZKP request is enabled - modifier onlyEnabledRequest(uint64 requestId) { - require(isZKPRequestEnabled(requestId), "Request is disabled"); + /// @dev Modifier to check if the request is enabled + modifier onlyEnabledRequest(uint256 requestId) { + if (!isRequestEnabled(requestId)) { + revert RequestIsDisabled(requestId); + } _; } - /// @dev Verifies a ZKP response without updating any proof status - /// @param requestId The ID of the ZKP request - /// @param inputs The public inputs for the proof - /// @param a The first component of the proof - /// @param b The second component of the proof - /// @param c The third component of the proof - /// @param sender The sender on behalf of which the proof is done - function verifyZKPResponse( - uint64 requestId, - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c, - address sender - ) - public - virtual - override - onlyEnabledRequest(requestId) - returns (ICircuitValidator.KeyToInputIndex[] memory) - { - return super.verifyZKPResponse(requestId, inputs, a, b, c, sender); - } - - /// @dev Checks if ZKP Request is enabled - /// @param requestId The ID of the ZKP request - /// @return True if ZKP Request enabled, otherwise returns false - function isZKPRequestEnabled( - uint64 requestId + /** + * @dev Checks if a request is enabled + * @param requestId The ID of the request + * @return True if the request enabled, otherwise returns false + */ + function isRequestEnabled( + uint256 requestId ) public view virtual checkRequestExistence(requestId, true) returns (bool) { return !_getRequestDisableStorage()._requestDisabling[requestId]; } - function _disableZKPRequest(uint64 requestId) internal checkRequestExistence(requestId, true) { + function _disableRequest(uint256 requestId) internal checkRequestExistence(requestId, true) { _getRequestDisableStorage()._requestDisabling[requestId] = true; } - function _enableZKPRequest(uint64 requestId) internal checkRequestExistence(requestId, true) { + function _enableRequest(uint256 requestId) internal checkRequestExistence(requestId, true) { _getRequestDisableStorage()._requestDisabling[requestId] = false; } function _getRequestIfCanBeVerified( - uint64 requestId + uint256 requestId ) internal view virtual override onlyEnabledRequest(requestId) - returns (IZKPVerifier.ZKPRequest storage) + returns (IVerifier.RequestData storage) { return super._getRequestIfCanBeVerified(requestId); } diff --git a/contracts/verifiers/RequestOwnership.sol b/contracts/verifiers/RequestOwnership.sol index 65eb23f4b..397d4ad15 100644 --- a/contracts/verifiers/RequestOwnership.sol +++ b/contracts/verifiers/RequestOwnership.sol @@ -1,16 +1,17 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.27; -import {ZKPVerifierBase} from "./ZKPVerifierBase.sol"; -import {IZKPVerifier} from "../interfaces/IZKPVerifier.sol"; +import {Verifier} from "./Verifier.sol"; +import {IVerifier} from "../interfaces/IVerifier.sol"; -abstract contract RequestOwnership is ZKPVerifierBase { +abstract contract RequestOwnership is Verifier { /// @custom:storage-location erc7201:iden3.storage.RequestOwnership struct RequestOwnershipStorage { - mapping(uint64 requestId => address requestOwner) _requestOwners; + mapping(uint256 requestId => address requestOwner) _requestOwners; } // keccak256(abi.encode(uint256(keccak256("iden3.storage.RequestOwnership")) - 1)) & ~bytes32(uint256(0xff)); + // solhint-disable-next-line const-name-snakecase bytes32 private constant RequestOwnershipStorageLocation = 0x6209bdc3799f5201408f7a7d4d471bb2a0100353e618451674b93f730b006a00; @@ -19,39 +20,30 @@ abstract contract RequestOwnership is ZKPVerifierBase { pure returns (RequestOwnershipStorage storage $) { + // solhint-disable-next-line no-inline-assembly assembly { $.slot := RequestOwnershipStorageLocation } } - /// @dev Modifier to check if the caller is ZKP Request owner - modifier onlyRequestOwner(uint64 requestId) virtual { - require(getRequestOwner(requestId) == _msgSender(), "Not a request owner"); - _; - } - - /// @dev Sets a ZKP request - /// @param requestId The ID of the ZKP request - /// @param request The ZKP request data - function setZKPRequest( - uint64 requestId, - IZKPVerifier.ZKPRequest calldata request - ) public virtual override { - super.setZKPRequest(requestId, request); - _setRequestOwner(requestId, _msgSender()); - } - - /// @dev Get a ZKP Request Owner address - /// @param requestId The ID of a ZKP Request - /// @return The ZKP Request Owner address + /** + * @dev Get a request owner address + * @param requestId The ID of a request + * @return The request owner address + */ function getRequestOwner( - uint64 requestId + uint256 requestId ) public view virtual checkRequestExistence(requestId, true) returns (address) { return _getRequestOwnershipStorage()._requestOwners[requestId]; } + function _setRequest(IVerifier.Request calldata request) internal virtual override { + super._setRequest(request); + _setRequestOwner(request.requestId, _msgSender()); + } + function _setRequestOwner( - uint64 requestId, + uint256 requestId, address requestOwner ) internal checkRequestExistence(requestId, true) { RequestOwnershipStorage storage $ = _getRequestOwnershipStorage(); diff --git a/contracts/verifiers/UniversalVerifier.sol b/contracts/verifiers/UniversalVerifier.sol index 20b341924..9251230dd 100644 --- a/contracts/verifiers/UniversalVerifier.sol +++ b/contracts/verifiers/UniversalVerifier.sol @@ -2,14 +2,16 @@ pragma solidity 0.8.27; import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; -import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol"; -import {IZKPVerifier} from "../interfaces/IZKPVerifier.sol"; +import {IRequestValidator} from "../interfaces/IRequestValidator.sol"; +import {IVerifier} from "../interfaces/IVerifier.sol"; import {RequestOwnership} from "./RequestOwnership.sol"; import {RequestDisableable} from "./RequestDisableable.sol"; import {ValidatorWhitelist} from "./ValidatorWhitelist.sol"; -import {ZKPVerifierBase} from "./ZKPVerifierBase.sol"; +import {Verifier} from "./Verifier.sol"; import {IState} from "../interfaces/IState.sol"; +error NotAnOwnerOrRequestOwner(address); + /// @title Universal Verifier Contract /// @notice A contract to manage ZKP (Zero-Knowledge Proof) requests and proofs. contract UniversalVerifier is @@ -21,43 +23,68 @@ contract UniversalVerifier is /** * @dev Version of contract */ - string public constant VERSION = "1.1.6"; + string public constant VERSION = "2.0.0"; - /// @dev Event emitted upon submitting a ZKP request - event ZKPResponseSubmitted(uint64 indexed requestId, address indexed caller); + /** + * @dev Event emitted upon submitting a request + */ + event ResponseSubmitted(uint256 indexed requestId, address indexed caller); - /// @dev Event emitted upon adding a ZKP request - event ZKPRequestSet( - uint64 indexed requestId, + /** + * @dev Event emitted upon submitting an auth response + */ + event AuthResponseSubmitted(string indexed authMethod, address indexed caller); + + /** + * @dev Event emitted upon adding a request + */ + event RequestSet( + uint256 indexed requestId, address indexed requestOwner, string metadata, address validator, - bytes data + bytes params ); - /// @dev Event emitted upon updating a ZKP request - event ZKPRequestUpdate( - uint64 indexed requestId, + /** + * @dev Event emitted upon adding an auth method by the owner + */ + event AuthMethodSet(string indexed authMethod, address validator, bytes params); + + /** + * @dev Event emitted upon updating a request + */ + event RequestUpdate( + uint256 indexed requestId, address indexed requestOwner, string metadata, address validator, - bytes data + bytes params ); + /** + * @dev Event emitted upon adding a multiRequest + */ + event MultiRequestSet(uint256 indexed multiRequestId, uint256[] requestIds, uint256[] groupIds); + /// @dev Modifier to check if the caller is the contract Owner or ZKP Request Owner - modifier onlyOwnerOrRequestOwner(uint64 requestId) { + modifier onlyOwnerOrRequestOwner(uint256 requestId) { address sender = _msgSender(); - require( - sender == getRequestOwner(requestId) || sender == owner(), - "Not an owner or request owner" - ); + if (sender != getRequestOwner(requestId) && sender != owner()) { + revert NotAnOwnerOrRequestOwner(sender); + } _; } + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + /// @dev Initializes the contract function initialize(IState state, address owner) public initializer { __Ownable_init(owner); - __ZKPVerifierBase_init(state); + __Verifier_init(state); } /// @dev Version of contract getter @@ -65,97 +92,66 @@ contract UniversalVerifier is return VERSION; } - /// @dev Sets a ZKP request - /// @param requestId The ID of the ZKP request - /// @param request The ZKP request data - function setZKPRequest( - uint64 requestId, - IZKPVerifier.ZKPRequest calldata request - ) public override(RequestOwnership, ValidatorWhitelist, ZKPVerifierBase) { - super.setZKPRequest(requestId, request); - - emit ZKPRequestSet( - requestId, - _msgSender(), - request.metadata, - address(request.validator), - request.data - ); + /** + * @dev Sets an auth type + * @param authMethod The auth type to add + */ + function setAuthMethod(IVerifier.AuthMethod calldata authMethod) public override onlyOwner { + super.setAuthMethod(authMethod); + emit AuthMethodSet(authMethod.authMethod, address(authMethod.validator), authMethod.params); } - /// @dev Update a ZKP request - /// @param requestId The ID of the ZKP request - /// @param request The ZKP request data - function updateZKPRequest( - uint64 requestId, - IZKPVerifier.ZKPRequest calldata request - ) public onlyOwner { - super._updateZKPRequest(requestId, request); + /** + * @dev Updates a request + * @param request The request data + */ + function updateRequest(IVerifier.Request calldata request) public onlyOwner { + super._updateRequest(request); - emit ZKPRequestUpdate( - requestId, + emit RequestUpdate( + request.requestId, _msgSender(), request.metadata, address(request.validator), - request.data + request.params ); } - /// @dev Submits a ZKP response and updates proof status - /// @param requestId The ID of the ZKP request - /// @param inputs The input data for the proof - /// @param a The first component of the proof - /// @param b The second component of the proof - /// @param c The third component of the proof - function submitZKPResponse( - uint64 requestId, - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c - ) public override { - super.submitZKPResponse(requestId, inputs, a, b, c); - emit ZKPResponseSubmitted(requestId, _msgSender()); + /** + * @dev Sets a multiRequest + * @param multiRequest The multiRequest data + */ + function setMultiRequest( + IVerifier.MultiRequest calldata multiRequest + ) public override checkMultiRequestExistence(multiRequest.multiRequestId, false) { + super.setMultiRequest(multiRequest); + emit MultiRequestSet( + multiRequest.multiRequestId, + multiRequest.requestIds, + multiRequest.groupIds + ); } /** - * @dev Submits an array of ZKP responses and updates proofs status - * @param responses The list of responses including ZKP request ID, ZK proof and metadata - * @param crossChainProof The list of cross chain proofs from universal resolver (oracle). This + * @dev Submits an array of responses and updates proofs status + * @param authResponse Auth responses including auth type and proof + * @param responses The list of responses including request ID, proof and metadata for requests + * @param crossChainProofs The list of cross chain proofs from universal resolver (oracle). This * includes identities and global states. */ - function submitZKPResponseV2( - IZKPVerifier.ZKPResponse[] memory responses, - bytes memory crossChainProof + function submitResponse( + AuthResponse memory authResponse, + Response[] memory responses, + bytes memory crossChainProofs ) public override { - super.submitZKPResponseV2(responses, crossChainProof); + super.submitResponse(authResponse, responses, crossChainProofs); + emit AuthResponseSubmitted(authResponse.authMethod, _msgSender()); + for (uint256 i = 0; i < responses.length; i++) { - emit ZKPResponseSubmitted(responses[i].requestId, _msgSender()); + emit ResponseSubmitted(responses[i].requestId, _msgSender()); } } - /// @dev Verifies a ZKP response without updating any proof status - /// @param requestId The ID of the ZKP request - /// @param inputs The public inputs for the proof - /// @param a The first component of the proof - /// @param b The second component of the proof - /// @param c The third component of the proof - /// @param sender The sender on behalf of which the proof is done - function verifyZKPResponse( - uint64 requestId, - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c, - address sender - ) - public - override(RequestDisableable, ValidatorWhitelist, ZKPVerifierBase) - returns (ICircuitValidator.KeyToInputIndex[] memory) - { - return super.verifyZKPResponse(requestId, inputs, a, b, c, sender); - } - /** * @dev Sets the state contract address */ @@ -163,60 +159,98 @@ contract UniversalVerifier is _setState(state); } - /// @dev Gets multiple ZKP requests within a range (disabled in this contract) - /// @param startIndex The starting index of the range - /// @param length The length of the range - /// @return An array of ZKP requests within the specified range - function getZKPRequests( - uint256 startIndex, - uint256 length - ) public view override returns (IZKPVerifier.ZKPRequest[] memory) { - revert("Not implemented in this version"); + /** + * @dev Sets the verifier ID + */ + function setVerifierID(uint256 verifierID) public onlyOwner { + _setVerifierID(verifierID); } - /// @dev Sets ZKP Request Owner address - /// @param requestId The ID of the ZKP request - /// @param requestOwner ZKP Request Owner address + /** + * @dev Sets the request owner address + * @param requestId The ID of the request + * @param requestOwner The address of the request owner + */ function setRequestOwner( - uint64 requestId, + uint256 requestId, address requestOwner ) public onlyOwnerOrRequestOwner(requestId) { _setRequestOwner(requestId, requestOwner); } - /// @dev Disables ZKP Request - /// @param requestId The ID of the ZKP request - function disableZKPRequest(uint64 requestId) public onlyOwnerOrRequestOwner(requestId) { - _disableZKPRequest(requestId); + /** + * @dev Disables Request + * @param requestId The ID of the request + */ + function disableRequest(uint256 requestId) public onlyOwnerOrRequestOwner(requestId) { + _disableRequest(requestId); } - /// @dev Enables ZKP Request - /// @param requestId The ID of the ZKP request - function enableZKPRequest(uint64 requestId) public onlyOwnerOrRequestOwner(requestId) { - _enableZKPRequest(requestId); + /** + * @dev Enables Request + * @param requestId The ID of the request + */ + function enableRequest(uint256 requestId) public onlyOwnerOrRequestOwner(requestId) { + _enableRequest(requestId); } - /// @dev Add new validator to the whitelist - /// @param validator Validator address - function addValidatorToWhitelist(ICircuitValidator validator) public onlyOwner { + /** + * @dev Adds a validator to the whitelist + * @param validator The address of the validator + */ + function addValidatorToWhitelist(IRequestValidator validator) public onlyOwner { _addValidatorToWhitelist(validator); } - /// @dev Remove validator from the whitelist - /// @param validator Validator address - function removeValidatorFromWhitelist(ICircuitValidator validator) public onlyOwner { + /** + * @dev Removes a validator from the whitelist + * @param validator The address of the validator + */ + function removeValidatorFromWhitelist(IRequestValidator validator) public onlyOwner { _removeValidatorFromWhitelist(validator); } + /** + * @dev Disables an auth method + * @param authMethod The auth method to disable + */ + function disableAuthMethod(string calldata authMethod) public override onlyOwner { + super.disableAuthMethod(authMethod); + } + + /** + * @dev Enables an auth type + * @param authMethod The auth type to enable + */ + function enableAuthMethod(string calldata authMethod) public override onlyOwner { + super.enableAuthMethod(authMethod); + } + function _getRequestIfCanBeVerified( - uint64 requestId + uint256 requestId ) internal view - override(RequestDisableable, ValidatorWhitelist, ZKPVerifierBase) - onlyEnabledRequest(requestId) - returns (IZKPVerifier.ZKPRequest storage) + override(RequestDisableable, ValidatorWhitelist, Verifier) + returns (IVerifier.RequestData storage) { return super._getRequestIfCanBeVerified(requestId); } + + function _setRequest( + Request calldata request + ) internal virtual override(RequestOwnership, ValidatorWhitelist, Verifier) { + super._setRequest(request); + emit RequestSet( + request.requestId, + request.owner, + request.metadata, + address(request.validator), + request.params + ); + } + + function _checkRequestOwner(Request calldata request) internal virtual override { + if (_msgSender() != owner()) super._checkRequestOwner(request); + } } diff --git a/contracts/verifiers/ValidatorWhitelist.sol b/contracts/verifiers/ValidatorWhitelist.sol index b668ec63a..5d2dc09c0 100644 --- a/contracts/verifiers/ValidatorWhitelist.sol +++ b/contracts/verifiers/ValidatorWhitelist.sol @@ -2,17 +2,21 @@ pragma solidity 0.8.27; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; -import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol"; -import {ZKPVerifierBase} from "./ZKPVerifierBase.sol"; -import {IZKPVerifier} from "../interfaces/IZKPVerifier.sol"; +import {IRequestValidator} from "../interfaces/IRequestValidator.sol"; +import {Verifier} from "./Verifier.sol"; +import {IVerifier} from "../interfaces/IVerifier.sol"; -contract ValidatorWhitelist is ZKPVerifierBase { +error ValidatorIsNotWhitelisted(address validator); +error ValidatorNotSupportInterface(address validator); + +contract ValidatorWhitelist is Verifier { /// @custom:storage-location erc7201:iden3.storage.ValidatorWhitelist struct ValidatorWhitelistStorage { - mapping(ICircuitValidator => bool isApproved) _validatorWhitelist; + mapping(IRequestValidator => bool isApproved) _validatorWhitelist; } // keccak256(abi.encode(uint256(keccak256("iden3.storage.ValidatorWhitelist")) - 1)) & ~bytes32(uint256(0xff)); + // solhint-disable-next-line const-name-snakecase bytes32 private constant ValidatorWhitelistStorageLocation = 0x76aa24e3538905838cc74060b2aa4c054b1e474aacf44741879e1850715e9300; @@ -21,79 +25,61 @@ contract ValidatorWhitelist is ZKPVerifierBase { pure returns (ValidatorWhitelistStorage storage $) { + // solhint-disable-next-line no-inline-assembly assembly { $.slot := ValidatorWhitelistStorageLocation } } /// @dev Modifier to check if the validator is whitelisted - modifier onlyWhitelistedValidator(ICircuitValidator validator) { - require(isWhitelistedValidator(validator), "Validator is not whitelisted"); + modifier onlyWhitelistedValidator(IRequestValidator validator) { + if (!isWhitelistedValidator(validator)) { + revert ValidatorIsNotWhitelisted(address(validator)); + } _; } - /// @dev Sets a ZKP request - /// @param requestId The ID of the ZKP request - /// @param request The ZKP request data - function setZKPRequest( - uint64 requestId, - IZKPVerifier.ZKPRequest calldata request - ) public virtual override onlyWhitelistedValidator(request.validator) { - super.setZKPRequest(requestId, request); - } - - /// @dev Verifies a ZKP response without updating any proof status - /// @param requestId The ID of the ZKP request - /// @param inputs The public inputs for the proof - /// @param a The first component of the proof - /// @param b The second component of the proof - /// @param c The third component of the proof - /// @param sender The sender on behalf of which the proof is done - function verifyZKPResponse( - uint64 requestId, - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c, - address sender - ) public virtual override returns (ICircuitValidator.KeyToInputIndex[] memory) { - ICircuitValidator validator = getZKPRequest(requestId).validator; - require(isWhitelistedValidator(validator), "Validator is not whitelisted"); - return super.verifyZKPResponse(requestId, inputs, a, b, c, sender); - } - - /// @dev Checks if validator is whitelisted - /// @param validator The validator address - /// @return True if validator is whitelisted, otherwise returns false + /** + * @dev Checks if validator is whitelisted + * @param validator The validator address + * @return True if validator is whitelisted, otherwise returns false + */ function isWhitelistedValidator( - ICircuitValidator validator + IRequestValidator validator ) public view virtual returns (bool) { return _getValidatorWhitelistStorage()._validatorWhitelist[validator]; } - function _addValidatorToWhitelist(ICircuitValidator validator) internal { - require( - IERC165(address(validator)).supportsInterface(type(ICircuitValidator).interfaceId), - "Validator doesn't support relevant interface" - ); + function _addValidatorToWhitelist(IRequestValidator validator) internal { + if (!IERC165(address(validator)).supportsInterface(type(IRequestValidator).interfaceId)) { + revert ValidatorNotSupportInterface(address(validator)); + } _getValidatorWhitelistStorage()._validatorWhitelist[validator] = true; } - function _removeValidatorFromWhitelist(ICircuitValidator validator) internal { + function _removeValidatorFromWhitelist(IRequestValidator validator) internal { _getValidatorWhitelistStorage()._validatorWhitelist[validator] = false; } function _getRequestIfCanBeVerified( - uint64 requestId + uint256 requestId ) internal view virtual override - onlyWhitelistedValidator(getZKPRequest(requestId).validator) - returns (IZKPVerifier.ZKPRequest storage) + onlyWhitelistedValidator(getRequest(requestId).validator) + returns (IVerifier.RequestData storage) { return super._getRequestIfCanBeVerified(requestId); } + + function _setRequest(Request calldata request) internal virtual override { + IRequestValidator validator = request.validator; + if (!isWhitelistedValidator(validator)) { + revert ValidatorIsNotWhitelisted(address(validator)); + } + super._setRequest(request); + } } diff --git a/contracts/verifiers/Verifier.sol b/contracts/verifiers/Verifier.sol new file mode 100644 index 000000000..2d49e817f --- /dev/null +++ b/contracts/verifiers/Verifier.sol @@ -0,0 +1,1046 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.27; + +import {ContextUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; +import {IRequestValidator} from "../interfaces/IRequestValidator.sol"; +import {IAuthValidator} from "../interfaces/IAuthValidator.sol"; +import {IState} from "../interfaces/IState.sol"; +import {IVerifier} from "../interfaces/IVerifier.sol"; +import {GenesisUtils} from "../lib/GenesisUtils.sol"; + +error AuthMethodNotFound(string authMethod); +error AuthMethodAlreadyExists(string authMethod); +error AuthMethodIsNotActive(string authMethod); +error GroupIdNotFound(uint256 groupId); +error GroupIdAlreadyExists(uint256 groupId); +error GroupMustHaveAtLeastTwoRequests(uint256 groupId); +error LinkIDNotTheSameForGroupedRequests(); +error MetadataNotSupportedYet(); +error MultiRequestIdAlreadyExists(uint256 multiRequestId); +error MultiRequestIdNotFound(uint256 multiRequestId); +error MultiRequestIdNotValid(uint256 expectedMultiRequestId, uint256 multiRequestId); +error NullifierSessionIDAlreadyExists(uint256 nullifierSessionID); +error ResponseFieldAlreadyExists(string responseFieldName); +error RequestIdAlreadyExists(uint256 requestId); +error RequestIdNotFound(uint256 requestId); +error RequestIdNotValid(uint256 expectedRequestId, uint256 requestId); +error RequestIdUsesReservedBytes(); +error RequestIdTypeNotValid(); +error RequestShouldNotHaveAGroup(uint256 requestId); +error UserIDMismatch(uint256 userIDFromAuth, uint256 userIDFromResponse); +error MissingUserIDInRequest(uint256 requestId); +error MissingUserIDInGroupOfRequests(uint256 groupId); +error UserNotAuthenticated(); +error VerifierIDIsNotValid(uint256 requestVerifierID, uint256 expectedVerifierID); +error ChallengeIsInvalid(); +error InvalidRequestOwner(address requestOwner, address sender); +error GroupIdNotValid(); + +abstract contract Verifier is IVerifier, ContextUpgradeable { + /// @dev Link ID field name + string private constant LINK_ID_PROOF_FIELD_NAME = "linkID"; + /// @dev User ID field name + string private constant USER_ID_INPUT_NAME = "userID"; + + // keccak256(abi.encodePacked("authV2")) + bytes32 private constant AUTHV2_METHOD_NAME_HASH = + 0x380ee2d21c7a4607d113dad9e76a0bc90f5325a136d5f0e14b6ccf849d948e25; + // keccak256(abi.encodePacked("challenge")) + bytes32 private constant CHALLENGE_FIELD_NAME_HASH = + 0x62357b294ca756256b576c5da68950c49d0d1823063551ffdcc1dad9d65a07a6; + // keccak256(abi.encodePacked("userID")) + bytes32 private constant USER_ID_FIELD_NAME_HASH = + 0xeaa28503c24395f30163098dfa9f1e1cd296dd52252064784e65d95934007382; + + struct AuthMethodData { + IAuthValidator validator; + bytes params; + bool isActive; + } + + struct GroupInfo { + uint256 id; + bytes concatenatedRequestIds; + bool userIdInputExists; + } + + /// @custom:storage-location erc7201:iden3.storage.Verifier + struct VerifierStorage { + // Information about requests + // solhint-disable-next-line + mapping(uint256 requestId => mapping(address sender => Proof)) _proofs; + mapping(uint256 requestId => IVerifier.RequestData) _requests; + uint256[] _requestIds; + IState _state; + mapping(uint256 groupId => uint256[] requestIds) _groupedRequests; + uint256[] _groupIds; + // Information about multiRequests + mapping(uint256 multiRequestId => IVerifier.MultiRequest) _multiRequests; + uint256[] _multiRequestIds; + // Information about auth methods and validators + string[] _authMethodsNames; + mapping(string authMethod => AuthMethodData) _authMethods; + mapping(uint256 nullifierSessionID => uint256 requestId) _nullifierSessionIDs; + // verifierID to check in requests + uint256 _verifierID; + } + + /** + * @dev Struct to store proof and associated data + */ + struct Proof { + bool isVerified; + mapping(string key => uint256 inputValue) responseFields; + string[] responseFieldNames; + // introduce artificial shift + 1 to avoid 0 index + mapping(string key => uint256 keyIndex) responseFieldIndexes; + string validatorVersion; + uint256 blockTimestamp; + uint256[44] __gap; + } + + // keccak256(abi.encode(uint256(keccak256("iden3.storage.Verifier")) -1 )) & ~bytes32(uint256(0xff)); + // solhint-disable-next-line const-name-snakecase + bytes32 internal constant VerifierStorageLocation = + 0x11369addde4aae8af30dcf56fa25ad3d864848d3201d1e9197f8b4da18a51a00; + + function _getVerifierStorage() private pure returns (VerifierStorage storage $) { + // solhint-disable-next-line no-inline-assembly + assembly { + $.slot := VerifierStorageLocation + } + } + + bytes2 internal constant VERIFIER_ID_TYPE = 0x01A1; + + /** + * @dev Modifier to check if the request exists + */ + modifier checkRequestExistence(uint256 requestId, bool existence) { + if (existence) { + if (!requestIdExists(requestId)) { + revert RequestIdNotFound(requestId); + } + } else { + if (requestIdExists(requestId)) { + revert RequestIdAlreadyExists(requestId); + } + } + _; + } + + /** + * @dev Modifier to check if the multiRequest exists + */ + modifier checkMultiRequestExistence(uint256 multiRequestId, bool existence) { + if (existence) { + if (!multiRequestIdExists(multiRequestId)) { + revert MultiRequestIdNotFound(multiRequestId); + } + } else { + if (multiRequestIdExists(multiRequestId)) { + revert MultiRequestIdAlreadyExists(multiRequestId); + } + } + _; + } + + /** + * @dev Modifier to check if the auth type exists + */ + modifier checkAuthMethodExistence(string memory authMethod, bool existence) { + if (existence) { + if (!authMethodExists(authMethod)) { + revert AuthMethodNotFound(authMethod); + } + } else { + if (authMethodExists(authMethod)) { + revert AuthMethodAlreadyExists(authMethod); + } + } + _; + } + + /** + * @dev Checks if a request ID exists + * @param requestId The ID of the request + * @return Whether the request ID exists + */ + function requestIdExists(uint256 requestId) public view returns (bool) { + return + _getVerifierStorage()._requests[requestId].validator != IRequestValidator(address(0)); + } + + /** + * @dev Checks if a group ID exists + * @param groupId The ID of the group + * @return Whether the group ID exists + */ + function groupIdExists(uint256 groupId) public view returns (bool) { + return _getVerifierStorage()._groupedRequests[groupId].length != 0; + } + + /** + * @dev Checks if a multiRequest ID exists + * @param multiRequestId The ID of the multiRequest + * @return Whether the multiRequest ID exists + */ + function multiRequestIdExists(uint256 multiRequestId) public view returns (bool) { + return + _getVerifierStorage()._multiRequests[multiRequestId].multiRequestId == multiRequestId; + } + + /** + * @dev Checks if an auth method exists + * @param authMethod The auth method + * @return Whether the auth type exists + */ + function authMethodExists(string memory authMethod) public view returns (bool) { + return + _getVerifierStorage()._authMethods[authMethod].validator != IAuthValidator(address(0)); + } + + /** + * @dev Sets different requests + * @param requests The list of requests + */ + function setRequests(IVerifier.Request[] calldata requests) public { + // 1. Check first that groupIds don't exist and keep the number of requests per group. + _checkGroupIdsAndRequestsPerGroup(requests); + + // 2. Set requests checking groups and nullifierSessionID uniqueness + for (uint256 i = 0; i < requests.length; i++) { + _checkRequestIdCorrectness( + requests[i].requestId, + requests[i].params, + requests[i].owner + ); + + _checkNullifierSessionIdUniqueness(requests[i]); + _checkVerifierID(requests[i]); + + _setRequest(requests[i]); + } + } + + /** + * @dev Gets a specific request by ID + * @param requestId The ID of the request + * @return request The request info + */ + function getRequest( + uint256 requestId + ) public view checkRequestExistence(requestId, true) returns (RequestInfo memory request) { + VerifierStorage storage $ = _getVerifierStorage(); + IVerifier.RequestData storage rd = $._requests[requestId]; + return + IVerifier.RequestInfo({ + requestId: requestId, + metadata: rd.metadata, + validator: rd.validator, + params: rd.params, + creator: rd.creator + }); + } + + /** + * @dev Sets a multiRequest + * @param multiRequest The multiRequest data + */ + function setMultiRequest( + IVerifier.MultiRequest calldata multiRequest + ) public virtual checkMultiRequestExistence(multiRequest.multiRequestId, false) { + uint256 expectedMultiRequestId = uint256( + keccak256( + abi.encodePacked(multiRequest.requestIds, multiRequest.groupIds, _msgSender()) + ) + ); + if (expectedMultiRequestId != multiRequest.multiRequestId) { + revert MultiRequestIdNotValid(expectedMultiRequestId, multiRequest.multiRequestId); + } + + VerifierStorage storage s = _getVerifierStorage(); + s._multiRequests[multiRequest.multiRequestId] = multiRequest; + s._multiRequestIds.push(multiRequest.multiRequestId); + + // checks for all the requests in this multiRequest + _checkRequestsInMultiRequest(multiRequest.multiRequestId); + } + + /** + * @dev Gets a specific multiRequest by ID + * @param multiRequestId The ID of the multiRequest + * @return multiRequest The multiRequest data + */ + function getMultiRequest( + uint256 multiRequestId + ) + public + view + checkMultiRequestExistence(multiRequestId, true) + returns (IVerifier.MultiRequest memory multiRequest) + { + return _getVerifierStorage()._multiRequests[multiRequestId]; + } + + /** + * @dev Submits an array of responses and updates proofs status + * @param authResponse Auth response including auth type and proof + * @param responses The list of responses including request ID, proof and metadata for requests + * @param crossChainProofs The list of cross chain proofs from universal resolver (oracle). This + * includes identities and global states. + */ + function submitResponse( + AuthResponse memory authResponse, + Response[] memory responses, + bytes memory crossChainProofs + ) public virtual { + VerifierStorage storage $ = _getVerifierStorage(); + address sender = _msgSender(); + + // 1. Process crossChainProofs + $._state.processCrossChainProofs(crossChainProofs); + + uint256 userIDFromAuthResponse; + AuthMethodData storage authMethodData = $._authMethods[authResponse.authMethod]; + if (!authMethodData.isActive) { + revert AuthMethodIsNotActive(authResponse.authMethod); + } + + // 2. Authenticate user and get userID + IAuthValidator.AuthResponseField[] memory authResponseFields; + (userIDFromAuthResponse, authResponseFields) = authMethodData.validator.verify( + sender, + authResponse.proof, + authMethodData.params + ); + + if (keccak256(abi.encodePacked(authResponse.authMethod)) == AUTHV2_METHOD_NAME_HASH) { + if ( + authResponseFields.length > 0 && + keccak256(abi.encodePacked(authResponseFields[0].name)) == CHALLENGE_FIELD_NAME_HASH + ) { + bytes32 expectedNonce = keccak256(abi.encode(sender, responses)) & + 0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + if (expectedNonce != bytes32(authResponseFields[0].value)) { + revert ChallengeIsInvalid(); + } + } + } + + if (userIDFromAuthResponse == 0) { + revert UserNotAuthenticated(); + } + + // 3. Verify all the responses, check userID from signals and write proof results, + // emit events (existing logic) + for (uint256 i = 0; i < responses.length; i++) { + IVerifier.Response memory response = responses[i]; + IVerifier.RequestData storage request = _getRequestIfCanBeVerified(response.requestId); + + IRequestValidator.ResponseField[] memory signals = request.validator.verify( + sender, + response.proof, + request.params, + response.metadata + ); + + // Check if userID from authResponse is the same as the one in the signals + _checkUserIDMatch(userIDFromAuthResponse, signals); + + _writeProofResults(response.requestId, request, sender, signals); + + if (response.metadata.length > 0) { + revert MetadataNotSupportedYet(); + } + } + } + + /** + * @dev Sets an auth method + * @param authMethod The auth method to add + */ + function setAuthMethod( + IVerifier.AuthMethod calldata authMethod + ) public virtual checkAuthMethodExistence(authMethod.authMethod, false) { + VerifierStorage storage s = _getVerifierStorage(); + s._authMethodsNames.push(authMethod.authMethod); + s._authMethods[authMethod.authMethod] = AuthMethodData({ + validator: authMethod.validator, + params: authMethod.params, + isActive: true + }); + } + + /** + * @dev Disables an auth method + * @param authMethod The auth method to disable + */ + function disableAuthMethod( + string calldata authMethod + ) public virtual checkAuthMethodExistence(authMethod, true) { + VerifierStorage storage s = _getVerifierStorage(); + s._authMethods[authMethod].isActive = false; + } + + /** + * @dev Enables an auth type + * @param authMethod The auth type to enable + */ + function enableAuthMethod( + string calldata authMethod + ) public virtual checkAuthMethodExistence(authMethod, true) { + VerifierStorage storage s = _getVerifierStorage(); + s._authMethods[authMethod].isActive = true; + } + + /** + * @dev Gets an auth type + * @param authMethod The Id of the auth type to get + * @return authMethodData The auth type data + */ + function getAuthMethod( + string calldata authMethod + ) + public + view + checkAuthMethodExistence(authMethod, true) + returns (AuthMethodData memory authMethodData) + { + return _getVerifierStorage()._authMethods[authMethod]; + } + + /** + * @dev Gets response field value + * @param requestId Id of the request + * @param sender Address of the user + * @param responseFieldName Name of the response field to get + */ + function getResponseFieldValue( + uint256 requestId, + address sender, + string memory responseFieldName + ) public view checkRequestExistence(requestId, true) returns (uint256) { + VerifierStorage storage s = _getVerifierStorage(); + return s._proofs[requestId][sender].responseFields[responseFieldName]; + } + + /** + * @dev Gets proof storage response fields + * @param requestId Id of the request + * @param sender Address of the user + */ + function getResponseFields( + uint256 requestId, + address sender + ) public view returns (IRequestValidator.ResponseField[] memory) { + VerifierStorage storage s = _getVerifierStorage(); + Proof storage proof = s._proofs[requestId][sender]; + + IRequestValidator.ResponseField[] + memory responseFields = new IRequestValidator.ResponseField[]( + proof.responseFieldNames.length + ); + + for (uint256 i = 0; i < proof.responseFieldNames.length; i++) { + responseFields[i] = IRequestValidator.ResponseField({ + name: proof.responseFieldNames[i], + value: proof.responseFields[proof.responseFieldNames[i]], + rawValue: "" + }); + } + + return responseFields; + } + + /** + * @dev Gets the status of the multiRequest verification + * @param multiRequestId The ID of the multiRequest + * @param userAddress The address of the user + * @return status The status of the multiRequest. "True" if all requests are verified, "false" otherwise + */ + function getMultiRequestProofsStatus( + uint256 multiRequestId, + address userAddress + ) + public + view + checkMultiRequestExistence(multiRequestId, true) + returns (IVerifier.RequestProofStatus[] memory) + { + // 1. Check if all requests statuses are true for the userAddress + IVerifier.RequestProofStatus[] memory requestProofStatus = _getMultiRequestProofsStatus( + multiRequestId, + userAddress + ); + + // 2. Check if all linked response fields are the same + bool linkedResponsesOK = _checkLinkedResponseFields(multiRequestId, userAddress); + + if (!linkedResponsesOK) { + revert LinkIDNotTheSameForGroupedRequests(); + } + + return requestProofStatus; + } + + /** + * @dev Checks if the proofs from a Multirequest submitted for a given sender and request ID are verified + * @param multiRequestId The ID of the multiRequest + * @param userAddress The address of the user + * @return status The status of the multiRequest. "True" if all requests are verified, "false" otherwise + */ + function areMultiRequestProofsVerified( + uint256 multiRequestId, + address userAddress + ) public view checkMultiRequestExistence(multiRequestId, true) returns (bool) { + // 1. Check if all requests are verified for the userAddress + bool verified = _areMultiRequestProofsVerified(multiRequestId, userAddress); + + if (verified) { + // 2. Check if all linked response fields are the same + bool linkedResponsesOK = _checkLinkedResponseFields(multiRequestId, userAddress); + + if (!linkedResponsesOK) { + verified = false; + } + } + + return verified; + } + + /** + * @dev Checks if a proof from a request submitted for a given sender and request ID is verified + * @param sender The sender's address + * @param requestId The ID of the request + * @return True if proof is verified + */ + function isRequestProofVerified( + address sender, + uint256 requestId + ) public view checkRequestExistence(requestId, true) returns (bool) { + VerifierStorage storage s = _getVerifierStorage(); + return s._proofs[requestId][sender].isVerified; + } + + /** + * @dev Get the requests count. + * @return Requests count. + */ + function getRequestsCount() public view returns (uint256) { + return _getVerifierStorage()._requestIds.length; + } + + /** + * @dev Get the group of requests count. + * @return Group of requests count. + */ + function getGroupsCount() public view returns (uint256) { + return _getVerifierStorage()._groupIds.length; + } + + /** + * @dev Get the group of requests. + * @return Group of requests. + */ + function getGroupedRequests( + uint256 groupID + ) public view returns (IVerifier.RequestInfo[] memory) { + VerifierStorage storage s = _getVerifierStorage(); + + IVerifier.RequestInfo[] memory requests = new IVerifier.RequestInfo[]( + s._groupedRequests[groupID].length + ); + + for (uint256 i = 0; i < s._groupedRequests[groupID].length; i++) { + uint256 requestId = s._groupedRequests[groupID][i]; + IVerifier.RequestData storage rd = s._requests[requestId]; + + requests[i] = IVerifier.RequestInfo({ + requestId: requestId, + metadata: rd.metadata, + validator: rd.validator, + params: rd.params, + creator: rd.creator + }); + } + + return requests; + } + + /** + * @dev Gets the address of the state contract linked to the verifier + * @return address State contract address + */ + function getStateAddress() public view virtual returns (address) { + return address(_getVerifierStorage()._state); + } + + /** + * @dev Gets the verifierID of the verifier contract + * @return uint256 verifierID of the verifier contract + */ + function getVerifierID() public view virtual returns (uint256) { + return _getVerifierStorage()._verifierID; + } + + /** + * @dev Checks the proof status for a given user and request ID + * @param sender The sender's address + * @param requestId The ID of the ZKP request + * @return The proof status structure + */ + function getRequestProofStatus( + address sender, + uint256 requestId + ) + public + view + checkRequestExistence(requestId, true) + returns (IVerifier.RequestProofStatus memory) + { + VerifierStorage storage s = _getVerifierStorage(); + Proof storage proof = s._proofs[requestId][sender]; + + return + IVerifier.RequestProofStatus( + requestId, + proof.isVerified, + proof.validatorVersion, + proof.blockTimestamp + ); + } + + function _setState(IState state) internal { + _getVerifierStorage()._state = state; + } + + // solhint-disable-next-line func-name-mixedcase + function __Verifier_init(IState state) internal onlyInitializing { + __Verifier_init_unchained(state); + } + + // solhint-disable-next-line func-name-mixedcase + function __Verifier_init_unchained(IState state) internal onlyInitializing { + _setState(state); + // initial calculation of verifierID from contract address and verifier id type defined + uint256 calculatedVerifierID = GenesisUtils.calcIdFromEthAddress( + VERIFIER_ID_TYPE, + address(this) + ); + _setVerifierID(calculatedVerifierID); + } + + function _setVerifierID(uint256 verifierID) internal { + VerifierStorage storage s = _getVerifierStorage(); + s._verifierID = verifierID; + } + + function _setRequest( + Request calldata request + ) internal virtual checkRequestExistence(request.requestId, false) { + _checkRequestOwner(request); + + VerifierStorage storage s = _getVerifierStorage(); + + s._requests[request.requestId] = IVerifier.RequestData({ + metadata: request.metadata, + validator: request.validator, + params: request.params, + creator: _msgSender() + }); + s._requestIds.push(request.requestId); + } + + function _checkRequestOwner(Request calldata request) internal virtual { + if (request.owner != _msgSender()) { + revert InvalidRequestOwner(request.owner, _msgSender()); + } + } + + function _checkVerifierID(IVerifier.Request calldata request) internal view { + VerifierStorage storage s = _getVerifierStorage(); + uint256 requestVerifierID = request + .validator + .getRequestParam(request.params, "verifierID") + .value; + + if (requestVerifierID != 0) { + if (requestVerifierID != s._verifierID) { + revert VerifierIDIsNotValid(requestVerifierID, s._verifierID); + } + } + } + + function _getRequestType(uint256 requestId) internal pure returns (uint16) { + // 0x0000000000000000 - prefix for old uint64 requests + // 0x0001000000000000 - prefix for keccak256 cut to fit in the remaining 192 bits + return uint16(requestId >> 240); + } + + function _checkRequestIdCorrectness( + uint256 requestId, + bytes calldata requestParams, + address requestOwner + ) internal pure { + // 1. Check prefix + uint16 requestType = _getRequestType(requestId); + if (requestType >= 2) { + revert RequestIdTypeNotValid(); + } + // 2. Check reserved bytes + if (((requestId << 16) >> 216) > 0) { + revert RequestIdUsesReservedBytes(); + } + // 3. Check if requestId matches the hash of the requestParams + // 0x0000000000000000FFFF...FF. Reserved first 8 bytes for the request Id type and future use + // 0x00010000000000000000...00. First 2 bytes for the request Id type + // - 0x0000... for old request Ids with uint64 + // - 0x0001... for new request Ids with uint256 + if (requestType == 1) { + uint256 hashValue = uint256(keccak256(abi.encodePacked(requestParams, requestOwner))); + uint256 expectedRequestId = (hashValue & + 0x0000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) + + 0x0001000000000000000000000000000000000000000000000000000000000000; + if (requestId != expectedRequestId) { + revert RequestIdNotValid(expectedRequestId, requestId); + } + } + } + + function _checkNullifierSessionIdUniqueness(IVerifier.Request calldata request) internal { + VerifierStorage storage s = _getVerifierStorage(); + uint256 nullifierSessionID = request + .validator + .getRequestParam(request.params, "nullifierSessionID") + .value; + if (nullifierSessionID != 0) { + if (s._nullifierSessionIDs[nullifierSessionID] != 0) { + revert NullifierSessionIDAlreadyExists(nullifierSessionID); + } + s._nullifierSessionIDs[nullifierSessionID] = nullifierSessionID; + } + } + + function _getGroupIDIndex( + uint256 groupID, + GroupInfo[] memory groupList, + uint256 listCount + ) internal pure returns (bool, uint256) { + for (uint256 j = 0; j < listCount; j++) { + if (groupList[j].id == groupID) { + return (true, j); + } + } + + return (false, 0); + } + + function _checkGroupsRequestsInfo( + GroupInfo[] memory groupList, + uint256 groupsCount + ) internal view { + VerifierStorage storage s = _getVerifierStorage(); + + for (uint256 i = 0; i < groupsCount; i++) { + uint256 calculatedGroupID = uint256(keccak256(groupList[i].concatenatedRequestIds)) & + 0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + if (calculatedGroupID != groupList[i].id) { + revert GroupIdNotValid(); + } + if (s._groupedRequests[groupList[i].id].length < 2) { + revert GroupMustHaveAtLeastTwoRequests(groupList[i].id); + } + if (groupList[i].userIdInputExists == false) { + revert MissingUserIDInGroupOfRequests(groupList[i].id); + } + } + } + + function _checkGroupIdsAndRequestsPerGroup(IVerifier.Request[] calldata requests) internal { + VerifierStorage storage s = _getVerifierStorage(); + + uint256 newGroupsCount = 0; + GroupInfo[] memory newGroupsInfo = new GroupInfo[](requests.length); + + for (uint256 i = 0; i < requests.length; i++) { + uint256 groupID = requests[i] + .validator + .getRequestParam(requests[i].params, "groupID") + .value; + + if (groupID != 0) { + (bool exists, uint256 groupIDIndex) = _getGroupIDIndex( + groupID, + newGroupsInfo, + newGroupsCount + ); + + if (!exists) { + if (groupIdExists(groupID)) { + revert GroupIdAlreadyExists(groupID); + } + s._groupIds.push(groupID); + s._groupedRequests[groupID].push(requests[i].requestId); + + newGroupsInfo[newGroupsCount] = GroupInfo({ + id: groupID, + concatenatedRequestIds: abi.encodePacked(requests[i].requestId), + userIdInputExists: _isUserIDInputInRequest(requests[i]) + }); + + newGroupsCount++; + } else { + s._groupedRequests[groupID].push(requests[i].requestId); + newGroupsInfo[groupIDIndex].concatenatedRequestIds = abi.encodePacked( + newGroupsInfo[groupIDIndex].concatenatedRequestIds, + requests[i].requestId + ); + if (_isUserIDInputInRequest(requests[i])) { + newGroupsInfo[groupIDIndex].userIdInputExists = true; + } + } + } else { + // revert if standalone request is without userId public input + if (!_isUserIDInputInRequest(requests[i])) { + revert MissingUserIDInRequest(requests[i].requestId); + } + } + } + + _checkGroupsRequestsInfo(newGroupsInfo, newGroupsCount); + } + + function _isUserIDInputInRequest( + IVerifier.Request memory request + ) internal view returns (bool) { + bool userIDInRequests = false; + + try request.validator.inputIndexOf(USER_ID_INPUT_NAME) { + userIDInRequests = true; + // solhint-disable-next-line no-empty-blocks + } catch {} + + return userIDInRequests; + } + + function _checkRequestsInMultiRequest(uint256 multiRequestId) internal view { + VerifierStorage storage s = _getVerifierStorage(); + + uint256[] memory requestIds = s._multiRequests[multiRequestId].requestIds; + uint256[] memory groupIds = s._multiRequests[multiRequestId].groupIds; + + // check that all the single requests doesn't have group + for (uint256 i = 0; i < requestIds.length; i++) { + if (!requestIdExists(requestIds[i])) { + revert RequestIdNotFound(requestIds[i]); + } + uint256 groupID = s + ._requests[requestIds[i]] + .validator + .getRequestParam(s._requests[requestIds[i]].params, "groupID") + .value; + + if (groupID != 0) { + revert RequestShouldNotHaveAGroup(requestIds[i]); + } + } + + for (uint256 i = 0; i < groupIds.length; i++) { + if (!groupIdExists(groupIds[i])) { + revert GroupIdNotFound(groupIds[i]); + } + } + } + + function _checkUserIDMatch( + uint256 userIDFromAuthResponse, + IRequestValidator.ResponseField[] memory signals + ) internal pure { + for (uint256 j = 0; j < signals.length; j++) { + if (keccak256(abi.encodePacked(signals[j].name)) == USER_ID_FIELD_NAME_HASH) { + if (userIDFromAuthResponse != signals[j].value) { + revert UserIDMismatch(userIDFromAuthResponse, signals[j].value); + } + } + } + } + + /** + * @dev Updates a request + * @param request The request data + */ + function _updateRequest( + IVerifier.Request calldata request + ) internal checkRequestExistence(request.requestId, true) { + VerifierStorage storage s = _getVerifierStorage(); + + s._requests[request.requestId] = IVerifier.RequestData({ + metadata: request.metadata, + validator: request.validator, + params: request.params, + creator: _msgSender() + }); + } + + function _checkLinkedResponseFields( + uint256 multiRequestId, + address sender + ) internal view returns (bool) { + VerifierStorage storage s = _getVerifierStorage(); + + for (uint256 i = 0; i < s._multiRequests[multiRequestId].groupIds.length; i++) { + uint256 groupId = s._multiRequests[multiRequestId].groupIds[i]; + + // Check linkID in the same group or requests is the same + uint256 requestLinkID = getResponseFieldValue( + s._groupedRequests[groupId][0], + sender, + LINK_ID_PROOF_FIELD_NAME + ); + for (uint256 j = 1; j < s._groupedRequests[groupId].length; j++) { + uint256 requestLinkIDToCompare = getResponseFieldValue( + s._groupedRequests[groupId][j], + sender, + LINK_ID_PROOF_FIELD_NAME + ); + if (requestLinkID != requestLinkIDToCompare) { + return false; + } + } + } + + return true; + } + + function _getMultiRequestProofsStatus( + uint256 multiRequestId, + address userAddress + ) internal view returns (IVerifier.RequestProofStatus[] memory) { + VerifierStorage storage s = _getVerifierStorage(); + IVerifier.MultiRequest storage multiRequest = s._multiRequests[multiRequestId]; + + uint256 lengthGroupIds; + + if (multiRequest.groupIds.length > 0) { + for (uint256 i = 0; i < multiRequest.groupIds.length; i++) { + uint256 groupId = multiRequest.groupIds[i]; + lengthGroupIds += s._groupedRequests[groupId].length; + } + } + + IVerifier.RequestProofStatus[] + memory requestProofStatus = new IVerifier.RequestProofStatus[]( + multiRequest.requestIds.length + lengthGroupIds + ); + + for (uint256 i = 0; i < multiRequest.requestIds.length; i++) { + uint256 requestId = multiRequest.requestIds[i]; + + requestProofStatus[i] = IVerifier.RequestProofStatus({ + requestId: requestId, + isVerified: s._proofs[requestId][userAddress].isVerified, + validatorVersion: s._proofs[requestId][userAddress].validatorVersion, + timestamp: s._proofs[requestId][userAddress].blockTimestamp + }); + } + + for (uint256 i = 0; i < multiRequest.groupIds.length; i++) { + uint256 groupId = multiRequest.groupIds[i]; + + for (uint256 j = 0; j < s._groupedRequests[groupId].length; j++) { + uint256 requestId = s._groupedRequests[groupId][j]; + + requestProofStatus[multiRequest.requestIds.length + j] = IVerifier + .RequestProofStatus({ + requestId: requestId, + isVerified: s._proofs[requestId][userAddress].isVerified, + validatorVersion: s._proofs[requestId][userAddress].validatorVersion, + timestamp: s._proofs[requestId][userAddress].blockTimestamp + }); + } + } + + return requestProofStatus; + } + + function _areMultiRequestProofsVerified( + uint256 multiRequestId, + address userAddress + ) internal view returns (bool) { + VerifierStorage storage s = _getVerifierStorage(); + IVerifier.MultiRequest storage multiRequest = s._multiRequests[multiRequestId]; + + for (uint256 i = 0; i < multiRequest.requestIds.length; i++) { + uint256 requestId = multiRequest.requestIds[i]; + + if (!s._proofs[requestId][userAddress].isVerified) { + return false; + } + } + + for (uint256 i = 0; i < multiRequest.groupIds.length; i++) { + uint256 groupId = multiRequest.groupIds[i]; + + for (uint256 j = 0; j < s._groupedRequests[groupId].length; j++) { + uint256 requestId = s._groupedRequests[groupId][j]; + + if (!s._proofs[requestId][userAddress].isVerified) { + return false; + } + } + } + + return true; + } + + function _getRequestIfCanBeVerified( + uint256 requestId + ) + internal + view + virtual + checkRequestExistence(requestId, true) + returns (IVerifier.RequestData storage) + { + VerifierStorage storage $ = _getVerifierStorage(); + return $._requests[requestId]; + } + + /** + * @dev Writes proof results. + * @param requestId The request ID of the proof + * @param sender The address of the sender of the proof + * @param responseFields The array of response fields of the proof + */ + function _writeProofResults( + uint256 requestId, + IVerifier.RequestData storage request, + address sender, + IRequestValidator.ResponseField[] memory responseFields + ) internal { + VerifierStorage storage s = _getVerifierStorage(); + Proof storage proof = s._proofs[requestId][sender]; + + // We only keep only 1 proof now without history. Prepared for the future if needed. + for (uint256 i = 0; i < responseFields.length; i++) { + if (proof.responseFieldIndexes[responseFields[i].name] == 0) { + proof.responseFields[responseFields[i].name] = responseFields[i].value; + proof.responseFieldNames.push(responseFields[i].name); + // we are not using a real index defined by length-1 here but defined by just length + // which shifts the index by 1 to avoid 0 value + proof.responseFieldIndexes[responseFields[i].name] = proof + .responseFieldNames + .length; + } else { + revert ResponseFieldAlreadyExists(responseFields[i].name); + } + } + + uint256 groupID = request.validator.getRequestParam(request.params, "groupID").value; + + proof.isVerified = true; + proof.validatorVersion = s._requests[requestId].validator.version(); + proof.blockTimestamp = block.timestamp; + } +} diff --git a/contracts/verifiers/ZKPVerifier.sol b/contracts/verifiers/ZKPVerifier.sol deleted file mode 100644 index e440d23c1..000000000 --- a/contracts/verifiers/ZKPVerifier.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; - -import {EmbeddedZKPVerifier} from "./EmbeddedZKPVerifier.sol"; - -/** - * @dev The ZKPVerifier is deprecated and will be removed in the future major versions - * Please use EmbeddedZKPVerifier instead - */ -contract ZKPVerifier is EmbeddedZKPVerifier {} diff --git a/contracts/verifiers/ZKPVerifierBase.sol b/contracts/verifiers/ZKPVerifierBase.sol deleted file mode 100644 index a128d1727..000000000 --- a/contracts/verifiers/ZKPVerifierBase.sol +++ /dev/null @@ -1,344 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; - -import {IZKPVerifier} from "../interfaces/IZKPVerifier.sol"; -import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol"; -import {ArrayUtils} from "../lib/ArrayUtils.sol"; -import {ContextUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; -import {IState} from "../interfaces/IState.sol"; -import {VerifierLib} from "../lib/VerifierLib.sol"; - -abstract contract ZKPVerifierBase is IZKPVerifier, ContextUpgradeable { - struct Metadata { - string key; - bytes value; - } - - /// @custom:storage-location erc7201:iden3.storage.ZKPVerifier - struct ZKPVerifierStorage { - mapping(address user => mapping(uint64 requestId => VerifierLib.Proof)) _proofs; - mapping(uint64 requestId => IZKPVerifier.ZKPRequest) _requests; - uint64[] _requestIds; - IState _state; - } - - // keccak256(abi.encode(uint256(keccak256("iden3.storage.ZKPVerifier")) - 1)) & ~bytes32(uint256(0xff)); - bytes32 internal constant ZKPVerifierStorageLocation = - 0x512d18c55869273fec77e70d8a8586e3fb133e90f1db24c6bcf4ff3506ef6a00; - - /// @dev Get the main storage using assembly to ensure specific storage location - function _getZKPVerifierStorage() private pure returns (ZKPVerifierStorage storage $) { - assembly { - $.slot := ZKPVerifierStorageLocation - } - } - - function _setState(IState state) internal { - _getZKPVerifierStorage()._state = state; - } - - using VerifierLib for ZKPVerifierStorage; - - function __ZKPVerifierBase_init(IState state) internal onlyInitializing { - __ZKPVerifierBase_init_unchained(state); - } - - function __ZKPVerifierBase_init_unchained(IState state) internal onlyInitializing { - _setState(state); - } - - /** - * @dev Max return array length for request queries - */ - uint256 public constant REQUESTS_RETURN_LIMIT = 1000; - - /// @dev Key to retrieve the linkID from the proof storage - string constant LINKED_PROOF_KEY = "linkID"; - - /// @dev Linked proof custom error - error LinkedProofError( - string message, - uint64 requestId, - uint256 linkID, - uint64 requestIdToCompare, - uint256 linkIdToCompare - ); - - /// @dev Modifier to check if the validator is set for the request - modifier checkRequestExistence(uint64 requestId, bool existence) { - if (existence) { - require(requestIdExists(requestId), "request id doesn't exist"); - } else { - require(!requestIdExists(requestId), "request id already exists"); - } - _; - } - - /// @dev Sets a ZKP request - /// @param requestId The ID of the ZKP request - /// @param request The ZKP request data - function setZKPRequest( - uint64 requestId, - IZKPVerifier.ZKPRequest calldata request - ) public virtual checkRequestExistence(requestId, false) { - ZKPVerifierStorage storage s = _getZKPVerifierStorage(); - s._requests[requestId] = request; - s._requestIds.push(requestId); - } - - /** - * @dev Set the ZKP request for the requestId. - * @param requestIds Request ids of the ZKP requests. - * @param requests ZKP requests to set. - */ - function setZKPRequests( - uint64[] calldata requestIds, - ZKPRequest[] calldata requests - ) public virtual { - require(requestIds.length == requests.length, "Request IDs and requests length mismatch"); - - for (uint256 i = 0; i < requestIds.length; i++) { - setZKPRequest(requestIds[i], requests[i]); - } - } - - /// @notice Submits a ZKP response and updates proof status - /// @param requestId The ID of the ZKP request - /// @param inputs The input data for the proof - /// @param a The first component of the proof - /// @param b The second component of the proof - /// @param c The third component of the proof - function submitZKPResponse( - uint64 requestId, - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c - ) public virtual { - address sender = _msgSender(); - ZKPVerifierStorage storage $ = _getZKPVerifierStorage(); - - IZKPVerifier.ZKPRequest storage request = _getRequestIfCanBeVerified(requestId); - ICircuitValidator.KeyToInputIndex[] memory keyToInpIdxs = request.validator.verify( - inputs, - a, - b, - c, - request.data, - sender - ); - - $.writeProofResults(sender, requestId, keyToInpIdxs, inputs); - } - - /// @notice Submits a ZKP response V2 and updates proof status - /// @param responses The list of responses including ZKP request ID, ZK proof and metadata - /// @param crossChainProofs The list of cross chain proofs from universal resolver (oracle) - function submitZKPResponseV2( - IZKPVerifier.ZKPResponse[] memory responses, - bytes memory crossChainProofs - ) public virtual { - ZKPVerifierStorage storage $ = _getZKPVerifierStorage(); - - $._state.processCrossChainProofs(crossChainProofs); - - for (uint256 i = 0; i < responses.length; i++) { - IZKPVerifier.ZKPResponse memory response = responses[i]; - - address sender = _msgSender(); - - IZKPVerifier.ZKPRequest storage request = _getRequestIfCanBeVerified( - response.requestId - ); - ICircuitValidator.Signal[] memory signals = request.validator.verifyV2( - response.zkProof, - request.data, - sender, - $._state - ); - - $.writeProofResultsV2(sender, response.requestId, signals); - - if (response.data.length > 0) { - revert("Metadata not supported yet"); - } - } - } - - /// @dev Verifies a ZKP response without updating any proof status - /// @param requestId The ID of the ZKP request - /// @param inputs The public inputs for the proof - /// @param a The first component of the proof - /// @param b The second component of the proof - /// @param c The third component of the proof - /// @param sender The sender on behalf of which the proof is done - function verifyZKPResponse( - uint64 requestId, - uint256[] memory inputs, - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c, - address sender - ) - public - virtual - checkRequestExistence(requestId, true) - returns (ICircuitValidator.KeyToInputIndex[] memory) - { - IZKPVerifier.ZKPRequest storage request = _getZKPVerifierStorage()._requests[requestId]; - return request.validator.verify(inputs, a, b, c, request.data, sender); - } - - /// @dev Gets the list of request IDs and verifies the proofs are linked - /// @param sender the user's address - /// @param requestIds the list of request IDs - /// Throws if the proofs are not linked - function verifyLinkedProofs(address sender, uint64[] calldata requestIds) public view virtual { - require(requestIds.length > 1, "Linked proof verification needs more than 1 request"); - - uint256 expectedLinkID = getProofStorageField(sender, requestIds[0], LINKED_PROOF_KEY); - - if (expectedLinkID == 0) { - revert("Can't find linkID for given request Ids and user address"); - } - - for (uint256 i = 1; i < requestIds.length; i++) { - uint256 actualLinkID = getProofStorageField(sender, requestIds[i], LINKED_PROOF_KEY); - - if (expectedLinkID != actualLinkID) { - revert LinkedProofError( - "Proofs are not linked", - requestIds[0], - expectedLinkID, - requestIds[i], - actualLinkID - ); - } - } - } - - /// @dev Gets a specific ZKP request by ID - /// @param requestId The ID of the ZKP request - /// @return zkpRequest The ZKP request data - function getZKPRequest( - uint64 requestId - ) - public - view - checkRequestExistence(requestId, true) - returns (IZKPVerifier.ZKPRequest memory zkpRequest) - { - return _getZKPVerifierStorage()._requests[requestId]; - } - - /// @dev Gets the count of ZKP requests - /// @return The count of ZKP requests - function getZKPRequestsCount() public view returns (uint256) { - return _getZKPVerifierStorage()._requestIds.length; - } - - /// @dev Checks if a ZKP request ID exists - /// @param requestId The ID of the ZKP request - /// @return Whether the request ID exists - function requestIdExists(uint64 requestId) public view override returns (bool) { - return - _getZKPVerifierStorage()._requests[requestId].validator != - ICircuitValidator(address(0)); - } - - /// @dev Gets multiple ZKP requests within a range - /// @param startIndex The starting index of the range - /// @param length The length of the range - /// @return An array of ZKP requests within the specified range - function getZKPRequests( - uint256 startIndex, - uint256 length - ) public view virtual returns (IZKPVerifier.ZKPRequest[] memory) { - ZKPVerifierStorage storage s = _getZKPVerifierStorage(); - (uint256 start, uint256 end) = ArrayUtils.calculateBounds( - s._requestIds.length, - startIndex, - length, - REQUESTS_RETURN_LIMIT - ); - - IZKPVerifier.ZKPRequest[] memory result = new IZKPVerifier.ZKPRequest[](end - start); - - for (uint256 i = start; i < end; i++) { - result[i - start] = s._requests[s._requestIds[i]]; - } - - return result; - } - - /// @dev Checks if proof submitted for a given sender and request ID - /// @param sender The sender's address - /// @param requestId The ID of the ZKP request - /// @return true if proof submitted - function isProofVerified( - address sender, - uint64 requestId - ) public view checkRequestExistence(requestId, true) returns (bool) { - return _getZKPVerifierStorage()._proofs[sender][requestId].isVerified; - } - - /// @dev Checks the proof status for a given user and request ID - /// @param sender The sender's address - /// @param requestId The ID of the ZKP request - /// @return The proof status structure - function getProofStatus( - address sender, - uint64 requestId - ) public view checkRequestExistence(requestId, true) returns (IZKPVerifier.ProofStatus memory) { - VerifierLib.Proof storage proof = _getZKPVerifierStorage()._proofs[sender][requestId]; - - return - IZKPVerifier.ProofStatus( - proof.isVerified, - proof.validatorVersion, - proof.blockNumber, - proof.blockTimestamp - ); - } - - /// @dev Gets the proof storage item for a given user, request ID and key - /// @param user The user's address - /// @param requestId The ID of the ZKP request - /// @return The proof - function getProofStorageField( - address user, - uint64 requestId, - string memory key - ) public view checkRequestExistence(requestId, true) returns (uint256) { - return _getZKPVerifierStorage()._proofs[user][requestId].storageFields[key]; - } - - /// @dev Gets the address of the state contract linked to the verifier - /// @return address of the state contract - function getStateAddress() public view virtual returns (address) { - return address(_getZKPVerifierStorage()._state); - } - - /// @dev Update a ZKP request - /// @param requestId The ID of the ZKP request - /// @param request The ZKP request data - function _updateZKPRequest( - uint64 requestId, - IZKPVerifier.ZKPRequest calldata request - ) internal checkRequestExistence(requestId, true) { - ZKPVerifierStorage storage s = _getZKPVerifierStorage(); - s._requests[requestId] = request; - } - - function _getRequestIfCanBeVerified( - uint64 requestId - ) - internal - view - virtual - checkRequestExistence(requestId, true) - returns (IZKPVerifier.ZKPRequest storage) - { - return _getZKPVerifierStorage()._requests[requestId]; - } -} diff --git a/hardhat.config.ts b/hardhat.config.ts index 28646e36c..2fdf0ef45 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -41,8 +41,85 @@ const config: HardhatUserConfig = { version: "0.8.27", }, ], + overrides: { + "contracts/verifiers/UniversalVerifier.sol": { + version: "0.8.27", + settings: { + optimizer: { + enabled: true, + runs: 80, + }, + }, + }, + "contracts/test-helpers/VerifierTestWrapper.sol": { + version: "0.8.27", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + "contracts/test-helpers/EmbeddedVerifierWrapper.sol": { + version: "0.8.27", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + "contracts/test-helpers/RequestDisableableTestWrapper.sol": { + version: "0.8.27", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + "contracts/test-helpers/RequestOwnershipTestWrapper.sol": { + version: "0.8.27", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + "contracts/test-helpers/ValidatorWhitelistTestWrapper.sol": { + version: "0.8.27", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + "contracts/state/State.sol": { + version: "0.8.27", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + }, }, networks: { + "billions-main": { + chainId: 45056, + url: `${process.env.BILLIONS_MAIN_RPC_URL}`, + // accounts: process.env.PRIVATE_KEY ? [`0x${process.env.PRIVATE_KEY}`] : DEFAULT_ACCOUNTS, + ledgerAccounts: [`${process.env.LEDGER_ACCOUNT}`], + }, + "billions-test": { + chainId: 6913, + url: `${process.env.BILLIONS_TEST_RPC_URL}`, + // accounts: process.env.PRIVATE_KEY ? [`0x${process.env.PRIVATE_KEY}`] : DEFAULT_ACCOUNTS, + ledgerAccounts: [`${process.env.LEDGER_ACCOUNT}`], + }, "privado-main": { chainId: 21000, url: `${process.env.PRIVADO_MAIN_RPC_URL}`, @@ -157,7 +234,6 @@ const config: HardhatUserConfig = { // -> In our case f4179bc3e4988a1a06f8d1 }, }, - requiredConfirmations: 5, }, etherscan: { @@ -170,8 +246,26 @@ const config: HardhatUserConfig = { "linea-sepolia": process.env.LINEA_EXPLORER_API_KEY || "", "zkevm-cardona": process.env.ZKEVM_EXPLORER_API_KEY || "", "zkevm-mainnet": process.env.ZKEVM_EXPLORER_API_KEY || "", + "billions-test": "test", + "billions-main": "main", }, customChains: [ + { + network: "billions-test", + chainId: 6913, + urls: { + apiURL: "https://billions-testnet-blockscout.eu-north-2.gateway.fm/api/", + browserURL: "https://docs.blockscout.com", + }, + }, + { + network: "billions-main", + chainId: 45056, + urls: { + apiURL: "https://billions-main-blockscout.eu-north-2.gateway.fm/api/", + browserURL: "https://docs.blockscout.com", + }, + }, { network: "polygon-amoy", chainId: 80002, diff --git a/helpers/DeployHelper.ts b/helpers/DeployHelper.ts index 2f7cef9cc..81b41caa0 100644 --- a/helpers/DeployHelper.ts +++ b/helpers/DeployHelper.ts @@ -22,12 +22,16 @@ import { TempContractDeployments, waitNotToInterfereWithHardhatIgnition, } from "./helperUtils"; -import { MCPaymentProxyModule } from "../ignition/modules/mcPayment"; +import { + MCPaymentProxyModule, + LinkedMultiQueryProxyModule, + EthIdentityValidatorModule, +} from "../ignition"; const SMT_MAX_DEPTH = 64; -export type Groth16VerifierType = "mtpV2" | "sigV2" | "v3" | "authV2"; -export type ValidatorType = "mtpV2" | "sigV2" | "v3" | "authV2"; +export type Groth16VerifierType = "mtpV2" | "sigV2" | "v3" | "lmq10" | "authV2" | undefined; +export type ValidatorType = "mtpV2" | "sigV2" | "v3" | "lmq" | "authV2" | "ethIdentity"; export class DeployHelper { constructor( @@ -57,7 +61,6 @@ export class DeployHelper { ): Promise<{ state: Contract; stateLib: Contract; - stateCrossChainLib: Contract; crossChainProofValidator: Contract; smtLib: Contract; poseidon1: Contract; @@ -81,7 +84,6 @@ export class DeployHelper { const { state, stateLib, - stateCrossChainLib, crossChainProofValidator, groth16VerifierStateTransition, defaultIdType, @@ -96,7 +98,6 @@ export class DeployHelper { return { state, stateLib: stateLib!, - stateCrossChainLib: stateCrossChainLib!, crossChainProofValidator: crossChainProofValidator!, defaultIdType, smtLib, @@ -118,7 +119,6 @@ export class DeployHelper { ): Promise<{ state: Contract; stateLib: Contract | null; - stateCrossChainLib: Contract | null; crossChainProofValidator: Contract | null; groth16VerifierStateTransition: Contract | null; defaultIdType; @@ -151,14 +151,13 @@ export class DeployHelper { } if (version) { - tmpContractDeployments.remove(); + //tmpContractDeployments.remove(); Logger.warning( `${contractsInfo.STATE.name} found already deployed to: ${await state?.getAddress()}`, ); return { state, stateLib: null, - stateCrossChainLib: null, crossChainProofValidator: null, groth16VerifierStateTransition: null, defaultIdType, @@ -182,23 +181,6 @@ export class DeployHelper { tmpContractDeployments.addContract(contractsInfo.STATE_LIB.name, await stateLib.getAddress()); } - let stateCrossChainLib; - stateCrossChainLib = await tmpContractDeployments.getContract( - contractsInfo.STATE_CROSS_CHAIN_LIB.name, - ); - if (stateCrossChainLib) { - Logger.warning( - `${contractsInfo.STATE_CROSS_CHAIN_LIB.name} found already deployed to: ${await stateCrossChainLib?.getAddress()}`, - ); - } else { - this.log("deploying StateCrossChainLib..."); - stateCrossChainLib = await this.deployStateCrossChainLib("StateCrossChainLib"); - tmpContractDeployments.addContract( - contractsInfo.STATE_CROSS_CHAIN_LIB.name, - await stateCrossChainLib.getAddress(), - ); - } - let crossChainProofValidator; crossChainProofValidator = await tmpContractDeployments.getContract( contractsInfo.CROSS_CHAIN_PROOF_VALIDATOR.name, @@ -223,7 +205,6 @@ export class DeployHelper { StateLib: await stateLib.getAddress(), SmtLib: smtLibAddress, PoseidonUnit1L: poseidon1Address, - StateCrossChainLib: await stateCrossChainLib.getAddress(), }, }); @@ -302,7 +283,6 @@ export class DeployHelper { return { state, stateLib, - stateCrossChainLib, crossChainProofValidator, groth16VerifierStateTransition, defaultIdType, @@ -319,7 +299,6 @@ export class DeployHelper { ): Promise<{ state: Contract; stateLib: Contract; - stateCrossChainLib: Contract; crossChainProofValidator: Contract; }> { this.log("======== State: upgrade started ========"); @@ -330,9 +309,6 @@ export class DeployHelper { this.log("deploying StateLib..."); const stateLib = await this.deployStateLib(); - this.log("deploying StateCrossChainLib..."); - const stateCrossChainLib = await this.deployStateCrossChainLib(); - this.log("upgrading state..."); /* @@ -349,7 +325,6 @@ export class DeployHelper { StateLib: await stateLib.getAddress(), SmtLib: smtLibAddress, PoseidonUnit1L: poseidon1Address, - StateCrossChainLib: await stateCrossChainLib.getAddress(), }, }); @@ -385,7 +360,6 @@ export class DeployHelper { state: stateContract, crossChainProofValidator: opvContract, stateLib, - stateCrossChainLib, }; } @@ -440,14 +414,6 @@ export class DeployHelper { return stateLib; } - async deployStateCrossChainLib(StateCrossChainLibName = "StateCrossChainLib"): Promise { - const stateCrossChainLib = await ethers.deployContract(StateCrossChainLibName); - await stateCrossChainLib.waitForDeployment(); - Logger.success(`StateCrossChainLib deployed to: ${await stateCrossChainLib.getAddress()}`); - - return stateCrossChainLib; - } - async deploySmtLibTestWrapper(maxDepth: number = SMT_MAX_DEPTH): Promise { const contractName = "SmtLibTestWrapper"; @@ -488,17 +454,6 @@ export class DeployHelper { return stateLibWrapper; } - async deployVerifierLib(): Promise { - const contractName = "VerifierLib"; - - const verifierLib = await ethers.deployContract(contractName); - await verifierLib.waitForDeployment(); - - Logger.success(`${contractName} deployed to: ${await verifierLib.getAddress()}`); - - return verifierLib; - } - async deployBinarySearchTestWrapper(): Promise { this.log("deploying poseidons..."); const [poseidon2Elements, poseidon3Elements] = await deployPoseidons([2, 3]); @@ -565,6 +520,31 @@ export class DeployHelper { return g16Verifier; } + getGroth16VerifierTypeFromValidatorType(validatorType: ValidatorType): Groth16VerifierType { + let groth16VerifierType; + switch (validatorType) { + case "mtpV2": + groth16VerifierType = "mtpV2"; + break; + case "sigV2": + groth16VerifierType = "sigV2"; + break; + case "v3": + groth16VerifierType = "v3"; + break; + case "lmq": + groth16VerifierType = "lmq10"; + break; + case "authV2": + groth16VerifierType = "authV2"; + break; + case "ethIdentity": + groth16VerifierType = undefined; + break; + } + return groth16VerifierType; + } + getGroth16VerifierWrapperName(groth16VerifierType: Groth16VerifierType): string { let g16VerifierContractWrapperName; switch (groth16VerifierType) { @@ -580,6 +560,9 @@ export class DeployHelper { case "authV2": g16VerifierContractWrapperName = contractsInfo.GROTH16_VERIFIER_AUTH_V2.name; break; + case "lmq10": + g16VerifierContractWrapperName = contractsInfo.GROTH16_VERIFIER_LINKED_MULTI_QUERY10.name; + break; } return g16VerifierContractWrapperName; } @@ -601,9 +584,12 @@ export class DeployHelper { break; case "v3": verification = contractsInfo.GROTH16_VERIFIER_V3.verificationOpts; + break; case "authV2": verification = contractsInfo.GROTH16_VERIFIER_AUTH_V2.verificationOpts; break; + case "lmq10": + verification = contractsInfo.GROTH16_VERIFIER_LINKED_MULTI_QUERY10.verificationOpts; } return verification; } @@ -625,6 +611,10 @@ export class DeployHelper { break; case "v3": verification = contractsInfo.VALIDATOR_V3.verificationOpts; + break; + case "lmq": + verification = contractsInfo.VALIDATOR_LINKED_MULTI_QUERY.verificationOpts; + break; case "authV2": verification = contractsInfo.VALIDATOR_AUTH_V2.verificationOpts; break; @@ -647,33 +637,32 @@ export class DeployHelper { async deployValidatorContractsWithVerifiers( validatorType: ValidatorType, - stateAddress: string, + stateContractAddress: string, deployStrategy: "basic" | "create2" = "basic", + groth16VerifierWrapperAddress?: string, ): Promise<{ - state: any; groth16VerifierWrapper: any; validator: any; }> { const contracts = await this.deployValidatorContracts( validatorType, - stateAddress, + stateContractAddress, deployStrategy, + groth16VerifierWrapperAddress, ); - const state = await ethers.getContractAt("State", stateAddress); return { validator: contracts.validator, groth16VerifierWrapper: contracts.groth16VerifierWrapper, - state, }; } async deployValidatorContracts( validatorType: ValidatorType, - stateAddress: string, + stateContractAddress: string, deployStrategy: "basic" | "create2" = "basic", + groth16VerifierWrapperAddress?: string, ): Promise<{ - state: any; validator: any; groth16VerifierWrapper: Contract | null; }> { @@ -690,9 +679,14 @@ export class DeployHelper { case "v3": validatorContractName = "CredentialAtomicQueryV3Validator"; break; + case "lmq": + validatorContractName = "LinkedMultiQueryValidator"; + break; case "authV2": validatorContractName = "AuthV2Validator"; break; + case "ethIdentity": + validatorContractName = "EthIdentityValidator"; } let validator; @@ -713,6 +707,12 @@ export class DeployHelper { case "authV2": validatorModule = AuthV2ValidatorProxyModule; break; + case "lmq": + validatorModule = LinkedMultiQueryProxyModule; + break; + case "ethIdentity": + validatorModule = EthIdentityValidatorModule; + break; } await waitNotToInterfereWithHardhatIgnition(undefined); @@ -735,20 +735,49 @@ export class DeployHelper { ); return { validator, - state: await ethers.getContractAt("State", stateAddress), groth16VerifierWrapper: null, }; } } } - const groth16VerifierWrapper = await this.deployGroth16VerifierWrapper(validatorType); + let groth16VerifierWrapper; + if (!groth16VerifierWrapperAddress) { + const groth16VerifierType = this.getGroth16VerifierTypeFromValidatorType(validatorType); + if (groth16VerifierType) { + groth16VerifierWrapper = await this.deployGroth16VerifierWrapper(groth16VerifierType); + } + } else { + groth16VerifierWrapper = await ethers.getContractAt( + this.getGroth16VerifierWrapperName( + this.getGroth16VerifierTypeFromValidatorType(validatorType), + ), + groth16VerifierWrapperAddress, + ); + } const ValidatorFactory = await ethers.getContractFactory(validatorContractName); const Create2AddressAnchorFactory = await ethers.getContractFactory( contractsInfo.CREATE2_ADDRESS_ANCHOR.name, ); + let validatorArgs; + + switch (validatorType) { + case "lmq": + validatorArgs = [await groth16VerifierWrapper.getAddress(), owner.address]; + break; + case "ethIdentity": + validatorArgs = [owner.address]; + break; + default: + validatorArgs = [ + stateContractAddress, + await groth16VerifierWrapper.getAddress(), + owner.address, + ]; + } + if (deployStrategy === "create2") { this.log("deploying with CREATE2 strategy..."); @@ -767,41 +796,36 @@ export class DeployHelper { // and force network files import, so creation, as they do not exist at the moment const validatorAddress = await validator.getAddress(); await upgrades.forceImport(validatorAddress, Create2AddressAnchorFactory); + validator = await upgrades.upgradeProxy(validatorAddress, ValidatorFactory, { unsafeAllow: ["external-library-linking"], redeployImplementation: "always", call: { fn: "initialize", - args: [await groth16VerifierWrapper.getAddress(), stateAddress, await owner.getAddress()], + args: validatorArgs, }, }); } else { this.log("deploying with BASIC strategy..."); - validator = await upgrades.deployProxy(ValidatorFactory, [ - await groth16VerifierWrapper.getAddress(), - stateAddress, - await owner.getAddress(), - ]); + validator = await upgrades.deployProxy(ValidatorFactory, validatorArgs); } validator.waitForDeployment(); Logger.success(`${validatorContractName} deployed to: ${await validator.getAddress()}`); - const state = await ethers.getContractAt("State", stateAddress); return { validator, - state, groth16VerifierWrapper, }; } - async deployValidatorStub(): Promise { - const stub = await ethers.getContractFactory("ValidatorStub"); + async deployValidatorStub(validatorName: string = "RequestValidatorStub"): Promise { + const stub = await ethers.getContractFactory(validatorName); const stubInstance = await stub.deploy(); await stubInstance.waitForDeployment(); - console.log("Validator stub deployed to:", await stubInstance.getAddress()); + console.log(`${validatorName} stub deployed to:`, await stubInstance.getAddress()); return stubInstance; } @@ -856,7 +880,6 @@ export class DeployHelper { async upgradeUniversalVerifier( verifierAddress: string, - verifierLibAddr: string, verifierContractName = contractsInfo.UNIVERSAL_VERIFIER.name, ): Promise { this.log("======== Verifier: upgrade started ========"); @@ -865,9 +888,6 @@ export class DeployHelper { this.log("upgrading verifier..."); const VerifierFactory = await ethers.getContractFactory(verifierContractName, { signer: proxyAdminOwner, - libraries: { - VerifierLib: verifierLibAddr, - }, }); this.log("upgrading proxy..."); @@ -916,29 +936,9 @@ export class DeployHelper { return primitiveTypeUtilsWrapper; } - async deployEmbeddedZKPVerifierWrapper( - owner: SignerWithAddress | undefined, - stateAddr: string, - verifierLibAddr: string, - ): Promise { - const Verifier = await ethers.getContractFactory("EmbeddedZKPVerifierWrapper", { - libraries: { - VerifierLib: verifierLibAddr, - }, - }); - // const zkpVerifier = await ZKPVerifier.deploy(await owner.getAddress()); - const verifier = await upgrades.deployProxy(Verifier, [await owner.getAddress(), stateAddr], { - unsafeAllow: ["external-library-linking"], - }); - await verifier.waitForDeployment(); - console.log("EmbeddedZKPVerifierWrapper deployed to:", await verifier.getAddress()); - return verifier; - } - async deployUniversalVerifier( owner: SignerWithAddress | undefined, stateAddr: string, - verifierLibAddr: string, deployStrategy: "basic" | "create2" = "basic", ): Promise { if (!owner) { @@ -948,9 +948,6 @@ export class DeployHelper { contractsInfo.UNIVERSAL_VERIFIER.name, { signer: owner, - libraries: { - VerifierLib: verifierLibAddr, - }, }, ); const Create2AddressAnchorFactory = await ethers.getContractFactory( diff --git a/helpers/UniversalVerifierContractMigrationHelper.ts b/helpers/UniversalVerifierContractMigrationHelper.ts index aab0623a9..3bec09d3d 100644 --- a/helpers/UniversalVerifierContractMigrationHelper.ts +++ b/helpers/UniversalVerifierContractMigrationHelper.ts @@ -104,13 +104,9 @@ export class UniversalVerifierContractMigrationHelper extends ContractMigrationS } @log - async upgradeContract( - universalVerifierContract: Contract, - opts: { verifierLibAddress: string }, - ): Promise { + async upgradeContract(universalVerifierContract: Contract): Promise { return await this._universalVerifierDeployHelper.upgradeUniversalVerifier( await universalVerifierContract.getAddress(), - opts.verifierLibAddress, ); } } diff --git a/helpers/constants.ts b/helpers/constants.ts index cdc8a607d..16111c4e9 100644 --- a/helpers/constants.ts +++ b/helpers/constants.ts @@ -56,6 +56,16 @@ export const chainIdInfoMap: Map = new Map() networkType: "test", oracleSigningAddress: ORACLE_SIGNING_ADDRESS_PRODUCTION, }) // ethereum sepolia + .set(6912, { + idType: "0x01B1", + networkType: "main", + oracleSigningAddress: ORACLE_SIGNING_ADDRESS_PRODUCTION, + }) // billions-main + .set(6913, { + idType: "0x01B2", + networkType: "test", + oracleSigningAddress: ORACLE_SIGNING_ADDRESS_PRODUCTION, + }) // billions-test .set(21000, { idType: "0x01A1", networkType: "main", @@ -108,9 +118,9 @@ export const contractsInfo = Object.freeze({ }, UNIVERSAL_VERIFIER: { name: "UniversalVerifier", - version: "1.1.6", - unifiedAddress: "0xfcc86A79fCb057A8e55C6B853dff9479C3cf607c", - create2Calldata: ethers.hexlify(ethers.toUtf8Bytes("iden3.create2.UniversalVerifier")), + version: "2.0.0", + unifiedAddress: "0x2B0D3f664A5EbbfBD76E6cbc2cA9A504a68d2F4F", + create2Calldata: ethers.hexlify(ethers.toUtf8Bytes("iden3.create2.UniversalVerifier.v2")), verificationOpts: { // For verifying the different contracts with proxy we need verification with different constructor arguments constructorArgsImplementation: [], @@ -125,7 +135,7 @@ export const contractsInfo = Object.freeze({ }, STATE: { name: "State", - version: "2.6.1", + version: "2.6.2", unifiedAddress: "0x3C9acB2205Aa72A05F6D77d708b5Cf85FCa3a896", create2Calldata: ethers.hexlify(ethers.toUtf8Bytes("iden3.create2.State")), verificationOpts: { @@ -141,10 +151,10 @@ export const contractsInfo = Object.freeze({ }, VALIDATOR_SIG: { name: "CredentialAtomicQuerySigV2Validator", - version: "2.1.1", - unifiedAddress: "0x59B347f0D3dd4B98cc2E056Ee6C53ABF14F8581b", + version: "3.0.0", + unifiedAddress: "0x5BD60F3Ef5890260906172EEe1f0a965707791f1", create2Calldata: ethers.hexlify( - ethers.toUtf8Bytes("iden3.create2.CredentialAtomicQuerySigV2Validator"), + ethers.toUtf8Bytes("iden3.create2.CredentialAtomicQuerySigV2Validator.v3"), ), verificationOpts: { constructorArgsImplementation: [], @@ -159,10 +169,10 @@ export const contractsInfo = Object.freeze({ }, VALIDATOR_MTP: { name: "CredentialAtomicQueryMTPV2Validator", - version: "2.1.1", - unifiedAddress: "0x27bDFFCeC5478a648f89764E22fE415486A42Ede", + version: "3.0.0", + unifiedAddress: "0xec9EF9c4595B46abF2b6A923BD1529081E03fbBB", create2Calldata: ethers.hexlify( - ethers.toUtf8Bytes("iden3.create2.CredentialAtomicQueryMTPV2Validator"), + ethers.toUtf8Bytes("iden3.create2.CredentialAtomicQueryMTPV2Validator.v3"), ), verificationOpts: { constructorArgsImplementation: [], @@ -177,10 +187,10 @@ export const contractsInfo = Object.freeze({ }, VALIDATOR_V3: { name: "CredentialAtomicQueryV3Validator", - version: "2.1.1-beta.1", - unifiedAddress: "0xd179f29d00Cd0E8978eb6eB847CaCF9E2A956336", + version: "3.0.0-beta.1", + unifiedAddress: "0xC616963610A5545EF89b373e1fEAE8A1e505FaFF", create2Calldata: ethers.hexlify( - ethers.toUtf8Bytes("iden3.create2.CredentialAtomicQueryV3Validator"), + ethers.toUtf8Bytes("iden3.create2.CredentialAtomicQueryV3Validator.v3"), ), verificationOpts: { constructorArgsImplementation: [], @@ -193,10 +203,26 @@ export const contractsInfo = Object.freeze({ libraries: {}, }, }, + VALIDATOR_LINKED_MULTI_QUERY: { + name: "LinkedMultiQueryValidator", + version: "1.0.0-beta.1", + unifiedAddress: "0xfA622418d7aBF33868545732CaD2C2E7ce9B16C8", + create2Calldata: ethers.hexlify(ethers.toUtf8Bytes("iden3.create2.LinkedMultiQueryValidator")), + verificationOpts: { + constructorArgsImplementation: [], + constructorArgsProxy: [ + "0x56fF81aBB5cdaC478bF236db717e4976b2ff841e", + "0xae15d2023a76174a940cbb2b7f44012c728b9d74", + "0x6964656e332e637265617465322e556e6976657273616c5665726966696572", + ], + constructorArgsProxyAdmin: ["0xAe15d2023A76174a940cbb2b7f44012c728b9d74"], + libraries: {}, + }, + }, VALIDATOR_AUTH_V2: { name: "AuthV2Validator", version: "1.0.0", - unifiedAddress: "0x49ebdC163fa014F310CeDBc8e4a0b15C738D8073", + unifiedAddress: "0x535F6a1B30533616CE4bD44081ea7A17CF2042B8", create2Calldata: ethers.hexlify(ethers.toUtf8Bytes("iden3.create2.AuthV2Validator")), verificationOpts: { constructorArgsImplementation: [], @@ -209,6 +235,22 @@ export const contractsInfo = Object.freeze({ libraries: {}, }, }, + VALIDATOR_ETH_IDENTITY: { + name: "EthIdentityValidator", + version: "1.0.0", + unifiedAddress: "0x8546bFd67F19dd0449dF73fb75A56BC9ddFA57Db", + create2Calldata: ethers.hexlify(ethers.toUtf8Bytes("iden3.create2.EthIdentityValidator")), + verificationOpts: { + constructorArgsImplementation: [], + constructorArgsProxy: [ + "0x56fF81aBB5cdaC478bF236db717e4976b2ff841e", + "0xae15d2023a76174a940cbb2b7f44012c728b9d74", + ethers.hexlify(ethers.toUtf8Bytes("iden3.create2.EthIdentityValidator")), + ], + constructorArgsProxyAdmin: ["0xAe15d2023A76174a940cbb2b7F44012C728B9d74"], + libraries: {}, + }, + }, IDENTITY_TREE_STORE: { name: "IdentityTreeStore", version: "1.1.0", @@ -332,46 +374,40 @@ export const contractsInfo = Object.freeze({ libraries: {}, }, }, - GROTH16_VERIFIER_AUTH_V2: { - name: "Groth16VerifierAuthV2Wrapper", + GROTH16_VERIFIER_LINKED_MULTI_QUERY10: { + name: "Groth16VerifierLinkedMultiQuery10Wrapper", unifiedAddress: "", create2Calldata: "", verificationOpts: { contract: - "contracts/lib/groth16-verifiers/Groth16VerifierAuthV2Wrapper.sol:Groth16VerifierAuthV2Wrapper", - constructorArgsImplementation: [], - libraries: {}, - }, - }, - STATE_LIB: { - name: "StateLib", - unifiedAddress: "", - create2Address: "", - verificationOpts: { + "contracts/lib/groth16-verifiers/Groth16VerifierLinkedMultiQuery10Wrapper.sol:Groth16VerifierLinkedMultiQuery10Wrapper", constructorArgsImplementation: [], libraries: {}, }, }, - STATE_CROSS_CHAIN_LIB: { - name: "StateCrossChainLib", + GROTH16_VERIFIER_AUTH_V2: { + name: "Groth16VerifierAuthV2Wrapper", unifiedAddress: "", - create2Address: "", + create2Calldata: "", verificationOpts: { + contract: + "contracts/lib/groth16-verifiers/Groth16VerifierAuthV2Wrapper.sol:Groth16VerifierAuthV2Wrapper", constructorArgsImplementation: [], libraries: {}, }, }, - VERIFIER_LIB: { - name: "VerifierLib", + STATE_LIB: { + name: "StateLib", unifiedAddress: "", - create2Address: "", + create2Calldata: "", verificationOpts: { constructorArgsImplementation: [], libraries: {}, }, }, - EMBEDDED_ZKP_VERIFIER_WRAPPER: { - name: "EmbeddedZKPVerifierWrapper", + + EMBEDDED_VERIFIER_WRAPPER: { + name: "EmbeddedVerifierWrapper", unifiedAddress: "", create2Calldata: "", }, @@ -488,6 +524,24 @@ export const TRANSPARENT_UPGRADEABLE_PROXY_ABI = [ stateMutability: "payable", type: "fallback", }, + { + inputs: [ + { + internalType: "address", + name: "newImplementation", + type: "address", + }, + { + internalType: "bytes", + name: "data", + type: "bytes", + }, + ], + name: "upgradeToAndCall", + outputs: [], + stateMutability: "payable", + type: "function", + }, ]; export const SIGNED_SERIALISED_TRANSACTION_GAS_LIMIT_25000000 = diff --git a/ignition/deployments/chain-6913/deployed_addresses.json b/ignition/deployments/chain-6913/deployed_addresses.json new file mode 100644 index 000000000..8f5472f64 --- /dev/null +++ b/ignition/deployments/chain-6913/deployed_addresses.json @@ -0,0 +1,12 @@ +{ + "Poseidon1Module#Poseidon1Element": "0xC72D76D7271924a2AD54a19D216640FeA3d138d9", + "Poseidon2Module#Poseidon2Element": "0x72F721D9D5f91353B505207C63B56cF3d9447edB", + "Poseidon3Module#Poseidon3Element": "0x5Bc89782d5eBF62663Df7Ce5fb4bc7408926A240", + "Poseidon4Module#Poseidon4Element": "0x0695cF2c6dfc438a4E40508741888198A6ccacC2", + "SmtLibModule#PoseidonUnit2L": "0x72F721D9D5f91353B505207C63B56cF3d9447edB", + "SmtLibModule#PoseidonUnit3L": "0x5Bc89782d5eBF62663Df7Ce5fb4bc7408926A240", + "SmtLibModule#SmtLib": "0x682364078e26C1626abD2B95109D2019E241F0F6", + "Create2AddressAnchorModule#Create2AddressAnchor": "0x56fF81aBB5cdaC478bF236db717e4976b2ff841e", + "StateProxyModule#TransparentUpgradeableProxy": "0x3C9acB2205Aa72A05F6D77d708b5Cf85FCa3a896", + "StateProxyModule#ProxyAdmin": "0x3F570C4fE07c532cd274dF2d1dB26D74cc5F8F9A" +} diff --git a/ignition/deployments/chain-6913/journal.jsonl b/ignition/deployments/chain-6913/journal.jsonl new file mode 100644 index 000000000..319a537e4 --- /dev/null +++ b/ignition/deployments/chain-6913/journal.jsonl @@ -0,0 +1,48 @@ + +{"chainId":6913,"type":"DEPLOYMENT_INITIALIZE"} +{"artifactId":"Poseidon1Module#Poseidon1Element","constructorArgs":[],"contractName":"Poseidon1Element","dependencies":[],"from":"0xcabae40a68bcb419c8d9a3ab5eaef63810c2d4f4","futureId":"Poseidon1Module#Poseidon1Element","futureType":"CONTRACT_DEPLOYMENT","libraries":{},"strategy":"create2","strategyConfig":{"salt":"0x000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d1"},"type":"DEPLOYMENT_EXECUTION_STATE_INITIALIZE","value":{"_kind":"bigint","value":"0"}} +{"futureId":"Poseidon1Module#Poseidon1Element","networkInteraction":{"data":"0x26307668000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001ac938600c600039611abd6000f37c01000000000000000000000000000000000000000000000000000000006000350480631caab9a71490635ba5832c14176200003757fe5b7f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad56020527f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e86040527f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff96060527f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c86080527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016004356000827f09c46e9ec68e9bd4fe1faaba294cba38a71aa177534cdd1b6c7dc0dbd0abd7a782089050827f0c0356530896eec42a97ed937f3135cfc5142b3ae405b8343c1d83ffa604cb81830891508281818082800980090990508282818082800980090991506200015e60005262001a96565b827f1e28a1d935698ad1142e51182bb54cf4a00ea5aabd6268bd317ea977cc154a3082089050827f27af2d831a9d2748080965db30e298e40e5757c3e008db964cf9e2b12b91251f83089150828181808280098009099050828281808280098009099150620001cf60005262001a96565b827f1e6f11ce60fc8f513a6a3cfe16ae175a41291462f214cd0879aaf43545b74e0382089050827f2a67384d3bbd5e438541819cb681f0be04462ed14c3613d8f719206268d142d3830891508281818082800980090990508282818082800980090991506200024060005262001a96565b827f0b66fdf356093a611609f8e12fbfecf0b985e381f025188936408f5d5c9f45d082089050827f012ee3ec1e78d470830c61093c2ade370b26c83cc5cebeeddaa6852dbdb09e2183089150828181808280098009099050828281808280098009099150620002b160005262001a96565b827f0252ba5f6760bfbdfd88f67f8175e3fd6cd1c431b099b6bb2d108e7b445bb1b982089050827f179474cceca5ff676c6bec3cef54296354391a8935ff71d6ef5aeaad7ca932f1830891508281818082800980090990506200031660005262001a96565b827f2c24261379a51bfa9228ff4a503fd4ed9c1f974a264969b37e1a2589bbed2b9182089050827f1cc1d7b62692e63eac2f288bd0695b43c2f63f5001fc0fc553e66c0551801b05830891508281818082800980090990506200037b60005262001a96565b827f255059301aada98bb2ed55f852979e9600784dbf17fbacd05d9eff5fd9c91b5682089050827f28437be3ac1cb2e479e1f5c0eccd32b3aea24234970a8193b11c29ce7e59efd983089150828181808280098009099050620003e060005262001a96565b827f28216a442f2e1f711ca4fa6b53766eb118548da8fb4f78d4338762c37f5f204382089050827f2c1f47cd17fa5adf1f39f4e7056dd03feee1efce03094581131f2377323482c9830891508281818082800980090990506200044560005262001a96565b827f07abad02b7a5ebc48632bcc9356ceb7dd9dafca276638a63646b8566a621afc982089050827f0230264601ffdf29275b33ffaab51dfe9429f90880a69cd137da0c4d15f96c3c83089150828181808280098009099050620004aa60005262001a96565b827f1bc973054e51d905a0f168656497ca40a864414557ee289e717e5d66899aa0a982089050827f2e1c22f964435008206c3157e86341edd249aff5c2d8421f2a6b22288f0a67fc830891508281818082800980090990506200050f60005262001a96565b827f1224f38df67c5378121c1d5f461bbc509e8ea1598e46c9f7a70452bc2bba86b882089050827f02e4e69d8ba59e519280b4bd9ed0068fd7bfe8cd9dfeda1969d2989186cde20e830891508281818082800980090990506200057460005262001a96565b827f1f1eccc34aaba0137f5df81fc04ff3ee4f19ee364e653f076d47e9735d98018e82089050827f1672ad3d709a353974266c3039a9a7311424448032cd1819eacb8a4d4284f58283089150828181808280098009099050620005d960005262001a96565b827f283e3fdc2c6e420c56f44af5192b4ae9cda6961f284d24991d2ed602df8c8fc782089050827f1c2a3d120c550ecfd0db0957170fa013683751f8fdff59d6614fbd69ff394bcc830891508281818082800980090990506200063e60005262001a96565b827f216f84877aac6172f7897a7323456efe143a9a43773ea6f296cb6b8177653fbd82089050827f2c0d272becf2a75764ba7e8e3e28d12bceaa47ea61ca59a411a1f51552f9478883089150828181808280098009099050620006a360005262001a96565b827f16e34299865c0e28484ee7a74c454e9f170a5480abe0508fcb4a6c3d89546f4382089050827f175ceba599e96f5b375a232a6fb9cc71772047765802290f48cd939755488fc5830891508281818082800980090990506200070860005262001a96565b827f0c7594440dc48c16fead9e1758b028066aa410bfbc354f54d8c5ffbb44a1ee3282089050827f1a3c29bc39f21bb5c466db7d7eb6fd8f760e20013ccf912c92479882d919fd8d830891508281818082800980090990506200076d60005262001a96565b827f0ccfdd906f3426e5c0986ea049b253400855d349074f5a6695c8eeabcd22e68f82089050827f14f6bc81d9f186f62bdb475ce6c9411866a7a8a3fd065b3ce0e699b67dd9e79683089150828181808280098009099050620007d260005262001a96565b827f0962b82789fb3d129702ca70b2f6c5aacc099810c9c495c888edeb7386b9705282089050827f1a880af7074d18b3bf20c79de25127bc13284ab01ef02575afef0c8f6a31a86d830891508281818082800980090990506200083760005262001a96565b827f10cba18419a6a332cd5e77f0211c154b20af2924fc20ff3f4c3012bb7ae9311b82089050827f057e62a9a8f89b3ebdc76ba63a9eaca8fa27b7319cae3406756a2849f302f10d830891508281818082800980090990506200089c60005262001a96565b827f287c971de91dc0abd44adf5384b4988cb961303bbf65cff5afa0413b44280cee82089050827f21df3388af1687bbb3bca9da0cca908f1e562bc46d4aba4e6f7f7960e306891d830891508281818082800980090990506200090160005262001a96565b827f1be5c887d25bce703e25cc974d0934cd789df8f70b498fd83eff8b560e1682b382089050827f268da36f76e568fb68117175cea2cd0dd2cb5d42fda5acea48d59c2706a0d5c1830891508281818082800980090990506200096660005262001a96565b827f0e17ab091f6eae50c609beaf5510ececc5d8bb74135ebd05bd06460cc26a5ed682089050827f04d727e728ffa0a67aee535ab074a43091ef62d8cf83d270040f5caa1f62af4083089150828181808280098009099050620009cb60005262001a96565b827f0ddbd7bf9c29341581b549762bc022ed33702ac10f1bfd862b15417d7e39ca6e82089050827f2790eb3351621752768162e82989c6c234f5b0d1d3af9b588a29c49c8789654b8308915082818180828009800909905062000a3060005262001a96565b827f1e457c601a63b73e4471950193d8a570395f3d9ab8b2fd0984b764206142f9e982089050827f21ae64301dca9625638d6ab2bbe7135ffa90ecd0c43ff91fc4c686fc46e091b08308915082818180828009800909905062000a9560005262001a96565b827f0379f63c8ce3468d4da293166f494928854be9e3432e09555858534eed8d350b82089050827f002d56420359d0266a744a080809e054ca0e4921a46686ac8c9f58a324c350498308915082818180828009800909905062000afa60005262001a96565b827f123158e5965b5d9b1d68b3cd32e10bbeda8d62459e21f4090fc2c5af963515a682089050827f0be29fc40847a941661d14bbf6cbe0420fbb2b6f52836d4e60c80eb49cad9ec18308915082818180828009800909905062000b5f60005262001a96565b827f1ac96991dec2bb0557716142015a453c36db9d859cad5f9a233802f24fdf4c1a82089050827f1596443f763dbcc25f4964fc61d23b3e5e12c9fa97f18a9251ca3355bcb0627e8308915082818180828009800909905062000bc460005262001a96565b827f12e0bcd3654bdfa76b2861d4ec3aeae0f1857d9f17e715aed6d049eae3ba321282089050827f0fc92b4f1bbea82b9ea73d4af9af2a50ceabac7f37154b1904e6c76c7cf964ba8308915082818180828009800909905062000c2960005262001a96565b827f1f9c0b1610446442d6f2e592a8013f40b14f7c7722236f4f9c7e96523387276282089050827f0ebd74244ae72675f8cde06157a782f4050d914da38b4c058d159f643dbbf4d38308915082818180828009800909905062000c8e60005262001a96565b827f2cb7f0ed39e16e9f69a9fafd4ab951c03b0671e97346ee397a839839dccfc6d182089050827f1a9d6e2ecff022cc5605443ee41bab20ce761d0514ce526690c72bca7352d9bf8308915082818180828009800909905062000cf360005262001a96565b827f2a115439607f335a5ea83c3bc44a9331d0c13326a9a7ba3087da182d648ec72f82089050827f23f9b6529b5d040d15b8fa7aee3e3410e738b56305cd44f29535c115c5a4c0608308915082818180828009800909905062000d5860005262001a96565b827f05872c16db0f72a2249ac6ba484bb9c3a3ce97c16d58b68b260eb939f0e6e8a782089050827f1300bdee08bb7824ca20fb80118075f40219b6151d55b5c52b624a7cdeddf6a78308915082818180828009800909905062000dbd60005262001a96565b827f19b9b63d2f108e17e63817863a8f6c288d7ad29916d98cb1072e4e7b7d52b37682089050827f015bee1357e3c015b5bda237668522f613d1c88726b5ec4224a20128481b4f7f8308915082818180828009800909905062000e2260005262001a96565b827f2953736e94bb6b9f1b9707a4f1615e4efe1e1ce4bab218cbea92c785b128ffd182089050827f0b069353ba091618862f806180c0385f851b98d372b45f544ce7266ed6608dfc8308915082818180828009800909905062000e8760005262001a96565b827f304f74d461ccc13115e4e0bcfb93817e55aeb7eb9306b64e4f588ac97d81f42982089050827f15bbf146ce9bca09e8a33f5e77dfe4f5aad2a164a4617a4cb8ee5415cde913fc8308915082818180828009800909905062000eec60005262001a96565b827f0ab4dfe0c2742cde44901031487964ed9b8f4b850405c10ca9ff23859572c8c682089050827f0e32db320a044e3197f45f7649a19675ef5eedfea546dea9251de39f9639779a8308915082818180828009800909905062000f5160005262001a96565b827f0a1756aa1f378ca4b27635a78b6888e66797733a82774896a3078efa516da01682089050827f044c4a33b10f693447fd17177f952ef895e61d328f85efa94254d6a2a25d93ef8308915082818180828009800909905062000fb660005262001a96565b827f2ed3611b725b8a70be655b537f66f700fe0879d79a496891d37b07b5466c4b8b82089050827f1f9ba4e8bab7ce42c8ecc3d722aa2e0eadfdeb9cfdd347b5d8339ea7120858aa830891508281818082800980090990506200101b60005262001a96565b827f1b233043052e8c288f7ee907a84e518aa38e82ac4502066db74056f865c5d3da82089050827f2431e1cc164bb8d074031ab72bd55b4c902053bfc0f14db0ca2f97b020875954830891508281818082800980090990506200108060005262001a96565b827f082f934c91f5aac330cd6953a0a7db45a13e322097583319a791f273965801fd82089050827f2b9a0a223e7538b0a34be074315542a3c77245e2ae7cbe999ad6bb930c48997c83089150828181808280098009099050620010e560005262001a96565b827f0e1cd91edd2cfa2cceb85483b887a9be8164163e75a8a00eb0b589cc70214e7d82089050827f2e1eac0f2bfdfd63c951f61477e3698999774f19854d00f588d324601cebe2f9830891508281818082800980090990506200114a60005262001a96565b827f0cbfa95f37fb74060c76158e769d6d157345784d8efdb33c23d748115b500b8382089050827f08f05b3be923ed44d65ad49d8a61e9a676d991e3a77513d9980c232dfa4a4f8483089150828181808280098009099050620011af60005262001a96565b827f22719e2a070bcd0852bf8e21984d0443e7284925dc0758a325a2dd510c047ef682089050827f041f596a9ee1cb2bc060f7fcc3a1ab4c7bdbf036119982c0f41f62b2f26830c0830891508281818082800980090990506200121460005262001a96565b827f233fd35de1be520a87628eb06f6b1d4c021be1c2d0dc464a19fcdd0986b10f8982089050827f0524b46d1aa87a5e4325e0a423ebc810d31e078aa1b4707eefcb453c61c9c267830891508281818082800980090990506200127960005262001a96565b827f2c34f424c81e5716ce47fcac894b85824227bb954b0f3199cc4486237c51521182089050827f0b5f2a4b63387819207effc2b5541fb72dd2025b5457cc97f33010327de4915e83089150828181808280098009099050620012de60005262001a96565b827f22207856082ccc54c5b72fe439d2cfd6c17435d2f57af6ceaefac41fe05c659f82089050827f24d57a8bf5da63fe4e24159b7f8950b5cdfb210194caf79f27854048ce2c8171830891508281818082800980090990506200134360005262001a96565b827f0afab181fdd5e0583b371d75bd693f98374ad7097bb01a8573919bb23b79396e82089050827f2dba9b108f208772998a52efac7cbd5676c0057194c16c0bf16290d62b1128ee83089150828181808280098009099050620013a860005262001a96565b827f26349b66edb8b16f56f881c788f53f83cbb83de0bd592b255aff13e6bce420b382089050827f25af7ce0e5e10357685e95f92339753ad81a56d28ecc193b235288a3e6f137db830891508281818082800980090990506200140d60005262001a96565b827f25b4ce7bd2294390c094d6a55edd68b970eed7aae88b2bff1f7c0187fe35011f82089050827f22c543f10f6c89ec387e53f1908a88e5de9cef28ebdf30b18cb9d54c1e02b631830891508281818082800980090990506200147260005262001a96565b827f0236f93e7789c4724fc7908a9f191e1e425e906a919d7a34df668e74882f87a982089050827f29350b401166ca010e7d27e37d05da99652bdae114eb01659cb497af980c4b5283089150828181808280098009099050620014d760005262001a96565b827f0eed787d65820d3f6bd31bbab547f75a65edb75d844ebb89ee1260916652363f82089050827f07cc1170f13b46f2036a753f520b3291fdcd0e99bd94297d1906f656f4de6fad830891508281818082800980090990506200153c60005262001a96565b827f22b939233b1d7205f49bcf613a3d30b1908786d7f9f5d10c2059435689e8acea82089050827f01451762a0aab81c8aad1dc8bc33e870740f083a5aa85438add650ace60ae5a683089150828181808280098009099050620015a160005262001a96565b827f23506bb5d8727d4461fabf1025d46d1fe32eaa61dec7da57e704fec0892fce8982089050827f2e484c44e838aea0bac06ae3f71bdd092a3709531e1efea97f8bd68907355522830891508281818082800980090990506200160660005262001a96565b827f0f4bc7d07ebafd64379e78c50bd2e42baf4a594545cedc2545418da26835b54c82089050827f1f4d3c8f6583e9e5fa76637862faaee851582388725df460e620996d50d8e74e830891508281818082800980090990506200166b60005262001a96565b827f093514e0c70711f82660d07be0e4a988fae02abc7b681d9153eb9bcb48fe738982089050827f1adab0c8e2b3bad346699a2b5f3bc03643ee83ece47228f24a58e0a347e153d883089150828181808280098009099050620016d060005262001a96565b827f1672b1726057d99dd14709ebb474641a378c1b94b8072bac1a22dbef9e80dad282089050827f1dfd53d4576af2e38f44f53fdcab468cc5d8e2fae0acc4ee30d47b239b479c14830891508281818082800980090990506200173560005262001a96565b827f0c6888a10b75b0f3a70a36263a37e17fe6d77d640f6fc3debc7f207753205c6082089050827f1addb933a65be77092b34a7e77d12fe8611a61e00ee6848b85091ecca9d1e508830891508281818082800980090990506200179a60005262001a96565b827f00d7540dcd268a845c10ae18d1de933cf638ff5425f0afff7935628e299d179182089050827f140c0e42687e9ead01b2827a5664ca9c26fedde4acd99db1d316939d20b82c0e83089150828181808280098009099050620017ff60005262001a96565b827f2f0c3a115d4317d191ba89b8d13d1806c20a0f9b24f8c5edc091e2ae5656598482089050827f0c4ee778ff7c14553006ed220cf9c81008a0cff670b22b82d8c538a1dc958c61830891508281818082800980090990506200186460005262001a96565b827f1704f2766d46f82c3693f00440ccc3609424ed26c0acc66227c3d7485de74c6982089050827f2f2d19cc3ea5d78ea7a02c1b51d244abf0769c9f8544e40239b66fe9009c3cfa83089150828181808280098009099050620018c960005262001a96565b827f1ae03853b75fcaba5053f112e2a8e8dcdd7ee6cb9cfed9c7d6c766a806fc662982089050827f0971aabf795241df51d131d0fa61aa5f3556921b2d6f014e4e41a86ddaf056d5830891508281818082800980090990508282818082800980090991506200193a60005262001a96565b827f1408c316e6014e1a91d4cf6b6e0de73eda624f8380df1c875f5c29f7bfe2f64682089050827f1667f3fe2edbe850248abe42b543093b6c89f1f773ef285341691f39822ef5bd83089150828181808280098009099050828281808280098009099150620019ab60005262001a96565b827f13bf7c5d0d2c4376a48b0a03557cdf915b81718409e5c133424c69576500fe3782089050827f07620a6dfb0b6cec3016adf3d3533c24024b95347856b79719bc0ba743a62c2c8308915082818180828009800909905082828180828009800909915062001a1c60005262001a96565b827f1574c7ef0c43545f36a8ca08bdbdd8b075d2959e2f322b731675de3e1982b4d082089050827f269e4b5b7a2eb21afd567970a717ceec5bd4184571c254fdc06e03a7ff8378f08308915082818180828009800909905082828180828009800909915062001a8d60005262001a96565b60005260206000f35b82602051820983604051840984910883606051830984608051850985910892509050600051560000000000000000000000000000000000000000000000","id":1,"to":"0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed","type":"ONCHAIN_INTERACTION","value":{"_kind":"bigint","value":"0"}},"type":"NETWORK_INTERACTION_REQUEST"} +{"futureId":"Poseidon1Module#Poseidon1Element","networkInteractionId":1,"nonce":5,"type":"TRANSACTION_PREPARE_SEND"} +{"futureId":"Poseidon1Module#Poseidon1Element","networkInteractionId":1,"nonce":5,"transaction":{"fees":{"gasPrice":{"_kind":"bigint","value":"1000000000"}},"hash":"0xc6524636bfc6576a7c7e27de0912cd38537383b3d2619d0c7a1864e426f36bb9"},"type":"TRANSACTION_SEND"} +{"futureId":"Poseidon1Module#Poseidon1Element","hash":"0xc6524636bfc6576a7c7e27de0912cd38537383b3d2619d0c7a1864e426f36bb9","networkInteractionId":1,"receipt":{"blockHash":"0xbae595fa2d6589fe7f943dc3b8a2f8b3cf4e66a756a84d73c35b751d10d18f1f","blockNumber":100793,"logs":[{"address":"0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed","data":"0x","logIndex":0,"topics":["0xb8fda7e00c6b06a2b54e58521bc5894fee35f1090e5a3bb6390bfe2b98b497f7","0x000000000000000000000000c72d76d7271924a2ad54a19d216640fea3d138d9","0x1fb806fe12ba202b72799840b31b8b2ba7246fc0a96873ac3602d29c91d8c2d0"]}],"status":"SUCCESS"},"type":"TRANSACTION_CONFIRM"} +{"futureId":"Poseidon1Module#Poseidon1Element","result":{"address":"0xC72D76D7271924a2AD54a19D216640FeA3d138d9","type":"SUCCESS"},"type":"DEPLOYMENT_EXECUTION_STATE_COMPLETE"} +{"artifactId":"Poseidon2Module#Poseidon2Element","constructorArgs":[],"contractName":"Poseidon2Element","dependencies":[],"from":"0xcabae40a68bcb419c8d9a3ab5eaef63810c2d4f4","futureId":"Poseidon2Module#Poseidon2Element","futureType":"CONTRACT_DEPLOYMENT","libraries":{},"strategy":"create2","strategyConfig":{"salt":"0x000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d1"},"type":"DEPLOYMENT_EXECUTION_STATE_INITIALIZE","value":{"_kind":"bigint","value":"0"}} +{"futureId":"Poseidon2Module#Poseidon2Element","networkInteraction":{"data":"0x26307668000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d10000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000261b38600c60003961260f6000f37c010000000000000000000000000000000000000000000000000000000060003504806329a5f2f6149063299e566014176200003757fe5b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b6020527f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e06040527f2b90bba00fca0589f617e7dcbfe82e0df706ab640ceb247b791a93b74e36736d6060527f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd7716080527f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2360a0527f101071f0032379b697315876690f053d148d4e109f5fb065c8aacc55a0f89bfa60c0527f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a760e0527f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee2911610100527f19a3fc0a56702bf417ba7fee3802593fa644470307043f7773279cd71d25d5e0610120527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016024356004356000837f0ee9a592ba9a9518d05986d656f40c2114c4993c11bb29938d21d47304cd8e6e82089050837f00f1445235f2148c5986587169fc1bcd887b08d4d00868df5696fff40956e86483089150837f08dff3487e8ac99e1f29a058d0fa80b930c728730b7ab36ce879f3890ecf73f58408925083818180828009800909905083828180828009800909915083838180828009800909925062000249600052620025ba565b837f2f27be690fdaee46c3ce28f7532b13c856c35342c84bda6e20966310fadc01d082089050837f2b2ae1acf68b7b8d2416bebf3d4f6234b763fe04b8043ee48b8327bebca16cf283089150837f0319d062072bef7ecca5eac06f97d4d55952c175ab6b03eae64b44c7dbf11cfa84089250838181808280098009099050838281808280098009099150838381808280098009099250620002ec600052620025ba565b837f28813dcaebaeaa828a376df87af4a63bc8b7bf27ad49c6298ef7b387bf28526d82089050837f2727673b2ccbc903f181bf38e1c1d40d2033865200c352bc150928adddf9cb7883089150837f234ec45ca27727c2e74abd2b2a1494cd6efbd43e340587d6b8fb9e31e65cc632840892508381818082800980090990508382818082800980090991508383818082800980090992506200038f600052620025ba565b837f15b52534031ae18f7f862cb2cf7cf760ab10a8150a337b1ccd99ff6e8797d42882089050837f0dc8fad6d9e4b35f5ed9a3d186b79ce38e0e8a8d1b58b132d701d4eecf68d1f683089150837f1bcd95ffc211fbca600f705fad3fb567ea4eb378f62e1fec97805518a47e4d9c8408925083818180828009800909905083828180828009800909915083838180828009800909925062000432600052620025ba565b837f10520b0ab721cadfe9eff81b016fc34dc76da36c2578937817cb978d069de55982089050837f1f6d48149b8e7f7d9b257d8ed5fbbaf42932498075fed0ace88a9eb81f5627f683089150837f1d9655f652309014d29e00ef35a2089bfff8dc1c816f0dc9ca34bdb5460c870584089250838181808280098009099050620004bd600052620025ba565b837f04df5a56ff95bcafb051f7b1cd43a99ba731ff67e47032058fe3d4185697cc7d82089050837f0672d995f8fff640151b3d290cedaf148690a10a8c8424a7f6ec282b6e4be82883089150837f099952b414884454b21200d7ffafdd5f0c9a9dcc06f2708e9fc1d8209b5c75b98408925083818180828009800909905062000548600052620025ba565b837f052cba2255dfd00c7c483143ba8d469448e43586a9b4cd9183fd0e843a6b9fa682089050837f0b8badee690adb8eb0bd74712b7999af82de55707251ad7716077cb93c464ddc83089150837f119b1590f13307af5a1ee651020c07c749c15d60683a8050b963d0a8e4b2bdd184089250838181808280098009099050620005d3600052620025ba565b837f03150b7cd6d5d17b2529d36be0f67b832c4acfc884ef4ee5ce15be0bfb4a8d0982089050837f2cc6182c5e14546e3cf1951f173912355374efb83d80898abe69cb317c9ea56583089150837f005032551e6378c450cfe129a404b3764218cadedac14e2b92d2cd73111bf0f9840892508381818082800980090990506200065e600052620025ba565b837f233237e3289baa34bb147e972ebcb9516469c399fcc069fb88f9da2cc28276b582089050837f05c8f4f4ebd4a6e3c980d31674bfbe6323037f21b34ae5a4e80c2d4c24d6028083089150837f0a7b1db13042d396ba05d818a319f25252bcf35ef3aeed91ee1f09b2590fc65b84089250838181808280098009099050620006e9600052620025ba565b837f2a73b71f9b210cf5b14296572c9d32dbf156e2b086ff47dc5df542365a404ec082089050837f1ac9b0417abcc9a1935107e9ffc91dc3ec18f2c4dbe7f22976a760bb5c50c46083089150837f12c0339ae08374823fabb076707ef479269f3e4d6cb104349015ee046dc93fc08408925083818180828009800909905062000774600052620025ba565b837f0b7475b102a165ad7f5b18db4e1e704f52900aa3253baac68246682e56e9a28e82089050837f037c2849e191ca3edb1c5e49f6e8b8917c843e379366f2ea32ab3aa88d7f844883089150837f05a6811f8556f014e92674661e217e9bd5206c5c93a07dc145fdb176a716346f84089250838181808280098009099050620007ff600052620025ba565b837f29a795e7d98028946e947b75d54e9f044076e87a7b2883b47b675ef5f38bd66e82089050837f20439a0c84b322eb45a3857afc18f5826e8c7382c8a1585c507be199981fd22f83089150837f2e0ba8d94d9ecf4a94ec2050c7371ff1bb50f27799a84b6d4a2a6f2a0982c887840892508381818082800980090990506200088a600052620025ba565b837f143fd115ce08fb27ca38eb7cce822b4517822cd2109048d2e6d0ddcca17d71c882089050837f0c64cbecb1c734b857968dbbdcf813cdf8611659323dbcbfc84323623be9caf183089150837f028a305847c683f646fca925c163ff5ae74f348d62c2b670f1426cef9403da538408925083818180828009800909905062000915600052620025ba565b837f2e4ef510ff0b6fda5fa940ab4c4380f26a6bcb64d89427b824d6755b5db9e30c82089050837f0081c95bc43384e663d79270c956ce3b8925b4f6d033b078b96384f50579400e83089150837f2ed5f0c91cbd9749187e2fade687e05ee2491b349c039a0bba8a9f4023a0bb3884089250838181808280098009099050620009a0600052620025ba565b837f30509991f88da3504bbf374ed5aae2f03448a22c76234c8c990f01f33a73520682089050837f1c3f20fd55409a53221b7c4d49a356b9f0a1119fb2067b41a7529094424ec6ad83089150837f10b4e7f3ab5df003049514459b6e18eec46bb2213e8e131e170887b47ddcb96c8408925083818180828009800909905062000a2b600052620025ba565b837f2a1982979c3ff7f43ddd543d891c2abddd80f804c077d775039aa3502e43adef82089050837f1c74ee64f15e1db6feddbead56d6d55dba431ebc396c9af95cad0f1315bd5c9183089150837f07533ec850ba7f98eab9303cace01b4b9e4f2e8b82708cfa9c2fe45a0ae146a08408925083818180828009800909905062000ab6600052620025ba565b837f21576b438e500449a151e4eeaf17b154285c68f42d42c1808a11abf3764c075082089050837f2f17c0559b8fe79608ad5ca193d62f10bce8384c815f0906743d6930836d4a9e83089150837f2d477e3862d07708a79e8aae946170bc9775a4201318474ae665b0b1b7e2730e8408925083818180828009800909905062000b41600052620025ba565b837f162f5243967064c390e095577984f291afba2266c38f5abcd89be0f5b2747eab82089050837f2b4cb233ede9ba48264ecd2c8ae50d1ad7a8596a87f29f8a7777a7009239331183089150837f2c8fbcb2dd8573dc1dbaf8f4622854776db2eece6d85c4cf4254e7c35e03b07a8408925083818180828009800909905062000bcc600052620025ba565b837f1d6f347725e4816af2ff453f0cd56b199e1b61e9f601e9ade5e88db870949da982089050837f204b0c397f4ebe71ebc2d8b3df5b913df9e6ac02b68d31324cd49af5c456552983089150837f0c4cb9dc3c4fd8174f1149b3c63c3c2f9ecb827cd7dc25534ff8fb75bc79c5028408925083818180828009800909905062000c57600052620025ba565b837f174ad61a1448c899a25416474f4930301e5c49475279e0639a616ddc45bc7b5482089050837f1a96177bcf4d8d89f759df4ec2f3cde2eaaa28c177cc0fa13a9816d49a38d2ef83089150837f066d04b24331d71cd0ef8054bc60c4ff05202c126a233c1a8242ace360b8a30a8408925083818180828009800909905062000ce2600052620025ba565b837f2a4c4fc6ec0b0cf52195782871c6dd3b381cc65f72e02ad527037a62aa1bd80482089050837f13ab2d136ccf37d447e9f2e14a7cedc95e727f8446f6d9d7e55afc01219fd64983089150837f1121552fca26061619d24d843dc82769c1b04fcec26f55194c2e3e869acc6a9a8408925083818180828009800909905062000d6d600052620025ba565b837f00ef653322b13d6c889bc81715c37d77a6cd267d595c4a8909a5546c7c97cff182089050837f0e25483e45a665208b261d8ba74051e6400c776d652595d9845aca35d8a397d383089150837f29f536dcb9dd7682245264659e15d88e395ac3d4dde92d8c46448db979eeba898408925083818180828009800909905062000df8600052620025ba565b837f2a56ef9f2c53febadfda33575dbdbd885a124e2780bbea170e456baace0fa5be82089050837f1c8361c78eb5cf5decfb7a2d17b5c409f2ae2999a46762e8ee416240a8cb9af183089150837f151aff5f38b20a0fc0473089aaf0206b83e8e68a764507bfd3d0ab4be74319c58408925083818180828009800909905062000e83600052620025ba565b837f04c6187e41ed881dc1b239c88f7f9d43a9f52fc8c8b6cdd1e76e47615b51f10082089050837f13b37bd80f4d27fb10d84331f6fb6d534b81c61ed15776449e801b7ddc9c296783089150837f01a5c536273c2d9df578bfbd32c17b7a2ce3664c2a52032c9321ceb1c4e8a8e48408925083818180828009800909905062000f0e600052620025ba565b837f2ab3561834ca73835ad05f5d7acb950b4a9a2c666b9726da832239065b7c3b0282089050837f1d4d8ec291e720db200fe6d686c0d613acaf6af4e95d3bf69f7ed516a597b64683089150837f041294d2cc484d228f5784fe7919fd2bb925351240a04b711514c9c80b65af1d8408925083818180828009800909905062000f99600052620025ba565b837f154ac98e01708c611c4fa715991f004898f57939d126e392042971dd90e81fc682089050837f0b339d8acca7d4f83eedd84093aef51050b3684c88f8b0b04524563bc6ea4da483089150837f0955e49e6610c94254a4f84cfbab344598f0e71eaff4a7dd81ed95b50839c82e8408925083818180828009800909905062001024600052620025ba565b837f06746a6156eba54426b9e22206f15abca9a6f41e6f535c6f3525401ea065462682089050837f0f18f5a0ecd1423c496f3820c549c27838e5790e2bd0a196ac917c7ff32077fb83089150837f04f6eeca1751f7308ac59eff5beb261e4bb563583ede7bc92a738223d6f76e1384089250838181808280098009099050620010af600052620025ba565b837f2b56973364c4c4f5c1a3ec4da3cdce038811eb116fb3e45bc1768d26fc0b375882089050837f123769dd49d5b054dcd76b89804b1bcb8e1392b385716a5d83feb65d437f29ef83089150837f2147b424fc48c80a88ee52b91169aacea989f6446471150994257b2fb01c63e9840892508381818082800980090990506200113a600052620025ba565b837f0fdc1f58548b85701a6c5505ea332a29647e6f34ad4243c2ea54ad897cebe54d82089050837f12373a8251fea004df68abcf0f7786d4bceff28c5dbbe0c3944f685cc0a0b1f283089150837f21e4f4ea5f35f85bad7ea52ff742c9e8a642756b6af44203dd8a1f35c1a9003584089250838181808280098009099050620011c5600052620025ba565b837f16243916d69d2ca3dfb4722224d4c462b57366492f45e90d8a81934f1bc3b14782089050837f1efbe46dd7a578b4f66f9adbc88b4378abc21566e1a0453ca13a4159cac04ac283089150837f07ea5e8537cf5dd08886020e23a7f387d468d5525be66f853b672cc96a88969a8408925083818180828009800909905062001250600052620025ba565b837f05a8c4f9968b8aa3b7b478a30f9a5b63650f19a75e7ce11ca9fe16c0b76c00bc82089050837f20f057712cc21654fbfe59bd345e8dac3f7818c701b9c7882d9d57b72a32e83f83089150837f04a12ededa9dfd689672f8c67fee31636dcd8e88d01d49019bd90b33eb33db6984089250838181808280098009099050620012db600052620025ba565b837f27e88d8c15f37dcee44f1e5425a51decbd136ce5091a6767e49ec9544ccd101a82089050837f2feed17b84285ed9b8a5c8c5e95a41f66e096619a7703223176c41ee433de4d183089150837f1ed7cc76edf45c7c404241420f729cf394e5942911312a0d6972b8bd53aff2b88408925083818180828009800909905062001366600052620025ba565b837f15742e99b9bfa323157ff8c586f5660eac6783476144cdcadf2874be45466b1a82089050837f1aac285387f65e82c895fc6887ddf40577107454c6ec0317284f033f27d0c78583089150837f25851c3c845d4790f9ddadbdb6057357832e2e7a49775f71ec75a96554d67c7784089250838181808280098009099050620013f1600052620025ba565b837f15a5821565cc2ec2ce78457db197edf353b7ebba2c5523370ddccc3d9f146a6782089050837f2411d57a4813b9980efa7e31a1db5966dcf64f36044277502f15485f28c7172783089150837f002e6f8d6520cd4713e335b8c0b6d2e647e9a98e12f4cd2558828b5ef6cb4c9b840892508381818082800980090990506200147c600052620025ba565b837f2ff7bc8f4380cde997da00b616b0fcd1af8f0e91e2fe1ed7398834609e0315d282089050837f00b9831b948525595ee02724471bcd182e9521f6b7bb68f1e93be4febb0d3cbe83089150837f0a2f53768b8ebf6a86913b0e57c04e011ca408648a4743a87d77adbf0c9c35128408925083818180828009800909905062001507600052620025ba565b837f00248156142fd0373a479f91ff239e960f599ff7e94be69b7f2a290305e1198d82089050837f171d5620b87bfb1328cf8c02ab3f0c9a397196aa6a542c2350eb512a2b2bcda983089150837f170a4f55536f7dc970087c7c10d6fad760c952172dd54dd99d1045e4ec34a8088408925083818180828009800909905062001592600052620025ba565b837f29aba33f799fe66c2ef3134aea04336ecc37e38c1cd211ba482eca17e2dbfae182089050837f1e9bc179a4fdd758fdd1bb1945088d47e70d114a03f6a0e8b5ba650369e6497383089150837f1dd269799b660fad58f7f4892dfb0b5afeaad869a9c4b44f9c9e1c43bdaf8f09840892508381818082800980090990506200161d600052620025ba565b837f22cdbc8b70117ad1401181d02e15459e7ccd426fe869c7c95d1dd2cb0f24af3882089050837f0ef042e454771c533a9f57a55c503fcefd3150f52ed94a7cd5ba93b9c7dacefd83089150837f11609e06ad6c8fe2f287f3036037e8851318e8b08a0359a03b304ffca62e828484089250838181808280098009099050620016a8600052620025ba565b837f1166d9e554616dba9e753eea427c17b7fecd58c076dfe42708b08f5b783aa9af82089050837f2de52989431a859593413026354413db177fbf4cd2ac0b56f855a888357ee46683089150837f3006eb4ffc7a85819a6da492f3a8ac1df51aee5b17b8e89d74bf01cf5f71e9ad8408925083818180828009800909905062001733600052620025ba565b837f2af41fbb61ba8a80fdcf6fff9e3f6f422993fe8f0a4639f962344c822514508682089050837f119e684de476155fe5a6b41a8ebc85db8718ab27889e85e781b214bace4827c383089150837f1835b786e2e8925e188bea59ae363537b51248c23828f047cff784b97b3fd80084089250838181808280098009099050620017be600052620025ba565b837f28201a34c594dfa34d794996c6433a20d152bac2a7905c926c40e285ab32eeb682089050837f083efd7a27d1751094e80fefaf78b000864c82eb571187724a761f88c22cc4e783089150837f0b6f88a3577199526158e61ceea27be811c16df7774dd8519e079564f61fd13b8408925083818180828009800909905062001849600052620025ba565b837f0ec868e6d15e51d9644f66e1d6471a94589511ca00d29e1014390e6ee4254f5b82089050837f2af33e3f866771271ac0c9b3ed2e1142ecd3e74b939cd40d00d937ab84c9859183089150837f0b520211f904b5e7d09b5d961c6ace7734568c547dd6858b364ce5e47951f17884089250838181808280098009099050620018d4600052620025ba565b837f0b2d722d0919a1aad8db58f10062a92ea0c56ac4270e822cca228620188a1d4082089050837f1f790d4d7f8cf094d980ceb37c2453e957b54a9991ca38bbe0061d1ed6e562d483089150837f0171eb95dfbf7d1eaea97cd385f780150885c16235a2a6a8da92ceb01e504233840892508381818082800980090990506200195f600052620025ba565b837f0c2d0e3b5fd57549329bf6885da66b9b790b40defd2c8650762305381b16887382089050837f1162fb28689c27154e5a8228b4e72b377cbcafa589e283c35d3803054407a18d83089150837f2f1459b65dee441b64ad386a91e8310f282c5a92a89e19921623ef8249711bc084089250838181808280098009099050620019ea600052620025ba565b837f1e6ff3216b688c3d996d74367d5cd4c1bc489d46754eb712c243f70d1b53cfbb82089050837f01ca8be73832b8d0681487d27d157802d741a6f36cdc2a0576881f932647887583089150837f1f7735706ffe9fc586f976d5bdf223dc680286080b10cea00b9b5de315f9650e8408925083818180828009800909905062001a75600052620025ba565b837f2522b60f4ea3307640a0c2dce041fba921ac10a3d5f096ef4745ca838285f01982089050837f23f0bee001b1029d5255075ddc957f833418cad4f52b6c3f8ce16c235572575b83089150837f2bc1ae8b8ddbb81fcaac2d44555ed5685d142633e9df905f66d9401093082d598408925083818180828009800909905062001b00600052620025ba565b837f0f9406b8296564a37304507b8dba3ed162371273a07b1fc98011fcd6ad72205f82089050837f2360a8eb0cc7defa67b72998de90714e17e75b174a52ee4acb126c8cd995f0a883089150837f15871a5cddead976804c803cbaef255eb4815a5e96df8b006dcbbc2767f889488408925083818180828009800909905062001b8b600052620025ba565b837f193a56766998ee9e0a8652dd2f3b1da0362f4f54f72379544f957ccdeefb420f82089050837f2a394a43934f86982f9be56ff4fab1703b2e63c8ad334834e4309805e777ae0f83089150837f1859954cfeb8695f3e8b635dcb345192892cd11223443ba7b4166e8876c0d1428408925083818180828009800909905062001c16600052620025ba565b837f04e1181763050e58013444dbcb99f1902b11bc25d90bbdca408d3819f4fed32b82089050837f0fdb253dee83869d40c335ea64de8c5bb10eb82db08b5e8b1f5e5552bfd05f2383089150837f058cbe8a9a5027bdaa4efb623adead6275f08686f1c08984a9d7c5bae9b4f1c08408925083818180828009800909905062001ca1600052620025ba565b837f1382edce9971e186497eadb1aeb1f52b23b4b83bef023ab0d15228b4cceca59a82089050837f03464990f045c6ee0819ca51fd11b0be7f61b8eb99f14b77e1e6634601d9e8b583089150837f23f7bfc8720dc296fff33b41f98ff83c6fcab4605db2eb5aaa5bc137aeb70a588408925083818180828009800909905062001d2c600052620025ba565b837f0a59a158e3eec2117e6e94e7f0e9decf18c3ffd5e1531a9219636158bbaf62f282089050837f06ec54c80381c052b58bf23b312ffd3ce2c4eba065420af8f4c23ed0075fd07b83089150837f118872dc832e0eb5476b56648e867ec8b09340f7a7bcb1b4962f0ff9ed1f9d018408925083818180828009800909905062001db7600052620025ba565b837f13d69fa127d834165ad5c7cba7ad59ed52e0b0f0e42d7fea95e1906b520921b182089050837f169a177f63ea681270b1c6877a73d21bde143942fb71dc55fd8a49f19f10c77b83089150837f04ef51591c6ead97ef42f287adce40d93abeb032b922f66ffb7e9a5a7450544d8408925083818180828009800909905062001e42600052620025ba565b837f256e175a1dc079390ecd7ca703fb2e3b19ec61805d4f03ced5f45ee6dd0f69ec82089050837f30102d28636abd5fe5f2af412ff6004f75cc360d3205dd2da002813d3e2ceeb283089150837f10998e42dfcd3bbf1c0714bc73eb1bf40443a3fa99bef4a31fd31be182fcc7928408925083818180828009800909905062001ecd600052620025ba565b837f193edd8e9fcf3d7625fa7d24b598a1d89f3362eaf4d582efecad76f879e3686082089050837f18168afd34f2d915d0368ce80b7b3347d1c7a561ce611425f2664d7aa51f0b5d83089150837f29383c01ebd3b6ab0c017656ebe658b6a328ec77bc33626e29e2e95b33ea61118408925083818180828009800909905062001f58600052620025ba565b837f10646d2f2603de39a1f4ae5e7771a64a702db6e86fb76ab600bf573f9010c71182089050837f0beb5e07d1b27145f575f1395a55bf132f90c25b40da7b3864d0242dcb1117fb83089150837f16d685252078c133dc0d3ecad62b5c8830f95bb2e54b59abdffbf018d96fa3368408925083818180828009800909905062001fe3600052620025ba565b837f0a6abd1d833938f33c74154e0404b4b40a555bbbec21ddfafd672dd62047f01a82089050837f1a679f5d36eb7b5c8ea12a4c2dedc8feb12dffeec450317270a6f19b34cf186083089150837f0980fb233bd456c23974d50e0ebfde4726a423eada4e8f6ffbc7592e3f1b93d6840892508381818082800980090990506200206e600052620025ba565b837f161b42232e61b84cbf1810af93a38fc0cece3d5628c9282003ebacb5c312c72b82089050837f0ada10a90c7f0520950f7d47a60d5e6a493f09787f1564e5d09203db47de1a0b83089150837f1a730d372310ba82320345a29ac4238ed3f07a8a2b4e121bb50ddb9af407f45184089250838181808280098009099050620020f9600052620025ba565b837f2c8120f268ef054f817064c369dda7ea908377feaba5c4dffbda10ef58e8c55682089050837f1c7c8824f758753fa57c00789c684217b930e95313bcb73e6e7b8649a4968f7083089150837f2cd9ed31f5f8691c8e39e4077a74faa0f400ad8b491eb3f7b47b27fa3fd1cf778408925083818180828009800909905062002184600052620025ba565b837f23ff4f9d46813457cf60d92f57618399a5e022ac321ca550854ae23918a22eea82089050837f09945a5d147a4f66ceece6405dddd9d0af5a2c5103529407dff1ea58f180426d83089150837f188d9c528025d4c2b67660c6b771b90f7c7da6eaa29d3f268a6dd223ec6fc630840892508381818082800980090990506200220f600052620025ba565b837f3050e37996596b7f81f68311431d8734dba7d926d3633595e0c0d8ddf4f0f47f82089050837f15af1169396830a91600ca8102c35c426ceae5461e3f95d89d829518d30afd7883089150837f1da6d09885432ea9a06d9f37f873d985dae933e351466b2904284da3320d8acc840892508381818082800980090990506200229a600052620025ba565b837f2796ea90d269af29f5f8acf33921124e4e4fad3dbe658945e546ee411ddaa9cb82089050837f202d7dd1da0f6b4b0325c8b3307742f01e15612ec8e9304a7cb0319e01d32d6083089150837f096d6790d05bb759156a952ba263d672a2d7f9c788f4c831a29dace4c0f8be5f8408925083818180828009800909905062002325600052620025ba565b837f054efa1f65b0fce283808965275d877b438da23ce5b13e1963798cb1447d25a482089050837f1b162f83d917e93edb3308c29802deb9d8aa690113b2e14864ccf6e18e4165f183089150837f21e5241e12564dd6fd9f1cdd2a0de39eedfefc1466cc568ec5ceb745a0506edc84089250838181808280098009099050838281808280098009099150838381808280098009099250620023c8600052620025ba565b837f1cfb5662e8cf5ac9226a80ee17b36abecb73ab5f87e161927b4349e10e4bdf0882089050837f0f21177e302a771bbae6d8d1ecb373b62c99af346220ac0129c53f666eb2410083089150837f1671522374606992affb0dd7f71b12bec4236aede6290546bcef7e1f515c2320840892508381818082800980090990508382818082800980090991508383818082800980090992506200246b600052620025ba565b837f0fa3ec5b9488259c2eb4cf24501bfad9be2ec9e42c5cc8ccd419d2a692cad87082089050837f193c0e04e0bd298357cb266c1506080ed36edce85c648cc085e8c57b1ab54bba83089150837f102adf8ef74735a27e9128306dcbc3c99f6f7291cd406578ce14ea2adaba68f8840892508381818082800980090990508382818082800980090991508383818082800980090992506200250e600052620025ba565b837f0fe0af7858e49859e2a54d6f1ad945b1316aa24bfbdd23ae40a6d0cb70c3eab182089050837f216f6717bbc7dedb08536a2220843f4e2da5f1daa9ebdefde8a5ea7344798d2283089150837f1da55cc900f0d21f4a3e694391918a1b3c23b2ac773c6b3ef88e2e422832516184089250838181808280098009099050838281808280098009099150838381808280098009099250620025b1600052620025ba565b60005260206000f35b8360205182098460405184098591088460605185098591088460805183098560a05185098691088560c05186098691088560e05184098661010051860987910886610120518709879108945092509050600051560000000000","id":1,"to":"0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed","type":"ONCHAIN_INTERACTION","value":{"_kind":"bigint","value":"0"}},"type":"NETWORK_INTERACTION_REQUEST"} +{"futureId":"Poseidon2Module#Poseidon2Element","networkInteractionId":1,"nonce":6,"type":"TRANSACTION_PREPARE_SEND"} +{"futureId":"Poseidon2Module#Poseidon2Element","networkInteractionId":1,"nonce":6,"transaction":{"fees":{"gasPrice":{"_kind":"bigint","value":"1000000000"}},"hash":"0x246776a273e5597f9996585dcee974536e84977169a4bb9b215fd0940f329289"},"type":"TRANSACTION_SEND"} +{"futureId":"Poseidon2Module#Poseidon2Element","hash":"0x246776a273e5597f9996585dcee974536e84977169a4bb9b215fd0940f329289","networkInteractionId":1,"receipt":{"blockHash":"0xd1d42ac9c7d142689c3c33bcb5ba7d32810c59e144d6c2842696fd332cd0bf8c","blockNumber":100798,"logs":[{"address":"0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed","data":"0x","logIndex":0,"topics":["0xb8fda7e00c6b06a2b54e58521bc5894fee35f1090e5a3bb6390bfe2b98b497f7","0x00000000000000000000000072f721d9d5f91353b505207c63b56cf3d9447edb","0x1fb806fe12ba202b72799840b31b8b2ba7246fc0a96873ac3602d29c91d8c2d0"]}],"status":"SUCCESS"},"type":"TRANSACTION_CONFIRM"} +{"futureId":"Poseidon2Module#Poseidon2Element","result":{"address":"0x72F721D9D5f91353B505207C63B56cF3d9447edB","type":"SUCCESS"},"type":"DEPLOYMENT_EXECUTION_STATE_COMPLETE"} +{"artifactId":"Poseidon3Module#Poseidon3Element","constructorArgs":[],"contractName":"Poseidon3Element","dependencies":[],"from":"0xcabae40a68bcb419c8d9a3ab5eaef63810c2d4f4","futureId":"Poseidon3Module#Poseidon3Element","futureType":"CONTRACT_DEPLOYMENT","libraries":{},"strategy":"create2","strategyConfig":{"salt":"0x000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d1"},"type":"DEPLOYMENT_EXECUTION_STATE_INITIALIZE","value":{"_kind":"bigint","value":"0"}} +{"futureId":"Poseidon3Module#Poseidon3Element","networkInteraction":{"data":"0x26307668000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d1000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000030bb38600c6000396130af6000f37c010000000000000000000000000000000000000000000000000000000060003504806325cc70e81490635a53025d14176200003757fe5b7f236d13393ef85cc48a351dd786dd7a1de5e39942296127fd87947223ae5108ad6020527f277686494f7644bbc4a9b194e10724eb967f1dc58718e59e3cedc821b2a7ae196040527f023db68784e3f0cc0b85618826a9b3505129c16479973b0a84a4529e66b09c626060527f1d359d245f286c12d50d663bae733f978af08cdbd63017c57b3a75646ff382c16080527f2a75a171563b807db525be259699ab28fe9bc7fb1f70943ff049bc970e841a0c60a0527f083abff5e10051f078e2827d092e1ae808b4dd3e15ccc3706f38ce4157b6770e60c0527f1a5ad71bbbecd8a97dc49cfdbae303ad24d5c4741eab8b7568a9ff8253a1eb6f60e0527f0d745fd00dd167fb86772133640f02ce945004a7bc2c59e8790f725c5d84f0af610100527f2070679e798782ef592a52ca9cef820d497ad2eecbaa7e42f366b3e521c4ed42610120527f2e18c8570d20bf5df800739a53da75d906ece318cd224ab6b3a2be979e2d7eab610140527f0fa86f0f27e4d3dd7f3367ce86f684f1f2e4386d3e5b9f38fa283c6aa723b608610160527f03f3e6fab791f16628168e4b14dbaeb657035ee3da6b2ca83f0c2491e0b403eb610180527f2f545e578202c9732488540e41f783b68ff0613fd79375f8ba8b3d30958e76776101a0527f23810bf82877fc19bff7eefeae3faf4bb8104c32ba4cd701596a15623d01476e6101c0527f014fcd5eb0be6d5beeafc4944034cf321c068ef930f10be2207ed58d2a34cdd66101e0527f00c15fc3a1d5733dd835eae0823e377f8ba4a8b627627cc2bb661c25d20fb52a610200527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016044356024356004356000847f19b849f69450b06848da1d39bd5e4a4302bb86744edc26238b0878e269ed23e582089050847f265ddfe127dd51bd7239347b758f0a1320eb2cc7450acc1dad47f80c8dcf34d683089150847f199750ec472f1809e0f66a545e1e51624108ac845015c2aa3dfc36bab497d8aa84089250847f157ff3fe65ac7208110f06a5f74302b14d743ea25067f0ffd032f787c7f1cdf8850893508481818082800980090990508482818082800980090991508483818082800980090992508484818082800980090993506200038160005262003015565b847f2e49c43c4569dd9c5fd35ac45fca33f10b15c590692f8beefe18f4896ac9490282089050847f0e35fb89981890520d4aef2b6d6506c3cb2f0b6973c24fa82731345ffa2d1f1e83089150847f251ad47cb15c4f1105f109ae5e944f1ba9d9e7806d667ffec6fe723002e0b99684089250847f13da07dc64d428369873e97160234641f8beb56fdd05e5f3563fa39d9c22df4e850893508481818082800980090990508482818082800980090991508483818082800980090992508484818082800980090993506200045660005262003015565b847f0c009b84e650e6d23dc00c7dccef7483a553939689d350cd46e7b89055fd473882089050847f011f16b1c63a854f01992e3956f42d8b04eb650c6d535eb0203dec74befdca0683089150847f0ed69e5e383a688f209d9a561daa79612f3f78d0467ad45485df07093f36754984089250847f04dba94a7b0ce9e221acad41472b6bbe3aec507f5eb3d33f463672264c9f789b850893508481818082800980090990508482818082800980090991508483818082800980090992508484818082800980090993506200052b60005262003015565b847f0a3f2637d840f3a16eb094271c9d237b6036757d4bb50bf7ce732ff1d4fa28e882089050847f259a666f129eea198f8a1c502fdb38fa39b1f075569564b6e54a485d1182323f83089150847f28bf7459c9b2f4c6d8e7d06a4ee3a47f7745d4271038e5157a32fdf7ede0d6a184089250847f0a1ca941f057037526ea200f489be8d4c37c85bbcce6a2aeec91bd6941432447850893508481818082800980090990508482818082800980090991508483818082800980090992508484818082800980090993506200060060005262003015565b847f0c6f8f958be0e93053d7fd4fc54512855535ed1539f051dcb43a26fd926361cf82089050847f123106a93cd17578d426e8128ac9d90aa9e8a00708e296e084dd57e69caaf81183089150847f26e1ba52ad9285d97dd3ab52f8e840085e8fa83ff1e8f1877b074867cd2dee7584089250847f1cb55cad7bd133de18a64c5c47b9c97cbe4d8b7bf9e095864471537e6a4ae2c585089350848181808280098009099050620006b160005262003015565b847f1dcd73e46acd8f8e0e2c7ce04bde7f6d2a53043d5060a41c7143f08e6e9055d082089050847f011003e32f6d9c66f5852f05474a4def0cda294a0eb4e9b9b12b9bb4512e557483089150847f2b1e809ac1d10ab29ad5f20d03a57dfebadfe5903f58bafed7c508dd2287ae8c84089250847f2539de1785b735999fb4dac35ee17ed0ef995d05ab2fc5faeaa69ae87bcec0a5850893508481818082800980090990506200076260005262003015565b847f0c246c5a2ef8ee0126497f222b3e0a0ef4e1c3d41c86d46e43982cb11d77951d82089050847f192089c4974f68e95408148f7c0632edbb09e6a6ad1a1c2f3f0305f5d03b527b83089150847f1eae0ad8ab68b2f06a0ee36eeb0d0c058529097d91096b756d8fdc2fb5a60d8584089250847f179190e5d0e22179e46f8282872abc88db6e2fdc0dee99e69768bd98c5d06bfb850893508481818082800980090990506200081360005262003015565b847f29bb9e2c9076732576e9a81c7ac4b83214528f7db00f31bf6cafe794a9b3cd1c82089050847f225d394e42207599403efd0c2464a90d52652645882aac35b10e590e6e691e0883089150847f064760623c25c8cf753d238055b444532be13557451c087de09efd454b23fd5984089250847f10ba3a0e01df92e87f301c4b716d8a394d67f4bf42a75c10922910a78f6b5b8785089350848181808280098009099050620008c460005262003015565b847f0e070bf53f8451b24f9c6e96b0c2a801cb511bc0c242eb9d361b77693f21471c82089050847f1b94cd61b051b04dd39755ff93821a73ccd6cb11d2491d8aa7f921014de252fb83089150847f1d7cb39bafb8c744e148787a2e70230f9d4e917d5713bb050487b5aa7d74070b84089250847f2ec93189bd1ab4f69117d0fe980c80ff8785c2961829f701bb74ac1f303b17db850893508481818082800980090990506200097560005262003015565b847f2db366bfdd36d277a692bb825b86275beac404a19ae07a9082ea46bd8351792682089050847f062100eb485db06269655cf186a68532985275428450359adc99cec6960711b883089150847f0761d33c66614aaa570e7f1e8244ca1120243f92fa59e4f900c567bf41f5a59b84089250847f20fc411a114d13992c2705aa034e3f315d78608a0f7de4ccf7a72e494855ad0d8508935084818180828009800909905062000a2660005262003015565b847f25b5c004a4bdfcb5add9ec4e9ab219ba102c67e8b3effb5fc3a30f317250bc5a82089050847f23b1822d278ed632a494e58f6df6f5ed038b186d8474155ad87e7dff62b37f4b83089150847f22734b4c5c3f9493606c4ba9012499bf0f14d13bfcfcccaa16102a29cc2f69e084089250847f26c0c8fe09eb30b7e27a74dc33492347e5bdff409aa3610254413d3fad795ce58508935084818180828009800909905062000ad760005262003015565b847f070dd0ccb6bd7bbae88eac03fa1fbb26196be3083a809829bbd626df348ccad982089050847f12b6595bdb329b6fb043ba78bb28c3bec2c0a6de46d8c5ad6067c4ebfd4250da83089150847f248d97d7f76283d63bec30e7a5876c11c06fca9b275c671c5e33d95bb7e8d72984089250847f1a306d439d463b0816fc6fd64cc939318b45eb759ddde4aa106d15d9bd9baaaa8508935084818180828009800909905062000b8860005262003015565b847f28a8f8372e3c38daced7c00421cb4621f4f1b54ddc27821b0d62d3d6ec7c56cf82089050847f0094975717f9a8a8bb35152f24d43294071ce320c829f388bc852183e1e2ce7e83089150847f04d5ee4c3aa78f7d80fde60d716480d3593f74d4f653ae83f4103246db2e8d6584089250847f2a6cf5e9aa03d4336349ad6fb8ed2269c7bef54b8822cc76d08495c12efde1878508935084818180828009800909905062000c3960005262003015565b847f2304d31eaab960ba9274da43e19ddeb7f792180808fd6e43baae48d7efcba3f382089050847f03fd9ac865a4b2a6d5e7009785817249bff08a7e0726fcb4e1c11d39d199f0b083089150847f00b7258ded52bbda2248404d55ee5044798afc3a209193073f7954d4d63b0b6484089250847f159f81ada0771799ec38fca2d4bf65ebb13d3a74f3298db36272c5ca65e92d9a8508935084818180828009800909905062000cea60005262003015565b847f1ef90e67437fbc8550237a75bc28e3bb9000130ea25f0c5471e144cf4264431f82089050847f1e65f838515e5ff0196b49aa41a2d2568df739bc176b08ec95a79ed82932e30d83089150847f2b1b045def3a166cec6ce768d079ba74b18c844e570e1f826575c1068c94c33f84089250847f0832e5753ceb0ff6402543b1109229c165dc2d73bef715e3f1c6e07c168bb1738508935084818180828009800909905062000d9b60005262003015565b847f02f614e9cedfb3dc6b762ae0a37d41bab1b841c2e8b6451bc5a8e3c390b6ad1682089050847f0e2427d38bd46a60dd640b8e362cad967370ebb777bedff40f6a0be27e7ed70583089150847f0493630b7c670b6deb7c84d414e7ce79049f0ec098c3c7c50768bbe29214a53a84089250847f22ead100e8e482674decdab17066c5a26bb1515355d5461a3dc06cc85327cea98508935084818180828009800909905062000e4c60005262003015565b847f25b3e56e655b42cdaae2626ed2554d48583f1ae35626d04de5084e0b6d2a6f1682089050847f1e32752ada8836ef5837a6cde8ff13dbb599c336349e4c584b4fdc0a0cf6f9d083089150847f2fa2a871c15a387cc50f68f6f3c3455b23c00995f05078f672a9864074d412e584089250847f2f569b8a9a4424c9278e1db7311e889f54ccbf10661bab7fcd18e7c7a7d835058508935084818180828009800909905062000efd60005262003015565b847f044cb455110a8fdd531ade530234c518a7df93f7332ffd2144165374b246b43d82089050847f227808de93906d5d420246157f2e42b191fe8c90adfe118178ddc723a531902583089150847f02fcca2934e046bc623adead873579865d03781ae090ad4a8579d2e7a680035584089250847f0ef915f0ac120b876abccceb344a1d36bad3f3c5ab91a8ddcbec2e060d8befac8508935084818180828009800909905062000fae60005262003015565b847f1797130f4b7a3e1777eb757bc6f287f6ab0fb85f6be63b09f3b16ef2b1405d3882089050847f0a76225dc04170ae3306c85abab59e608c7f497c20156d4d36c668555decc6e583089150847f1fffb9ec1992d66ba1e77a7b93209af6f8fa76d48acb664796174b5326a31a5c84089250847f25721c4fc15a3f2853b57c338fa538d85f8fbba6c6b9c6090611889b797b9c5f850893508481818082800980090990506200105f60005262003015565b847f0c817fd42d5f7a41215e3d07ba197216adb4c3790705da95eb63b982bfcaf75a82089050847f13abe3f5239915d39f7e13c2c24970b6df8cf86ce00a22002bc15866e52b5a9683089150847f2106feea546224ea12ef7f39987a46c85c1bc3dc29bdbd7a92cd60acb4d391ce84089250847f21ca859468a746b6aaa79474a37dab49f1ca5a28c748bc7157e1b3345bb0f959850893508481818082800980090990506200111060005262003015565b847f05ccd6255c1e6f0c5cf1f0df934194c62911d14d0321662a8f1a48999e34185b82089050847f0f0e34a64b70a626e464d846674c4c8816c4fb267fe44fe6ea28678cb09490a483089150847f0558531a4e25470c6157794ca36d0e9647dbfcfe350d64838f5b1a8a2de0d4bf84089250847f09d3dca9173ed2faceea125157683d18924cadad3f655a60b72f5864961f145585089350848181808280098009099050620011c160005262003015565b847f0328cbd54e8c0913493f866ed03d218bf23f92d68aaec48617d4c722e5bd433582089050847f2bf07216e2aff0a223a487b1a7094e07e79e7bcc9798c648ee3347dd5329d34b83089150847f1daf345a58006b736499c583cb76c316d6f78ed6a6dffc82111e11a63fe412df84089250847f176563472456aaa746b694c60e1823611ef39039b2edc7ff391e6f2293d2c404850893508481818082800980090990506200127260005262003015565b847f2ef1e0fad9f08e87a3bb5e47d7e33538ca964d2b7d1083d4fb0225035bd3f8db82089050847f226c9b1af95babcf17b2b1f57c7310179c1803dec5ae8f0a1779ed36c817ae2a83089150847f14bce3549cc3db7428126b4c3a15ae0ff8148c89f13fb35d35734eb5d4ad0def84089250847f2debff156e276bb5742c3373f2635b48b8e923d301f372f8e550cfd4034212c7850893508481818082800980090990506200132360005262003015565b847f2d4083cf5a87f5b6fc2395b22e356b6441afe1b6b29c47add7d0432d1d4760c782089050847f0c225b7bcd04bf9c34b911262fdc9c1b91bf79a10c0184d89c317c53d7161c2983089150847f03152169d4f3d06ec33a79bfac91a02c99aa0200db66d5aa7b835265f9c9c8f384089250847f0b61811a9210be78b05974587486d58bddc8f51bfdfebbb87afe8b7aa7d3199c85089350848181808280098009099050620013d460005262003015565b847f203e000cad298daaf7eba6a5c5921878b8ae48acf7048f16046d637a533b6f7882089050847f1a44bf0937c722d1376672b69f6c9655ba7ee386fda1112c0757143d1bfa914683089150847f0376b4fae08cb03d3500afec1a1f56acb8e0fde75a2106d7002f59c5611d4daa84089250847f00780af2ca1cad6465a2171250fdfc32d6fc241d3214177f3d553ef363182185850893508481818082800980090990506200148560005262003015565b847f10774d9ab80c25bdeb808bedfd72a8d9b75dbe18d5221c87e9d857079bdc31d582089050847f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e883089150847f00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1684089250847f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428c850893508481818082800980090990506200153660005262003015565b847f2840d045e9bc22b259cfb8811b1e0f45b77f7bdb7f7e2b46151a1430f608e3c582089050847f062752f86eebe11a009c937e468c335b04554574c2990196508e01fa5860186b83089150847f06041bdac48205ac87adb87c20a478a71c9950c12a80bc0a55a8e83eaaf0474684089250847f04a533f236c422d1ff900a368949b0022c7a2ae092f308d82b1dcbbf51f5000d85089350848181808280098009099050620015e760005262003015565b847f13e31d7a67232fd811d6a955b3d4f25dfe066d1e7dc33df04bde50a2b2d05b2a82089050847f011c2683ae91eb4dfbc13d6357e8599a9279d1648ff2c95d2f79905bb13920f183089150847f0b0d219346b8574525b1a270e0b4cba5d56c928e3e2c2bd0a1ecaed015aaf6ae84089250847f14abdec8db9c6dc970291ee638690209b65080781ef9fd13d84c7a726b5f1364850893508481818082800980090990506200169860005262003015565b847f1a0b70b4b26fdc28fcd32aa3d266478801eb12202ef47ced988d0376610be10682089050847f278543721f96d1307b6943f9804e7fe56401deb2ef99c4d12704882e7278b60783089150847f16eb59494a9776cf57866214dbd1473f3f0738a325638d8ba36535e011d5825984089250847f2567a658a81ffb444f240088fa5524c69a9e53eeab6b7f8c41c3479dcf8c644a850893508481818082800980090990506200174960005262003015565b847f29aa1d7c151e9ad0a7ab39f1abd9cf77ab78e0215a5715a6b882ade840bb13d882089050847f15c091233e60efe0d4bbfce2b36415006a4f017f9a85388ce206b91f99f2c98483089150847f16bd7d22ff858e5e0882c2c999558d77e7673ad5f1915f9feb679a8115f014cf84089250847f02db50480a07be0eb2c2e13ed6ef4074c0182d9b668b8e08ffe676925004202585089350848181808280098009099050620017fa60005262003015565b847f05e4a220e6a3bc9f7b6806ec9d6cdba186330ef2bf7adb4c13ba866343b7311982089050847f1dda05ebc30170bc98cbf2a5ee3b50e8b5f70bc424d39fa4104d37f1cbcf7a4283089150847f0184bef721888187f645b6fee3667f3c91da214414d89ba5cd301f22b0de899084089250847f1498a307e68900065f5e8276f62aef1c37414b84494e1577ad1a6d64341b78ec85089350848181808280098009099050620018ab60005262003015565b847f25f40f82b31dacc4f4939800b9d2c3eacef737b8fab1f864fe33548ad46bd49d82089050847f09d317cc670251943f6f5862a30d2ea9e83056ce4907bfbbcb1ff31ce5bb965083089150847f2f77d77786d979b23ba4ce4a4c1b3bd0a41132cd467a86ab29b913b6cf3149d084089250847f0f53dafd535a9f4473dc266b6fccc6841bbd336963f254c152f89e785f729bbf850893508481818082800980090990506200195c60005262003015565b847f25c1fd72e223045265c3a099e17526fa0e6976e1c00baf16de96de85deef2fa282089050847f2a902c8980c17faae368d385d52d16be41af95c84eaea3cf893e65d6ce4a8f6283089150847f1ce1580a3452ecf302878c8976b82be96676dd114d1dc8d25527405762f8352984089250847f24a6073f91addc33a49a1fa306df008801c5ec569609034d2fc50f7f0f4d00568508935084818180828009800909905062001a0d60005262003015565b847f25e52dbd6124530d9fc27fe306d71d4583e07ca554b5d1577f256c68b0be2b7482089050847f23dffae3c423fa7a93468dbccfb029855974be4d0a7b29946796e5b6cd70f15d83089150847f06342da370cc0d8c49b77594f6b027c480615d50be36243a99591bc9924ed6f584089250847f2754114281286546b75f09f115fc751b4778303d0405c1b4cc7df0d8e9f639258508935084818180828009800909905062001abe60005262003015565b847f15c19e8534c5c1a8862c2bc1d119eddeabf214153833d7bdb59ee197f8187cf582089050847f265fe062766d08fab4c78d0d9ef3cabe366f3be0a821061679b4b3d2d77d5f3e83089150847f13ccf689d67a3ec9f22cb7cd0ac3a327d377ac5cd0146f048debfd098d3ec7be84089250847f17662f7456789739f81cd3974827a887d92a5e05bdf3fe6b9fbccca4524aaebd8508935084818180828009800909905062001b6f60005262003015565b847f21b29c76329b31c8ef18631e515f7f2f82ca6a5cca70cee4e809fd624be7ad5d82089050847f18137478382aadba441eb97fe27901989c06738165215319939eb17b01fa975c83089150847f2bc07ea2bfad68e8dc724f5fef2b37c2d34f761935ffd3b739ceec4668f37e8884089250847f2ddb2e376f54d64a563840480df993feb4173203c2bd94ad0e602077aef9a03e8508935084818180828009800909905062001c2060005262003015565b847f277eb50f2baa706106b41cb24c602609e8a20f8d72f613708adb25373596c3f782089050847f0d4de47e1aba34269d0c620904f01a56b33fc4b450c0db50bb7f87734c9a1fe583089150847f0b8442bfe9e4a1b4428673b6bd3eea6f9f445697058f134aae908d0279a29f0c84089250847f11fe5b18fbbea1a86e06930cb89f7d4a26e186a65945e96574247fddb720f8f58508935084818180828009800909905062001cd160005262003015565b847f224026f6dfaf71e24d25d8f6d9f90021df5b774dcad4d883170e4ad89c33a0d682089050847f0b2ca6a999fe6887e0704dad58d03465a96bc9e37d1091f61bc9f9c62bbeb82483089150847f221b63d66f0b45f9d40c54053a28a06b1d0a4ce41d364797a1a7e0c96529f42184089250847f30185c48b7b2f1d53d4120801b047d087493bce64d4d24aedce2f4836bb84ad48508935084818180828009800909905062001d8260005262003015565b847f23f5d372a3f0e3cba989e223056227d3533356f0faa48f27f8267318632a61f082089050847f2716683b32c755fd1bf8235ea162b1f388e1e0090d06162e8e6dfbe4328f3e3b83089150847f0977545836866fa204ca1d853ec0909e3d140770c80ac67dc930c69748d5d4bc84089250847f1444e8f592bdbfd8025d91ab4982dd425f51682d31472b05e81c43c0f9434b318508935084818180828009800909905062001e3360005262003015565b847f26e04b65e9ca8270beb74a1c5cb8fee8be3ffbfe583f7012a00f874e7718fbe382089050847f22a5c2fa860d11fe34ee47a5cd9f869800f48f4febe29ad6df69816fb1a914d283089150847f174b54d9907d8f5c6afd672a738f42737ec338f3a0964c629f7474dd44c5c8d784089250847f1db1db8aa45283f31168fa66694cf2808d2189b87c8c8143d56c871907b39b878508935084818180828009800909905062001ee460005262003015565b847f1530bf0f46527e889030b8c7b7dfde126f65faf8cce0ab66387341d813d1bfd182089050847f0b73f613993229f59f01c1cec8760e9936ead9edc8f2814889330a2f2bade45783089150847f29c25a22fe2164604552aaea377f448d587ab977fc8227787bd2dc0f36bcf41e84089250847f2b30d53ed1759bfb8503da66c92cf4077abe82795dc272b377df57d77c8755268508935084818180828009800909905062001f9560005262003015565b847f12f6d703b5702aab7b7b7e69359d53a2756c08c85ede7227cf5f0a2916787cd282089050847f2520e18300afda3f61a40a0b8837293a55ad01071028d4841ffa9ac70636411383089150847f1ec9daea860971ecdda8ed4f346fa967ac9bc59278277393c68f09fa03b8b95f84089250847f0a99b3e178db2e2e432f5cd5bef8fe4483bf5cbf70ed407c08aae24b830ad725850893508481818082800980090990506200204660005262003015565b847f07cda9e63db6e39f086b89b601c2bbe407ee0abac3c817a1317abad7c577849282089050847f08c9c65a4f955e8952d571b191bb0adb49bd8290963203b35d48aab38f8fc3a383089150847f2737f8ce1d5a67b349590ddbfbd709ed9af54a2a3f2719d33801c9c17bdd9c9e84089250847f1049a6c65ff019f0d28770072798e8b7909432bd0c129813a9f179ba627f7d6a85089350848181808280098009099050620020f760005262003015565b847f18b4fe968732c462c0ea5a9beb27cecbde8868944fdf64ee60a5122361daeddb82089050847f2ff2b6fd22df49d2440b2eaeeefa8c02a6f478cfcf11f1b2a4f7473483885d1983089150847f2ec5f2f1928fe932e56c789b8f6bbcb3e8be4057cbd8dbd18a1b352f5cef42ff84089250847f265a5eccd8b92975e33ad9f75bf3426d424a4c6a7794ee3f08c1d100378e545e85089350848181808280098009099050620021a860005262003015565b847f2405eaa4c0bde1129d6242bb5ada0e68778e656cfcb366bf20517da1dfd4279c82089050847f094c97d8c194c42e88018004cbbf2bc5fdb51955d8b2d66b76dd98a2dbf6041783089150847f2c30d5f33bb32c5c22b9979a605bf64d508b705221e6a686330c9625c2afe0b884089250847f01a75666f6241f6825d01cc6dcb1622d4886ea583e87299e6aa2fc716fdb6cf5850893508481818082800980090990506200225960005262003015565b847f0a3290e8398113ea4d12ac091e87be7c6d359ab9a66979fcf47bf2e87d382fcb82089050847f154ade9ca36e268dfeb38461425bb0d8c31219d8fa0dfc75ecd21bf69aa0cc7483089150847f27aa8d3e25380c0b1b172d79c6f22eee99231ef5dc69d8dc13a4b5095d02877284089250847f2cf4051e6cab48301a8b2e3bca6099d756bbdf485afa1f549d395bbcbd806461850893508481818082800980090990506200230a60005262003015565b847f301e70f729f3c94b1d3f517ddff9f2015131feab8afa5eebb0843d7f84b23e7182089050847f298beb64f812d25d8b4d9620347ab02332dc4cef113ae60d17a8d7a4c91f83bc83089150847f1b362e72a5f847f84d03fd291c3c471ed1c14a15b221680acf11a3f02e46aa9584089250847f0dc8a2146110c0b375432902999223d5aa1ef6e78e1e5ebcbc1d9ba41dc1c73785089350848181808280098009099050620023bb60005262003015565b847f0a48663b34ce5e1c05dc93092cb69778cb21729a72ddc03a08afa1eb922ff27982089050847f0a87391fb1cd8cdf6096b64a82f9e95f0fe46f143b702d74545bb314881098ee83089150847f1b5b2946f7c28975f0512ff8e6ca362f8826edd7ea9c29f382ba8a2a0892fd5d84089250847f01001cf512ac241d47ebe2239219bc6a173a8bbcb8a5b987b4eac1f533315b6b850893508481818082800980090990506200246c60005262003015565b847f2fd977c70f645db4f704fa7d7693da727ac093d3fb5f5febc72beb17d8358a3282089050847f23c0039a3fab4ad3c2d7cc688164f39e761d5355c05444d99be763a97793a9c483089150847f19d43ee0c6081c052c9c0df6161eaac1aec356cf435888e79f27f22ff03fa25d84089250847f2d9b10c2f2e7ac1afddccffd94a563028bf29b646d020830919f9d5ca1cefe59850893508481818082800980090990506200251d60005262003015565b847f2457ca6c2f2aa30ec47e4aff5a66f5ce2799283e166fc81cdae2f2b9f83e426782089050847f0abc392fe85eda855820592445094022811ee8676ed6f0c3044dfb54a7c10b3583089150847f19d2cc5ca549d1d40cebcd37f3ea54f31161ac3993acf3101d2c2bc30eac1eb084089250847f0f97ae3033ffa01608aafb26ae13cd393ee0e4ec041ba644a3d3ab546e98c9c885089350848181808280098009099050620025ce60005262003015565b847f16dbc78fd28b7fb8260e404cf1d427a7fa15537ea4e168e88a166496e88cfeca82089050847f240faf28f11499b916f085f73bc4f22eef8344e576f8ad3d1827820366d5e07b83089150847f0a1bb075aa37ff0cfe6c8531e55e1770eaba808c8fdb6dbf46f8cab58d9ef1af84089250847f2e47e15ea4a47ff1a6a853aaf3a644ca38d5b085ac1042fdc4a705a7ce089f4d850893508481818082800980090990506200267f60005262003015565b847f166e5bf073378348860ca4a9c09d39e1673ab059935f4df35fb14528375772b682089050847f18b42d7ffdd2ea4faf235902f057a2740cacccd027233001ed10f96538f0916f83089150847f089cb1b032238f5e4914788e3e3c7ead4fc368020b3ed38221deab1051c3770284089250847f242acd3eb3a2f72baf7c7076dd165adf89f9339c7b971921d9e70863451dd8d1850893508481818082800980090990506200273060005262003015565b847f174fbb104a4ee302bf47f2bd82fce896eac9a068283f326474af860457245c3b82089050847f17340e71d96f466d61f3058ce092c67d2891fb2bb318613f780c275fe1116c6b83089150847f1e8e40ac853b7d42f00f2e383982d024f098b9f8fd455953a2fd380c4df7f6b284089250847f0529898dc0649907e1d4d5e284b8d1075198c55cad66e8a9bf40f92938e2e96185089350848181808280098009099050620027e160005262003015565b847f2162754db0baa030bf7de5bb797364dce8c77aa017ee1d7bf65f21c4d4e5df8f82089050847f12c7553698c4bf6f3ceb250ae00c58c2a9f9291efbde4c8421bef44741752ec683089150847f292643e3ba2026affcb8c5279313bd51a733c93353e9d9c79cb723136526508e84089250847f00ccf13e0cb6f9d81d52951bea990bd5b6c07c5d98e66ff71db6e74d5b87d158850893508481818082800980090990506200289260005262003015565b847f185d1e20e23b0917dd654128cf2f3aaab6723873cb30fc22b0f86c15ab645b4b82089050847f14c61c836d55d3df742bdf11c60efa186778e3de0f024c0f13fe53f8d8764e1f83089150847f0f356841b3f556fce5dbe4680457691c2919e2af53008184d03ee1195d72449e84089250847f1b8fd9ff39714e075df124f887bf40b383143374fd2080ba0c0a6b6e8fa5b3e8850893508481818082800980090990506200294360005262003015565b847f0e86a8c2009c140ca3f873924e2aaa14fc3c8ae04e9df0b3e9103418796f602482089050847f2e6c5e898f5547770e5462ad932fcdd2373fc43820ca2b16b0861421e79155c883089150847f05d797f1ab3647237c14f9d1df032bc9ff9fe1a0ecd377972ce5fd5a0c01460484089250847f29a3110463a5aae76c3d152875981d0c1daf2dcd65519ef5ca8929851da8c00885089350848181808280098009099050620029f460005262003015565b847f2974da7bc074322273c3a4b91c05354cdc71640a8bbd1f864b732f816388331482089050847f1ed0fb06699ba249b2a30621c05eb12ca29cb91aa082c8bfcce9c522889b47dc83089150847f1c793ef0dcc51123654ff26d8d863feeae29e8c572eca912d80c8ae36e40fe9b84089250847f1e6aac1c6d3dd3157956257d3d234ef18c91e82589a78169fbb4a8770977dc2f8508935084818180828009800909905062002aa560005262003015565b847f1a20ada7576234eee6273dd6fa98b25ed037748080a47d948fcda33256fb6bf582089050847f191033d6d85ceaa6fc7a9a23a6fd9996642d772045ece51335d49306728af96c83089150847f006e5979da7e7ef53a825aa6fddc3abfc76f200b3740b8b232ef481f5d06297b84089250847f0b0d7e69c651910bbef3e68d417e9fa0fbd57f596c8f29831eff8c0174cdb06d8508935084818180828009800909905062002b5660005262003015565b847f25caf5b0c1b93bc516435ec084e2ecd44ac46dbbb033c5112c4b20a25c9cdf9d82089050847f12c1ea892cc31e0d9af8b796d9645872f7f77442d62fd4c8085b2f150f72472a83089150847f16af29695157aba9b8bbe3afeb245feee5a929d9f928b9b81de6dadc78c32aae84089250847f0136df457c80588dd687fb2f3be18691705b87ec5a4cfdc168d31084256b67dc8508935084818180828009800909905062002c0760005262003015565b847f1639a28c5b4c81166aea984fba6e71479e07b1efbc74434db95a285060e7b08982089050847f03d62fbf82fd1d4313f8e650f587ec06816c28b700bdc50f7e232bd9b5ca9b7683089150847f11aeeb527dc8ce44b4d14aaddca3cfe2f77a1e40fc6da97c249830de1edfde5484089250847f13f9b9a41274129479c5e6138c6c8ee36a670e6bc68c7a49642b645807bfc8248508935084818180828009800909905062002cb860005262003015565b847f0e4772fa3d75179dc8484cd26c7c1f635ddeeed7a939440c506cae8b7ebcd15b82089050847f1b39a00cbc81e427de4bdec58febe8d8b5971752067a612b39fc46a68c5d4db483089150847f2bedb66e1ad5a1d571e16e2953f48731f66463c2eb54a245444d1c0a3a25707e84089250847f2cf0a09a55ca93af8abd068f06a7287fb08b193b608582a27379ce35da915dec8508935084818180828009800909905084828180828009800909915084838180828009800909925084848180828009800909935062002d8d60005262003015565b847f2d1bd78fa90e77aa88830cabfef2f8d27d1a512050ba7db0753c8fb863efb38782089050847f065610c6f4f92491f423d3071eb83539f7c0d49c1387062e630d7fd283dc339483089150847f2d933ff19217a5545013b12873452bebcc5f9969033f15ec642fb464bd60736884089250847f1aa9d3fe4c644910f76b92b3e13b30d500dae5354e79508c3c49c8aa99e0258b8508935084818180828009800909905084828180828009800909915084838180828009800909925084848180828009800909935062002e6260005262003015565b847f027ef04869e482b1c748638c59111c6b27095fa773e1aca078cea1f1c8450bdd82089050847f2b7d524c5172cbbb15db4e00668a8c449f67a2605d9ec03802e3fa136ad0b8fb83089150847f0c7c382443c6aa787c8718d86747c7f74693ae25b1e55df13f7c3c1dd735db0f84089250847f00b4567186bc3f7c62a7b56acf4f76207a1f43c2d30d0fe4a627dcdd9bd790788508935084818180828009800909905084828180828009800909915084838180828009800909925084848180828009800909935062002f3760005262003015565b847f1e41fc29b825454fe6d61737fe08b47fb07fe739e4c1e61d0337490883db4fd582089050847f12507cd556b7bbcc72ee6dafc616584421e1af872d8c0e89002ae8d3ba0653b683089150847f13d437083553006bcef312e5e6f52a5d97eb36617ef36fe4d77d3e97f71cb5db84089250847f163ec73251f85443687222487dda9a65467d90b22f0b38664686077c6a4486d5850893508481818082800980090990508482818082800980090991508483818082800980090992508484818082800980090993506200300c60005262003015565b60005260206000f35b8460205182098560405184098691088560605185098691088560805186098691088560a05183098660c05185098791088660e05186098791088661010051870987910886610120518409876101405186098891088761016051870988910887610180518809889108876101a0518509886101c0518709899108886101e0518809899108886102005189098991089650945092509050600051560000000000","id":1,"to":"0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed","type":"ONCHAIN_INTERACTION","value":{"_kind":"bigint","value":"0"}},"type":"NETWORK_INTERACTION_REQUEST"} +{"futureId":"Poseidon3Module#Poseidon3Element","networkInteractionId":1,"nonce":7,"type":"TRANSACTION_PREPARE_SEND"} +{"futureId":"Poseidon3Module#Poseidon3Element","networkInteractionId":1,"nonce":7,"transaction":{"fees":{"gasPrice":{"_kind":"bigint","value":"1000000000"}},"hash":"0xc3c76f7cef35e3819a2090412247e5b10bd984a493df4354c3b5356e0a75702c"},"type":"TRANSACTION_SEND"} +{"futureId":"Poseidon3Module#Poseidon3Element","hash":"0xc3c76f7cef35e3819a2090412247e5b10bd984a493df4354c3b5356e0a75702c","networkInteractionId":1,"receipt":{"blockHash":"0x2878613c238e1e086d9dacbe0c8b77f582432b3345af5e4045b2032c6b4c21d7","blockNumber":100803,"logs":[{"address":"0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed","data":"0x","logIndex":0,"topics":["0xb8fda7e00c6b06a2b54e58521bc5894fee35f1090e5a3bb6390bfe2b98b497f7","0x0000000000000000000000005bc89782d5ebf62663df7ce5fb4bc7408926a240","0x1fb806fe12ba202b72799840b31b8b2ba7246fc0a96873ac3602d29c91d8c2d0"]}],"status":"SUCCESS"},"type":"TRANSACTION_CONFIRM"} +{"futureId":"Poseidon3Module#Poseidon3Element","result":{"address":"0x5Bc89782d5eBF62663Df7Ce5fb4bc7408926A240","type":"SUCCESS"},"type":"DEPLOYMENT_EXECUTION_STATE_COMPLETE"} +{"artifactId":"Poseidon4Module#Poseidon4Element","constructorArgs":[],"contractName":"Poseidon4Element","dependencies":[],"from":"0xcabae40a68bcb419c8d9a3ab5eaef63810c2d4f4","futureId":"Poseidon4Module#Poseidon4Element","futureType":"CONTRACT_DEPLOYMENT","libraries":{},"strategy":"create2","strategyConfig":{"salt":"0x000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d1"},"type":"DEPLOYMENT_EXECUTION_STATE_INITIALIZE","value":{"_kind":"bigint","value":"0"}} +{"futureId":"Poseidon4Module#Poseidon4Element","networkInteraction":{"data":"0x26307668000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000003fa038600c600039613f946000f37c0100000000000000000000000000000000000000000000000000000000600035048063248f66771490631e86251914176200003757fe5b7f251e7fdf99591080080b0af133b9e4369f22e57ace3cd7f64fc6fdbcf38d7da16020527f25fb50b65acf4fb047cbd3b1c17d97c7fe26ea9ca238d6e348550486e91c77656040527f293d617d7da72102355f39ebf62f91b06deb5325f367a4556ea1e31ed57678336060527f104d0295ab00c85e960111ac25da474366599e575a9b7edf6145f14ba6d3c1c46080527f0aaa35e2c84baf117dea3e336cd96a39792b3813954fe9bf3ed5b90f2f69c97760a0527f2a70b9f1d4bbccdbc03e17c1d1dcdb02052903dc6609ea6969f661b2eb74c83960c0527f281154651c921e746315a9934f1b8a1bba9f92ad8ef4b979115b8e2e991ccd7a60e0527f28c2be2f8264f95f0b53c732134efa338ccd8fdb9ee2b45fb86a894f7db36c37610100527f21888041e6febd546d427c890b1883bb9b626d8cb4dc18dcc4ec8fa75e530a13610120527f14ddb5fada0171db80195b9592d8cf2be810930e3ea4574a350d65e2cbff4941610140527f2f69a7198e1fbcc7dea43265306a37ed55b91bff652ad69aa4fa8478970d401d610160527f001c1edd62645b73ad931ab80e37bbb267ba312b34140e716d6a3747594d3052610180527f15b98ce93e47bc64ce2f2c96c69663c439c40c603049466fa7f9a4b228bfc32b6101a0527f12c7e2adfa524e5958f65be2fbac809fcba8458b28e44d9265051de33163cf9c6101c0527f2efc2b90d688134849018222e7b8922eaf67ce79816ef468531ec2de53bbd1676101e0527f0c3f050a6bf5af151981e55e3e1a29a13c3ffa4550bd2514f1afd6c5f721f830610200527f0dec54e6dbf75205fa75ba7992bd34f08b2efe2ecd424a73eda7784320a1a36e610220527f1c482a25a729f5df20225815034b196098364a11f4d988fb7cc75cf32d8136fa610240527f2625ce48a7b39a4252732624e4ab94360812ac2fc9a14a5fb8b607ae9fd8514a610260527f07f017a7ebd56dd086f7cd4fd710c509ed7ef8e300b9a8bb9fb9f28af710251f610280527f2a20e3a4a0e57d92f97c9d6186c6c3ea7c5e55c20146259be2f78c2ccc2e35956102a0527f1049f8210566b51faafb1e9a5d63c0ee701673aed820d9c4403b01feb727a5496102c0527f02ecac687ef5b4b568002bd9d1b96b4bef357a69e3e86b5561b9299b82d69c8e6102e0527f2d3a1aea2e6d44466808f88c9ba903d3bdcb6b58ba40441ed4ebcf11bbe1e37b610300527f14074bb14c982c81c9ad171e4f35fe49b39c4a7a72dbb6d9c98d803bfed65e64610320527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016064356044356024356004356000857f0eb544fee2815dda7f53e29ccac98ed7d889bb4ebd47c3864f3c2bd81a6da89182089050857f0554d736315b8662f02fdba7dd737fbca197aeb12ea64713ba733f28475128cb83089150857f2f83b9df259b2b68bcd748056307c37754907df0c0fb0035f5087c58d5e8c2d484089250857f2ca70e2e8d7f39a12447ac83052451b461f15f8b41a75ef31915208f5aba968385089350857f1cb5f9319be6a45e91b04d7222271c94994196f12ed22c5d4ec719cb83ecfea9860894508581818082800980090990508582818082800980090991508583818082800980090992508584818082800980090993508585818082800980090994506200050360005262003ea1565b857f2eb4f99c69f966ebf8a42192de7ff61621c7bb47b93750c2b9ea08d18446c12282089050857f224a28e5a35385a7c5198169e405d9ea0fc7da8b93ee13b6d5f7d099e299520e83089150857f0f7411b465e600eed8afdd6afca49c3036f33ecbd9a0f97823796b993bbd82f784089250857f0f9d0d5aad2c9555a2be7150392d8d9819b208ae3370f99a0626f9ff5d90e4e385089350857f1e9a96dc8292bb596f52a59538d329229732b25259cf744b6a12d30702d6fba0860894508581818082800980090990508582818082800980090991508583818082800980090992508584818082800980090993508585818082800980090994506200060a60005262003ea1565b857f08780514ccd90380887d578c45555e593cfe52eab4b945c6c2cd4d528fb3fe3c82089050857f272498fced686c7ac8149fa3f73ef8c2ced64717e3556d5a59f119d629ccb5fc83089150857f01ef8f9dd7c93aac4b7cb80930bd06eb45bd350aff585f10e3d0ef8a782ef7df84089250857f045b9f59b6595e614dc08f222b469b138e886e64bf3c40aa97ea0ae754934d3085089350857f0ac1e91c57d9da919fd6f59d2a40ff8ea3e41e24e247a387adf2584295d61c66860894508581818082800980090990508582818082800980090991508583818082800980090992508584818082800980090993508585818082800980090994506200071160005262003ea1565b857f028a1621a94054b0c7f9a421353cd89d0fd67061aee99979d12e68f04e62d13482089050857f26b41802c071ea4c9632647ed059236e50c19c3fb3c96d09d02aae2a0dcd9dbc83089150857f2fb5dda8072bb72cbaac2f63e468215e05c9de06758db6a94af34384aedb462b84089250857f2212d3a0f5fccaf244ff3547fd823249ad8ab8ba2a18d383dd05c56ee894d85085089350857f1b041ad5b2f0684258e4dfaeea09be56a3276fdb19f44c015cd0c7eed465e2e3860894508581818082800980090990508582818082800980090991508583818082800980090992508584818082800980090993508585818082800980090994506200081860005262003ea1565b857f0a01776bb22f4b6b8eccff33e76fded3144fb7e3ac14e846a91e64afb1500eff82089050857f2b7b5674aaecc3cbf34d3f275066d549a4f33ae8c15cf827f7936440810ace4383089150857f29d299b80cd4489e4cf75779ed54b48c60b042257b78fc004c1b803381a3bdfd84089250857f1c46831d9a74529357641c219d721a74a427110032b5e1dd19dde30424be401e85089350857f06d7626c953ccb72f37141dc34d578e036296c0657674f80739ae1d883e9126986089450858181808280098009099050620008ef60005262003ea1565b857f28ffddc86f18c136c54002748e0c410edc5c440a3022cd960f108c71cda2930c82089050857f2e67f7ee5e4aa295f85deed09e400b17be67f1b7ed2ab6adb8ec0619f6fbc5e983089150857f26ce38fa636c90630e97f25114a79a2dca56859ef759e53ce7abf22c24e80f2784089250857f2e6e07c3c95bf7c34dd7a01d00a7ffec42cb3d16a1f72721afacb4c4cfd35db185089350857f2aa74f7597f0c9f45f91d7961c3a54fb8890d276612e1246384b1470da24d8cc86089450858181808280098009099050620009c660005262003ea1565b857f287d681a46a2faae2c7c090f668ab45b8a71313c1509183e2ec0ca639b7f73fe82089050857f212bd19df812eaaef4a40600528f3d7da5d3106ff565aa3b11e29f3305e73c0483089150857f1154f7cf519186bf1aafb14b350eb860f97fd9740926dab93809c2840471350484089250857f1dff6385cb31f1c24637810a4bd1b16fbf5152905be36583da747e79661fc20785089350857f0e444582d22b4e76c081d34c44c18e424011a34d5476252863ea3c606b551e5c8608945085818180828009800909905062000a9d60005262003ea1565b857f0323c9e433ba66c4abab6638328f02f1815773e9c2846323ff72d3aab7e4eff882089050857f12746bbd71791059193bba79cdec448f25b8cf002740112db70f2c6876a9c29d83089150857f1173b7d112c2a798fd9b9d3751842c75d466c837cf50d73efd049eb4438a224084089250857f13d51c1090a1ad4876d1e555d7fed13da8e5713b25026ebe5fdb4808703243da85089350857f00874c1344a4ad51ff8dcb7cbd2d9743cb72743f0394efe7f4a58ebeb956baa18608945085818180828009800909905062000b7460005262003ea1565b857f22df22131aaab85865ce236b07f244fa0eea48d3546e97d6a32a562074fef08f82089050857f0bf964d2dbd25b908708b437a445fc3e984524a59101e6c18bf5eb05a919f15583089150857f09b18d9b917a55bca302be1f7f181e0e640b9d73a9ab298c69b435b5fc502f3284089250857f094f5534444fae36a4bfc1d5bf3dc05bfbbbc70a6365366dd6745a5067289e4385089350857f2999bab1a5f25210519fa6622af53a15a3e240c0da5701cb784fddc0dc23f01f8608945085818180828009800909905062000c4b60005262003ea1565b857f2f6898c07581f6371ca94db73710e88084301bce8a93d13669575a11b03a3d2382089050857f07268eaaba08bc19ec16d7e1318a4740565deb1e8e5742f862174b1a6866fccb83089150857f186279b003454db01339ff77113bc9eb62603e078e1c6689a6c9582c41a0529f84089250857f18a3f736509197d6e4915bdd04d3e5ddb67e2cc5de9a22750768e5524737172c85089350857f0a21fa1988cf38d877cc1e2ed24c808c725e2d4bcb2d3a007b5987b87085671d8608945085818180828009800909905062000d2260005262003ea1565b857f15b285cbe26c467f1faf5ef6a64625228328c184a2c43bc00b36a135e785fba282089050857f164b7062c4671cf08c08b8c3f9806d560b7775b7c902f5788cd28de3e779f16183089150857f0890ba0819ac0a6f86d9865fe7e50ef361c61d3d43b6e65d7a24f651249baa7084089250857f2fbea4d65d7ed425a42712e5a721e4eaa627ac5cb0eb878ccc2ee0aed543e92285089350857f0492bf383c36fa55540303a3b536f85e7b70a58e854ab9b9103d7f5f379abaaa8608945085818180828009800909905062000df960005262003ea1565b857f05e91fe944e944104e20251c565142d61d6185a9ce85675f6a969d56292dc24e82089050857f12fe5c2029e4b33893d463cb041acad0995b9621e6e49c3b7e380a76e36e6c1c83089150857f024154adf0255d47958f7723921474131f2629fadc89496906cd01dc6fa0784e84089250857f18824a09e6afaf4a36ed2462a86bd0bad798815644f2bbde8813c13457a4555085089350857f0c8b482dba0ad51be9f255de0c3dbddddf84a630af68d50bbb06983e3d5d58a58608945085818180828009800909905062000ed060005262003ea1565b857f17325fd0ab635871363e0a1667d3b67c5a4fa67fcd6aaf86441392878fdb05e682089050857f050ae95f6d2f1519122f5af67b690f31e550773fa8d18bf71cc6d0e911fa402e83089150857f0f0d139a0e81e943038cb288d62636764bbb6295f07569885771ec84edc50c4084089250857f1c0f8697795689cdf70fd2f2c0f93d1a79b39ebc7a1b1c549dbbca7b8e747cd685089350857f2bd0f940ad936b796d2bc2e048bc979e49be23a4b13598f9fe536a16dc1d81e68608945085818180828009800909905062000fa760005262003ea1565b857f27eb1be27c9c4e934778c09a0053337fa06ebb275e096d167ce54d1e96ee62cb82089050857f2e4889d830a67e5a8f96bdd3155a7ca3284fbd307d1f71b0f151be62548e2aea83089150857f193fe3db0ab47d3c5d2ec5e9c5bd9983c9891f2cadc165db6064bbe6fcc1e30584089250857f2bf3086e96c36c7bce415907ad0c40ed6e9661c009679e4e37cb13027c83e52585089350857f12f16e2de6d4ad46a98cdb697c6cad5dd5e7e413f741ccf29ff2ea486e59bb28860894508581818082800980090990506200107e60005262003ea1565b857f2a72147d230119f3a0262e3653ddd19f33f3d5d6ec6c4bf0ad919b0343b92d2f82089050857f21be0e2c4bfd64e56dc47f957806dc5f0a2d9bcc26412e2977df79acc10ba97483089150857f0e2d7e1dc946d70b2749a3b54367b25a71b84fb911aa57ae137fd4b6c21b444a84089250857f2667f7fb5a4fa1246170a745d8a4188cc31adb0eae3325dc9f3f07d4b92b3e2e85089350857f2ccc6f431fb7400730a783b66064697a1550c12b08dfeb72830e107da78e3405860894508581818082800980090990506200115560005262003ea1565b857f08888a94fc5a2ca34f0201462420001fae6dbee9e8ca0c242ec50621e38e6e5d82089050857f02977b34eeaa3cb6ad40dd42c9b6fdd7a0d2fbe753af88b36acfcd3ccbc53f2a83089150857f120ccce13d28b75cfd6fb6c9ea13a648bfcfe0d7e6ff8e9610b5e9f971e16b9a84089250857f09fad2269c4a8e93c81e1b9770ea098c92787a4575b2bd73a0bf2af32f86ff3c85089350857f026091fd3d4c44d50a4b310e4ac6f0fa0debdb70775eeb8af630cffb60092d6f860894508581818082800980090990506200122c60005262003ea1565b857f29404aa2ba565b77bb7fba9dfb6fc3212543cc56afad6afcb904fd2bca89399482089050857f2749475c399aaf39d4e87c2548695b4ef1ffd86590e0827de7201351b7c883f983089150857f098c842322479f7239912b50424685cba2ebe2dc2e4da70ac7557dab65ffa22284089250857f18cef581222b647e31238e57fead7d5c758ace14c93c4da40191d0c053b5193685089350857f13177839c68a5080d4e746745e43711d3cbc0ca4a108f98d63b2aa681698de60860894508581818082800980090990506200130360005262003ea1565b857f020ca696f531e43ec088f56f4b74325626cc4df712c0e5f0a907d88e5f0deffd82089050857f27230eede9cccfc9fa805a30fc548db693d13708c646841d16e028387c7ac02283089150857f01645911c1198b01d64fde34a342a1786497c05969a015439057d2fe75bb281c84089250857f2c323fe16481bf496e439c88341ce25f198971e14487056cfdca4a451a5d864385089350857f0fc082dfe70728e8450bd2074c3e22e1b022c124d3bffe8b5af88ae6db5085c886089450858181808280098009099050620013da60005262003ea1565b857f2052c174800db209d8cdca568dcc25b3be9642116ac4c77efe8a488b423521ee82089050857f28e420e10df2fbb5af96d621d55423190be351ce8129065a8dd9fd05b3ece9c083089150857f25698ca5e24a1b799f783c4462a24db655d6ae1bdacd1cb549d6e0bc3ae5069a84089250857f160a9981a5c89a57cf8ffbfa57d51049a297b61074422ac134d9b857d6984d3585089350857f21c91a39e145c3bc34d9b694b843f3bf8b7cebf59ddbb0a064642b069997f3d486089450858181808280098009099050620014b160005262003ea1565b857f1ac8d80dcd5ee876d2b09345ef112345d6eaa029d93f03b6d10975461e41734c82089050857f0ab3e6ad0ecf8b8e7c1662a4174c52225d822895e2755544b8dbcea5657ce02c83089150857f1c675182512620ae27e3b0b917b3a21ca52ef3ef5909b4e1c5b2237cbdab337784089250857f2cdbc998dfd7affd3d948d0c85bad2e2e37a4a3e07a7d75d0c8a9092ac2bed4585089350857f23b584a56e2117b0774bf67cc0dee33324337350309dff833e491a133bb63b2e860894508581818082800980090990506200158860005262003ea1565b857f1e9e2b310f60ba9f8cb73030a3c9d2a10d133bc6ba4ec1152f3d20de1465e9a582089050857f0e01e365ba5b3031abc3e720140ae746c9ab5dab987520c460bcd4f1fa5b22db83089150857f040884cdcfc64bfc7b7127340498d5c443382011b61c9a4b1387d85bc1264e6884089250857f190b1ee1205eb9500c74a3998f2bea36353f1724d6067ed0a0a17de311ef966885089350857f1647c72aec6c4388d04f52fc23cd9c08c1dfcf65ce61e165fc28d1f832bd3b2c860894508581818082800980090990506200165f60005262003ea1565b857f2430006346a0145f799880cc4c8736269f5494d89fb48b02842e595b71e4541d82089050857f177b9a08343917e1365107a3da3ae7f69d853902bb16bacb3221850252b757af83089150857f04a420e642b11ae94e58862a68f5e32609cd53d0ae29423439b11d04666df4f884089250857f25d0e0f739fb39fc105a88fab0afd810de2461858e956ccccdfabeddb6a25c8f85089350857f04476d91b7eff2fd85905cbf58651edc320cb15610eaed452c4d4ffa0c740a27860894508581818082800980090990506200173660005262003ea1565b857f1090c0b68b3d7d7b8bc9ca2419eb8dea1c28f6d5e1250cb5e9780fd9ca286fae82089050857f25393ce3b9256d50448a725c5c7cd5ad376f2d435855c10ebf2899cb5c6617be83089150857f25931c0c7371f4f1fc862f306e6e5830ed824388d6b9342697d144f0fab4663084089250857f2396cb501700bbe6c82aad51b0fb79cf8a4d353185d5808203f73f22afbf62f685089350857f26a363483348b58954ea748a7129a7b0a3dc9068c3cca7b5b3f0ce03b8724884860894508581818082800980090990506200180d60005262003ea1565b857f27ca107ca204f2a18d6f1535b92c5478c99b893334215f6ba7a0e5b45fcd689782089050857f26da28fc097ed77ce4662bde326b2cceac15f7301178581d8d2d02b3b2d9105683089150857f056ab351691d8bb3703e3055070ac9cc655774c1bb35d57572971ba56ee0cb8984089250857f2638b57f23b754aec76d109a2f481aa3c22547a11ffc50152d729af632376a9085089350857f304754bb8c57d60732f492c2605184fdc33e46a532bdec80ea7bc5519ede7cef86089450858181808280098009099050620018e460005262003ea1565b857f00d1727f8457ee03514f155b5806cbf748ec6857fc554010752ac93a9b7619ac82089050857f00ee1f3c66fbc05c43ba295a303c72fab5bca86805ec9419c588e50947761fa383089150857f0afafadcf5b4dd4a4a76b5a1d82415fd10a19fbcfc59078c61f9297eb675d97284089250857f0b2449f39746085e86ce45e8eed108ee65a234835a0a6a5ea8996d124dd04d0a85089350857f206b0ce2f1b2c5b7c9f37b0045227095f6c6f071ec3bdda76a7ddf4823dd5dd686089450858181808280098009099050620019bb60005262003ea1565b857f0feba4fb87834c7cb696e67433628cd6caffc3a4ef20fea852c7e1029459409c82089050857f254dbfac74c49b0b8926752e084e02513b06f1315e6d70e18173e972336e55d383089150857f0addb1372cee4e164655168c367559e19606c5bd17910aeb37719edfa0ca876284089250857f26b25b7e257f3e97c799024fb019f65c6ca4d8d81b1ae16221a589d68831d75985089350857f090995b79acec240413b8d4c658787e5a4657b9ab00bdb5b1960b1059e113ba38608945085818180828009800909905062001a9260005262003ea1565b857f08dbdc2e21ef11f2c57299687843cea3eb0d8e40e99131f42974178d44f73b7b82089050857f09e8aba671481197679faf752a0f78e342fe9c491596ab6758f170939785179f83089150857f1deb05180e833e45659052a7ebaf816c7efd12a7f9eec94b7bc7c683f1363d5c84089250857f19a70ec6bdfc9098a926efbcc04aa9ee248997e8b2c24af335fd6523e525087985089350857f21d773660adafb8a879986f9aab4890566353a3777d8a3f1eb93abe10bbf1f648608945085818180828009800909905062001b6960005262003ea1565b857f09f1890f72e9dc713e20ba637b89d5d397a6b01fcd667347f6f46617841c390182089050857f05af459361eb454d2a300c61e446998d48fa1f897bf219d608c2145c33b111c383089150857f0fa1a1d6829f0345664a66dc75a657335f336f15f340756cfa12fc850cc8b51384089250857f02e47a35bcc0c3a0bda0b1c0307ad543f4280fcf87f636f853655cf97a628bb085089350857f14f773e9834c6bdeb8f90e78bf4c24b7203411460112491036621895204d0f128608945085818180828009800909905062001c4060005262003ea1565b857f102d98cf502ed843255cf19d29bc7d8e642abe7cfd639992ffb091962fc8f7cc82089050857f043dd5f4aa5a76dd4c47f6c65da7ca2320d4c73ad3294738cba686a7e91373c283089150857f21833819c3337194a6c0d29a48d4f2676f0e7c79743a306f4cfdb2b26bd11efa84089250857f0f281925cf5ee649b474a6819d116ca3eb4eca246c311ecadc53262a3cff2b5385089350857f0d3e2477a7b10beb44709c7746d6824edf625dd60504d5dc93ce662f15c238d68608945085818180828009800909905062001d1760005262003ea1565b857f2cd7f641bedbf66956ff8a01be9cde35d80f80ab51e73b49acbfc3eff5aefc4482089050857f29e95b492bf2f95f4d09380f98b74e389149d24045811d7a86dd861310463cf883089150857f22da66bc62e8f011266efca86a6c810f9ae4c51af6ffeb57f8b3c50df83cc13e84089250857f0fe6d30de7a82d163023491794f4aca3220db79e8129df3643072d841925554a85089350857f0050e842a1299909123c46eff185c23ad312d03fef1adfecc7e07ecb298fd67f8608945085818180828009800909905062001dee60005262003ea1565b857f2130a3a7b3221222be34cc53a42d7733666f9ddf714ed7c5885cbbdb63108c2182089050857f2df9ee294edf99e3d8d5883fe0566c24aa66731f34a93280e1d328e67b33c9fa83089150857f1bf7d6e489ad8c0cf26eb68cc21ff54158132396dc250aeba4b6fc5fc337276284089250857f0c602fa155be958761eaf739617ab136cf7b807728bf7fe35d4778d311780e5485089350857f2e50e2c5b36aa20532407d86b8d22d7d5154080a24972faeb63faf0121ed7f218608945085818180828009800909905062001ec560005262003ea1565b857f17c2510982a7b5825710d6290ec4f782f674995ee8409b42b459123b180332e182089050857f0b0d52f03c8af7276803ecf2465b885b21337b538eabd2f6b2ab255f376b42a883089150857f0f5633df1972b9455953d88a63f80647a9ac77c6c0f85d4561972dd8fab8bd1484089250857f0ebf7ad29ca13804e1422e939681155124780ff43e76e929035498130a7f157285089350857f1aff13c81bda47e80b02962173bba343e18f94bee27c8a57661b1103a720ffe28608945085818180828009800909905062001f9c60005262003ea1565b857f210449dbf5cf3061da2465be85505862d3f31de1a3b58ff35713be57efac6c0782089050857f088230c2794e50c57d75cd6d3c7b9dbe19d1e2f1d3001044b93ad1c3ee62981783089150857f1c408c256490b0a1da08dc464138dfc78cce9a9e16c7705617a4d6dbb20e7e3a84089250857f074517e081eb4c1f22d1771200fb07658f7c77654d58440490dd6f557e9e390385089350857f02d04e9c21df1dbd88524bdb203691b4cee5530559d6cf0fa05adf61e12fdcbf860894508581818082800980090990506200207360005262003ea1565b857f2eb7a011b8bce91082e13ebd75de3b58eb9b4650dae9f11aa81db32cf1b67b1382089050857f2efda77ed35f4af0299f75d6e8a849b54d2ac6bf95368304e6030c18f0cf17b583089150857f09199dcafd50ce642eddbeda65206d4f61a73d10852b8114c51b2440192ae06484089250857f268c5cfc446d399c4dd319db666a75b5cb655d8c1797e9fa76181cb4216e156285089350857f2303a652c949071826b0e9a36c80578697b44e912cce6687012854eda11a18dc860894508581818082800980090990506200214a60005262003ea1565b857f27c53563b12a6ee2c3f041f31dc45922bc5353eb110868d237073f4efb35fbdf82089050857f1201a87eaf4ae618f02bd82d0a5109049969b5248cfe90f42c278f22615d2b0e83089150857f2c43169439fcd69ead8214997bb069becafcb1ba2c51e5706cb4b43dab2a443d84089250857f0683597315359040ea03c45d6984c6894f46cbb36d702e3c4fb9847e6304d94485089350857f03545706706eab36afb93b128febd16fb0425e158314197b77795ad3a798d183860894508581818082800980090990506200222160005262003ea1565b857f1a33c254ec117619d35f1fc051b31728740bed23a6a37870edb393b71a0c0e6b82089050857f1ffe6968a4470cd567b0c002281caf996e88f71e759b87e6f338e517f1690c7883089150857f0fd66e03ba8808ffecb059c899fd80f4140ddd5d2a5c4483107f4e02e355b39384089250857f263ab69f13b966f8197394552906b17e6c8617a7bdd5d74a7be3396b7fe013ab85089350857f16a425e47d1110625054d5a165de413e3bd87d5aa3958fdd6eb7e03e39ba404686089450858181808280098009099050620022f860005262003ea1565b857f2dc510a4719ec10cad752f03c673f0e253cc31d13e39e909fcc5f73af9138d9a82089050857f24df8e8d856c5b5e1bd1cad23d07dda3423c5179329b7a82cb4aa709a94576e583089150857f2bcc94ff4fc3c76f3cd5c68915a042e87628249a01b09561bdf24a6cdce5620f84089250857f076c1e88dc540c8d8de54e343df7c429d3295f52c38cffe6b48be86852da97df85089350857f09b5f209a451ac431c051fb12d9a5e4fe40ee1601120947da990fb8e12cb46e186089450858181808280098009099050620023cf60005262003ea1565b857f205f17b0d8729e2eaa88d6a44135a6ab64e9424f55b0f1ea0683af75eb677c0782089050857f281c5c688836f6cf912638c38be046cd091681f0a41761720cdd1edf9f23702983089150857f1a053e6878e900f45f4d67448c471cf3009a44e7a02ea50e4afa44f2592621f584089250857f100dc7d426debe3007fb7ceac84e4f5468efcb897e7bbee981742839d59e064c85089350857f17022672a016a957bb87e2cfadc8b75fb28905bdb62c82c80b1cb31b411e49c886089450858181808280098009099050620024a660005262003ea1565b857f1086db7e2760fc8b71053a87ebe151239fb8b547182b170de0c27203f954f4d282089050857f15384fe39d73b63302460ae4c2942fac2b41fb65a185536fb85dd24fd758406483089150857f2ebb599fe9136d424bf4abc5342c6c7447b1a853205fcfb5519e55135770900884089250857f1b4b5e87cfb9262cfec3c0f0542e4c5a4cf278292b4ce3eed996fac6f4d3728885089350857f2465053ae50b6885801f3f82e302cafbbb4a7581bb4fba60b637febe659e5057860894508581818082800980090990506200257d60005262003ea1565b857f114f32edcdea09cd095c5bb5d38f1b97da9f05e18b3708bf6e0ab9d3d54859ef82089050857f2bc70dfeb2baab2f6b387cd77be779ac2e5e5519f3d18123ee28d8c2543c714883089150857f01c9bf7a203ce22b775e3a61ad7e77b6a78348b9f6ec68a412e49bfe32c0541584089250857f0514b0fe5909ea887bedb0295fbbcec355cfb575ff6a97cd9f4ad00ccb57ee9b85089350857f267c76ec81934cc81a132a8b058910a12092520b12a201af03e3202d7b6c1b7e860894508581818082800980090990506200265460005262003ea1565b857f29170e3322b3d8d5c78c84babbb470adf1622493ce83e95cfb151cf757bde5d682089050857f019f6a8124b19e33af33e5d3873f9c335c6f09a45486cab536dd596ca41d951983089150857f1904aa4d6908544a8b348e9db1981c27009ed8ea171518ae5405d036242b60e984089250857f26f17873949bc679f7f043956694e422b3cee1de9dd6f6473b932a476455ff1a85089350857f1ac668f612b8243c193b33720b8aa54040c476031197131ebdcac9b18bc48f75860894508581818082800980090990506200272b60005262003ea1565b857f0996d961a75c0d07196dae45bf624766ccfbf8555be9796da52f81568ef0663d82089050857f030c97e1b8cad1d4fd50d1b4383fbe6674d171f99c63febb5425b395c24fc81983089150857f06e3ad6a46900e2d3953370255b68f89b3e523f1fe502642ee226f2d8bd0848f84089250857f1d6b3755331cd0216b6880e42f9880f565cb94b0e0455153a329890588cc916e85089350857f28e4dcba4b96f12a59b041535e730ac8c35189dc0b85ac033dd38c08bae531f2860894508581818082800980090990506200280260005262003ea1565b857f08b6086046a835508ccf484f2974b6a6b0712a476260376c7a3b3e4bc4a47a1482089050857f162cd2ca7fe3b5f1444bcec97812019bb6fd85fba6a0536a89643e15b9bb3b5283089150857f28f1e03baaea9bbc05af5b11937e4f5cb5c9a9c1192063d1998c01c64d483a7684089250857f1bdb062778d7c15da395af2734c25faa0127d2aab4aa71366031a0bb6791ce1085089350857f2375839502e09890cb2914e829627e0e0fc98870b2324a8b50329ebdd24749cb86089450858181808280098009099050620028d960005262003ea1565b857f1fa8662fbcb61fb3ad7c55668dc9423a332dc87cfb2df456e92d33611ed7bb5082089050857f1e4fad2dd6b0a6f1f8707f721716c8a446e2fb2c47a5138f3f7f9736079d769483089150857f211256d16c7269fd6df6f5fcdd1fa788ba3bd050059f53d261b0f5f13731ffe784089250857f2e49084b336eceaa4f8e2a2e6af08318f42060e574dda341f4a1079b12bcc5a585089350857f0ce19f54cdc39f7f3bf35192ac6808211aecea08dfe14cab758d25891fb00bb986089450858181808280098009099050620029b060005262003ea1565b857f0011c5d56c390e893cc394221261d8748dc60451e4ae4e1c84a8468bab2c14cb82089050857f17d79ff06b63ac2a8a9e05ee6af3dbb7ca60e17bfa39b47514a8cd8051579b4c83089150857f19a7d3a446cb5393dc74560093592b06b1a8b35cd6416a2ecab00173639015fa84089250857f030c00a0933dcdba2a808b2e1b9282f331f04596d8928da7aa6c3c97237037a685089350857f16bcb447ce2d50f3ae25ad080695382e935d2d00184c4acc9370be8aab64139c8608945085818180828009800909905062002a8760005262003ea1565b857f12341b46b0150aa25ea4ec8715312997e62124f37cab7b6d39255b7cd66feb1d82089050857f0e86d13917f44050b72a97b2bf610c84002fc28e296d1044dc89212db6a49ff483089150857f08e6eb4089d37d66d357e00b53d7f30d1052a181f8f2eb14d059025b110c726284089250857f2ea123856245f6c84738d15dd1481a0c0415ccb351a1e0cee10c48ce97ca7b1885089350857f2dca72b2ebcab8c23446e00330b163104195789025413abf664db0f9c84dfa6f8608945085818180828009800909905062002b5e60005262003ea1565b857f06ff9ed50d327e8463329f585ec924b3f2f6b4235f036fa4c64a26cbd42b6a6b82089050857f246a10b7e3e0089947f7c9bda3d54df8e2a60e0cca84ea2ac630a4535afbf73083089150857f22a63501c5f04b9018719ed99d700ee52f846a715ae67ad75c96b39d688b669184089250857f2f4c50477f7fd9c671799ac5d2e224cdb9164f58351d8aa140ec07e514fae93785089350857f10ffb7aad1f51c7d13b17f4d876d9a1e38f0ba8a4a23d4b50cda32cad851567e8608945085818180828009800909905062002c3560005262003ea1565b857f0e9cefddc3c2d3bea4d39722532d5420784027352187e7af1a056935c35803ae82089050857f07af84a4d3141e7ac23352e6dc6ea4afa1656f96a33c8978a3e83bdd4ba62b4183089150857f2d9e31a10aebc761f8de00d14b1e566d1a39323d6e89b638e940f3ec8a22c3c584089250857f27f19a6532e66b5333db1afd592f66f1d36034b314dad8447656747be27e64c785089350857f0058fa3c8454d63354b2024c3b4a577a180ed99f8f3155cd7e4d617d47d07ffd8608945085818180828009800909905062002d0c60005262003ea1565b857f041627b6715b780967957c080699343eb0414a205d3a175d708964956816a5d582089050857f006ac49dd9253edc7f632e57b958ccecd98201471cf1f66589888f12b727c52d83089150857f0131adffd8bd7254b1d8c3616bbe3386ec0c9c0d6d25a9a4ec46a6bf1830139884089250857f1c4a6f52c9fccf7a4138e413ef62a28377977ad7e25e49a3cf030e1cd8f9f5b685089350857f03f2a6be51ec677f946551b3860ea479fee048ae2078aeb7d1f7958d2c2645f68608945085818180828009800909905062002de360005262003ea1565b857f2da770aad2c2eb09391a0cb78ef3a9648a1372d8543119564d7376396b8ddc6282089050857f15278463665f74cddc1802febfab02cec9d45fe866c359c738062afb75d64a0383089150857f12fe278aa36544eac9731027090518d434e38ea966a08a6f8d580638ac54c77384089250857f149b9c802182558a4c45d119d3f4cc7fd8587604ca4f0d6e21b06ff30b6a23b685089350857f0812e7b4d847bc8517d19319772f3c9855e044fd60dbac9a0adc4959b691dfe48608945085818180828009800909905062002eba60005262003ea1565b857f02ed8d8ddeafe3d9d8df7f28a0bfaa7f555813c7e7503aea2a66973703a0c61b82089050857f0ebd073ba0537b514deb6029f921029e55e5e4d9a03d6b6ba1304038662d4db883089150857f15c754d5b14b2c4205c6ba8d2ccd028255b3e792c6afa08b44ee75b62eff9f5984089250857f169515c89ac5479db0ed8fa6fa311b391cc1235270f4cbc5c29e7cbc30e8732a85089350857f25479fbfb3a68f982388f2621001101608bdc29f6ff037696d9161f5cd9a4fef8608945085818180828009800909905062002f9160005262003ea1565b857f14475c4bd520451f3c852cb0311a578ca7f8e6e972182196ce09486e94be607182089050857f045a691066cc66bec9baf2798833a1dfd3a847502aec8d5f5c4e73363d09779983089150857f26029c0c267c799fb833ac8a11e3a3f0147a8ca037221b90013b8bcb37eba68384089250857f163facb34ff572fbf7c946969c1c260873ce12a6a94a3e45b8101d5b948d164185089350857f2c714e96e1913b351d969320cc69d5ec13e06a6275e58688af8ee00c4240ee28860894508581818082800980090990506200306860005262003ea1565b857f1c1661e2a7ce74b75aba84665ecd2bf9ddd6268f06debfe2d52b804eff1d5fa682089050857f06a69ae795ee9bfe5e5af3e6619a47d26635b34c2a0889fea8c3c068b7dc2c7183089150857f113d58535d892115c5d28b4c19a3609374dbdbadf54195c731416c85d731d46a84089250857f2ab89102e2b8d5e638ff97d761da6042e534f1ff47f7917a2ca1a74063b4610185089350857f03c11ca79e41fdfe962730c45e699546349031893da2b4fd39804fd6a15ad1b3860894508581818082800980090990506200313f60005262003ea1565b857f27096c672621403888014ddbbbfc9da1f7f67b4d4cfe846c6adf040faaf2669c82089050857f2de32ad15497aef4d504d4deeb53b13c66db790ce486130caa9dc2b57ef5be0d83089150857f0dc108f2b0a280d2fd5d341310722a2d28c738dddaec9f3d255754448eefd00184089250857f1869f3b763fe8164c96858a1bb9efad5bcdc3eebc409be7c7d34ca50365d832f85089350857f022ed3a2d9ff31cbf82559fe6a911843b616945e16a568d48c6d33767129682d860894508581818082800980090990506200321660005262003ea1565b857f2155d6005210169e3944ed1365bd0e7292fca1f27c19c26610c6aec077d026bc82089050857f0de1ba7a562a8f7acae93263f5f1b4bbec0c0556c91af3db3ea5928c8caeae8583089150857f05dbb4406024beabcfce5bf46ec7da38126f740bce8d637b6351dfa7da90256384089250857f05d4149baac413bed4d8dc8ad778d32c00e789e3fcd72dccc97e5427a368fd5e85089350857f01cdf8b452d97c2b9be5046e7397e76ff0b6802fa941c7879212e22172c27b2e86089450858181808280098009099050620032ed60005262003ea1565b857f1fc6a71867027f56af8085ff81adce33c4d7c5015eced8c71b0a22279d46c07c82089050857f1040bef4c642d0345d4d59a5a7a3a42ba9e185b75306d9c3568e0fda96aaafc283089150857f16b79c3a6bf316e0ff2c91b289334a4d2b21e95676431918a8081475ab8fad0d84089250857f20dff1bc30f6db6b434b3a1387e3c8c6a34070e52b601fc13cbe1cdcd59f474e85089350857f0212ac2ab7a6eaaec254955030a970f8062dd4171a726a8bdfb7fd8512ae060d86089450858181808280098009099050620033c460005262003ea1565b857f2f29377491474442869a109c9215637cb02dc03134f0044213c8119f6996ae0982089050857f0984ca6a5f9185d525ec93c33fea603273be9f3866aa284c5837d9f32d814bfa83089150857f0d080a6b6b3b60700d299bd6fa81220de491361c8a6bd19ceb0ee9294b24f02884089250857f0e65cd99e84b052f6789530638cb0ad821acc85b6400264dce929ed7c85a454485089350857f2e208875bc7ac1224808f72c716cd05ee30e3d20380ff6a655975da12736920b860894508581818082800980090990506200349b60005262003ea1565b857f2989f3ae477c2fd376a0b0ff3d7dfac1ae2e3b894afd29f64a60d1aa8592bad582089050857f11361ce544e941379222d101e6fac0ce918106a463290a3e3a74c3cea718945983089150857f1e8d014b86cb5a7da539e10c173f6a75d122a822b8fb366c34c8bd05a206143884089250857f173f65adec8deee27ba812ad29558e23a0c2324167ef6c91212ee2c28ee9873385089350857f01c36daaf9f01f1bafee8bd0c779ac3e5da5df7ad45499d0991bd695310eddd9860894508581818082800980090990506200357260005262003ea1565b857f1353acb08c05adb4aa9ab1c485bb85fff277d1a3f2fc89944a6f5741f381e56282089050857f2e5abd2537207cad1860e71ea1188ee4009d33deb4f93aeb20f1c87a3b064d3483089150857f191d5c5edaef42d3d02eedbb7ab8562513deb4eb34913a13421726ba8f69455c84089250857f11d7f8d1f269264282a263fea6d7599d82a04c74c127de9dee7939dd2dcd089e85089350857f04218fde366829ed90f79ad5e67997973445cb4cd6bc6f951bad085286cac971860894508581818082800980090990506200364960005262003ea1565b857f0070772f7cf52453048397ca5f47a202027b73b489301c3227b71c730d76d6dd82089050857f038a389baef5d9a7c865b065687a1d9b67681a98cd051634c1dc04dbe3d2b86183089150857f09a5eefab8b36a80cda446b2b4b59ccd0f39d00966a50beaf19860789015a6e584089250857f01b588848b8b47c8b969c145109b4b583d9ec99edfacb7489d16212c7584cd8c85089350857f0b846e4a390e560f6e1af6dfc3341419545e5abfa323d817fed91e30d42954a6860894508581818082800980090990506200372060005262003ea1565b857f23a6679c7d9adb660d43a02ddb900040eb1513bc394fc4f985cabfe85ce72fe382089050857f2e0374a699197e343e5caa35f1351e9f4c3402fb7c85ecccf72f31d6fe08925483089150857f0752cd899e52dc4d7f7a08af4cde3ff64b8cc0b1176bb9ec37d41913a7a27b4884089250857f068f8813127299dac349a2b6d57397a50275142b664b802c99e2873dd7ae55a785089350857f2ba70a102355d549677574167434b3f986872d04a295b5b8b374330f2da202b586089450858181808280098009099050620037f760005262003ea1565b857f2c467af88748abf6a334d1df03b5521309f9099b825dd289b8609e70a0b5082882089050857f05c5f20bef1bd82701009a2b448ae881e3a52c2d1a31957296d29e5763e8f49783089150857f0dc6385fdc567be5842a381f6006e2c60cd083a2c649d9f23ac8c9fe61b7387184089250857f142d3983f3dc7f7e19d49911b8670fa70378d5b84150d25ed255baa8114b369c85089350857f29a01efb2f6aa894fd7e6d98c96a0fa0f36f86a7a99aa35c00fa18c1b2df67bf86089450858181808280098009099050620038ce60005262003ea1565b857f0525ffee737d605138c4a5066644ec630ab9e8afc64555b7d2a1af04eb613a7682089050857f1e807dca81d79581f076677ca0e822767e164f614910264ef177cf4238301dc883089150857f0385fb3f89c74dc993510816472474d34c0223e0f733a52fdba56082dbd8757c84089250857f037640dc1afc0143e1a6298e53cae59fcfabd7016fd6ef1af558f337bab0ea0185089350857f1341999a1ed86919f12a6c5260829eee5fd56cf031da8050b7e4c0de896074b486089450858181808280098009099050620039a560005262003ea1565b857f069eb075866b0af356906d4bafb10ad773afd642efdcc5657b244f65bed8ece782089050857f171c0b81e62136e395b38e8e08b3e646d2726101d3afaa02ea1909a61903369683089150857f2c81814c9453f51cb6eb55c311753e84cbbdcb39bfe696f95575107502acced884089250857f29d843c0415d35d9e3b33fadcf274b2ab04b39032adca92ce39b8a86a7c3a60485089350857f085d6a1070f3513d8436bccdabb78750d8e15ea5947f2cdaa7669cf3fae7728b8608945085818180828009800909905062003a7c60005262003ea1565b857f11820363ed541daa10a44ba665bf302cdbf1dd4e6706b02c9e2a5cda412fc39482089050857f201935a58f5c57fc02b60d61a83785bddfd3150e05f1df5d105840b751a1631783089150857f0a8c2820c56971aae27a952abd33a03d46794eedd686cd8ecfed610e87c02e9a84089250857f180638ff301a64ca04abd6d0bd7500b6650b65ff33e6be1fd50dbc163a28187785089350857f095c716266f1de59044f97114a4158a3f85ca8a937cfbec63e9b321a812dd36b8608945085818180828009800909905085828180828009800909915085838180828009800909925085848180828009800909935085858180828009800909945062003b8360005262003ea1565b857f17c31ea02fbc378320d86ffed6c7ca1583b618c5c1a687818d4087a497d7349082089050857f05b86c4bb8ef318b6a7227e4192d149d3c17a9764ccd660de4d50a77f192a91b83089150857f265bc95df4a4c4876ff70d7ea2fde2c7ab15f4a6ae0d237cd6ce74ba986c7a7b84089250857f24752b47bc6c6bc8d9bbe48f5fef2f6908701739c5f5b4b3d6c886d4715c792985089350857f14814a1e0f492a4ea0d86e527a96482178d624b98da96ee5e583b9324d974efe8608945085818180828009800909905085828180828009800909915085838180828009800909925085848180828009800909935085858180828009800909945062003c8a60005262003ea1565b857f10def931073b6479bd60577378f29381997c8e041d3cfb3dc7523bca906f00bd82089050857f14f7ae770bf7e95f7f706c0d8ab4ed03fa0b880d28c69d031b4592c98610175f83089150857f1aef50a0cee751b59f926af40e8035d19decc9d428ebe4e775c5cc9dce1ce58984089250857f041935607172f68eba65ca60068dfe3b086c2a2d57d09602951214b57e73cf5a85089350857f26863e9dd24255d1573bd083959b856c0493fbefe83c819837a151d3bf452cb88608945085818180828009800909905085828180828009800909915085838180828009800909925085848180828009800909935085858180828009800909945062003d9160005262003ea1565b857f2036efb6f9830965eb3d7a068bd087c9f5adf251ba62052c652738e63ff8b3af82089050857f0c712a975b74dc9d766b639a029969ca30be4f75a753f854b00fa4f1b4f4ee9b83089150857f08014dab3cd1667e27afc99bfac1e6807afdff6456492ca3375731d38753969984089250857f198d07192db4fac2a82a4a79839d6a2b97c4dd4d37b4e8f3b53009f79b34e6a485089350857f29eb1de42a3ad381b23b4131426897a32709b29d53bb946dfd15784d1f63e5728608945085818180828009800909905085828180828009800909915085838180828009800909925085848180828009800909935085858180828009800909945062003e9860005262003ea1565b60005260206000f35b8560205182098660405184098791088660605185098791088660805186098791088660a05187098791088660c05183098760e05185098891088761010051860988910887610120518709889108876101405188098891088761016051840988610180518609899108886101a0518709899108886101c0518809899108886101e051890989910888610200518509896102205187098a9108896102405188098a9108896102605189098a910889610280518a098a9108896102a05186098a6102c05188098b91088a6102e05189098b91088a610300518a098b91088a610320518b098b91089850965094509250905060005156","id":1,"to":"0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed","type":"ONCHAIN_INTERACTION","value":{"_kind":"bigint","value":"0"}},"type":"NETWORK_INTERACTION_REQUEST"} +{"futureId":"Poseidon4Module#Poseidon4Element","networkInteractionId":1,"nonce":8,"type":"TRANSACTION_PREPARE_SEND"} +{"futureId":"Poseidon4Module#Poseidon4Element","networkInteractionId":1,"nonce":8,"transaction":{"fees":{"gasPrice":{"_kind":"bigint","value":"1000000000"}},"hash":"0xe3a7fcb16ab69dbbe579ac98fb7b2a3ed7271b23906056873678dd25bc4f58ba"},"type":"TRANSACTION_SEND"} +{"futureId":"Poseidon4Module#Poseidon4Element","hash":"0xe3a7fcb16ab69dbbe579ac98fb7b2a3ed7271b23906056873678dd25bc4f58ba","networkInteractionId":1,"receipt":{"blockHash":"0x66913c4f7cbf0d1016b82917c114d1bef6a66723bb46e53c27027ecf05b7178a","blockNumber":100808,"logs":[{"address":"0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed","data":"0x","logIndex":0,"topics":["0xb8fda7e00c6b06a2b54e58521bc5894fee35f1090e5a3bb6390bfe2b98b497f7","0x0000000000000000000000000695cf2c6dfc438a4e40508741888198a6ccacc2","0x1fb806fe12ba202b72799840b31b8b2ba7246fc0a96873ac3602d29c91d8c2d0"]}],"status":"SUCCESS"},"type":"TRANSACTION_CONFIRM"} +{"futureId":"Poseidon4Module#Poseidon4Element","result":{"address":"0x0695cF2c6dfc438a4E40508741888198A6ccacC2","type":"SUCCESS"},"type":"DEPLOYMENT_EXECUTION_STATE_COMPLETE"} +{"artifactId":"SmtLibModule#PoseidonUnit2L","contractAddress":"0x72F721D9D5f91353B505207C63B56cF3d9447edB","contractName":"PoseidonUnit2L","dependencies":[],"futureId":"SmtLibModule#PoseidonUnit2L","futureType":"NAMED_ARTIFACT_CONTRACT_AT","strategy":"create2","strategyConfig":{"salt":"0x000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d1"},"type":"CONTRACT_AT_EXECUTION_STATE_INITIALIZE"} +{"artifactId":"SmtLibModule#PoseidonUnit3L","contractAddress":"0x5Bc89782d5eBF62663Df7Ce5fb4bc7408926A240","contractName":"PoseidonUnit3L","dependencies":[],"futureId":"SmtLibModule#PoseidonUnit3L","futureType":"NAMED_ARTIFACT_CONTRACT_AT","strategy":"create2","strategyConfig":{"salt":"0x000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d1"},"type":"CONTRACT_AT_EXECUTION_STATE_INITIALIZE"} +{"artifactId":"SmtLibModule#SmtLib","constructorArgs":[],"contractName":"SmtLib","dependencies":["SmtLibModule#PoseidonUnit2L","SmtLibModule#PoseidonUnit3L"],"from":"0xcabae40a68bcb419c8d9a3ab5eaef63810c2d4f4","futureId":"SmtLibModule#SmtLib","futureType":"NAMED_ARTIFACT_CONTRACT_DEPLOYMENT","libraries":{"PoseidonUnit2L":"0x72F721D9D5f91353B505207C63B56cF3d9447edB","PoseidonUnit3L":"0x5Bc89782d5eBF62663Df7Ce5fb4bc7408926A240"},"strategy":"create2","strategyConfig":{"salt":"0x000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d1"},"type":"DEPLOYMENT_EXECUTION_STATE_INITIALIZE","value":{"_kind":"bigint","value":"0"}} +{"futureId":"SmtLibModule#SmtLib","networkInteraction":{"data":"0x26307668000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000002f95612f43610052600b82828239805160001a6073146045577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106101405760003560e01c806379f97125116100c2578063a751be2411610086578063a751be24146103f5578063c1d29f0114610413578063dc9a7c8c1461043c578063dea7633a1461046c578063e170cf6e1461049c578063ec145108146104cc57610140565b806379f971251461030c578063893f99f31461033c57806391761b751461036c57806392f5b06c1461039c5780639e43b813146103cc57610140565b806340a73d981161010957806340a73d981461022e5780635db40cda1461024c57806362e8f2151461027c578063792a470f146102ac57806379c17a96146102dc57610140565b806278f030146101455780630912610a14610175578063138271361461019e57806317c850f0146101ce57806321d60953146101fe575b600080fd5b61015f600480360381019061015a9190611f7a565b6104fc565b60405161016c9190611fc9565b60405180910390f35b81801561018157600080fd5b5061019c60048036038101906101979190611f7a565b61051f565b005b6101b860048036038101906101b39190611fe4565b6105fa565b6040516101c591906121c0565b60405180910390f35b6101e860048036038101906101e39190611f7a565b610629565b6040516101f5919061225d565b60405180910390f35b61021860048036038101906102139190611fe4565b610688565b60405161022591906123a2565b60405180910390f35b610236610765565b6040516102439190611fc9565b60405180910390f35b61026660048036038101906102619190611f7a565b61076b565b60405161027391906121c0565b60405180910390f35b610296600480360381019061029191906123c4565b61078e565b6040516102a39190611fc9565b60405180910390f35b6102c660048036038101906102c19190611fe4565b61079f565b6040516102d391906121c0565b60405180910390f35b6102f660048036038101906102f19190611fe4565b6107ce565b60405161030391906121c0565b60405180910390f35b610326600480360381019061032191906123c4565b610afa565b6040516103339190611fc9565b60405180910390f35b610356600480360381019061035191906123c4565b610b88565b6040516103639190611fc9565b60405180910390f35b610386600480360381019061038191906123f1565b610b96565b60405161039391906123a2565b60405180910390f35b6103b660048036038101906103b19190611f7a565b610cf5565b6040516103c39190612467565b60405180910390f35b8180156103d857600080fd5b506103f360048036038101906103ee9190611f7a565b610d1a565b005b6103fd610d9c565b60405161040a9190611fc9565b60405180910390f35b81801561041f57600080fd5b5061043a60048036038101906104359190611fe4565b610da2565b005b61045660048036038101906104519190611f7a565b610e5e565b604051610463919061225d565b60405180910390f35b61048660048036038101906104819190611f7a565b610ebd565b604051610493919061225d565b60405180910390f35b6104b660048036038101906104b19190611f7a565b610f71565b6040516104c39190612561565b60405180910390f35b6104e660048036038101906104e191906123c4565b611004565b6040516104f39190612467565b60405180910390f35b600082600201600083815260200190815260200160002080549050905092915050565b60008111610562576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610559906125ff565b60405180910390fd5b816003015481116105a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161059f9061266b565b60405180910390fd5b6101008111156105ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105e4906126fd565b60405180910390fd5b8082600301819055505050565b610602611e49565b600061060e8584610629565b905061061f858583600001516107ce565b9150509392505050565b610631611e92565b42821115610674576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161066b90612769565b60405180910390fd5b6106808383600061101f565b905092915050565b60606000806106a2866001018054905086866103e8611066565b91509150600082826106b491906127b8565b67ffffffffffffffff8111156106cd576106cc6127ec565b5b60405190808252806020026020018201604052801561070657816020015b6106f3611e92565b8152602001906001900390816106eb5790505b50905060008390505b8281101561075757610721888261115d565b82858361072e91906127b8565b8151811061073f5761073e61281b565b5b6020026020010181905250808060010191505061070f565b508093505050509392505050565b6103e881565b610773611e49565b610786838361078186610afa565b6107ce565b905092915050565b600081600101805490509050919050565b6107a7611e49565b60006107b38584610e5e565b90506107c4858583600001516107ce565b9150509392505050565b6107d6611e49565b83826107e28282610cf5565b610821576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161081890612896565b60405180910390fd5b6000866003015467ffffffffffffffff811115610841576108406127ec565b5b60405190808252806020026020018201604052801561086f5781602001602082028036833780820191505090505b50905060005b87600301548110156108af5760008282815181106108965761089561281b565b5b6020026020010181815250508080600101915050610875565b5060006040518061010001604052808781526020016000151581526020018381526020018881526020016000815260200160001515815260200160008152602001600081525090506000869050610904611ec8565b60005b8a600301548111610ae95761091c8b84610f71565b91506000600281111561093257610931612482565b5b8260000151600281111561094957610948612482565b5b0315610ae9576001600281111561096357610962612482565b5b8260000151600281111561097a57610979612482565b5b036109f25783606001518260600151036109b25760018460200190151590811515815250508160800151846080018181525050610ae9565b60018460a001901515908115158152505081606001518460c001818152505081608001518460e00181815250508160800151846080018181525050610ae9565b600280811115610a0557610a04612482565b5b82600001516002811115610a1c57610a1b612482565b5b03610a9b57600180828660600151901c1603610a665781604001519250816020015184604001518281518110610a5557610a5461281b565b5b602002602001018181525050610a96565b81602001519250816040015184604001518281518110610a8957610a8861281b565b5b6020026020010181815250505b610ad6565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610acd90612902565b60405180910390fd5b8080610ae190612922565b915050610907565b508296505050505050509392505050565b600081610b0681611004565b610b45576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b3c906129b6565b60405180910390fd5b8260010160018460010180549050610b5d91906127b8565b81548110610b6e57610b6d61281b565b5b906000526020600020906003020160000154915050919050565b600081600301549050919050565b60608484610ba48282610cf5565b610be3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bda90612896565b60405180910390fd5b60008760020160008881526020019081526020016000209050600080610c11838054905089896103e8611066565b9150915060008282610c2391906127b8565b67ffffffffffffffff811115610c3c57610c3b6127ec565b5b604051908082528060200260200182016040528015610c7557816020015b610c62611e92565b815260200190600190039081610c5a5790505b50905060008390505b82811015610ce357610cad8c868381548110610c9d57610c9c61281b565b5b906000526020600020015461115d565b828583610cba91906127b8565b81518110610ccb57610cca61281b565b5b60200260200101819052508080600101915050610c7e565b50809650505050505050949350505050565b6000808360020160008481526020019081526020016000208054905011905092915050565b610d2382611004565b15610d63576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d5a90612a22565b60405180910390fd5b610d6d828261051f565b610d7b8260008060006112aa565b60018260040160006101000a81548160ff0219169083151502179055505050565b61010081565b82610dac81611004565b610deb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610de2906129b6565b60405180910390fd5b60006040518060a0016040528060016002811115610e0c57610e0b612482565b5b815260200160008152602001600081526020018581526020018481525090506000610e3686610afa565b90506000610e478784846000611367565b9050610e55878242436112aa565b50505050505050565b610e66611e92565b43821115610ea9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ea090612a8e565b60405180910390fd5b610eb58383600161101f565b905092915050565b610ec5611e92565b8282610ed18282610cf5565b610f10576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f0790612896565b60405180910390fd5b6000856002016000868152602001908152602001600020905060008160018380549050610f3d91906127b8565b81548110610f4e57610f4d61281b565b5b90600052602060002001549050610f65878261115d565b94505050505092915050565b610f79611ec8565b8260000160008381526020019081526020016000206040518060a00160405290816000820160009054906101000a900460ff166002811115610fbe57610fbd612482565b5b6002811115610fd057610fcf612482565b5b8152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905092915050565b60008160040160009054906101000a900460ff169050919050565b611027611e92565b60008061103f85858861160b9092919063ffffffff16565b915091508061105157611050612aae565b5b61105b868361115d565b925050509392505050565b600080600084116110ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110a390612b29565b60405180910390fd5b828411156110ef576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110e690612b95565b60405180910390fd5b858510611131576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161112890612c01565b60405180910390fd5b6000848661113f9190612c21565b90508681111561114d578690505b8581925092505094509492505050565b611165611e92565b60006001846001018054905061117b91906127b8565b8314905060008460010184815481106111975761119661281b565b5b906000526020600020906003020190506040518060c0016040528082600001548152602001836111fa57866001016001876111d29190612c21565b815481106111e3576111e261281b565b5b9060005260206000209060030201600001546111fd565b60005b8152602001826001015481526020018361124a57866001016001876112229190612c21565b815481106112335761123261281b565b5b90600052602060002090600302016001015461124d565b60005b8152602001826002015481526020018361129a57866001016001876112729190612c21565b815481106112835761128261281b565b5b90600052602060002090600302016002015461129d565b60005b8152509250505092915050565b83600101604051806060016040528085815260200184815260200183815250908060018154018082558091505060019003906000526020600020906003020160009091909190915060008201518160000155602082015181600101556040820151816002015550508360020160008481526020019081526020016000206001856001018054905061133b91906127b8565b908060018154018082558091505060019003906000526020600020016000909190919091505550505050565b600084600301548211156113b0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113a790612ca1565b60405180910390fd5b60008560000160008581526020019081526020016000206040518060a00160405290816000820160009054906101000a900460ff1660028111156113f7576113f6612482565b5b600281111561140957611408612482565b5b81526020016001820154815260200160028201548152602001600382015481526020016004820154815250509050600080600090506000600281111561145257611451612482565b5b8360000151600281111561146957611468612482565b5b0361147f5761147888886117f8565b90506115fd565b6001600281111561149357611492612482565b5b836000015160028111156114aa576114a9612482565b5b036114e15786606001518360600151146114cf576114ca888885886119e9565b6114da565b6114d988886117f8565b5b90506115fc565b6002808111156114f4576114f3612482565b5b8360000151600281111561150b5761150a612482565b5b036115fb57611518611ec8565b600180878a60600151901c160361158d576115458989866040015160018a6115409190612c21565b611367565b92506040518060a0016040528060028081111561156557611564612482565b5b81526020018560200151815260200184815260200160008152602001600081525090506115ed565b6115a98989866020015160018a6115a49190612c21565b611367565b92506040518060a001604052806002808111156115c9576115c8612482565b5b81526020018481526020018560400151815260200160008152602001600081525090505b6115f789826117f8565b9150505b5b5b809350505050949350505050565b600080600085600101805490500361162957600080915091506117f0565b6000806001876001018054905061164091906127b8565b905060005b8183116117e5576002838361165a9190612c21565b6116649190612cf0565b905060006116be8960010183815481106116815761168061281b565b5b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505088611be8565b905087810361178a575b600189600101805490506116dc91906127b8565b82101561177a5760006117478a6001016001856116f99190612c21565b8154811061170a5761170961281b565b5b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505089611be8565b905088810361176357828061175b90612922565b935050611774565b8260019650965050505050506117f0565b506116c8565b81600195509550505050506117f0565b808811156117a65760018261179f9190612c21565b93506117df565b80881080156117b55750600082115b156117ce576001826117c791906127b8565b92506117de565b60008095509550505050506117f0565b5b50611645565b816001945094505050505b935093915050565b60008061180483611c9a565b90506000600281111561181a57611819612482565b5b84600001600083815260200190815260200160002060000160009054906101000a900460ff16600281111561185257611851612482565b5b1461196d578260000151600281111561186e5761186d612482565b5b84600001600083815260200190815260200160002060000160009054906101000a900460ff1660028111156118a6576118a5612482565b5b146118b4576118b3612aae565b5b826020015184600001600083815260200190815260200160002060010154146118e0576118df612aae565b5b8260400151846000016000838152602001908152602001600020600201541461190c5761190b612aae565b5b8260600151846000016000838152602001908152602001600020600301541461193857611937612aae565b5b8260800151846000016000838152602001908152602001600020600401541461196457611963612aae565b5b809150506119e3565b8284600001600083815260200190815260200160002060008201518160000160006101000a81548160ff021916908360028111156119ae576119ad612482565b5b021790555060208201518160010155604082015181600201556060820151816003015560808201518160040155905050809150505b92915050565b600084600301548210611a31576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a2890612ca1565b60405180910390fd5b611a39611ec8565b6000600180858860600151901c161490506000600180868860600151901c1614905080151582151503611b1f576000611a8089898960018a611a7b9190612c21565b6119e9565b90508215611acb576040518060a00160405280600280811115611aa657611aa5612482565b5b8152602001600081526020018281526020016000815260200160008152509350611b0a565b6040518060a00160405280600280811115611ae957611ae8612482565b5b81526020018281526020016000815260200160008152602001600081525093505b611b1489856117f8565b945050505050611be0565b8115611b77576040518060a00160405280600280811115611b4357611b42612482565b5b8152602001611b5188611c9a565b8152602001611b5f89611c9a565b81526020016000815260200160008152509250611bc5565b6040518060a00160405280600280811115611b9557611b94612482565b5b8152602001611ba389611c9a565b8152602001611bb188611c9a565b815260200160008152602001600081525092505b611bcf88886117f8565b50611bda88846117f8565b93505050505b949350505050565b6000600180811115611bfd57611bfc612482565b5b826001811115611c1057611c0f612482565b5b03611c215782604001519050611c94565b60006001811115611c3557611c34612482565b5b826001811115611c4857611c47612482565b5b03611c595782602001519050611c94565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c8b90612d6d565b60405180910390fd5b92915050565b6000806000905060016002811115611cb557611cb4612482565b5b83600001516002811115611ccc57611ccb612482565b5b03611d795760006040518060600160405280856060015181526020018560800151815260200160018152509050735bc89782d5ebf62663df7ce5fb4bc7408926a2406325cc70e8826040518263ffffffff1660e01b8152600401611d309190612e11565b602060405180830381865af4158015611d4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d719190612e41565b915050611e40565b600280811115611d8c57611d8b612482565b5b83600001516002811115611da357611da2612482565b5b03611e3f577372f721d9d5f91353b505207c63b56cf3d9447edb6329a5f2f660405180604001604052808660200151815260200186604001518152506040518263ffffffff1660e01b8152600401611dfb9190612ef2565b602060405180830381865af4158015611e18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e3c9190612e41565b90505b5b80915050919050565b6040518061010001604052806000815260200160001515815260200160608152602001600081526020016000815260200160001515815260200160008152602001600081525090565b6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060a0016040528060006002811115611ee757611ee6612482565b5b8152602001600081526020016000815260200160008152602001600081525090565b600080fd5b6000819050919050565b611f2181611f0e565b8114611f2c57600080fd5b50565b600081359050611f3e81611f18565b92915050565b6000819050919050565b611f5781611f44565b8114611f6257600080fd5b50565b600081359050611f7481611f4e565b92915050565b60008060408385031215611f9157611f90611f09565b5b6000611f9f85828601611f2f565b9250506020611fb085828601611f65565b9150509250929050565b611fc381611f44565b82525050565b6000602082019050611fde6000830184611fba565b92915050565b600080600060608486031215611ffd57611ffc611f09565b5b600061200b86828701611f2f565b935050602061201c86828701611f65565b925050604061202d86828701611f65565b9150509250925092565b61204081611f44565b82525050565b60008115159050919050565b61205b81612046565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60006120998383612037565b60208301905092915050565b6000602082019050919050565b60006120bd82612061565b6120c7818561206c565b93506120d28361207d565b8060005b838110156121035781516120ea888261208d565b97506120f5836120a5565b9250506001810190506120d6565b5085935050505092915050565b6000610100830160008301516121296000860182612037565b50602083015161213c6020860182612052565b506040830151848203604086015261215482826120b2565b91505060608301516121696060860182612037565b50608083015161217c6080860182612037565b5060a083015161218f60a0860182612052565b5060c08301516121a260c0860182612037565b5060e08301516121b560e0860182612037565b508091505092915050565b600060208201905081810360008301526121da8184612110565b905092915050565b60c0820160008201516121f86000850182612037565b50602082015161220b6020850182612037565b50604082015161221e6040850182612037565b5060608201516122316060850182612037565b5060808201516122446080850182612037565b5060a082015161225760a0850182612037565b50505050565b600060c08201905061227260008301846121e2565b92915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60c0820160008201516122ba6000850182612037565b5060208201516122cd6020850182612037565b5060408201516122e06040850182612037565b5060608201516122f36060850182612037565b5060808201516123066080850182612037565b5060a082015161231960a0850182612037565b50505050565b600061232b83836122a4565b60c08301905092915050565b6000602082019050919050565b600061234f82612278565b6123598185612283565b935061236483612294565b8060005b8381101561239557815161237c888261231f565b975061238783612337565b925050600181019050612368565b5085935050505092915050565b600060208201905081810360008301526123bc8184612344565b905092915050565b6000602082840312156123da576123d9611f09565b5b60006123e884828501611f2f565b91505092915050565b6000806000806080858703121561240b5761240a611f09565b5b600061241987828801611f2f565b945050602061242a87828801611f65565b935050604061243b87828801611f65565b925050606061244c87828801611f65565b91505092959194509250565b61246181612046565b82525050565b600060208201905061247c6000830184612458565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600381106124c2576124c1612482565b5b50565b60008190506124d3826124b1565b919050565b60006124e3826124c5565b9050919050565b6124f3816124d8565b82525050565b60a08201600082015161250f60008501826124ea565b5060208201516125226020850182612037565b5060408201516125356040850182612037565b5060608201516125486060850182612037565b50608082015161255b6080850182612037565b50505050565b600060a08201905061257660008301846124f9565b92915050565b600082825260208201905092915050565b7f4d6178206465707468206d7573742062652067726561746572207468616e207a60008201527f65726f0000000000000000000000000000000000000000000000000000000000602082015250565b60006125e960238361257c565b91506125f48261258d565b604082019050919050565b60006020820190508181036000830152612618816125dc565b9050919050565b7f4d61782064657074682063616e206f6e6c7920626520696e6372656173656400600082015250565b6000612655601f8361257c565b91506126608261261f565b602082019050919050565b6000602082019050818103600083015261268481612648565b9050919050565b7f4d61782064657074682069732067726561746572207468616e2068617264206360008201527f6170000000000000000000000000000000000000000000000000000000000000602082015250565b60006126e760228361257c565b91506126f28261268b565b604082019050919050565b60006020820190508181036000830152612716816126da565b9050919050565b7f4e6f206675747572652074696d657374616d707320616c6c6f77656400000000600082015250565b6000612753601c8361257c565b915061275e8261271d565b602082019050919050565b6000602082019050818103600083015261278281612746565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006127c382611f44565b91506127ce83611f44565b92508282039050818111156127e6576127e5612789565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f526f6f7420646f6573206e6f7420657869737400000000000000000000000000600082015250565b600061288060138361257c565b915061288b8261284a565b602082019050919050565b600060208201905081810360008301526128af81612873565b9050919050565b7f496e76616c6964206e6f64652074797065000000000000000000000000000000600082015250565b60006128ec60118361257c565b91506128f7826128b6565b602082019050919050565b6000602082019050818103600083015261291b816128df565b9050919050565b600061292d82611f44565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361295f5761295e612789565b5b600182019050919050565b7f536d74206973206e6f7420696e697469616c697a656400000000000000000000600082015250565b60006129a060168361257c565b91506129ab8261296a565b602082019050919050565b600060208201905081810360008301526129cf81612993565b9050919050565b7f536d7420697320616c726561647920696e697469616c697a6564000000000000600082015250565b6000612a0c601a8361257c565b9150612a17826129d6565b602082019050919050565b60006020820190508181036000830152612a3b816129ff565b9050919050565b7f4e6f2066757475726520626c6f636b7320616c6c6f7765640000000000000000600082015250565b6000612a7860188361257c565b9150612a8382612a42565b602082019050919050565b60006020820190508181036000830152612aa781612a6b565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b7f4c656e6774682073686f756c642062652067726561746572207468616e203000600082015250565b6000612b13601f8361257c565b9150612b1e82612add565b602082019050919050565b60006020820190508181036000830152612b4281612b06565b9050919050565b7f4c656e677468206c696d69742065786365656465640000000000000000000000600082015250565b6000612b7f60158361257c565b9150612b8a82612b49565b602082019050919050565b60006020820190508181036000830152612bae81612b72565b9050919050565b7f537461727420696e646578206f7574206f6620626f756e647300000000000000600082015250565b6000612beb60198361257c565b9150612bf682612bb5565b602082019050919050565b60006020820190508181036000830152612c1a81612bde565b9050919050565b6000612c2c82611f44565b9150612c3783611f44565b9250828201905080821115612c4f57612c4e612789565b5b92915050565b7f4d61782064657074682072656163686564000000000000000000000000000000600082015250565b6000612c8b60118361257c565b9150612c9682612c55565b602082019050919050565b60006020820190508181036000830152612cba81612c7e565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000612cfb82611f44565b9150612d0683611f44565b925082612d1657612d15612cc1565b5b828204905092915050565b7f496e76616c696420736561726368207479706500000000000000000000000000600082015250565b6000612d5760138361257c565b9150612d6282612d21565b602082019050919050565b60006020820190508181036000830152612d8681612d4a565b9050919050565b600060039050919050565b600081905092915050565b6000819050919050565b6000602082019050919050565b612dc381612d8d565b612dcd8184612d98565b9250612dd882612da3565b8060005b83811015612e09578151612df0878261208d565b9650612dfb83612dad565b925050600181019050612ddc565b505050505050565b6000606082019050612e266000830184612dba565b92915050565b600081519050612e3b81611f4e565b92915050565b600060208284031215612e5757612e56611f09565b5b6000612e6584828501612e2c565b91505092915050565b600060029050919050565b600081905092915050565b6000819050919050565b6000602082019050919050565b612ea481612e6e565b612eae8184612e79565b9250612eb982612e84565b8060005b83811015612eea578151612ed1878261208d565b9650612edc83612e8e565b925050600181019050612ebd565b505050505050565b6000604082019050612f076000830184612e9b565b9291505056fea26469706673582212205abbe031e31994d755b34f8c95303d957ba6b4e7ac64a9fa5d1846ab9c21a73b64736f6c634300081b00330000000000000000000000","id":1,"to":"0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed","type":"ONCHAIN_INTERACTION","value":{"_kind":"bigint","value":"0"}},"type":"NETWORK_INTERACTION_REQUEST"} +{"futureId":"SmtLibModule#SmtLib","networkInteractionId":1,"nonce":9,"type":"TRANSACTION_PREPARE_SEND"} +{"futureId":"SmtLibModule#SmtLib","networkInteractionId":1,"nonce":9,"transaction":{"fees":{"gasPrice":{"_kind":"bigint","value":"1000000000"}},"hash":"0xeca09dfb3ab842c50322cd146deca688c97e91a924777abdea48a19e44656f75"},"type":"TRANSACTION_SEND"} +{"futureId":"SmtLibModule#SmtLib","hash":"0xeca09dfb3ab842c50322cd146deca688c97e91a924777abdea48a19e44656f75","networkInteractionId":1,"receipt":{"blockHash":"0xf636fa50893fd035b03df9d3c95e058a8641c14ef4e2f8600683b8d733e97b8a","blockNumber":100813,"logs":[{"address":"0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed","data":"0x","logIndex":0,"topics":["0xb8fda7e00c6b06a2b54e58521bc5894fee35f1090e5a3bb6390bfe2b98b497f7","0x000000000000000000000000682364078e26c1626abd2b95109d2019e241f0f6","0x1fb806fe12ba202b72799840b31b8b2ba7246fc0a96873ac3602d29c91d8c2d0"]}],"status":"SUCCESS"},"type":"TRANSACTION_CONFIRM"} +{"futureId":"SmtLibModule#SmtLib","result":{"address":"0x682364078e26C1626abD2B95109D2019E241F0F6","type":"SUCCESS"},"type":"DEPLOYMENT_EXECUTION_STATE_COMPLETE"} +{"artifactId":"StateProxyModule#TransparentUpgradeableProxy","constructorArgs":["0x56fF81aBB5cdaC478bF236db717e4976b2ff841e","0xae15d2023a76174a940cbb2b7f44012c728b9d74","0x6964656e332e637265617465322e5374617465"],"contractName":"TransparentUpgradeableProxy","dependencies":[],"from":"0xae15d2023a76174a940cbb2b7f44012c728b9d74","futureId":"StateProxyModule#TransparentUpgradeableProxy","futureType":"CONTRACT_DEPLOYMENT","libraries":{},"strategy":"create2","strategyConfig":{"salt":"0x000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d1"},"type":"DEPLOYMENT_EXECUTION_STATE_INITIALIZE","value":{"_kind":"bigint","value":"0"}} +{"futureId":"StateProxyModule#TransparentUpgradeableProxy","networkInteraction":{"data":"0x26307668000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001b8560a0604052604051611ae5380380611ae58339818101604052810190610025919061074f565b828161003782826100c460201b60201c565b5050816040516100469061056f565b61005091906107cd565b604051809103906000f08015801561006c573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250506100bc6100b161014960201b60201c565b61015360201b60201c565b50505061086f565b6100d3826101ab60201b60201c565b8173ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a260008151111561013657610130828261027e60201b60201c565b50610145565b61014461030860201b60201c565b5b5050565b6000608051905090565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f61018261034560201b60201c565b826040516101919291906107e8565b60405180910390a16101a8816103a260201b60201c565b50565b60008173ffffffffffffffffffffffffffffffffffffffff163b0361020757806040517f4c9c8ce30000000000000000000000000000000000000000000000000000000081526004016101fe91906107cd565b60405180910390fd5b8061023a7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b61048b60201b60201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60606000808473ffffffffffffffffffffffffffffffffffffffff16846040516102a89190610858565b600060405180830381855af49150503d80600081146102e3576040519150601f19603f3d011682016040523d82523d6000602084013e6102e8565b606091505b50915091506102fe85838361049560201b60201c565b9250505092915050565b6000341115610343576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60006103797fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360001b61048b60201b60201c565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036104145760006040517f62e77ba200000000000000000000000000000000000000000000000000000000815260040161040b91906107cd565b60405180910390fd5b806104477fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360001b61048b60201b60201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000819050919050565b6060826104b0576104ab8261052a60201b60201c565b610522565b600082511480156104d8575060008473ffffffffffffffffffffffffffffffffffffffff163b145b1561051a57836040517f9996b31500000000000000000000000000000000000000000000000000000000815260040161051191906107cd565b60405180910390fd5b819050610523565b5b9392505050565b60008151111561053d5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a2b806110ba83390190565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006105bb82610590565b9050919050565b6105cb816105b0565b81146105d657600080fd5b50565b6000815190506105e8816105c2565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610641826105f8565b810181811067ffffffffffffffff821117156106605761065f610609565b5b80604052505050565b600061067361057c565b905061067f8282610638565b919050565b600067ffffffffffffffff82111561069f5761069e610609565b5b6106a8826105f8565b9050602081019050919050565b60005b838110156106d35780820151818401526020810190506106b8565b60008484015250505050565b60006106f26106ed84610684565b610669565b90508281526020810184848401111561070e5761070d6105f3565b5b6107198482856106b5565b509392505050565b600082601f830112610736576107356105ee565b5b81516107468482602086016106df565b91505092915050565b60008060006060848603121561076857610767610586565b5b6000610776868287016105d9565b9350506020610787868287016105d9565b925050604084015167ffffffffffffffff8111156107a8576107a761058b565b5b6107b486828701610721565b9150509250925092565b6107c7816105b0565b82525050565b60006020820190506107e260008301846107be565b92915050565b60006040820190506107fd60008301856107be565b61080a60208301846107be565b9392505050565b600081519050919050565b600081905092915050565b600061083282610811565b61083c818561081c565b935061084c8185602086016106b5565b80840191505092915050565b60006108648284610827565b915081905092915050565b60805161083061088a600039600061010601526108306000f3fe608060405261000c61000e565b005b610016610102565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16036100f757634f1ef28660e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166000357fffffffff00000000000000000000000000000000000000000000000000000000167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146100ea576040517fd2b576ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6100f261012a565b610100565b6100ff610160565b5b565b60007f0000000000000000000000000000000000000000000000000000000000000000905090565b6000806000366004908092610141939291906104f1565b81019061014e91906106da565b9150915061015c8282610172565b5050565b61017061016b6101e5565b6101f4565b565b61017b8261021a565b8173ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a26000815111156101d8576101d282826102e7565b506101e1565b6101e061036b565b5b5050565b60006101ef6103a8565b905090565b3660008037600080366000845af43d6000803e8060008114610215573d6000f35b3d6000fd5b60008173ffffffffffffffffffffffffffffffffffffffff163b0361027657806040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815260040161026d9190610757565b60405180910390fd5b806102a37f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b6103ff565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60606000808473ffffffffffffffffffffffffffffffffffffffff168460405161031191906107e3565b600060405180830381855af49150503d806000811461034c576040519150601f19603f3d011682016040523d82523d6000602084013e610351565b606091505b5091509150610361858383610409565b9250505092915050565b60003411156103a6576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60006103d67f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b6103ff565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000819050919050565b60608261041e5761041982610498565b610490565b60008251148015610446575060008473ffffffffffffffffffffffffffffffffffffffff163b145b1561048857836040517f9996b31500000000000000000000000000000000000000000000000000000000815260040161047f9190610757565b60405180910390fd5b819050610491565b5b9392505050565b6000815111156104ab5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000604051905090565b600080fd5b600080fd5b60008085851115610505576105046104e7565b5b83861115610516576105156104ec565b5b6001850283019150848603905094509492505050565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061056182610536565b9050919050565b61057181610556565b811461057c57600080fd5b50565b60008135905061058e81610568565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6105e78261059e565b810181811067ffffffffffffffff82111715610606576106056105af565b5b80604052505050565b60006106196104dd565b905061062582826105de565b919050565b600067ffffffffffffffff821115610645576106446105af565b5b61064e8261059e565b9050602081019050919050565b82818337600083830152505050565b600061067d6106788461062a565b61060f565b90508281526020810184848401111561069957610698610599565b5b6106a484828561065b565b509392505050565b600082601f8301126106c1576106c0610594565b5b81356106d184826020860161066a565b91505092915050565b600080604083850312156106f1576106f061052c565b5b60006106ff8582860161057f565b925050602083013567ffffffffffffffff8111156107205761071f610531565b5b61072c858286016106ac565b9150509250929050565b600061074182610536565b9050919050565b61075181610736565b82525050565b600060208201905061076c6000830184610748565b92915050565b600081519050919050565b600081905092915050565b60005b838110156107a657808201518184015260208101905061078b565b60008484015250505050565b60006107bd82610772565b6107c7818561077d565b93506107d7818560208601610788565b80840191505092915050565b60006107ef82846107b2565b91508190509291505056fea264697066735822122084eee66f637082aaeba4fe604bf5d46830c8fb5c3a38d6b59fb60a44b2f3960f64736f6c634300081b0033608060405234801561001057600080fd5b50604051610a2b380380610a2b833981810160405281019061003291906101e2565b80600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036100a55760006040517f1e4fbdf700000000000000000000000000000000000000000000000000000000815260040161009c919061021e565b60405180910390fd5b6100b4816100bb60201b60201c565b5050610239565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101af82610184565b9050919050565b6101bf816101a4565b81146101ca57600080fd5b50565b6000815190506101dc816101b6565b92915050565b6000602082840312156101f8576101f761017f565b5b6000610206848285016101cd565b91505092915050565b610218816101a4565b82525050565b6000602082019050610233600083018461020f565b92915050565b6107e3806102486000396000f3fe60806040526004361061004a5760003560e01c8063715018a61461004f5780638da5cb5b146100665780639623609d14610091578063ad3cb1cc146100ad578063f2fde38b146100d8575b600080fd5b34801561005b57600080fd5b50610064610101565b005b34801561007257600080fd5b5061007b610115565b604051610088919061040c565b60405180910390f35b6100ab60048036038101906100a691906105eb565b61013e565b005b3480156100b957600080fd5b506100c26101b9565b6040516100cf91906106d9565b60405180910390f35b3480156100e457600080fd5b506100ff60048036038101906100fa91906106fb565b6101f2565b005b610109610278565b61011360006102ff565b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b610146610278565b8273ffffffffffffffffffffffffffffffffffffffff16634f1ef2863484846040518463ffffffff1660e01b815260040161018292919061077d565b6000604051808303818588803b15801561019b57600080fd5b505af11580156101af573d6000803e3d6000fd5b5050505050505050565b6040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b6101fa610278565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361026c5760006040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401610263919061040c565b60405180910390fd5b610275816102ff565b50565b6102806103c3565b73ffffffffffffffffffffffffffffffffffffffff1661029e610115565b73ffffffffffffffffffffffffffffffffffffffff16146102fd576102c16103c3565b6040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016102f4919061040c565b60405180910390fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006103f6826103cb565b9050919050565b610406816103eb565b82525050565b600060208201905061042160008301846103fd565b92915050565b6000604051905090565b600080fd5b600080fd5b6000610446826103eb565b9050919050565b6104568161043b565b811461046157600080fd5b50565b6000813590506104738161044d565b92915050565b610482816103eb565b811461048d57600080fd5b50565b60008135905061049f81610479565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6104f8826104af565b810181811067ffffffffffffffff82111715610517576105166104c0565b5b80604052505050565b600061052a610427565b905061053682826104ef565b919050565b600067ffffffffffffffff821115610556576105556104c0565b5b61055f826104af565b9050602081019050919050565b82818337600083830152505050565b600061058e6105898461053b565b610520565b9050828152602081018484840111156105aa576105a96104aa565b5b6105b584828561056c565b509392505050565b600082601f8301126105d2576105d16104a5565b5b81356105e284826020860161057b565b91505092915050565b60008060006060848603121561060457610603610431565b5b600061061286828701610464565b935050602061062386828701610490565b925050604084013567ffffffffffffffff81111561064457610643610436565b5b610650868287016105bd565b9150509250925092565b600081519050919050565b600082825260208201905092915050565b60005b83811015610694578082015181840152602081019050610679565b60008484015250505050565b60006106ab8261065a565b6106b58185610665565b93506106c5818560208601610676565b6106ce816104af565b840191505092915050565b600060208201905081810360008301526106f381846106a0565b905092915050565b60006020828403121561071157610710610431565b5b600061071f84828501610490565b91505092915050565b600081519050919050565b600082825260208201905092915050565b600061074f82610728565b6107598185610733565b9350610769818560208601610676565b610772816104af565b840191505092915050565b600060408201905061079260008301856103fd565b81810360208301526107a48184610744565b9050939250505056fea26469706673582212207baa771409eae5083c71e95f60df546b11a1b6cd507fd487b5af0bc72db119c664736f6c634300081b003300000000000000000000000056ff81abb5cdac478bf236db717e4976b2ff841e000000000000000000000000ae15d2023a76174a940cbb2b7f44012c728b9d74000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000136964656e332e637265617465322e537461746500000000000000000000000000000000000000000000000000000000000000000000000000000000","id":1,"to":"0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed","type":"ONCHAIN_INTERACTION","value":{"_kind":"bigint","value":"0"}},"type":"NETWORK_INTERACTION_REQUEST"} +{"artifactId":"Create2AddressAnchorModule#Create2AddressAnchor","constructorArgs":[],"contractName":"Create2AddressAnchor","dependencies":[],"from":"0xAe15d2023A76174a940cbb2b7F44012C728B9d74","futureId":"Create2AddressAnchorModule#Create2AddressAnchor","futureType":"CONTRACT_DEPLOYMENT","libraries":{},"strategy":"create2","strategyConfig":{"salt":"0x000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d1"},"type":"DEPLOYMENT_EXECUTION_STATE_INITIALIZE","value":{"_kind":"bigint","value":"0"}} +{"futureId":"Create2AddressAnchorModule#Create2AddressAnchor","networkInteraction":{"data":"0x26307668000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d1000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000116005600c60003960056000f360006000f3000000000000000000000000000000","id":1,"to":"0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed","type":"ONCHAIN_INTERACTION","value":{"_kind":"bigint","value":"0"}},"type":"NETWORK_INTERACTION_REQUEST"} +{"futureId":"Create2AddressAnchorModule#Create2AddressAnchor","networkInteractionId":1,"nonce":3,"type":"TRANSACTION_PREPARE_SEND"} +{"futureId":"Create2AddressAnchorModule#Create2AddressAnchor","networkInteractionId":1,"nonce":3,"transaction":{"fees":{"gasPrice":{"_kind":"bigint","value":"1000000000"}},"hash":"0x4434c7e6d718acd7f4e7cb4a56d65ac610b2a2aaabec647d59606639a4170b8a"},"type":"TRANSACTION_SEND"} +{"futureId":"Create2AddressAnchorModule#Create2AddressAnchor","hash":"0x4434c7e6d718acd7f4e7cb4a56d65ac610b2a2aaabec647d59606639a4170b8a","networkInteractionId":1,"receipt":{"blockHash":"0x13cd885375bd12f870bc9a513543230e453940b2463763db38571eb49d52cff4","blockNumber":125513,"logs":[{"address":"0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed","data":"0x","logIndex":0,"topics":["0xb8fda7e00c6b06a2b54e58521bc5894fee35f1090e5a3bb6390bfe2b98b497f7","0x00000000000000000000000056ff81abb5cdac478bf236db717e4976b2ff841e","0x1fb806fe12ba202b72799840b31b8b2ba7246fc0a96873ac3602d29c91d8c2d0"]}],"status":"SUCCESS"},"type":"TRANSACTION_CONFIRM"} +{"futureId":"Create2AddressAnchorModule#Create2AddressAnchor","result":{"address":"0x56fF81aBB5cdaC478bF236db717e4976b2ff841e","type":"SUCCESS"},"type":"DEPLOYMENT_EXECUTION_STATE_COMPLETE"} +{"futureId":"StateProxyModule#TransparentUpgradeableProxy","networkInteractionId":1,"nonce":5,"type":"TRANSACTION_PREPARE_SEND"} +{"futureId":"StateProxyModule#TransparentUpgradeableProxy","networkInteractionId":1,"nonce":5,"transaction":{"fees":{"gasPrice":{"_kind":"bigint","value":"1000000000"}},"hash":"0xf6451cf8e5b5e3be691df4936eab95b6e4e1dfbb5deee43b9672175ea726b71e"},"type":"TRANSACTION_SEND"} +{"futureId":"StateProxyModule#TransparentUpgradeableProxy","hash":"0xf6451cf8e5b5e3be691df4936eab95b6e4e1dfbb5deee43b9672175ea726b71e","networkInteractionId":1,"receipt":{"blockHash":"0x40c513ada3586baf6c25b81c6dd5f4244a62059449f4582eed6446d27f75ff9c","blockNumber":125559,"logs":[{"address":"0x3C9acB2205Aa72A05F6D77d708b5Cf85FCa3a896","data":"0x","logIndex":0,"topics":["0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b","0x00000000000000000000000056ff81abb5cdac478bf236db717e4976b2ff841e"]},{"address":"0x3F570C4fE07c532cd274dF2d1dB26D74cc5F8F9A","data":"0x","logIndex":1,"topics":["0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0","0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000ae15d2023a76174a940cbb2b7f44012c728b9d74"]},{"address":"0x3C9acB2205Aa72A05F6D77d708b5Cf85FCa3a896","data":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003f570c4fe07c532cd274df2d1db26d74cc5f8f9a","logIndex":2,"topics":["0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f"]},{"address":"0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed","data":"0x","logIndex":3,"topics":["0xb8fda7e00c6b06a2b54e58521bc5894fee35f1090e5a3bb6390bfe2b98b497f7","0x0000000000000000000000003c9acb2205aa72a05f6d77d708b5cf85fca3a896","0x1fb806fe12ba202b72799840b31b8b2ba7246fc0a96873ac3602d29c91d8c2d0"]}],"status":"SUCCESS"},"type":"TRANSACTION_CONFIRM"} +{"futureId":"StateProxyModule#TransparentUpgradeableProxy","result":{"address":"0x3C9acB2205Aa72A05F6D77d708b5Cf85FCa3a896","type":"SUCCESS"},"type":"DEPLOYMENT_EXECUTION_STATE_COMPLETE"} +{"artifactId":"StateProxyModule#TransparentUpgradeableProxy","dependencies":["StateProxyModule#TransparentUpgradeableProxy"],"emitterAddress":"0x3C9acB2205Aa72A05F6D77d708b5Cf85FCa3a896","eventIndex":0,"eventName":"AdminChanged","futureId":"StateProxyModule#TransparentUpgradeableProxy.AdminChanged.newAdmin.0","nameOrIndex":"newAdmin","result":"0x3F570C4fE07c532cd274dF2d1dB26D74cc5F8F9A","strategy":"create2","strategyConfig":{"salt":"0x000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d1"},"txToReadFrom":"0xf6451cf8e5b5e3be691df4936eab95b6e4e1dfbb5deee43b9672175ea726b71e","type":"READ_EVENT_ARGUMENT_EXECUTION_STATE_INITIALIZE"} +{"artifactId":"StateProxyModule#ProxyAdmin","contractAddress":"0x3F570C4fE07c532cd274dF2d1dB26D74cc5F8F9A","contractName":"ProxyAdmin","dependencies":["StateProxyModule#TransparentUpgradeableProxy.AdminChanged.newAdmin.0"],"futureId":"StateProxyModule#ProxyAdmin","futureType":"NAMED_ARTIFACT_CONTRACT_AT","strategy":"create2","strategyConfig":{"salt":"0x000000000000000000000000000000000000000000f4179bc3e4988a1a06f8d1"},"type":"CONTRACT_AT_EXECUTION_STATE_INITIALIZE"} \ No newline at end of file diff --git a/ignition/index.ts b/ignition/index.ts index dd87e66b3..115310b9d 100644 --- a/ignition/index.ts +++ b/ignition/index.ts @@ -1,9 +1,13 @@ -export * from "./modules/credentialAtomicQuerySigV2Validator"; +export * from "./modules/create2AddressAnchor"; export * from "./modules/credentialAtomicQueryMTPV2Validator"; +export * from "./modules/credentialAtomicQuerySigV2Validator"; export * from "./modules/credentialAtomicQueryV3Validator"; export * from "./modules/authV2Validator"; -export * from "./modules/state"; +export * from "./modules/ethIdentityValidator"; export * from "./modules/identityTreeStore"; export * from "./modules/libraries"; +export * from "./modules/linkedMultiQuery"; +export * from "./modules/mcPayment"; +export * from "./modules/state"; export * from "./modules/universalVerifier"; export * from "./modules/vcPayment"; diff --git a/ignition/modules/crate2AddressAnchor.ts b/ignition/modules/create2AddressAnchor.ts similarity index 100% rename from ignition/modules/crate2AddressAnchor.ts rename to ignition/modules/create2AddressAnchor.ts diff --git a/ignition/modules/ethIdentityValidator.ts b/ignition/modules/ethIdentityValidator.ts new file mode 100644 index 000000000..bb3166991 --- /dev/null +++ b/ignition/modules/ethIdentityValidator.ts @@ -0,0 +1,36 @@ +import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; +import { + contractsInfo, + TRANSPARENT_UPGRADEABLE_PROXY_ABI, + TRANSPARENT_UPGRADEABLE_PROXY_BYTECODE, +} from "../../helpers/constants"; + +export const EthIdentityValidatorModule = buildModule("EthIdentityValidatorModule", (m) => { + const proxyAdminOwner = m.getAccount(0); + + // This contract is supposed to be deployed to the same address across many networks, + // so the first implementation address is a dummy contract that does nothing but accepts any calldata. + // Therefore, it is a mechanism to deploy TransparentUpgradeableProxy contract + // with constant constructor arguments, so predictable init bytecode and predictable CREATE2 address. + // Subsequent upgrades are supposed to switch this proxy to the real implementation. + + const proxy = m.contract( + "TransparentUpgradeableProxy", + { + abi: TRANSPARENT_UPGRADEABLE_PROXY_ABI, + contractName: "TransparentUpgradeableProxy", + bytecode: TRANSPARENT_UPGRADEABLE_PROXY_BYTECODE, + sourceName: "", + linkReferences: {}, + }, + [ + contractsInfo.CREATE2_ADDRESS_ANCHOR.unifiedAddress, + proxyAdminOwner, + contractsInfo.VALIDATOR_ETH_IDENTITY.create2Calldata, + ], + ); + + const proxyAdminAddress = m.readEventArgument(proxy, "AdminChanged", "newAdmin"); + const proxyAdmin = m.contractAt("ProxyAdmin", proxyAdminAddress); + return { proxyAdmin, proxy }; +}); diff --git a/ignition/modules/libraries.ts b/ignition/modules/libraries.ts index e6225aacc..ddb26aab2 100644 --- a/ignition/modules/libraries.ts +++ b/ignition/modules/libraries.ts @@ -125,8 +125,3 @@ export const SpongePoseidonModule = buildModule("SpongePoseidonModule", (m) => { }); return { spongePoseidon }; }); - -export const VerifierLibModule = buildModule("VerifierLibModule", (m) => { - const verifierLib = m.contract("VerifierLib"); - return { verifierLib }; -}); diff --git a/ignition/modules/linkedMultiQuery.ts b/ignition/modules/linkedMultiQuery.ts new file mode 100644 index 000000000..c0ab174b4 --- /dev/null +++ b/ignition/modules/linkedMultiQuery.ts @@ -0,0 +1,36 @@ +import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; +import { + contractsInfo, + TRANSPARENT_UPGRADEABLE_PROXY_ABI, + TRANSPARENT_UPGRADEABLE_PROXY_BYTECODE, +} from "../../helpers/constants"; + +export const LinkedMultiQueryProxyModule = buildModule("LinkedMultiQueryModule", (m) => { + const proxyAdminOwner = m.getAccount(0); + + // This contract is supposed to be deployed to the same address across many networks, + // so the first implementation address is a dummy contract that does nothing but accepts any calldata. + // Therefore, it is a mechanism to deploy TransparentUpgradeableProxy contract + // with constant constructor arguments, so predictable init bytecode and predictable CREATE2 address. + // Subsequent upgrades are supposed to switch this proxy to the real implementation. + + const proxy = m.contract( + "TransparentUpgradeableProxy", + { + abi: TRANSPARENT_UPGRADEABLE_PROXY_ABI, + contractName: "TransparentUpgradeableProxy", + bytecode: TRANSPARENT_UPGRADEABLE_PROXY_BYTECODE, + sourceName: "", + linkReferences: {}, + }, + [ + contractsInfo.CREATE2_ADDRESS_ANCHOR.unifiedAddress, + proxyAdminOwner, + contractsInfo.VALIDATOR_LINKED_MULTI_QUERY.create2Calldata, + ], + ); + + const proxyAdminAddress = m.readEventArgument(proxy, "AdminChanged", "newAdmin"); + const proxyAdmin = m.contractAt("ProxyAdmin", proxyAdminAddress); + return { proxyAdmin, proxy }; +}); diff --git a/package-lock.json b/package-lock.json index 3588ecdf8..89ff07519 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,6 +50,7 @@ "resolved": "https://registry.npmjs.org/@0xpolygonid/js-sdk/-/js-sdk-1.20.0.tgz", "integrity": "sha512-qLvUMTw9iHRDo7pPe9mgaScr5H16HC3RSoUz06OrKNzoIkYkm59Qq7LgmCh3fCXbqs9iFqPKMOn4KdjU2HIhTQ==", "dev": true, + "license": "MIT or Apache-2.0", "dependencies": { "@noble/curves": "^1.4.0", "ajv": "8.12.0", diff --git a/package.json b/package.json index ed0b9d1b4..b1088ec02 100644 --- a/package.json +++ b/package.json @@ -127,11 +127,6 @@ "deploy:universalverifier:linea-mainnet": "npx hardhat run scripts/deploy/deployUniversalVerifier.ts --network linea-mainnet", "deploy:universalverifier:ethereum-mainnet": "npx hardhat run scripts/deploy/deployUniversalVerifier.ts --network ethereum-mainnet", "deploy:universalverifier:privado-main": "npx hardhat run scripts/deploy/deployUniversalVerifier.ts --network privado-main", - "deploy:stateCrossChainFullSet:localhost": "npx hardhat run scripts/deploy/deployCrossChainVerifierWithRequests.ts --network localhost", - "deploy:stateCrossChainFullSet:polygon-amoy": "npx hardhat run scripts/deploy/deployCrossChainVerifierWithRequests.ts --network polygon-amoy", - "deploy:stateCrossChainFullSet:zkevm-cardona": "npx hardhat run scripts/deploy/deployCrossChainVerifierWithRequests.ts --network zkevm-cardona", - "deploy:stateCrossChainFullSet:zkevm-mainnet": "npx hardhat run scripts/deploy/deployCrossChainVerifierWithRequests.ts --network zkevm-mainnet", - "deploy:stateCrossChainFullSet:linea-sepolia": "npx hardhat run scripts/deploy/deployCrossChainVerifierWithRequests.ts --network linea-sepolia", "deploy:set:request:polygon-amoy": "npx hardhat run scripts/maintenance/setProofRequest.ts --network polygon-amoy", "deploy:set:request:linea-sepolia": "npx hardhat run scripts/maintenance/setProofRequest.ts --network linea-sepolia", "deploy:vc-payment:polygon-amoy": "npx hardhat run scripts/deploy/deployVCPayment.ts --network polygon-amoy", diff --git a/patches/@nomicfoundation+hardhat-ledger+1.0.3.patch b/patches/@nomicfoundation+hardhat-ledger+1.0.3.patch index 195fcb0e8..ada307fcd 100644 --- a/patches/@nomicfoundation+hardhat-ledger+1.0.3.patch +++ b/patches/@nomicfoundation+hardhat-ledger+1.0.3.patch @@ -12,7 +12,7 @@ index caf192d..6e992c0 100644 + try { + accounts = (await this._wrappedProvider.request(args)); + } catch (error) { -+ if (error.message.includes("the method has been deprecated: eth_accounts")) { ++ if (error.message.includes("eth_accounts")) { + accounts = []; + } else { + throw error; diff --git a/scripts/deploy/deployCreate2AddressAnchor.ts b/scripts/deploy/deployCreate2AddressAnchor.ts index 782d99206..7e08c0971 100644 --- a/scripts/deploy/deployCreate2AddressAnchor.ts +++ b/scripts/deploy/deployCreate2AddressAnchor.ts @@ -1,5 +1,5 @@ import { ethers, ignition } from "hardhat"; -import { Create2AddressAnchorModule } from "../../ignition/modules/crate2AddressAnchor"; +import { Create2AddressAnchorModule } from "../../ignition/modules/create2AddressAnchor"; import { contractsInfo } from "../../helpers/constants"; async function main() { diff --git a/scripts/deploy/deployCrossChainVerifierWithRequests.ts b/scripts/deploy/deployCrossChainVerifierWithRequests.ts deleted file mode 100644 index 834a0030c..000000000 --- a/scripts/deploy/deployCrossChainVerifierWithRequests.ts +++ /dev/null @@ -1,533 +0,0 @@ -import hre, { ethers, network } from "hardhat"; -import { packV3ValidatorParams, packValidatorParams } from "../../test/utils/validator-pack-utils"; -import { DeployHelper } from "../../helpers/DeployHelper"; -import { calculateQueryHashV2, calculateQueryHashV3 } from "../../test/utils/query-hash-utils"; -import { - buildDIDType, - genesisFromEthAddress, - Id, - Blockchain, - DidMethod, - NetworkId, - SchemaHash, - DID, -} from "@iden3/js-iden3-core"; -import { Hex } from "@iden3/js-crypto"; -import { Merklizer } from "@iden3/js-jsonld-merklization"; -import path from "path"; -import fs from "fs"; -import { CircuitId, Operators } from "@0xpolygonid/js-sdk"; -import { getChainId } from "../../helpers/helperUtils"; - -const removePreviousIgnitionFiles = true; - -async function main() { - const deployHelper = await DeployHelper.initialize(null, true); - - const [signer] = await ethers.getSigners(); - - // const signerAddr = await signer.getAddress(); - // console.log(signerAddr); - // const provider = ethers.provider; - // console.log(ethers.formatEther(await provider.getBalance(signerAddr))); - // return; - - const chainId = await getChainId(); - const networkName = hre.network.name; - - if (removePreviousIgnitionFiles && (networkName === "localhost" || networkName === "hardhat")) { - console.log("Removing previous ignition files for chain: ", chainId); - fs.rmSync(`./ignition/deployments/chain-${chainId}`, { recursive: true, force: true }); - } - // ##################### State with StateCrossChainLib deploy ##################### - - const { state, crossChainProofValidator } = await deployHelper.deployStateWithLibraries(); - - // ##################### Validator deploy ##################### - - const { validator: validatorMTP } = await deployHelper.deployValidatorContractsWithVerifiers( - "mtpV2", - await state.getAddress(), - ); - - const { validator: validatorSig } = await deployHelper.deployValidatorContractsWithVerifiers( - "sigV2", - await state.getAddress(), - ); - - const { validator: validatorV3 } = await deployHelper.deployValidatorContractsWithVerifiers( - "v3", - await state.getAddress(), - ); - - // ##################### VerifierLib deploy ##################### - const verifierLib = await deployHelper.deployVerifierLib(); - - // ##################### Universal Verifier deploy ##################### - const verifier = await deployHelper.deployUniversalVerifier( - undefined, - await state.getAddress(), - await verifierLib.getAddress(), - ); - - const addToWhiteList1 = await verifier.addValidatorToWhitelist(await validatorSig.getAddress()); - await addToWhiteList1.wait(); - const addToWhiteList2 = await verifier.addValidatorToWhitelist(await validatorMTP.getAddress()); - await addToWhiteList2.wait(); - const addToWhiteList3 = await verifier.addValidatorToWhitelist(await validatorV3.getAddress()); - await addToWhiteList3.wait(); - - // ##################### SetZKPRequest ##################### - - const methodId = "ade09fcd"; - - console.log( - "================= setZKPRequest V3 SIG Transak `email-verified` $eq true ===================", - ); - - const schemaHashIndividualKYC = "83588135147751541079133521251473709708"; - const coreSchemaIndividualKYC = coreSchemaFromStr(schemaHashIndividualKYC); - - const verifierId = buildVerifierId(await verifier.getAddress(), { - blockchain: Blockchain.Polygon, - networkId: NetworkId.Amoy, - method: DidMethod.Iden3, - }); - - console.log(DID.parseFromId(verifierId).string()); - - // merklized path to field in the W3C credential according to JSONLD schema e.g. birthday in the KYCAgeCredential under the url "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld" - const schemaClaimPathKeyEmailVerified = - "6690925644799482311359070256240649323225600882434741819138192893258972267385"; - - const requestIdEmailVerified = 1; - - const queryV3EmailVerified = { - requestId: requestIdEmailVerified, - schema: schemaHashIndividualKYC, - claimPathKey: schemaClaimPathKeyEmailVerified, - operator: Operators.EQ, - value: [await Merklizer.hashValue("http://www.w3.org/2001/XMLSchema#boolean", true)], - slotIndex: 0, - queryHash: "", - circuitIds: [CircuitId.AtomicQueryV3OnChain], - allowedIssuers: [], - skipClaimRevocationCheck: false, - verifierID: verifierId.bigInt(), - nullifierSessionID: 8372131, - groupID: 0, - proofType: 0, - }; - - queryV3EmailVerified.queryHash = calculateQueryHashV3( - queryV3EmailVerified.value.map((i) => BigInt(i)), - coreSchemaIndividualKYC.bigInt().toString(), - queryV3EmailVerified.slotIndex, - queryV3EmailVerified.operator, - queryV3EmailVerified.claimPathKey, - queryV3EmailVerified.value.length, - 1, // merklized - queryV3EmailVerified.skipClaimRevocationCheck ? 0 : 1, - queryV3EmailVerified.verifierID.toString(), - queryV3EmailVerified.nullifierSessionID, - ).toString(); - - const dataV3EmailVerified = packV3ValidatorParams(queryV3EmailVerified); - - const invokeRequestMetadataEmailVerified = { - id: "7f38a193-0918-4a48-9fac-36adfdb8b542", - typ: "application/iden3comm-plain-json", - type: "https://iden3-communication.io/proofs/1.0/contract-invoke-request", - thid: "7f38a193-0918-4a48-9fac-36adfdb8b542", - from: DID.parseFromId(verifierId).string(), - body: { - reason: "for testing submitZKPResponseV2", - transaction_data: { - contract_address: await verifier.getAddress(), - method_id: methodId, - chain_id: chainId, - network: networkName, - }, - scope: [ - { - id: queryV3EmailVerified.requestId, - circuitId: queryV3EmailVerified.circuitIds[0], - query: { - allowedIssuers: !queryV3EmailVerified.allowedIssuers.length - ? ["*"] - : queryV3EmailVerified.allowedIssuers, - context: "ipfs://Qmdhuf9fhqzweDa1TgoajDEj7Te7p28eeeZVfiioAjUC15", - credentialSubject: { - "email-verified": { - $eq: true, - }, - }, - type: "IndividualKYC", - }, - }, - ], - }, - }; - - await verifier.setZKPRequest(requestIdEmailVerified, { - metadata: JSON.stringify(invokeRequestMetadataEmailVerified), - validator: validatorV3, - data: dataV3EmailVerified, - }); - - console.log(JSON.stringify(invokeRequestMetadataEmailVerified, null, "\t")); - - console.log(`Request ID: ${requestIdEmailVerified} is set`); - - console.log("================= setZKPRequest V3 SIG Transak `email` SD ==================="); - - // merklized path to field in the W3C credential according to JSONLD schema e.g. birthday in the KYCAgeCredential under the url "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld" - const schemaClaimPathKeyEmail = - "45494603366705166835171894278075990839428579528180465081820758291950364182"; - - const requestIdEmail = 11; - - const queryV3EmailSD = { - requestId: requestIdEmail, - schema: schemaHashIndividualKYC, - claimPathKey: schemaClaimPathKeyEmail, - operator: Operators.SD, - value: [], - slotIndex: 0, - queryHash: "", - circuitIds: [CircuitId.AtomicQueryV3OnChain], - allowedIssuers: [], - skipClaimRevocationCheck: false, - verifierID: verifierId.bigInt(), - nullifierSessionID: 11837213, - groupID: 0, - proofType: 0, - }; - - queryV3EmailSD.queryHash = calculateQueryHashV3( - queryV3EmailSD.value.map((i) => BigInt(i)), - coreSchemaIndividualKYC.bigInt().toString(), - queryV3EmailSD.slotIndex, - queryV3EmailSD.operator, - queryV3EmailSD.claimPathKey, - queryV3EmailSD.value.length, - 1, // merklized - queryV3EmailSD.skipClaimRevocationCheck ? 0 : 1, - queryV3EmailSD.verifierID.toString(), - queryV3EmailSD.nullifierSessionID, - ).toString(); - - const dataV3EmailSD = packV3ValidatorParams(queryV3EmailSD); - - const invokeRequestMetadataEmailSd = { - id: "7f38a193-0918-4a48-9fac-36adfdb8b543", - typ: "application/iden3comm-plain-json", - type: "https://iden3-communication.io/proofs/1.0/contract-invoke-request", - thid: "7f38a193-0918-4a48-9fac-36adfdb8b543", - from: DID.parseFromId(verifierId).string(), - body: { - reason: "for testing submitZKPResponseV2", - transaction_data: { - contract_address: await verifier.getAddress(), - method_id: methodId, - chain_id: chainId, - network: networkName, - }, - scope: [ - { - id: queryV3EmailSD.requestId, - circuitId: queryV3EmailSD.circuitIds[0], - query: { - allowedIssuers: !queryV3EmailSD.allowedIssuers.length - ? ["*"] - : queryV3EmailSD.allowedIssuers, - context: "ipfs://Qmdhuf9fhqzweDa1TgoajDEj7Te7p28eeeZVfiioAjUC15", - credentialSubject: { - email: {}, - }, - type: "IndividualKYC", - }, - }, - ], - }, - }; - - await verifier.setZKPRequest(requestIdEmail, { - metadata: JSON.stringify(invokeRequestMetadataEmailSd), - validator: validatorV3, - data: dataV3EmailSD, - }); - - console.log(JSON.stringify(invokeRequestMetadataEmailSd, null, "\t")); - - console.log(`Request ID: ${requestIdEmail} is set`); - - console.log("================= setZKPRequest SIG V2 ==================="); - - // you can run https://go.dev/play/p/oB_oOW7kBEw to get schema hash and claimPathKey using YOUR schema - const schemaBigInt = "74977327600848231385663280181476307657"; - - // merklized path to field in the W3C credential according to JSONLD schema e.g. birthday in the KYCAgeCredential under the url "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld" - const schemaClaimPathKey = - "20376033832371109177683048456014525905119173674985843915445634726167450989630"; - - const requestId_Sig = 4; - - const query: any = { - requestId: requestId_Sig, - schema: schemaBigInt, - claimPathKey: schemaClaimPathKey, - operator: Operators.LT, - slotIndex: 0, - value: [20020101, ...new Array(63).fill(0)], // for operators 1-3 only first value matters - circuitIds: [CircuitId.AtomicQuerySigV2OnChain], - skipClaimRevocationCheck: false, - claimPathNotExists: 0, - }; - - query.queryHash = calculateQueryHashV2( - query.value, - query.schema, - query.slotIndex, - query.operator, - query.claimPathKey, - query.claimPathNotExists, - ).toString(); - - const invokeRequestMetadataKYCAgeCredential_SigV2 = { - id: "7f38a193-0918-4a48-9fac-36adfdb8b543", - typ: "application/iden3comm-plain-json", - type: "https://iden3-communication.io/proofs/1.0/contract-invoke-request", - thid: "7f38a193-0918-4a48-9fac-36adfdb8b543", - from: DID.parseFromId(verifierId).string(), - body: { - reason: "for testing submitZKPResponseV2", - transaction_data: { - contract_address: await verifier.getAddress(), - method_id: methodId, - chain_id: chainId, - network: networkName, - }, - scope: [ - { - circuitId: CircuitId.AtomicQuerySigV2OnChain, - id: requestId_Sig, - query: { - allowedIssuers: ["*"], - context: - "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld", - credentialSubject: { - birthday: { - $lt: 20020101, - }, - }, - type: "KYCAgeCredential", - }, - }, - ], - }, - }; - - let data = packValidatorParams(query); - await verifier.setZKPRequest( - requestId_Sig, - { - metadata: JSON.stringify(invokeRequestMetadataKYCAgeCredential_SigV2), - validator: validatorSig, - data: data, - }, - // { - // gasPrice: 50000000000, - // initialBaseFeePerGas: 25000000000, - // gasLimit: 10000000 - // } - ); - console.log(JSON.stringify(invokeRequestMetadataKYCAgeCredential_SigV2, null, "\t")); - - console.log(`Request ID: ${requestId_Sig} is set`); - - console.log("================= setZKPRequest MTP V2 ==================="); - - query.circuitIds = [CircuitId.AtomicQueryMTPV2OnChain]; - data = packValidatorParams(query); - const requestId_Mtp = 2; - - const invokeRequestMetadataKYCAgeCredential_MTPV2 = { - id: "7f38a193-0918-4a48-9fac-36adfdb8b543", - typ: "application/iden3comm-plain-json", - type: "https://iden3-communication.io/proofs/1.0/contract-invoke-request", - thid: "7f38a193-0918-4a48-9fac-36adfdb8b543", - from: DID.parseFromId(verifierId).string(), - body: { - reason: "for testing submitZKPResponseV2", - transaction_data: { - contract_address: await verifier.getAddress(), - method_id: methodId, - chain_id: chainId, - network: networkName, - }, - scope: [ - { - circuitId: CircuitId.AtomicQueryMTPV2OnChain, - id: requestId_Mtp, - query: { - allowedIssuers: ["*"], - context: - "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld", - credentialSubject: { - birthday: { - $lt: 20020101, - }, - }, - type: "KYCAgeCredential", - }, - }, - ], - }, - }; - - await verifier.setZKPRequest( - requestId_Mtp, - { - metadata: JSON.stringify(invokeRequestMetadataKYCAgeCredential_MTPV2), - validator: validatorMTP, - data: data, - }, - // { - // gasPrice: 50000000000, - // initialBaseFeePerGas: 25000000000, - // gasLimit: 10000000 - // } - ); - - console.log(JSON.stringify(invokeRequestMetadataKYCAgeCredential_MTPV2, null, "\t")); - - console.log(`Request ID: ${requestId_Mtp} is set`); - - console.log("================= setZKPRequest V3 SIG KYCAgeCredential ==================="); - - const requestId_V3_KYCAgeCredential = 5; - - const queryV3KYCAgeCredential = { - requestId: requestId_V3_KYCAgeCredential, - schema: schemaBigInt, - claimPathKey: schemaClaimPathKey, - operator: Operators.LT, - value: [20020101, ...new Array(63).fill(0)], // for operators 1-3 only first value matters - slotIndex: 0, - queryHash: "", - circuitIds: [CircuitId.AtomicQueryV3OnChain], - allowedIssuers: [], - skipClaimRevocationCheck: false, - verifierID: verifierId.bigInt(), - nullifierSessionID: 11837215, - groupID: 0, - proofType: 0, - }; - - queryV3KYCAgeCredential.queryHash = calculateQueryHashV3( - queryV3KYCAgeCredential.value.map((i) => BigInt(i)), - queryV3KYCAgeCredential.schema, - queryV3KYCAgeCredential.slotIndex, - queryV3KYCAgeCredential.operator, - queryV3KYCAgeCredential.claimPathKey, - 1, //queryV3KYCAgeCredential.value.length, // for operator LT it should be 1 for value - 1, // merklized - queryV3KYCAgeCredential.skipClaimRevocationCheck ? 0 : 1, - queryV3KYCAgeCredential.verifierID.toString(), - queryV3KYCAgeCredential.nullifierSessionID, - ).toString(); - - const dataV3KYCAgeCredential = packV3ValidatorParams(queryV3KYCAgeCredential); - - const invokeRequestMetadataKYCAgeCredential = { - id: "7f38a193-0918-4a48-9fac-36adfdb8b543", - typ: "application/iden3comm-plain-json", - type: "https://iden3-communication.io/proofs/1.0/contract-invoke-request", - thid: "7f38a193-0918-4a48-9fac-36adfdb8b543", - from: DID.parseFromId(verifierId).string(), - body: { - reason: "for testing submitZKPResponseV2", - transaction_data: { - contract_address: await verifier.getAddress(), - method_id: methodId, - chain_id: chainId, - network: networkName, - }, - scope: [ - { - id: queryV3KYCAgeCredential.requestId, - circuitId: queryV3KYCAgeCredential.circuitIds[0], - query: { - allowedIssuers: !queryV3KYCAgeCredential.allowedIssuers.length - ? ["*"] - : queryV3KYCAgeCredential.allowedIssuers, - context: - "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld", - credentialSubject: { - birthday: { - $lt: 20020101, - }, - }, - type: "KYCAgeCredential", - }, - }, - ], - }, - }; - - await verifier.setZKPRequest(requestId_V3_KYCAgeCredential, { - metadata: JSON.stringify(invokeRequestMetadataKYCAgeCredential), - validator: validatorV3, - data: dataV3KYCAgeCredential, - }); - - console.log(JSON.stringify(invokeRequestMetadataKYCAgeCredential, null, "\t")); - - console.log(`Request ID: ${requestId_V3_KYCAgeCredential} is set`); - - const outputJson = { - proxyAdminOwnerAddress: await signer.getAddress(), - universalVerifierOwnerAddress: await signer.getAddress(), - state: await state.getAddress(), - universalVerifier: await verifier.getAddress(), - crossChainProofValidator: await crossChainProofValidator.getAddress(), - validatorSig: await validatorSig.getAddress(), - validatorMTP: await validatorMTP.getAddress(), - validatorV3: await validatorV3.getAddress(), - network: networkName, - chainId, - }; - - const pathOutputJson = path.join( - __dirname, - `../deployments_output/deploy_cross_chain_verification_with_requests_output_${chainId}_${networkName}.json`, - ); - fs.writeFileSync(pathOutputJson, JSON.stringify(outputJson, null, 1)); -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error); - process.exit(1); - }); - -export function buildVerifierId( - address: string, - info: { method: string; blockchain: string; networkId: string }, -): Id { - address = address.replace("0x", ""); - const ethAddrBytes = Hex.decodeString(address); - const ethAddr = ethAddrBytes.slice(0, 20); - const genesis = genesisFromEthAddress(ethAddr); - - const tp = buildDIDType(info.method, info.blockchain, info.networkId); - - return new Id(tp, genesis); -} - -export const coreSchemaFromStr = (schemaIntString: string) => { - const schemaInt = BigInt(schemaIntString); - return SchemaHash.newSchemaHashFromInt(schemaInt); -}; diff --git a/scripts/deploy/deployState.ts b/scripts/deploy/deployState.ts index 7c71c34ca..d8ad13edd 100644 --- a/scripts/deploy/deployState.ts +++ b/scripts/deploy/deployState.ts @@ -40,22 +40,13 @@ async function main() { // if the state contract already exists we won't have new contracts deployed // to verify and to save the output - if ( - groth16VerifierStateTransition && - stateLib && - stateCrossChainLib && - crossChainProofValidator - ) { + if (groth16VerifierStateTransition && stateLib && crossChainProofValidator) { await verifyContract(await state.getAddress(), contractsInfo.STATE.verificationOpts); await verifyContract( await groth16VerifierStateTransition.getAddress(), contractsInfo.GROTH16_VERIFIER_STATE_TRANSITION.verificationOpts, ); await verifyContract(await stateLib.getAddress(), contractsInfo.STATE_LIB.verificationOpts); - await verifyContract( - await stateCrossChainLib.getAddress(), - contractsInfo.STATE_CROSS_CHAIN_LIB.verificationOpts, - ); await verifyContract( await crossChainProofValidator.getAddress(), contractsInfo.CROSS_CHAIN_PROOF_VALIDATOR.verificationOpts, @@ -69,7 +60,6 @@ async function main() { proxyAdminOwnerAddress: await signer.getAddress(), state: await state.getAddress(), stateLib: await stateLib?.getAddress(), - stateCrossChainLib: await stateCrossChainLib?.getAddress(), crossChainProofValidator: await crossChainProofValidator?.getAddress(), network: networkName, chainId, diff --git a/scripts/deploy/deployUniversalVerifier.ts b/scripts/deploy/deployUniversalVerifier.ts index 1e1188b8e..46ab57abe 100644 --- a/scripts/deploy/deployUniversalVerifier.ts +++ b/scripts/deploy/deployUniversalVerifier.ts @@ -6,10 +6,7 @@ import { getChainId, getConfig, getStateContractAddress, - Logger, - TempContractDeployments, verifyContract, - waitNotToInterfereWithHardhatIgnition, } from "../../helpers/helperUtils"; import { contractsInfo } from "../../helpers/constants"; @@ -24,36 +21,11 @@ async function main() { const deployHelper = await DeployHelper.initialize(null, true); - const tmpContractDeployments = new TempContractDeployments( - "./scripts/deployments_output/temp_deployments_output.json", - ); - - let verifierLib = await tmpContractDeployments.getContract(contractsInfo.VERIFIER_LIB.name); - if (verifierLib) { - Logger.warning( - `${contractsInfo.VERIFIER_LIB.name} found already deployed to: ${await verifierLib?.getAddress()}`, - ); - } else { - verifierLib = await deployHelper.deployVerifierLib(); - const tx = await verifierLib.deploymentTransaction(); - await waitNotToInterfereWithHardhatIgnition(tx); - tmpContractDeployments.addContract( - contractsInfo.VERIFIER_LIB.name, - await verifierLib.getAddress(), - ); - await verifyContract( - await verifierLib.getAddress(), - contractsInfo.VERIFIER_LIB.verificationOpts, - ); - } - const universalVerifier = await deployHelper.deployUniversalVerifier( undefined, stateContractAddress, - await verifierLib.getAddress(), deployStrategy, ); - tmpContractDeployments.remove(); await verifyContract( await universalVerifier.getAddress(), @@ -68,7 +40,6 @@ async function main() { const outputJson = { proxyAdminOwnerAddress: await signer.getAddress(), universalVerifier: await universalVerifier.getAddress(), - verifierLib: await verifierLib.getAddress(), state: stateContractAddress, network: networkName, chainId, diff --git a/scripts/deploy/deployValidators.ts b/scripts/deploy/deployValidators.ts index b3f5b3c1b..1c42f3ddf 100644 --- a/scripts/deploy/deployValidators.ts +++ b/scripts/deploy/deployValidators.ts @@ -13,14 +13,14 @@ async function main() { const config = getConfig(); const chainId = await getChainId(); - const stateContractAddress = await getStateContractAddress(); - const validators: ValidatorType[] = ["mtpV2", "sigV2", "v3", "authV2"]; + const validators: ValidatorType[] = ["mtpV2", "sigV2", "v3", "lmq", "authV2", "ethIdentity"]; const deployStrategy: "basic" | "create2" = config.deployStrategy == "create2" ? "create2" : "basic"; const [signer] = await hre.ethers.getSigners(); const deployHelper = await DeployHelper.initialize(null, true); + const stateContractAddress = await getStateContractAddress(); const validatorsInfo: any = []; for (const v of validators) { @@ -33,12 +33,13 @@ async function main() { await verifyContract(await validator.getAddress(), deployHelper.getValidatorVerification(v)); // only add validators info if groth16VerifierWrapper is deployed + validatorsInfo.push({ + validatorType: v, + validator: await validator.getAddress(), + groth16verifier: await groth16VerifierWrapper?.getAddress(), + }); + if (groth16VerifierWrapper) { - validatorsInfo.push({ - validatorType: v, - validator: await validator.getAddress(), - groth16verifier: await groth16VerifierWrapper?.getAddress(), - }); await verifyContract( await groth16VerifierWrapper.getAddress(), deployHelper.getGroth16VerifierWrapperVerification(v), diff --git a/scripts/deployments_output/deploy_libraries_output_6913_billions-test.json b/scripts/deployments_output/deploy_libraries_output_6913_billions-test.json new file mode 100644 index 000000000..baafced94 --- /dev/null +++ b/scripts/deployments_output/deploy_libraries_output_6913_billions-test.json @@ -0,0 +1,10 @@ +{ + "poseidon1": "0xC72D76D7271924a2AD54a19D216640FeA3d138d9", + "poseidon2": "0x72F721D9D5f91353B505207C63B56cF3d9447edB", + "poseidon3": "0x5Bc89782d5eBF62663Df7Ce5fb4bc7408926A240", + "poseidon4": "0x0695cF2c6dfc438a4E40508741888198A6ccacC2", + "smtLib": "0x682364078e26C1626abD2B95109D2019E241F0F6", + "network": "billions-test", + "chainId": 6913, + "deployStrategy": "create2" +} \ No newline at end of file diff --git a/scripts/deployments_output/deploy_state_output_6913_billions-test.json b/scripts/deployments_output/deploy_state_output_6913_billions-test.json new file mode 100644 index 000000000..08f689531 --- /dev/null +++ b/scripts/deployments_output/deploy_state_output_6913_billions-test.json @@ -0,0 +1,9 @@ +{ + "proxyAdminOwnerAddress": "0xAe15d2023A76174a940cbb2b7F44012C728B9d74", + "state": "0x3C9acB2205Aa72A05F6D77d708b5Cf85FCa3a896", + "stateLib": "0xBEba000A99c4d00706f46AC99aF06223BeF26d9a", + "crossChainProofValidator": "0x55b9f84605B30Df9Bb9d817A6900219F25218157", + "network": "billions-test", + "chainId": 6913, + "deployStrategy": "create2" +} \ No newline at end of file diff --git a/scripts/maintenance/addValidatorsToUniversalVerifier.ts b/scripts/maintenance/addValidatorsToUniversalVerifier.ts index 8b5e0b95c..1456bdc6b 100644 --- a/scripts/maintenance/addValidatorsToUniversalVerifier.ts +++ b/scripts/maintenance/addValidatorsToUniversalVerifier.ts @@ -17,7 +17,9 @@ async function main() { validatorMTPAddr, validatorSigAddr, validatorV3Addr, - validatorAuthV2Addr; + validatorLmqAddr, + validatorAuthV2Addr, + validatorEthIdentityAddr; if (deployStrategy === "basic") { const uvDeployOutput = fs.readFileSync( @@ -36,14 +38,25 @@ async function main() { ); const { validatorsInfo } = JSON.parse(validatorsDeployOutput.toString()); for (const v of validatorsInfo) { - if (v.validatorType === "mtpV2") { - validatorMTPAddr = v.validator; - } else if (v.validatorType === "sigV2") { - validatorSigAddr = v.validator; - } else if (v.validatorType === "v3") { - validatorV3Addr = v.validator; - } else if (v.validatorType === "authV2") { - validatorAuthV2Addr = v.validator; + switch (v.validatorType) { + case "mtpV2": + validatorMTPAddr = v.validator; + break; + case "sigV2": + validatorSigAddr = v.validator; + break; + case "v3": + validatorV3Addr = v.validator; + break; + case "lmq": + validatorLmqAddr = v.validator; + break; + case "authV2": + validatorAuthV2Addr = v.validator; + break; + case "ethIdentity": + validatorEthIdentityAddr = v.validator; + break; } } } else { @@ -52,7 +65,9 @@ async function main() { validatorMTPAddr = contractsInfo.VALIDATOR_MTP.unifiedAddress; validatorSigAddr = contractsInfo.VALIDATOR_SIG.unifiedAddress; validatorV3Addr = contractsInfo.VALIDATOR_V3.unifiedAddress; + validatorLmqAddr = contractsInfo.VALIDATOR_LINKED_MULTI_QUERY.unifiedAddress; validatorAuthV2Addr = contractsInfo.VALIDATOR_AUTH_V2.unifiedAddress; + validatorEthIdentityAddr = contractsInfo.VALIDATOR_ETH_IDENTITY.unifiedAddress; } const universalVerifier = await ethers.getContractAt( @@ -62,7 +77,7 @@ async function main() { console.log("Adding validators to Universal Verifier..."); - const validators = [ + const requestValidators = [ { validatorContractAddress: validatorMTPAddr, validatorContractName: contractsInfo.VALIDATOR_MTP.name, @@ -76,12 +91,12 @@ async function main() { validatorContractName: contractsInfo.VALIDATOR_V3.name, }, { - validatorContractAddress: validatorAuthV2Addr, - validatorContractName: contractsInfo.VALIDATOR_AUTH_V2.name, + validatorContractAddress: validatorLmqAddr, + validatorContractName: contractsInfo.VALIDATOR_LINKED_MULTI_QUERY.name, }, ]; - for (const v of validators) { + for (const v of requestValidators) { const isWhitelisted = await universalVerifier.isWhitelistedValidator( v.validatorContractAddress, ); @@ -102,6 +117,38 @@ async function main() { ); } } + + const authValidators = [ + { + authMethod: "authV2", + authValidatorAddress: validatorAuthV2Addr, + }, + { + authMethod: "ethIdentity", + authValidatorAddress: validatorEthIdentityAddr, + }, + ]; + + for (const v of authValidators) { + console.log( + `Setting auth method ${v.authMethod}: AuthValidator address (${v.authValidatorAddress})...`, + ); + try { + const setAuthMethodTx = await universalVerifier.connect(signer).setAuthMethod({ + authMethod: v.authMethod, + validator: v.authValidatorAddress, + params: "0x", + }); + await setAuthMethodTx.wait(); + Logger.success( + `Auth method ${v.authMethod}: AuthValidator address (${v.authValidatorAddress}) set`, + ); + } catch (error) { + if (error.message.includes("AuthMethodAlreadyExists")) { + Logger.warning(`Auth method ${v.authMethod} already set`); + } else throw error; + } + } } main() diff --git a/scripts/maintenance/checkContractsVerificationManually.ts b/scripts/maintenance/checkContractsVerificationManually.ts index 6a35c530d..04a218df6 100644 --- a/scripts/maintenance/checkContractsVerificationManually.ts +++ b/scripts/maintenance/checkContractsVerificationManually.ts @@ -2,29 +2,16 @@ import { verifyContract } from "../../helpers/helperUtils"; import { contractsInfo } from "../../helpers/constants"; async function main() { - const StateCrossChainLibAddress: string = ""; const StateLibAddress: string = ""; - const VerifierLibAddress: string = ""; const StateAddress: string = ""; if (StateAddress.includes("0x")) { await verifyContract(StateAddress, contractsInfo.STATE.verificationOpts); } - if (StateCrossChainLibAddress.includes("0x")) { - await verifyContract( - StateCrossChainLibAddress, - contractsInfo.STATE_CROSS_CHAIN_LIB.verificationOpts, - ); - } - if (StateLibAddress.includes("0x")) { await verifyContract(StateLibAddress, contractsInfo.STATE_LIB.verificationOpts); } - - if (VerifierLibAddress.includes("0x")) { - await verifyContract(VerifierLibAddress, contractsInfo.VERIFIER_LIB.verificationOpts); - } } main() diff --git a/scripts/maintenance/checkEmbeddedZKPVerifier.ts b/scripts/maintenance/checkEmbeddedZKPVerifier.ts index e919726c3..e69de29bb 100644 --- a/scripts/maintenance/checkEmbeddedZKPVerifier.ts +++ b/scripts/maintenance/checkEmbeddedZKPVerifier.ts @@ -1,70 +0,0 @@ -import { getStateContractAddress, Logger } from "../../helpers/helperUtils"; -import { contractsInfo } from "../../helpers/constants"; -import hre, { ethers } from "hardhat"; -import { - setZKPRequest_KYCAgeCredential, - submitZKPResponses_KYCAgeCredential, -} from "../upgrade/verifiers/helpers/testVerifier"; -import { Contract } from "ethers"; - -// Replace these addresses with the ones you want to test -const embeddedZKPVerifierAddress = ""; -const validatorSigV2Address = ""; -const validatorMTPV2Address = ""; -const validatorV3Address = ""; - -async function testVerification(verifier: Contract) { - const requestId_V3 = 7254189; - await setZKPRequest_KYCAgeCredential(requestId_V3, verifier, validatorV3Address, "v3"); - await submitZKPResponses_KYCAgeCredential(requestId_V3, verifier, "v3", { - stateContractAddress: await getStateContractAddress(), - verifierContractAddress: await verifier.getAddress(), - checkSubmitZKResponseV2: false, - }); - - const requestId_SigV2 = 7254190; - await setZKPRequest_KYCAgeCredential(requestId_SigV2, verifier, validatorSigV2Address, "sigV2"); - await submitZKPResponses_KYCAgeCredential(requestId_SigV2, verifier, "sigV2", { - stateContractAddress: await getStateContractAddress(), - verifierContractAddress: await verifier.getAddress(), - checkSubmitZKResponseV2: false, - }); - - const requestId_MTPV2 = 7254191; - await setZKPRequest_KYCAgeCredential(requestId_MTPV2, verifier, validatorMTPV2Address, "mtpV2"); - await submitZKPResponses_KYCAgeCredential(requestId_MTPV2, verifier, "mtpV2", { - stateContractAddress: await getStateContractAddress(), - verifierContractAddress: await verifier.getAddress(), - checkSubmitZKResponseV2: false, - }); -} - -async function main() { - console.log( - `\nChecking EmbeddedZKPVerifier verification on ${hre.network.name} with address ${embeddedZKPVerifierAddress}...`, - ); - - const embeddedZKPVerifier = await ethers.getContractAt( - contractsInfo.EMBEDDED_ZKP_VERIFIER_WRAPPER.name, - embeddedZKPVerifierAddress, - ); - - try { - await testVerification(embeddedZKPVerifier); - Logger.success( - `${hre.network.name} embedded ZKP Verifier onchain ${embeddedZKPVerifierAddress} verified`, - ); - } catch (error) { - console.error(error); - Logger.error( - `${hre.network.name} embedded ZKP Verifier onchain ${embeddedZKPVerifierAddress} not verified`, - ); - } -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error); - process.exit(1); - }); diff --git a/scripts/maintenance/disableProxyContract.ts b/scripts/maintenance/disableProxyContract.ts index 3a271e490..a04a0bd5c 100644 --- a/scripts/maintenance/disableProxyContract.ts +++ b/scripts/maintenance/disableProxyContract.ts @@ -21,7 +21,10 @@ async function main() { await new Promise((resolve) => setTimeout(resolve, 20000)); // !!!!! Put proper function name here to make some check, e.g. getDefaultIdType() for State contract !!!!! - await expect(contract.getDefaultIdType()).to.be.revertedWith("The contract is disabled"); + await expect(contract.getDefaultIdType()).to.be.revertedWithCustomError( + contract, + "TheContractIsDisabled", + ); const network = hre.network.name; console.log( diff --git a/scripts/maintenance/setProofRequest.ts b/scripts/maintenance/setProofRequest.ts index 33aca1647..467ca4a42 100644 --- a/scripts/maintenance/setProofRequest.ts +++ b/scripts/maintenance/setProofRequest.ts @@ -2,8 +2,7 @@ import hre, { ethers } from "hardhat"; import { packV3ValidatorParams, packValidatorParams } from "../../test/utils/validator-pack-utils"; import { calculateQueryHashV2, calculateQueryHashV3 } from "../../test/utils/query-hash-utils"; import { Blockchain, DidMethod, NetworkId, DID } from "@iden3/js-iden3-core"; -import { buildVerifierId } from "../deploy/deployCrossChainVerifierWithRequests"; -import { byteEncoder, CircuitId, Operators } from "@0xpolygonid/js-sdk"; +import { buildVerifierId, byteEncoder, CircuitId, Operators } from "@0xpolygonid/js-sdk"; import { contractsInfo } from "../../helpers/constants"; import { Hex } from "@iden3/js-crypto"; import { getChainId } from "../../helpers/helperUtils"; @@ -16,7 +15,7 @@ export function getAuthV2RequestId(): number { } async function main() { - const circuitName: CircuitId = CircuitId.AuthV2; // TODO put your circuit here; + const circuitName: CircuitId = CircuitId.AtomicQueryV3OnChain; // TODO put your circuit here; let requestId = 117; // TODO put your request here; const allowedIssuers = []; // TODO put your allowed issuers here diff --git a/scripts/upgrade/state/state-upgrade.ts b/scripts/upgrade/state/state-upgrade.ts index c9bdb7e56..b812c51ea 100644 --- a/scripts/upgrade/state/state-upgrade.ts +++ b/scripts/upgrade/state/state-upgrade.ts @@ -79,22 +79,17 @@ async function main() { const defaultIdTypeBefore = await stateContract.getDefaultIdType(); const stateOwnerAddressBefore = await stateContract.owner(); - const { state, stateLib, stateCrossChainLib, crossChainProofValidator } = - await stateDeployHelper.upgradeState( - await stateContract.getAddress(), - true, - contractsInfo.SMT_LIB.unifiedAddress, - contractsInfo.POSEIDON_1.unifiedAddress, - ); + const { state, stateLib, crossChainProofValidator } = await stateDeployHelper.upgradeState( + await stateContract.getAddress(), + true, + contractsInfo.SMT_LIB.unifiedAddress, + contractsInfo.POSEIDON_1.unifiedAddress, + ); console.log("Version after: ", await state.VERSION()); await verifyContract(await state.getAddress(), contractsInfo.STATE.verificationOpts); await verifyContract(await stateLib.getAddress(), contractsInfo.STATE_LIB.verificationOpts); - await verifyContract( - await stateCrossChainLib.getAddress(), - contractsInfo.STATE_CROSS_CHAIN_LIB.verificationOpts, - ); await verifyContract( await crossChainProofValidator.getAddress(), contractsInfo.CROSS_CHAIN_PROOF_VALIDATOR.verificationOpts, @@ -149,7 +144,6 @@ async function main() { verifier: contractsInfo.GROTH16_VERIFIER_STATE_TRANSITION.unifiedAddress, stateLib: await stateLib.getAddress(), smtLib: contractsInfo.SMT_LIB.unifiedAddress, - stateCrossChainLib: await stateCrossChainLib.getAddress(), crossChainProofValidator: await crossChainProofValidator.getAddress(), poseidon1: contractsInfo.POSEIDON_1.unifiedAddress, poseidon2: contractsInfo.POSEIDON_2.unifiedAddress, diff --git a/scripts/upgrade/verifiers/embedded-verifier-upgrade.ts b/scripts/upgrade/verifiers/embedded-verifier-upgrade.ts index f3009b213..ef7fb600d 100644 --- a/scripts/upgrade/verifiers/embedded-verifier-upgrade.ts +++ b/scripts/upgrade/verifiers/embedded-verifier-upgrade.ts @@ -17,11 +17,11 @@ async function main() { const chainId = await getChainId(); const network = hre.network.name; - // EmbeddedZKPVerifer is abstract contract + // EmbeddedVerifer is abstract contract // In real upgrade, you should use THE NAME as THE ADDRESS - // of your custom contract, which inherits EmbeddedZKPVerifer + // of your custom contract, which inherits EmbeddedVerifer let verifierContract = await ethers.getContractAt( - "", // EmbeddedZKPVerifierWrapper + "", // EmbeddedVerifierWrapper "", ); @@ -42,14 +42,10 @@ async function main() { const verifierRequestsCountBeforeUpgrade = await verifierContract.getZKPRequestsCount(); console.log("Owner Address Before Upgrade: ", verifierOwnerAddressBeforeUpgrade); - const verifierLib = await deployerHelper.deployVerifierLib(); - // **** Upgrade Embedded Verifier **** - const verifierFactory = await ethers.getContractFactory("EmbeddedZKPVerifierWrapper", { - libraries: { - VerifierLib: await verifierLib.getAddress(), - }, - }); + const verifierFactory = await ethers.getContractFactory( + contractsInfo.EMBEDDED_VERIFIER_WRAPPER.name, + ); try { verifierContract = await upgrades.upgradeProxy( @@ -98,7 +94,6 @@ async function main() { const outputJson = { proxyAdminOwnerAddress: await signer.getAddress(), verifierContract: await verifierContract.getAddress(), - verifierLib: await verifierLib.getAddress(), state: stateContractAddress, network: network, chainId, diff --git a/scripts/upgrade/verifiers/helpers/testVerifier.ts b/scripts/upgrade/verifiers/helpers/testVerifier.ts index 056d8d4dd..a0004ef24 100644 --- a/scripts/upgrade/verifiers/helpers/testVerifier.ts +++ b/scripts/upgrade/verifiers/helpers/testVerifier.ts @@ -7,24 +7,15 @@ import { packV3ValidatorParams, packValidatorParams, } from "../../../../test/utils/validator-pack-utils"; -import { - Blockchain, - buildDIDType, - BytesHelper, - DID, - DidMethod, - genesisFromEthAddress, - Id, - NetworkId, -} from "@iden3/js-iden3-core"; +import { Blockchain, BytesHelper, DID, DidMethod, NetworkId } from "@iden3/js-iden3-core"; import hre from "hardhat"; -import { Hex } from "@iden3/js-crypto"; import { initCircuitStorage, initInMemoryDataStorageAndWallets, initProofService, } from "./walletSetup"; import { + buildVerifierId, CircuitId, core, CredentialRequest, @@ -130,20 +121,6 @@ async function generateProof( return { proof, pub_signals }; } -function buildVerifierId( - address: string, - info: { method: string; blockchain: string; networkId: string }, -): Id { - address = address.replace("0x", ""); - const ethAddrBytes = Hex.decodeString(address); - const ethAddr = ethAddrBytes.slice(0, 20); - const genesis = genesisFromEthAddress(ethAddr); - - const tp = buildDIDType(info.method, info.blockchain, info.networkId); - - return new Id(tp, genesis); -} - function prepareProof(proof: ProofData) { const { pi_a, pi_b, pi_c } = proof; const [[p1, p2], [p3, p4]] = pi_b; diff --git a/scripts/upgrade/verifiers/universal-verifier-upgrade.ts b/scripts/upgrade/verifiers/universal-verifier-upgrade.ts index 9144bcff2..988da70bb 100644 --- a/scripts/upgrade/verifiers/universal-verifier-upgrade.ts +++ b/scripts/upgrade/verifiers/universal-verifier-upgrade.ts @@ -123,16 +123,8 @@ async function main() { expect(await universalVerifierContract.isWhitelistedValidator(validator)).to.equal(true); } - const verifierLib = await deployerHelper.deployVerifierLib(); - const txVerifLib = await verifierLib.deploymentTransaction(); - await waitNotToInterfereWithHardhatIgnition(txVerifLib); - - await verifyContract(await verifierLib.getAddress(), contractsInfo.VERIFIER_LIB.verificationOpts); - // **** Upgrade Universal Verifier **** - await universalVerifierMigrationHelper.upgradeContract(universalVerifierContract, { - verifierLibAddress: await verifierLib.getAddress(), - }); + await universalVerifierMigrationHelper.upgradeContract(universalVerifierContract); // ************************ console.log("Checking data after upgrade"); @@ -217,7 +209,6 @@ async function main() { const outputJson = { proxyAdminOwnerAddress: await proxyAdminOwnerSigner.getAddress(), universalVerifier: await universalVerifierContract.getAddress(), - verifierLib: await verifierLib.getAddress(), state: stateContractAddress, network: network, chainId, diff --git a/test/IdentityTreeStore/IdentityTreeStore.test.ts b/test/IdentityTreeStore/IdentityTreeStore.test.ts index 230db1a09..f6096d66b 100644 --- a/test/IdentityTreeStore/IdentityTreeStore.test.ts +++ b/test/IdentityTreeStore/IdentityTreeStore.test.ts @@ -295,10 +295,11 @@ describe("IdentityTreeStore", function () { await expect( identityTreeStore.getRevocationStatusByIdAndState(id, state, nonce), - ).to.be.rejectedWith("Invalid state node"); + ).to.be.revertedWithCustomError(identityTreeStore, "InvalidStateNode"); - await expect(identityTreeStore.getRevocationStatus(id, nonce)).to.be.rejectedWith( - "Invalid state node", + await expect(identityTreeStore.getRevocationStatus(id, nonce)).to.be.revertedWithCustomError( + identityTreeStore, + "InvalidStateNode", ); }); }); diff --git a/test/check-unified-addresses.test.ts b/test/check-unified-addresses.test.ts new file mode 100644 index 000000000..8df396d4f --- /dev/null +++ b/test/check-unified-addresses.test.ts @@ -0,0 +1,79 @@ +import { buildModule } from "@nomicfoundation/ignition-core"; +import { + contractsInfo, + TRANSPARENT_UPGRADEABLE_PROXY_ABI, + TRANSPARENT_UPGRADEABLE_PROXY_BYTECODE, +} from "../helpers/constants"; +import { ignition } from "hardhat"; +import { Logger } from "../helpers/helperUtils"; + +// Replace here with your own proxy admin owner address +const proxyAdminOwnerAddress = "0xAe15d2023A76174a940cbb2b7F44012C728B9d74"; + +const Create2AddressAnchorModule = buildModule("Create2AddressAnchorModule", (m) => { + const create2AddressAnchor = m.contract(contractsInfo.CREATE2_ADDRESS_ANCHOR.name, { + abi: [], + contractName: contractsInfo.CREATE2_ADDRESS_ANCHOR.name, + bytecode: "0x6005600C60003960056000F360006000F3", + sourceName: "", + linkReferences: {}, + }); + + return { create2AddressAnchor }; +}); + +const GeneralProxyModule = buildModule("GeneralProxyModule", (m) => { + const create2Calldata = m.getParameter("create2Calldata", 0); + + const proxy = m.contract( + "TransparentUpgradeableProxy", + { + abi: TRANSPARENT_UPGRADEABLE_PROXY_ABI, + contractName: "TransparentUpgradeableProxy", + bytecode: TRANSPARENT_UPGRADEABLE_PROXY_BYTECODE, + sourceName: "", + linkReferences: {}, + }, + [contractsInfo.CREATE2_ADDRESS_ANCHOR.unifiedAddress, proxyAdminOwnerAddress, create2Calldata], + ); + + const proxyAdminAddress = m.readEventArgument(proxy, "AdminChanged", "newAdmin"); + const proxyAdmin = m.contractAt("ProxyAdmin", proxyAdminAddress); + + return { proxyAdmin, proxy }; +}); + +it("Calculate and check unified addresses for proxy contracts", async () => { + await ignition.deploy(Create2AddressAnchorModule, { strategy: "create2" }); + let isCheckSuccess = true; + + for (const property in contractsInfo) { + if (contractsInfo[property].create2Calldata !== "") { + const proxyDeployed = ( + await ignition.deploy(GeneralProxyModule, { + strategy: "create2", + parameters: { + GeneralProxyModule: { + create2Calldata: contractsInfo[property].create2Calldata, + }, + }, + }) + ).proxy; + await proxyDeployed.waitForDeployment(); + if ((await proxyDeployed.getAddress()) !== contractsInfo[property].unifiedAddress) { + Logger.error( + `${contractsInfo[property].name} deployed with unified address: ${await proxyDeployed.getAddress()} (expected: ${contractsInfo[property].unifiedAddress})`, + ); + isCheckSuccess = false; + } else { + Logger.success( + `${contractsInfo[property].name} deployed with unified address: ${await proxyDeployed.getAddress()}`, + ); + } + } + } + + if (!isCheckSuccess) { + throw new Error("Unified address check failed"); + } +}); diff --git a/test/cross-chain/cross-chain-proof-validator.test.ts b/test/cross-chain/cross-chain-proof-validator.test.ts index e6df7592d..e14c4b275 100644 --- a/test/cross-chain/cross-chain-proof-validator.test.ts +++ b/test/cross-chain/cross-chain-proof-validator.test.ts @@ -92,9 +92,9 @@ describe("State Cross Chain", function () { }; const proof = await packIdentityStateUpdateWithSignature(ism, signer); - await expect(crossChainProofValidator.processIdentityStateProof(proof)).to.be.rejectedWith( - "Oracle timestamp cannot be in the past", - ); + await expect( + crossChainProofValidator.processIdentityStateProof(proof), + ).to.be.revertedWithCustomError(crossChainProofValidator, "OracleTimestampCannotBeInThePast"); }); it("Oracle replacedAtTimestamp or oracle timestamp cannot be in the future", async function () { @@ -108,8 +108,11 @@ describe("State Cross Chain", function () { }; let proof = await packGlobalStateUpdateWithSignature(gsm, signer); - await expect(crossChainProofValidator.processGlobalStateProof(proof)).to.be.rejectedWith( - "Oracle replacedAtTimestamp or oracle timestamp cannot be in the future", + await expect( + crossChainProofValidator.processGlobalStateProof(proof), + ).to.be.revertedWithCustomError( + crossChainProofValidator, + "OracleReplacedAtTimestampCannotBeInTheFuture", ); const ism: IdentityStateMessage = { @@ -120,8 +123,11 @@ describe("State Cross Chain", function () { }; proof = await packIdentityStateUpdateWithSignature(ism, signer); - await expect(crossChainProofValidator.processIdentityStateProof(proof)).to.be.rejectedWith( - "Oracle replacedAtTimestamp or oracle timestamp cannot be in the future", + await expect( + crossChainProofValidator.processIdentityStateProof(proof), + ).to.be.revertedWithCustomError( + crossChainProofValidator, + "OracleReplacedAtTimestampCannotBeInTheFuture", ); }); @@ -136,8 +142,11 @@ describe("State Cross Chain", function () { }; let proof = await packGlobalStateUpdateWithSignature(gsm, signer, true); - await expect(crossChainProofValidator.processGlobalStateProof(proof)).to.be.rejectedWith( - "Global state proof signing address is not valid", + await expect( + crossChainProofValidator.processGlobalStateProof(proof), + ).to.be.revertedWithCustomError( + crossChainProofValidator, + "GlobalStateProofSigningAddressInvalid", ); const ism: IdentityStateMessage = { @@ -148,8 +157,11 @@ describe("State Cross Chain", function () { }; proof = await packIdentityStateUpdateWithSignature(ism, signer, true); - await expect(crossChainProofValidator.processIdentityStateProof(proof)).to.be.rejectedWith( - "Identity state proof signing address is not valid", + await expect( + crossChainProofValidator.processIdentityStateProof(proof), + ).to.be.revertedWithCustomError( + crossChainProofValidator, + "IdentityStateProofSigningAddressInvalid", ); }); @@ -164,9 +176,9 @@ describe("State Cross Chain", function () { }; let proof = await packGlobalStateUpdateWithSignature(gsm, signer, false, true); - await expect(crossChainProofValidator.processGlobalStateProof(proof)).to.be.rejectedWith( - "Global state proof is not valid", - ); + await expect( + crossChainProofValidator.processGlobalStateProof(proof), + ).to.be.revertedWithCustomError(crossChainProofValidator, "GlobalStateProofInvalid"); const ism: IdentityStateMessage = { timestamp: currentTimestamp, @@ -176,9 +188,9 @@ describe("State Cross Chain", function () { }; proof = await packIdentityStateUpdateWithSignature(ism, signer, false, true); - await expect(crossChainProofValidator.processIdentityStateProof(proof)).to.be.rejectedWith( - "Identity state proof is not valid", - ); + await expect( + crossChainProofValidator.processIdentityStateProof(proof), + ).to.be.revertedWithCustomError(crossChainProofValidator, "IdentityStateProofInvalid"); }); }); diff --git a/test/disable-proxy.test.ts b/test/disable-proxy.test.ts index 37a7edb53..ae87ea7dc 100644 --- a/test/disable-proxy.test.ts +++ b/test/disable-proxy.test.ts @@ -20,8 +20,8 @@ describe("Disable Proxy Contract test", async () => { const alwaysRevertFactory = await ethers.getContractFactory("AlwaysRevert"); await upgrades.upgradeProxy(await verifier.getAddress(), alwaysRevertFactory); - await expect(verifier.verifyProof(d[0], d[1], d[2], d[3])).to.be.revertedWith( - "The contract is disabled", + await expect(verifier.verifyProof(d[0], d[1], d[2], d[3])).to.be.rejectedWith( + "TheContractIsDisabled()", ); await upgrades.upgradeProxy(await verifier.getAddress(), verifierStubFactory); diff --git a/test/integration-tests/data/user_claim_issued_on_userid_v3.json b/test/integration-tests/data/user_claim_issued_on_userid_v3.json new file mode 100644 index 000000000..1752523dc --- /dev/null +++ b/test/integration-tests/data/user_claim_issued_on_userid_v3.json @@ -0,0 +1,43 @@ +{ + "pub_signals": [ + "23273167900576580892722615617815475823351560716009055944677723144398443009", + "5163501582380794606957519356304223666405959765481558471633650858228490409290", + "2943483356559152311923412925436024635269538717812859789851139200242297094", + "20336008450539684768013573494073798243349685857640613070314041678185349736439", + "0", + "0", + "1", + "41", + "583091486781463398742321306787801699791102451699", + "0", + "22057981499787921734624217749308316644136637822444794206796063681866502657", + "2943483356559152311923412925436024635269538717812859789851139200242297094", + "1642074362", + "1" + ], + "proof": { + "pi_a": [ + "19669163552065605232226440325758625657636624385583277995594891950486344866508", + "10711637643378840554760385822550851249555527485204302585948254974040755477609", + "1" + ], + "pi_b": [ + [ + "2876377569478858706516978096403208510392181149089058781420525859804877516279", + "9515133907790273150201355935211769526767866212205498667361695701553682353137" + ], + [ + "14869390077573764384106112054362589649141652233556283316748964628563711405904", + "1151936578002145346443589143139936031757296603439509995084143527963932212544" + ], + ["1", "0"] + ], + "pi_c": [ + "18589419753357207419833045626873608018236514226418635490877679898608141092303", + "4377014052512563002949775596611087745477480197663974829547855257127755207594", + "1" + ], + "protocol": "groth16", + "curve": "bn128" + } +} diff --git a/test/integration-tests/data/user_genesis_auth.json b/test/integration-tests/data/user_genesis_auth.json new file mode 100644 index 000000000..68afce0f9 --- /dev/null +++ b/test/integration-tests/data/user_genesis_auth.json @@ -0,0 +1,32 @@ +{ + "pub_signals": [ + "23273167900576580892722615617815475823351560716009055944677723144398443009", + "5212973139745638668633720237501954966656555739014896868936311397139229290378", + "0" + ], + "proof": { + "pi_a": [ + "1238064536595227341390695164336084541847939190316067358993916901940214723234", + "15799255647621631452959766830308132916683864863600158271743280920118665788588", + "1" + ], + "pi_b": [ + [ + "17670400722045843961660874132388709522679013234267198690084857080641983583843", + "5287730570087617132913682200031155642104951958077715792787827776465000719881" + ], + [ + "6075263630519803963226139789246602077914731950499703659787166643095603330195", + "7938053062178962435112746593441459158641110827412215757397151271877979765565" + ], + ["1", "0"] + ], + "pi_c": [ + "21010592776578764547907351859929622777512296832984420047235514552228625464856", + "18192765798069122918377413910327891618012999130269311083464781452775699686570", + "1" + ], + "protocol": "groth16", + "curve": "bn128" + } +} diff --git a/test/integration-tests/data/user_genesis_auth_challenge_invalid.json b/test/integration-tests/data/user_genesis_auth_challenge_invalid.json new file mode 100644 index 000000000..890bb82c7 --- /dev/null +++ b/test/integration-tests/data/user_genesis_auth_challenge_invalid.json @@ -0,0 +1,32 @@ +{ + "pub_signals": [ + "23273167900576580892722615617815475823351560716009055944677723144398443009", + "2378043419791432977129888049610162411300945363341716024701363947598560258096", + "0" + ], + "proof": { + "pi_a": [ + "9541867327348938145541193982123992297208138293358805560483945427733735306124", + "13833819619741404300235158867440476234063725794567625680704749737959767863116", + "1" + ], + "pi_b": [ + [ + "20359745551134549335223867766905772056177316525265757287933840985984292914937", + "1780864031735933858234307839702997430255911747389589653941781093680324195492" + ], + [ + "12080937648102594742202930954953883943640192768810066345568670629167309979739", + "13280726496624428913315243268401447342745276267258692974299666120924393078428" + ], + ["1", "0"] + ], + "pi_c": [ + "12131738695386235649587882341686961353232752515854843634252155993701923991681", + "18949649035566368476284982950769667836111086011759734792131512893325609072891", + "1" + ], + "protocol": "groth16", + "curve": "bn128" + } +} diff --git a/test/integration-tests/data/user_linked_multi_query.json b/test/integration-tests/data/user_linked_multi_query.json new file mode 100644 index 000000000..9bb0c3d1c --- /dev/null +++ b/test/integration-tests/data/user_linked_multi_query.json @@ -0,0 +1,51 @@ +{ + "pub_signals": [ + "20336008450539684768013573494073798243349685857640613070314041678185349736439", + "1", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "3326382892536126749483088946048689911243394580824744244053752370464747528203", + "9907132056133666096701539062450765284880813426582692863734448403438789333698", + "13362042977965885903820557513534065802896288300017199700677633721405805677442", + "13362042977965885903820557513534065802896288300017199700677633721405805677442", + "13362042977965885903820557513534065802896288300017199700677633721405805677442", + "13362042977965885903820557513534065802896288300017199700677633721405805677442", + "13362042977965885903820557513534065802896288300017199700677633721405805677442", + "13362042977965885903820557513534065802896288300017199700677633721405805677442", + "13362042977965885903820557513534065802896288300017199700677633721405805677442", + "13362042977965885903820557513534065802896288300017199700677633721405805677442" + ], + "proof": { + "pi_a": [ + "10541909102768476058347747538132221338909944796214430823937430621918433820572", + "12998271972533338175505729586393778918022420191938730276405884463074788961369", + "1" + ], + "pi_b": [ + [ + "21786734761872104002981387083471529709973058267263166350818620656227477577301", + "6784160731236418180364992784613101482914038854158831514386379008042983363743" + ], + [ + "17941889499361474971416705471447893349857158046615762117348229875623276791888", + "5989944269623828035204132704907772907469171386995335116029892218132563943912" + ], + ["1", "0"] + ], + "pi_c": [ + "17192623970124500187048482626581622763069786710232775241298788913349580516363", + "17848067197475549139335038191779648120820902475170770311958006870826316291138", + "1" + ], + "protocol": "groth16", + "curve": "bn128" + } +} diff --git a/test/integration-tests/integration-verifier.test.ts b/test/integration-tests/integration-verifier.test.ts new file mode 100644 index 000000000..fe7469939 --- /dev/null +++ b/test/integration-tests/integration-verifier.test.ts @@ -0,0 +1,290 @@ +import { ethers } from "hardhat"; +import { DeployHelper } from "../../helpers/DeployHelper"; +import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; +import { prepareInputs } from "../utils/state-utils"; +import authProofJson from "./data/user_genesis_auth.json"; +import authInvalidChallengeProofJson from "./data/user_genesis_auth_challenge_invalid.json"; +import v3ProofJson from "./data/user_claim_issued_on_userid_v3.json"; +import linkedProofJson from "./data/user_linked_multi_query.json"; +import { packZKProof } from "../utils/packData"; +import { expect } from "chai"; +import { + packLinkedMultiQueryValidatorParams, + packV3ValidatorParams, +} from "../utils/validator-pack-utils"; +import { CircuitId } from "@0xpolygonid/js-sdk"; +import { calculateQueryHashV3 } from "../utils/query-hash-utils"; +import { TEN_YEARS } from "../../helpers/constants"; +import { calculateGroupID, calculateMultiRequestId } from "../utils/id-calculation-utils"; + +describe("Verifier Integration test", async function () { + let verifier, v3Validator, lmqValidator; + let signer; + + const requestIdV3 = 32; + const requestIdLMK = 33; + const groupID = calculateGroupID([BigInt(requestIdV3), BigInt(requestIdLMK)]); + + const value = ["20020101", ...new Array(63).fill("0")]; + + const schema = "267831521922558027206082390043321796944"; + const slotIndex = 0; // 0 for signature + const operator = 7; + const claimPathKey = + "20376033832371109177683048456014525905119173674985843915445634726167450989630"; + const [merklized, isRevocationChecked, valueArrSize] = [1, 1, 1]; + const nullifierSessionId = "0"; + const verifierId = "21929109382993718606847853573861987353620810345503358891473103689157378049"; + const queryHash = calculateQueryHashV3( + value, + schema, + slotIndex, + operator, + claimPathKey, + valueArrSize, + merklized, + isRevocationChecked, + verifierId, + nullifierSessionId, + ); + + const query = { + schema, + claimPathKey, + operator, + slotIndex, + value, + circuitIds: [CircuitId.AtomicQueryV3OnChain], + skipClaimRevocationCheck: false, + queryHash, + groupID: groupID, + nullifierSessionID: nullifierSessionId, // for ethereum based user + proofType: 1, // 1 for BJJ + verifierID: verifierId, + }; + + const crossChainProofs = "0x"; + const metadatas = "0x"; + const authMethod = "authV2"; + + const v3Params = packV3ValidatorParams(query); + + const twoQueries = { + claimPathKey: [ + 20376033832371109177683048456014525905119173674985843915445634726167450989630n, + 20376033832371109177683048456014525905119173674985843915445634726167450989630n, + ], + operator: [2, 6], + slotIndex: [0, 0], + value: [ + [20020101, ...new Array(63).fill(0)], + [20030101, ...new Array(63).fill(0)], + ], + queryHash: [ + 3326382892536126749483088946048689911243394580824744244053752370464747528203n, + 9907132056133666096701539062450765284880813426582692863734448403438789333698n, + ], + circuitIds: ["linkedMultiQuery10-beta.1"], + groupID: groupID, + verifierID: verifierId, + }; + + const twoQueriesParams = packLinkedMultiQueryValidatorParams(twoQueries); + + const v3Proof = getProof(v3ProofJson); + const lmqProof = getProof(linkedProofJson); + + function getProof(proofJson: any) { + const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson); + const proof = packZKProof(inputs, pi_a, pi_b, pi_c); + return proof; + } + + async function deployContractsFixture() { + [signer] = await ethers.getSigners(); + + const verifier = await ethers.deployContract("VerifierTestWrapper", []); + + const deployHelper = await DeployHelper.initialize(null, true); + const { state } = await deployHelper.deployStateWithLibraries(["0x0212"]); + await verifier.initialize(await state.getAddress()); + + const { validator: authValidator } = await deployHelper.deployValidatorContractsWithVerifiers( + "authV2", + await state.getAddress(), + ); + await authValidator.setProofExpirationTimeout(TEN_YEARS); + await authValidator.setGISTRootExpirationTimeout(TEN_YEARS); + + const authMethod = { + authMethod: "authV2", + validator: await authValidator.getAddress(), + params: "0x", + }; + await verifier.setAuthMethod(authMethod); + + const { validator: v3Validator } = await deployHelper.deployValidatorContractsWithVerifiers( + "v3", + await state.getAddress(), + ); + await v3Validator.setProofExpirationTimeout(TEN_YEARS); + await v3Validator.setGISTRootExpirationTimeout(TEN_YEARS); + + const { validator: lmkValidator } = await deployHelper.deployValidatorContractsWithVerifiers( + "lmq", + await state.getAddress(), + ); + + return { state, verifier, authValidator, v3Validator, lmkValidator }; + } + + beforeEach(async () => { + ({ verifier, v3Validator, lmkValidator: lmqValidator } = await loadFixture(deployContractsFixture)); + + await verifier.setVerifierID(query.verifierID); + }); + + it("Should revert with ChallengeIsInvalid for auth proof", async function () { + const authInvalidChallengeProof = getProof(authInvalidChallengeProofJson); + + await verifier.setRequests([ + { + requestId: requestIdV3, + metadata: "metadata", + validator: await v3Validator.getAddress(), + owner: signer.address, + params: v3Params, + }, + { + requestId: requestIdLMK, + metadata: "metadata", + validator: await lmqValidator.getAddress(), + owner: signer.address, + params: twoQueriesParams, + }, + ]); + + await expect( + verifier.submitResponse( + { + authMethod: authMethod, + proof: authInvalidChallengeProof, + }, + [ + { + requestId: requestIdV3, + proof: v3Proof, + metadata: metadatas, + }, + { + requestId: requestIdLMK, + proof: lmqProof, + metadata: metadatas, + }, + ], + crossChainProofs, + ), + ).to.be.revertedWithCustomError(verifier, "ChallengeIsInvalid"); + }); + + it("Should revert with MissingUserIDInGroupOfRequests", async function () { + const groupID = calculateGroupID([BigInt(requestIdLMK), BigInt(requestIdLMK + 1)]); + + const twoQueriesParamsNew = packLinkedMultiQueryValidatorParams({ ...twoQueries, groupID }); + + await expect( + verifier.setRequests([ + { + requestId: requestIdLMK, + metadata: "metadata", + validator: await lmqValidator.getAddress(), + owner: signer.address, + params: twoQueriesParamsNew, + }, + { + requestId: requestIdLMK + 1, + metadata: "metadata", + validator: await lmqValidator.getAddress(), + owner: signer.address, + params: twoQueriesParamsNew, + }, + ]), + ) + .to.be.revertedWithCustomError(verifier, "MissingUserIDInGroupOfRequests") + .withArgs(groupID); + }); + + it("Should verify", async function () { + const authProof = getProof(authProofJson); + + // 1. Create the requests + await verifier.setRequests([ + { + requestId: requestIdV3, + metadata: "metadata", + validator: await v3Validator.getAddress(), + owner: signer.address, + params: v3Params, + }, + { + requestId: requestIdLMK, + metadata: "metadata", + validator: await lmqValidator.getAddress(), + owner: signer.address, + params: twoQueriesParams, + }, + ]); + + const multiRequest = { + multiRequestId: calculateMultiRequestId([], [groupID], signer.address), + requestIds: [], + groupIds: [groupID], + metadata: "0x", + }; + + // 2. Create the multi-request + await expect(verifier.setMultiRequest(multiRequest)).not.to.be.reverted; + const multiRequestIdExists = await verifier.multiRequestIdExists(multiRequest.multiRequestId); + expect(multiRequestIdExists).to.be.true; + + let areMultiRequestProofsVerified = await verifier.areMultiRequestProofsVerified( + multiRequest.multiRequestId, + await signer.getAddress(), + ); + expect(areMultiRequestProofsVerified).to.be.false; + + // 3. Submitting a response with valid proofs + await expect( + verifier.submitResponse( + { + authMethod: authMethod, + proof: authProof, + }, + [ + { + requestId: requestIdV3, + proof: v3Proof, + metadata: metadatas, + }, + { + requestId: requestIdLMK, + proof: lmqProof, + metadata: metadatas, + }, + ], + crossChainProofs, + ), + ).not.to.be.reverted; + + areMultiRequestProofsVerified = await verifier.areMultiRequestProofsVerified( + multiRequest.multiRequestId, + await signer.getAddress(), + ); + expect(areMultiRequestProofsVerified).to.be.true; + }); + + // An integration test with a MultiRequest + // The multiRequest has a single group with two requests inside + // One request is based on V3 validator + // Another one is based on LinkedMultiQuery validator +}); diff --git a/test/onchain-identity/claim-builder.test.ts b/test/onchain-identity/claim-builder.test.ts index 374c9fd5d..dde6c256d 100644 --- a/test/onchain-identity/claim-builder.test.ts +++ b/test/onchain-identity/claim-builder.test.ts @@ -2,7 +2,7 @@ import { expect } from "chai"; import { OnchainIdentityDeployHelper } from "../../helpers/OnchainIdentityDeployHelper"; import fs from "fs"; -describe("Claim builder tests", function() { +describe("Claim builder tests", function () { let identity; before(async () => { @@ -12,118 +12,512 @@ describe("Claim builder tests", function() { it("validate buildClaim", async function () { const inputs = [ - { // schemaHash - contractInput: ['75118319212313495155413841331241344325', 0, false, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - expectedClaims: ['75118319212313495155413841331241344325', '0', '0', '0', '0', '0', '0', '0'] - }, - { // id index - contractInput: ['75118319212313495155413841331241344325', 1, false, false, 0, 0, '25425363284463910957419549722021124450832239517990785975889689633068548096', 0, 0, 0, 0, 0, 0, 0], - expectedClaims: ['755683053054190422082163056194777767237', '25425363284463910957419549722021124450832239517990785975889689633068548096', '0', '0', '0', '0', '0', '0'] - }, - { // id value - contractInput: ['75118319212313495155413841331241344325', 2, false, false, 0, 0, '25425363284463910957419549722021124450832239517990785975889689633068548096', 0, 0, 0, 0, 0, 0, 0], - expectedClaims: ['1095965419975128885545537663626545978693', '0', '0', '0', '0', '25425363284463910957419549722021124450832239517990785975889689633068548096', '0', '0'] - }, - { // expirationDate - contractInput: ['75118319212313495155413841331241344325', 2, true, false, 0, 0, '25425363284463910957419549722021124450832239517990785975889689633068548096', 0, 1857686340, 0, 0, 0, 0, 0], - expectedClaims: ['3818224355342636593252534523080691670341', '0', '0', '0', '34268264483206187164568125440', '25425363284463910957419549722021124450832239517990785975889689633068548096', '0', '0'] - }, - { // updatableFlag - contractInput: ['75118319212313495155413841331241344325', 2, true, true, 0, 0, '25425363284463910957419549722021124450832239517990785975889689633068548096', 0, 1857686340, 0, 0, 0, 0, 0], - expectedClaims: ['9262742226077652008666528241988983053637', '0', '0', '0', '34268264483206187164568125440', '25425363284463910957419549722021124450832239517990785975889689633068548096', '0', '0'] - }, - { // merklized index - contractInput: ['75118319212313495155413841331241344325', 2, true, true, 1, 0, '25425363284463910957419549722021124450832239517990785975889689633068548096', 0, 1857686340, '93352129123234552352342342353456456452342343456345234121567843345', 0, 0, 0, 0], - expectedClaims: ['20151777967547682839494515679805565820229', '0', '93352129123234552352342342353456456452342343456345234121567843345', '0', '34268264483206187164568125440', '25425363284463910957419549722021124450832239517990785975889689633068548096', '0', '0'] - }, - { // merklized value - contractInput: ['75118319212313495155413841331241344325', 2, true, true, 2, 0, '25425363284463910957419549722021124450832239517990785975889689633068548096', 0, 1857686340, '93352129123234552352342342353456456452342343456345234121567843345', 0, 0, 0, 0], - expectedClaims: ['31040813709017713670322503117622148586821', '0', '0', '0', '34268264483206187164568125440', '25425363284463910957419549722021124450832239517990785975889689633068548096', '93352129123234552352342342353456456452342343456345234121567843345', '0'] - }, - { // version - contractInput: ['75118319212313495155413841331241344325', 2, true, true, 2, 89220123, '25425363284463910957419549722021124450832239517990785975889689633068548096', 0, 1857686340, '93352129123234552352342342353456456452342343456345234121567843345', 0, 0, 0, 0], - expectedClaims: ['130395355847364581104005408845894865439016836786170092869', '0', '0', '0', '34268264483206187164568125440', '25425363284463910957419549722021124450832239517990785975889689633068548096', '93352129123234552352342342353456456452342343456345234121567843345', '0'] - }, - { // revocation nonce - contractInput: ['75118319212313495155413841331241344325', 2, true, true, 2, 89220123, '25425363284463910957419549722021124450832239517990785975889689633068548096', 3312445, 1857686340, '93352129123234552352342342353456456452342343456345234121567843345', 0, 0, 0, 0], - expectedClaims: ['130395355847364581104005408845894865439016836786170092869', '0', '0', '0', '34268264483206187164571437885', '25425363284463910957419549722021124450832239517990785975889689633068548096', '93352129123234552352342342353456456452342343456345234121567843345', '0'] - }, - { // data slots - contractInput: ['75118319212313495155413841331241344325', 2, true, true, 0, 89220123, '25425363284463910957419549722021124450832239517990785975889689633068548096', 3312445, 1857686340, '0', '16243864111864693853212588481963275789994876191154110553066821559749894481761', '7078462697308959301666117070269719819629678436794910510259518359026273676830', '12448278679517811784508557734102986855579744384337338465055621486538311281772', '9260608685281348956030279125705000716237952776955782848598673606545494194823'], - expectedClaims: ['130395355847364559325933925905833203783041961153004559685', '0', '16243864111864693853212588481963275789994876191154110553066821559749894481761', '7078462697308959301666117070269719819629678436794910510259518359026273676830', '34268264483206187164571437885', '25425363284463910957419549722021124450832239517990785975889689633068548096', '12448278679517811784508557734102986855579744384337338465055621486538311281772', '9260608685281348956030279125705000716237952776955782848598673606545494194823'] - }, + { + // schemaHash + contractInput: [ + "75118319212313495155413841331241344325", + 0, + false, + false, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + expectedClaims: [ + "75118319212313495155413841331241344325", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + ], + }, + { + // id index + contractInput: [ + "75118319212313495155413841331241344325", + 1, + false, + false, + 0, + 0, + "25425363284463910957419549722021124450832239517990785975889689633068548096", + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + expectedClaims: [ + "755683053054190422082163056194777767237", + "25425363284463910957419549722021124450832239517990785975889689633068548096", + "0", + "0", + "0", + "0", + "0", + "0", + ], + }, + { + // id value + contractInput: [ + "75118319212313495155413841331241344325", + 2, + false, + false, + 0, + 0, + "25425363284463910957419549722021124450832239517990785975889689633068548096", + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + expectedClaims: [ + "1095965419975128885545537663626545978693", + "0", + "0", + "0", + "0", + "25425363284463910957419549722021124450832239517990785975889689633068548096", + "0", + "0", + ], + }, + { + // expirationDate + contractInput: [ + "75118319212313495155413841331241344325", + 2, + true, + false, + 0, + 0, + "25425363284463910957419549722021124450832239517990785975889689633068548096", + 0, + 1857686340, + 0, + 0, + 0, + 0, + 0, + ], + expectedClaims: [ + "3818224355342636593252534523080691670341", + "0", + "0", + "0", + "34268264483206187164568125440", + "25425363284463910957419549722021124450832239517990785975889689633068548096", + "0", + "0", + ], + }, + { + // updatableFlag + contractInput: [ + "75118319212313495155413841331241344325", + 2, + true, + true, + 0, + 0, + "25425363284463910957419549722021124450832239517990785975889689633068548096", + 0, + 1857686340, + 0, + 0, + 0, + 0, + 0, + ], + expectedClaims: [ + "9262742226077652008666528241988983053637", + "0", + "0", + "0", + "34268264483206187164568125440", + "25425363284463910957419549722021124450832239517990785975889689633068548096", + "0", + "0", + ], + }, + { + // merklized index + contractInput: [ + "75118319212313495155413841331241344325", + 2, + true, + true, + 1, + 0, + "25425363284463910957419549722021124450832239517990785975889689633068548096", + 0, + 1857686340, + "93352129123234552352342342353456456452342343456345234121567843345", + 0, + 0, + 0, + 0, + ], + expectedClaims: [ + "20151777967547682839494515679805565820229", + "0", + "93352129123234552352342342353456456452342343456345234121567843345", + "0", + "34268264483206187164568125440", + "25425363284463910957419549722021124450832239517990785975889689633068548096", + "0", + "0", + ], + }, + { + // merklized value + contractInput: [ + "75118319212313495155413841331241344325", + 2, + true, + true, + 2, + 0, + "25425363284463910957419549722021124450832239517990785975889689633068548096", + 0, + 1857686340, + "93352129123234552352342342353456456452342343456345234121567843345", + 0, + 0, + 0, + 0, + ], + expectedClaims: [ + "31040813709017713670322503117622148586821", + "0", + "0", + "0", + "34268264483206187164568125440", + "25425363284463910957419549722021124450832239517990785975889689633068548096", + "93352129123234552352342342353456456452342343456345234121567843345", + "0", + ], + }, + { + // version + contractInput: [ + "75118319212313495155413841331241344325", + 2, + true, + true, + 2, + 89220123, + "25425363284463910957419549722021124450832239517990785975889689633068548096", + 0, + 1857686340, + "93352129123234552352342342353456456452342343456345234121567843345", + 0, + 0, + 0, + 0, + ], + expectedClaims: [ + "130395355847364581104005408845894865439016836786170092869", + "0", + "0", + "0", + "34268264483206187164568125440", + "25425363284463910957419549722021124450832239517990785975889689633068548096", + "93352129123234552352342342353456456452342343456345234121567843345", + "0", + ], + }, + { + // revocation nonce + contractInput: [ + "75118319212313495155413841331241344325", + 2, + true, + true, + 2, + 89220123, + "25425363284463910957419549722021124450832239517990785975889689633068548096", + 3312445, + 1857686340, + "93352129123234552352342342353456456452342343456345234121567843345", + 0, + 0, + 0, + 0, + ], + expectedClaims: [ + "130395355847364581104005408845894865439016836786170092869", + "0", + "0", + "0", + "34268264483206187164571437885", + "25425363284463910957419549722021124450832239517990785975889689633068548096", + "93352129123234552352342342353456456452342343456345234121567843345", + "0", + ], + }, + { + // data slots + contractInput: [ + "75118319212313495155413841331241344325", + 2, + true, + true, + 0, + 89220123, + "25425363284463910957419549722021124450832239517990785975889689633068548096", + 3312445, + 1857686340, + "0", + "16243864111864693853212588481963275789994876191154110553066821559749894481761", + "7078462697308959301666117070269719819629678436794910510259518359026273676830", + "12448278679517811784508557734102986855579744384337338465055621486538311281772", + "9260608685281348956030279125705000716237952776955782848598673606545494194823", + ], + expectedClaims: [ + "130395355847364559325933925905833203783041961153004559685", + "0", + "16243864111864693853212588481963275789994876191154110553066821559749894481761", + "7078462697308959301666117070269719819629678436794910510259518359026273676830", + "34268264483206187164571437885", + "25425363284463910957419549722021124450832239517990785975889689633068548096", + "12448278679517811784508557734102986855579744384337338465055621486538311281772", + "9260608685281348956030279125705000716237952776955782848598673606545494194823", + ], + }, ]; for (let i = 0; i < inputs.length; i++) { - const input = inputs[i]; - const claims = await identity.buildClaim(input.contractInput); - // console.log(claims); - claims.forEach((c, cIndex) => { - expect(c == input.expectedClaims[cIndex]).to.be.true; - }); + const input = inputs[i]; + const claims = await identity.buildClaim(input.contractInput); + // console.log(claims); + claims.forEach((c, cIndex) => { + expect(c == input.expectedClaims[cIndex]).to.be.true; + }); } }); it("validate buildClaim errors", async function () { const inputs = [ - { // idPosition = 0 & id not null - contractInput: ['75118319212313495155413841331241344325', 0, false, false, 0, 0, '8764639037689384765', 0, 0, 0, 0, 0, 0, 0], - expectedErr: 'id should be empty' - }, - { // idPosition = 1 & id null - contractInput: ['75118319212313495155413841331241344325', 1, false, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - expectedErr: 'id should be not empty' - }, - { // idPosition = 2 & id null - contractInput: ['75118319212313495155413841331241344325', 2, false, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - expectedErr: 'id should be not empty' - }, - { // idPosition = 3 - invalid position - contractInput: ['75118319212313495155413841331241344325', 3, false, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - expectedErr: 'invalid id position' - }, - { // expirable = false & expiration date not null - contractInput: ['75118319212313495155413841331241344325', 0, false, false, 0, 0, 0, 0, 89220123, 0, 0, 0, 0, 0], - expectedErr: 'expirationDate should be 0 for non expirable claim' - }, - { // updatable = false & version not null - contractInput: ['75118319212313495155413841331241344325', 0, false, false, 0, 12133, 0, 0, 0, 0, 0, 0, 0, 0], - expectedErr: 'version should be 0 for non updatable claim' - }, - { // merklizedRootPosition = 1 & indx data slot not null - contractInput: ['75118319212313495155413841331241344325', 0, false, false, 1, 0, 0, 0, 0, 0, 1234421, 0, 0, 0], - expectedErr: 'data slots should be empty' - }, - { // merklizedRootPosition = 2 & value data slot not null - contractInput: ['75118319212313495155413841331241344325', 0, false, false, 1, 0, 0, 0, 0, 0, 0, 0, 123445, 0], - expectedErr: 'data slots should be empty' - }, - { // merklizedRootPosition = 0 & merklizedRoot not null - contractInput: ['75118319212313495155413841331241344325', 0, false, false, 0, 0, 0, 0, 0, '972355817823445311', 0, 0, 0, 0], - expectedErr: 'merklizedRoot should be 0 for non merklized claim' - }, + { + // idPosition = 0 & id not null + contractInput: [ + "75118319212313495155413841331241344325", + 0, + false, + false, + 0, + 0, + "8764639037689384765", + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + expectedErr: "IdShouldBeEmpty", + }, + { + // idPosition = 1 & id null + contractInput: [ + "75118319212313495155413841331241344325", + 1, + false, + false, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + expectedErr: "IdShouldBeNotEmpty", + }, + { + // idPosition = 2 & id null + contractInput: [ + "75118319212313495155413841331241344325", + 2, + false, + false, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + expectedErr: "IdShouldBeNotEmpty", + }, + { + // idPosition = 3 - invalid position + contractInput: [ + "75118319212313495155413841331241344325", + 3, + false, + false, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + expectedErr: "InvalidIdPosition", + }, + { + // expirable = false & expiration date not null + contractInput: [ + "75118319212313495155413841331241344325", + 0, + false, + false, + 0, + 0, + 0, + 0, + 89220123, + 0, + 0, + 0, + 0, + 0, + ], + expectedErr: "ExpirationDateShouldBeZeroForNonExpirableClaim", + }, + { + // updatable = false & version not null + contractInput: [ + "75118319212313495155413841331241344325", + 0, + false, + false, + 0, + 12133, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + expectedErr: "VersionShouldBeZeroForNonUpdatableClaim", + }, + { + // merklizedRootPosition = 1 & indx data slot not null + contractInput: [ + "75118319212313495155413841331241344325", + 0, + false, + false, + 1, + 0, + 0, + 0, + 0, + 0, + 1234421, + 0, + 0, + 0, + ], + expectedErr: "DataSlotsShouldBeEmpty", + }, + { + // merklizedRootPosition = 2 & value data slot not null + contractInput: [ + "75118319212313495155413841331241344325", + 0, + false, + false, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 123445, + 0, + ], + expectedErr: "DataSlotsShouldBeEmpty", + }, + { + // merklizedRootPosition = 0 & merklizedRoot not null + contractInput: [ + "75118319212313495155413841331241344325", + 0, + false, + false, + 0, + 0, + 0, + 0, + 0, + "972355817823445311", + 0, + 0, + 0, + 0, + ], + expectedErr: "MerklizedRootShouldBeZeroForNonMerklizedClaim", + }, ]; for (let i = 0; i < inputs.length; i++) { - const input = inputs[i]; - try { - await identity.buildClaim(input.contractInput); - expect.fail('The transaction should have thrown an error'); - } catch (err: any) { - expect(err.message).to.include(input.expectedErr); - } + const input = inputs[i]; + try { + await identity.buildClaim(input.contractInput); + expect.fail("The transaction should have thrown an error"); + } catch (err: any) { + expect(err.message).to.include(input.expectedErr); + } } - }); it("validate buildClaim from file", async function () { - var inputs: any[] = JSON.parse(fs.readFileSync(require.resolve('./vectorsGen/data/claimBuilderData.json'), 'utf-8')) - console.log(inputs.length) + var inputs: any[] = JSON.parse( + fs.readFileSync(require.resolve("./vectorsGen/data/claimBuilderData.json"), "utf-8"), + ); + console.log(inputs.length); for (let i = 0; i < inputs.length; i++) { - const input = inputs[i]; - const claims = await identity.buildClaim(input.contractInput); - claims.forEach((c, cIndex) => { - expect(c == input.expectedClaims[cIndex]).to.be.true; - }); + const input = inputs[i]; + const claims = await identity.buildClaim(input.contractInput); + claims.forEach((c, cIndex) => { + expect(c == input.expectedClaims[cIndex]).to.be.true; + }); } }); - }); diff --git a/test/onchain-identity/onchain-identity.test.ts b/test/onchain-identity/onchain-identity.test.ts index b954f7352..6210caa40 100644 --- a/test/onchain-identity/onchain-identity.test.ts +++ b/test/onchain-identity/onchain-identity.test.ts @@ -626,7 +626,7 @@ describe("Genesis state doens't have history of states", () => { await identity.getRootsByState(latestState); expect.fail("The transaction should have thrown an error"); } catch (err: any) { - expect(err.message).to.include("Roots for this state doesn't exist"); + expect(err.message).to.include("RootsForThisStateDoesntExist"); } }); }); diff --git a/test/primitiveUtils/primitiveUtils.test.ts b/test/primitiveUtils/primitiveUtils.test.ts index 9bad04c65..57817f117 100644 --- a/test/primitiveUtils/primitiveUtils.test.ts +++ b/test/primitiveUtils/primitiveUtils.test.ts @@ -1,6 +1,5 @@ import { DeployHelper } from "../../helpers/DeployHelper"; import { expect } from "chai"; -import { ethers } from "hardhat"; let utilsWrapper; @@ -38,10 +37,9 @@ describe("uint conversions", function () { }); it("invalid challenge (uint256 LE address) must produce error", async () => { - const address = "0x3930000000000000000000000000000000000000"; const uint256 = "5010846606798320903600395684540411235907858077292797642081699116"; await expect(utilsWrapper.uint256LEToAddress(uint256)).to.be.rejectedWith( - "given uint256 is not a representation of an address, 12 most significant bytes should be zero", + "GivenInputNotAnAddressRepresentation(5010846606798320903600395684540411235907858077292797642081699116)", ); }); diff --git a/test/state/state.test.ts b/test/state/state.test.ts index 51e30f987..8d591174a 100644 --- a/test/state/state.test.ts +++ b/test/state/state.test.ts @@ -44,8 +44,9 @@ describe("State transition with real groth16 verifier", () => { const modifiedStateTransition = JSON.parse(JSON.stringify(stateTransitionsWithProofs[0])); modifiedStateTransition.pub_signals[2] = "100"; // change state to make zk proof invalid - await expect(publishState(state, modifiedStateTransition)).to.be.rejectedWith( - "Zero-knowledge proof of state transition is not valid", + await expect(publishState(state, modifiedStateTransition)).to.be.revertedWithCustomError( + state, + "ZeroKnowledgeProofOfStateTransitionIsNotValid", ); }); @@ -136,9 +137,9 @@ describe("State transition negative cases", () => { const modifiedStateTransition = JSON.parse(JSON.stringify(stateTransitionsWithNoProofs[1])); modifiedStateTransition.oldState = 10; - await expect(publishStateWithStubProof(state, modifiedStateTransition)).to.be.rejectedWith( - "Old state does not match the latest state", - ); + await expect( + publishStateWithStubProof(state, modifiedStateTransition), + ).to.be.revertedWithCustomError(state, "OldStateDoesNotMatchTheLatestState"); }); it("Old state is genesis but identity already exists", async () => { @@ -147,36 +148,36 @@ describe("State transition negative cases", () => { const modifiedStateTransition = JSON.parse(JSON.stringify(stateTransitionsWithNoProofs[1])); modifiedStateTransition.isOldStateGenesis = true; - await expect(publishStateWithStubProof(state, modifiedStateTransition)).to.be.rejectedWith( - "Old state is genesis but identity already exists", - ); + await expect( + publishStateWithStubProof(state, modifiedStateTransition), + ).to.be.revertedWithCustomError(state, "OldStateIsGenesisButIdentityAlreadyExists"); }); it("Old state is not genesis but identity does not yet exist", async () => { const modifiedStateTransition = JSON.parse(JSON.stringify(stateTransitionsWithNoProofs[0])); modifiedStateTransition.isOldStateGenesis = false; - await expect(publishStateWithStubProof(state, modifiedStateTransition)).to.be.rejectedWith( - "Old state is not genesis but identity does not yet exist", - ); + await expect( + publishStateWithStubProof(state, modifiedStateTransition), + ).to.be.revertedWithCustomError(state, "OldStateIsNotGenesisButIdentityDoesNotExist"); }); it("ID should not be zero", async () => { const modifiedStateTransition = JSON.parse(JSON.stringify(stateTransitionsWithNoProofs[0])); modifiedStateTransition.id = 0; - await expect(publishStateWithStubProof(state, modifiedStateTransition)).to.be.rejectedWith( - "ID should not be zero", - ); + await expect( + publishStateWithStubProof(state, modifiedStateTransition), + ).to.be.revertedWithCustomError(state, "IdShouldNotBeZero"); }); it("New state should not be zero", async () => { const modifiedStateTransition = JSON.parse(JSON.stringify(stateTransitionsWithNoProofs[0])); modifiedStateTransition.newState = 0; - await expect(publishStateWithStubProof(state, modifiedStateTransition)).to.be.rejectedWith( - "New state should not be zero", - ); + await expect( + publishStateWithStubProof(state, modifiedStateTransition), + ).to.be.revertedWithCustomError(state, "NewStateShouldNotBeZero"); }); it("Should allow only one unique state per identity", async () => { @@ -190,8 +191,9 @@ describe("State transition negative cases", () => { isOldStateGenesis: false, }; - await expect(publishStateWithStubProof(state, stateTransition)).to.be.rejectedWith( - "New state already exists", + await expect(publishStateWithStubProof(state, stateTransition)).to.be.revertedWithCustomError( + state, + "NewStateAlreadyExists", ); }); }); @@ -433,12 +435,14 @@ describe("Check replacedAt timestamp expirations", () => { expect(await state.getGistRootReplacedAt("0x0112", 0)).to.be.equal(0); - await expect(state.getGistRootReplacedAt("0x0112", 10)).to.be.rejectedWith( - "GIST root entry not found", + await expect(state.getGistRootReplacedAt("0x0112", 10)).to.be.revertedWithCustomError( + state, + "GistRootEntryNotFound", ); - await expect(state.getGistRootReplacedAt("0x0212", 10)).to.be.rejectedWith( - "Cross-chain GIST root not found", + await expect(state.getGistRootReplacedAt("0x0212", 10)).to.be.revertedWithCustomError( + state, + "CrossChainGistRootNotFound", ); expect( @@ -453,13 +457,13 @@ describe("Check replacedAt timestamp expirations", () => { BigInt("0xD9C10A0BFB514F30B64E115D7EEB3D547C240C104E03D4548375669FE1201"), 0, ), - ).to.be.rejectedWith("State entry not found"); + ).to.be.revertedWithCustomError(state, "StateEntryNotFound"); await expect( state.getStateReplacedAt( BigInt("0xD9C10A0BFB514F30B64E115D7EEB3D547C240C104E03D4548375669FE1202"), 0, ), - ).to.be.rejectedWith("Cross-chain state not found"); + ).to.be.revertedWithCustomError(state, "CrossChainStateNotFound"); }); }); diff --git a/test/state/stateV2_v3_migration.test.ts b/test/state/stateV2_v3_migration.test.ts deleted file mode 100644 index eae3a7b2a..000000000 --- a/test/state/stateV2_v3_migration.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { expect } from "chai"; -import { ethers, network} from "hardhat"; -import { publishState } from "../utils/state-utils"; -import { DeployHelper } from "../../helpers/DeployHelper"; -import { StateContractMigrationHelper } from "../../helpers/StateContractMigrationHelper"; - -const stateTransitionsWithProofs = [ - require("./data/user_state_genesis_transition.json"), - require("./data/user_state_next_transition.json"), - ]; - - const stateTransitionsWithNoProofs = [ - { - id: '6901746346790563787434755862277025452451108972170386555162524223864832', - oldState: '1099511627776', - newState: '2199023255552', - isOldStateGenesis: true, - }, - { - id: '6901746346790563787434755862277025452451108972170386555162524223864832', - oldState: '2199023255552', - newState: '3298534883328', - isOldStateGenesis: false, - }, - ]; - -describe.skip("Get State old Contract and migrate to latest version", () => { - let guWrpr; - let deployHelper; - let signers; - - before(async function () { - signers = await ethers.getSigners(); - deployHelper = await DeployHelper.initialize(); - guWrpr = await deployHelper.deployGenesisUtilsWrapper(); - }); - - it("Check migration", async () => { - // 1. init old contract by abi & address - const stateContractMigrationHelper = new StateContractMigrationHelper(deployHelper, signers[0]); - const oldContractABI = []; // abi of contract that will be upgraded - const stateContractAddress = ''; // address of contract that will be upgraded - const stateContractInstance = await stateContractMigrationHelper.getInitContract({ - contractNameOrAbi: oldContractABI, - address: stateContractAddress, - }); - - // 2. publish first state - const params1 = await publishState(stateContractInstance, stateTransitionsWithProofs[0]); - const res1 = await stateContractInstance.getStateInfoById(params1.id); - expect(res1.state).to.be.equal(BigInt(params1.newState).toString()); - - // 3. migrate - const { state: stateV3 } = await stateContractMigrationHelper.upgradeContract(stateContractInstance); - - // 4. publish second state - const params2 = await publishState(stateV3, stateTransitionsWithProofs[1]); - const res2 = await stateV3.getStateInfoById(params2.id); - expect(res2.state).to.be.equal(BigInt(params2.newState).toString()); - - // 5. check _defaultIdType is not initialized - await expect(stateV3.getDefaultIdType()).to.be.rejectedWith( - "Default Id Type is not initialized", - ); - // 6. initialize _defaultIdType - const { defaultIdType } = await deployHelper.getDefaultIdType(); - await stateV3.setDefaultIdType(defaultIdType); - const defIdTypeValue = await stateV3.getDefaultIdType(); - expect(defaultIdType).to.be.equal(defIdTypeValue); - - // 7. run new 'transitStateGeneric' method - const onchainId = await guWrpr.calcOnchainIdFromAddress( - defaultIdType, - await signers[0].getAddress(), - ); - await stateV3.transitStateGeneric( - onchainId, - stateTransitionsWithNoProofs[0].oldState, - stateTransitionsWithNoProofs[0].newState, - stateTransitionsWithNoProofs[0].isOldStateGenesis, - 1, - [] - ); - - const res3 = await stateV3.getStateInfoById(onchainId); - expect(res3.state).to.be.equal(bigInt(stateTransitionsWithNoProofs[0].newState).toString()); - - }); -}); diff --git a/test/stateLib/stateLib.test.ts b/test/stateLib/stateLib.test.ts index d23cc8f79..0e48123cf 100644 --- a/test/stateLib/stateLib.test.ts +++ b/test/stateLib/stateLib.test.ts @@ -27,24 +27,24 @@ describe("Negative tests", function () { it("getStateInfoByID: should be reverted if identity does not exist", async () => { const missingID = 777; - await expect(stateLibWrpr.getStateInfoById(missingID)).to.be.revertedWith( - "Identity does not exist", + await expect(stateLibWrpr.getStateInfoById(missingID)).to.be.rejectedWith( + "IdentityDoesNotExist()", ); }); it("getStateInfoHistoryById: should be reverted if identity does not exist", async () => { const missingID = 777; - await expect(stateLibWrpr.getStateInfoHistoryById(missingID, 0, 1)).to.be.revertedWith( - "Identity does not exist", + await expect(stateLibWrpr.getStateInfoHistoryById(missingID, 0, 1)).to.be.rejectedWith( + "IdentityDoesNotExist()", ); }); it("getStateInfoHistoryLengthById: should be reverted if identity does not exist", async () => { const missingID = 777; - await expect(stateLibWrpr.getStateInfoHistoryLengthById(missingID)).to.be.revertedWith( - "Identity does not exist", + await expect(stateLibWrpr.getStateInfoHistoryLengthById(missingID)).to.be.rejectedWith( + "IdentityDoesNotExist()", ); }); @@ -52,21 +52,17 @@ describe("Negative tests", function () { const id = id1Inputs[0].id; const missingState = 888; - await expect(stateLibWrpr.getStateInfoByIdAndState(id, missingState)).to.be.revertedWith( - "State does not exist", + await expect(stateLibWrpr.getStateInfoByIdAndState(id, missingState)).to.be.rejectedWith( + "StateDoesNotExist()", ); }); it("Zero timestamp and block should be only in the first identity state", async () => { await expect(stateLibWrpr.addGenesisState(2, 20)).to.be.not.reverted; - await expect(stateLibWrpr.addGenesisState(2, 20)).to.be.revertedWith( - "Zero timestamp and block should be only in the first identity state", - ); + await expect(stateLibWrpr.addGenesisState(2, 20)).to.be.rejectedWith("IdentityAlreadyExists()"); await expect(stateLibWrpr.addState(3, 30)).to.be.not.reverted; - await expect(stateLibWrpr.addGenesisState(3, 30)).to.be.revertedWith( - "Zero timestamp and block should be only in the first identity state", - ); + await expect(stateLibWrpr.addGenesisState(3, 30)).to.be.rejectedWith("IdentityAlreadyExists()"); }); }); @@ -117,13 +113,13 @@ describe("StateInfo history", function () { }); it("should be reverted if length is zero", async () => { - await expect(stateLibWrpr.getStateInfoHistoryById(id1, 0, 0)).to.be.revertedWith( + await expect(stateLibWrpr.getStateInfoHistoryById(id1, 0, 0)).to.be.rejectedWith( "Length should be greater than 0", ); }); it("should be reverted if length limit exceeded", async () => { - await expect(stateLibWrpr.getStateInfoHistoryById(id1, 0, 10 ** 6)).to.be.revertedWith( + await expect(stateLibWrpr.getStateInfoHistoryById(id1, 0, 10 ** 6)).to.be.rejectedWith( "Length limit exceeded", ); }); @@ -131,7 +127,7 @@ describe("StateInfo history", function () { it("should be reverted if startIndex is out of bounds", async () => { await expect( stateLibWrpr.getStateInfoHistoryById(id1, id1HistoryLength, 100), - ).to.be.revertedWith("Start index out of bounds"); + ).to.be.rejectedWith("Start index out of bounds"); }); it("should not revert if startIndex + length >= historyLength", async () => { @@ -262,7 +258,7 @@ describe("State history duplicates", function () { await stateLibWrpr.addState(id, state); await expect( stateLibWrpr.getStateInfoListByIdAndState(id, state, 0, 10 ** 6), - ).to.be.revertedWith("Length limit exceeded"); + ).to.be.rejectedWith("Length limit exceeded"); }); it("should revert if out of bounds", async () => { @@ -271,7 +267,7 @@ describe("State history duplicates", function () { await stateLibWrpr.addState(id, state); await stateLibWrpr.addState(id, state); await stateLibWrpr.addState(id, state); - await expect(stateLibWrpr.getStateInfoListByIdAndState(id, state, 3, 100)).to.be.revertedWith( + await expect(stateLibWrpr.getStateInfoListByIdAndState(id, state, 3, 100)).to.be.rejectedWith( "Start index out of bounds", ); diff --git a/test/utils/id-calculation-utils.ts b/test/utils/id-calculation-utils.ts new file mode 100644 index 000000000..73559eaa4 --- /dev/null +++ b/test/utils/id-calculation-utils.ts @@ -0,0 +1,31 @@ +import { ethers } from "hardhat"; + +export function calculateGroupID(requestIds: bigint[]): bigint { + const types = Array(requestIds.length).fill("uint256"); + + const groupID = + BigInt(ethers.keccak256(ethers.solidityPacked(types, requestIds))) & + BigInt("0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + + return groupID; +} + +export function calculateRequestID(params: string, address: string): bigint { + const requestId = + (BigInt(ethers.keccak256(ethers.solidityPacked(["bytes", "address"], [params, address]))) & + BigInt("0x0000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")) + + BigInt("0x0001000000000000000000000000000000000000000000000000000000000000"); + return requestId; +} + +export function calculateMultiRequestId( + requestIds: bigint[], + groupIds: bigint[], + sender: string, +): bigint { + return BigInt( + ethers.keccak256( + ethers.solidityPacked(["uint256[]", "uint256[]", "address"], [requestIds, groupIds, sender]), + ), + ); +} diff --git a/test/utils/validator-pack-utils.ts b/test/utils/validator-pack-utils.ts index 68cde7af3..900c6386c 100644 --- a/test/utils/validator-pack-utils.ts +++ b/test/utils/validator-pack-utils.ts @@ -15,7 +15,7 @@ export function packValidatorParams(query: any, allowedIssuers: any[] = []): str "uint256[] allowedIssuers," + "string[] circuitIds," + "bool skipClaimRevocationCheck," + - "uint256 claimPathNotExists" + + "uint256 claimPathNotExists," + ")", ], [ @@ -31,7 +31,7 @@ export function packValidatorParams(query: any, allowedIssuers: any[] = []): str skipClaimRevocationCheck: query.skipClaimRevocationCheck, claimPathNotExists: query.claimPathNotExists, }, - ] + ], ); } @@ -70,6 +70,35 @@ export function packV3ValidatorParams(query: any, allowedIssuers: any[] = []): s proofType: query.proofType, verifierID: query.verifierID, }, - ] + ], + ); +} + +export function packLinkedMultiQueryValidatorParams(query: any): string { + return abiCoder.encode( + [ + "tuple(" + + "uint256[] claimPathKey," + + "uint256[] operator," + + "uint256[] slotIndex," + + "uint256[][] value," + + "uint256[] queryHash," + + "string[] circuitIds," + + "uint256 groupID," + + "uint256 verifierID," + + ")", + ], + [ + { + claimPathKey: query.claimPathKey, + operator: query.operator, + slotIndex: query.slotIndex, + value: query.value, + queryHash: query.queryHash, + circuitIds: query.circuitIds, + groupID: query.groupID, + verifierID: query.verifierID, + }, + ], ); } diff --git a/test/validators/authv2/index.ts b/test/validators/authv2/index.ts new file mode 100644 index 000000000..091f99c9f --- /dev/null +++ b/test/validators/authv2/index.ts @@ -0,0 +1,113 @@ +import { expect } from "chai"; +import { prepareInputs, publishState } from "../../utils/state-utils"; +import { DeployHelper } from "../../../helpers/DeployHelper"; +import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; +import { packZKProof } from "../../utils/packData"; +import { time } from "@nomicfoundation/hardhat-network-helpers"; +import { contractsInfo } from "../../../helpers/constants"; + +const testCases: any[] = [ + { + name: "Validate AuthV2", + sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + stateTransitions: [ + require("../common-data/issuer_from_genesis_state_to_first_transition_v3.json"), + ], + userID: 23273167900576580892722615617815475823351560716009055944677723144398443009n, + }, + { + name: "Validation of Gist root not found", + sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + stateTransitions: [ + require("../common-data/issuer_from_genesis_state_to_first_transition_v3.json"), + ], + userID: 23273167900576580892722615617815475823351560716009055944677723144398443009n, + gistRoot: 2n, + errorMessage: "GistRootEntryNotFound()", + }, +]; + +describe("Auth V2 Validator", function () { + let state: any, authV2validator; + + async function deployContractsFixture() { + const deployHelper = await DeployHelper.initialize(null, true); + + const { state: stateContract } = await deployHelper.deployStateWithLibraries(["0x0212"]); + + const verifierStub = await deployHelper.deployGroth16VerifierValidatorStub(); + + const contracts = await deployHelper.deployValidatorContractsWithVerifiers( + "authV2", + await stateContract.getAddress(), + "basic", + await verifierStub.getAddress(), + ); + const validator = contracts.validator; + + return { + stateContract, + validator, + }; + } + + beforeEach(async () => { + ({ stateContract: state, validator: authV2validator } = + await loadFixture(deployContractsFixture)); + }); + + for (const test of testCases) { + it(test.name, async function () { + this.timeout(50000); + + for (let i = 0; i < test.stateTransitions.length; i++) { + if (test.stateTransitionDelayMs) { + await time.increase(test.stateTransitionDelayMs); + } + await publishState(state, test.stateTransitions[i]); + } + + const challenge = + test.challenge || "0x0000000000000000000000000000000000000000000000000000000000000001"; + + const proof = { + pub_signals: [test.userID, challenge, test.gistRoot || "0"], + proof: { + pi_a: ["0", "0", "0"], + pi_b: [ + ["0", "0"], + ["0", "0"], + ["0", "0"], + ], + pi_c: ["0", "0", "0"], + protocol: "groth16", + curve: "bn128", + }, + }; + + const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proof); + + const data = "0x00"; + + // Check verify function + const zkProof = packZKProof(inputs, pi_a, pi_b, pi_c); + + if (test.errorMessage) { + await expect(authV2validator.verify(test.sender, zkProof, data)).to.be.rejectedWith( + test.errorMessage, + ); + } else if (test.errorMessage === "") { + await expect(authV2validator.verify(test.sender, zkProof, data)).to.be.reverted; + } else { + const result = await authV2validator.verify(test.sender, zkProof, data); + + expect(result[0]).to.be.equal(test.userID); + } + }); + } + + it("check version", async () => { + const version = await authV2validator.version(); + expect(version).to.be.equal(contractsInfo.VALIDATOR_AUTH_V2.version); + }); +}); diff --git a/test/validators/eth-identity/index.ts b/test/validators/eth-identity/index.ts new file mode 100644 index 000000000..76ae23601 --- /dev/null +++ b/test/validators/eth-identity/index.ts @@ -0,0 +1,34 @@ +import { DeployHelper } from "../../../helpers/DeployHelper"; +import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; +import { ethers } from "hardhat"; +import { expect } from "chai"; + +describe("Eth Identity Validator", function () { + let validator: any; + + async function deployContractsFixture() { + const deployHelper = await DeployHelper.initialize(null, true); + const { state: stateContract } = await deployHelper.deployStateWithLibraries(["0x0212"]); + const stateContractAddress = await stateContract.getAddress(); + ({ validator } = await deployHelper.deployValidatorContracts( + "ethIdentity", + stateContractAddress, + )); + } + + before(async () => { + await loadFixture(deployContractsFixture); + }); + + it("should deploy EthIdentityValidator contract", async function () { + const sender = "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266"; + const userId = "0xd056622b9ffcf797282b86acef4f688ad1ae5d69ff3000000000000001201"; + + const encoder = new ethers.AbiCoder(); + const proof = encoder.encode(["uint256"], [userId]); + + const result = await validator.verify(sender, proof, "0x"); + expect(result[0]).to.equal(userId); + expect(result[1].length).to.equal(0); + }); +}); diff --git a/test/validators/linked-multi-query/linked-multi-query.test.ts b/test/validators/linked-multi-query/linked-multi-query.test.ts new file mode 100644 index 000000000..6c54b985c --- /dev/null +++ b/test/validators/linked-multi-query/linked-multi-query.test.ts @@ -0,0 +1,210 @@ +import { ethers, upgrades } from "hardhat"; +import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; +import { packZKProof } from "../../utils/packData"; +import { packLinkedMultiQueryValidatorParams } from "../../utils/validator-pack-utils"; +import { expect } from "chai"; +import { contractsInfo } from "../../../helpers/constants"; + +describe("Test linkedMultiQuery10.circom", function () { + let validator, groth16Verifier; + let signer; + + const linkId = "1"; + const merklized = "1"; + const operator1 = "1"; + const operator2 = "16"; + const operatorOutput1 = "0"; + const operatorOutput2 = "777"; + const queryHash1 = "100"; + const queryHash2 = "200"; + + const dummyZKProof = [ + ["0", "0"], + [ + ["0", "0"], + ["0", "0"], + ], + ["0", "0"], + ]; + + const proofForOneQuery = packZKProof( + [linkId, merklized] + .concat([operatorOutput1, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + .concat([queryHash1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + ...dummyZKProof, + ); + + const proofForTwoQueries = packZKProof( + [linkId, merklized] + .concat([operatorOutput1, operatorOutput2, 0, 0, 0, 0, 0, 0, 0, 0]) + .concat([queryHash1, queryHash2, 0, 0, 0, 0, 0, 0, 0, 0]), + ...dummyZKProof, + ); + + const oneQuery = { + claimPathKey: [0, 0], + operator: [operator1], + slotIndex: [0, 0], + value: [ + [0, 0], + [0, 0], + ], + queryHash: [queryHash1], + circuitIds: ["linkedMultiQuery10-beta.1"], + groupID: 1, + verifierID: 1, + }; + + const oneQueryParams = packLinkedMultiQueryValidatorParams(oneQuery); + + const twoQueries = { + claimPathKey: [0, 0], + operator: [operator1, operator2], + slotIndex: [0, 0], + value: [ + [0, 0], + [0, 0], + ], + queryHash: [queryHash1, queryHash2], + circuitIds: ["linkedMultiQuery10-beta.1"], + groupID: 1, + verifierID: 1, + }; + + const twoQueriesParams = packLinkedMultiQueryValidatorParams(twoQueries); + + async function deployContractsFixture() { + [signer] = await ethers.getSigners(); + const groth16Verifier = await ethers.deployContract("Groth16VerifierValidatorStub"); + const lmqValidator = await ethers.getContractFactory("LinkedMultiQueryValidator"); + const g16address = await groth16Verifier.getAddress(); + const validator = await upgrades.deployProxy(lmqValidator, [g16address, signer.address]); + return { validator, groth16Verifier }; + } + + beforeEach(async () => { + ({ validator, groth16Verifier } = await loadFixture(deployContractsFixture)); + }); + + it("Should verify", async function () { + const result = await validator.verify( + signer.address, + proofForTwoQueries, + twoQueriesParams, + "0x", + ); + expect(result).to.deep.equal([ + ["linkID", linkId, "0x"], + ["operatorOutput_1", 777n, "0x"], + ]); + + // have more than one operator output + }); + + it("Should throw if circuitId is not linkedMultiQuery10-beta.1", async function () { + const params = packLinkedMultiQueryValidatorParams({ + ...oneQuery, + circuitIds: ["someWrongCircuitId"], + }); + + await expect(validator.verify(signer.address, proofForOneQuery, params, "0x")) + .to.be.revertedWithCustomError(validator, "WrongCircuitID") + .withArgs("someWrongCircuitId"); + }); + + it("More than 10 queries in request params should throw", async function () { + const params = packLinkedMultiQueryValidatorParams({ + ...oneQuery, + queryHash: Array(11).fill(queryHash1), + }); + + await expect(validator.verify(signer.address, proofForOneQuery, params, "0x")) + .to.be.revertedWithCustomError(validator, "TooManyQueries") + .withArgs(11); + }); + + it("Should throw if wrong query hash", async function () { + const params = packLinkedMultiQueryValidatorParams({ + ...oneQuery, + queryHash: [queryHash2], + }); + + await expect(validator.verify(signer.address, proofForOneQuery, params, "0x")) + .to.be.revertedWithCustomError(validator, "InvalidQueryHash") + .withArgs(queryHash2, queryHash1); + }); + + it("Should throw if groupID or linkID is 0", async function () { + const paramsWithZeroGroupID = packLinkedMultiQueryValidatorParams({ + ...oneQuery, + groupID: 0, + }); + + await expect( + validator.verify(signer.address, proofForOneQuery, paramsWithZeroGroupID, "0x"), + ).to.be.revertedWithCustomError(validator, "GroupIDCannotBeZero"); + + const proofForOneQueryWithZeroLinkID = packZKProof( + [0, merklized] + .concat([operatorOutput1, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + .concat([queryHash1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + ...dummyZKProof, + ); + + await expect( + validator.verify(signer.address, proofForOneQueryWithZeroLinkID, oneQueryParams, "0x"), + ).to.be.revertedWithCustomError(validator, "LinkIDCannotBeZero"); + }); + + it("getRequestParam should return the correct values", async function () { + let resultParam = await validator.getRequestParam(oneQueryParams, "groupID"); + expect(resultParam).to.deep.equal(["groupID", oneQuery.groupID]); + resultParam = await validator.getRequestParam(oneQueryParams, "verifierID"); + expect(resultParam).to.deep.equal(["verifierID", oneQuery.verifierID]); + resultParam = await validator.getRequestParam(oneQueryParams, "nullifierSessionID"); + expect(resultParam).to.deep.equal(["nullifierSessionID", 0]); + }); + + it("Should throw if failed ZK verification", async function () { + await groth16Verifier.stub_setVerifyResult(false); + + await expect( + validator.verify(signer.address, proofForOneQuery, oneQueryParams, "0x"), + ).to.be.revertedWithCustomError(validator, "InvalidGroth16Proof"); + }); + + it("Contract version should be 1.0.0-beta.1", async function () { + expect(await validator.VERSION()).to.equal("1.0.0-beta.1"); + expect(await validator.version()).to.equal("1.0.0-beta.1"); + }); + + it("check version", async () => { + const version = await validator.version(); + expect(version).to.be.equal(contractsInfo.VALIDATOR_LINKED_MULTI_QUERY.version); + }); + + it("check getRequestParam", async () => { + const query: any = { + claimPathKey: [1, 2], + operator: [2, 3], + slotIndex: [0], + value: [ + [20020101, ...new Array(63).fill(0)], + [20030101, ...new Array(63).fill(0)], + ], + queryHash: [3, 4], + circuitIds: ["circuitName"], + groupID: 4, + verifierID: 5, + }; + + const params = packLinkedMultiQueryValidatorParams(query); + + let resultParam = await validator.getRequestParam(params, "groupID"); + expect(resultParam).to.deep.equal(["groupID", 4]); + resultParam = await validator.getRequestParam(params, "verifierID"); + expect(resultParam).to.deep.equal(["verifierID", 5]); + resultParam = await validator.getRequestParam(params, "nullifierSessionID"); + expect(resultParam).to.deep.equal(["nullifierSessionID", 0]); + }); +}); diff --git a/test/validators/mtp/index.ts b/test/validators/mtp/index.ts index 4e341f8ef..5ba9ed368 100644 --- a/test/validators/mtp/index.ts +++ b/test/validators/mtp/index.ts @@ -5,8 +5,9 @@ import { packValidatorParams } from "../../utils/validator-pack-utils"; import { CircuitId } from "@0xpolygonid/js-sdk"; import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; import { time } from "@nomicfoundation/hardhat-network-helpers"; -import { TEN_YEARS } from "../../../helpers/constants"; +import { contractsInfo, TEN_YEARS } from "../../../helpers/constants"; import { packZKProof } from "../../utils/packData"; +import { ethers } from "hardhat"; const tenYears = TEN_YEARS; const testCases: any[] = [ @@ -86,7 +87,7 @@ const testCases: any[] = [ stateTransitionDelayMs: 2000, // [1....][2....][3....][4....] - each block is 2 seconds long proofJson: require("./data/valid_mtp_user_non_genesis.json"), setRevStateExpiration: 3, // [1....][2....][3..*.][4....] <-- (*) - marks where the expiration threshold is - errorMessage: "Non-Revocation state of Issuer expired", + errorMessage: "NonRevocationStateOfIssuerIsExpired()", setProofExpiration: tenYears, }, { @@ -100,7 +101,7 @@ const testCases: any[] = [ stateTransitionDelayMs: 2000, // [1....][2....][3....][4....] - each block is 2 seconds long proofJson: require("./data/valid_mtp_user_non_genesis.json"), // generated on step 2 setGISTRootExpiration: 3, // [1....][2....][3..*.][4....] <-- (*) - marks where the expiration threshold is - errorMessage: "Gist root is expired", + errorMessage: "GistRootIsExpired()", setProofExpiration: tenYears, }, { @@ -111,7 +112,7 @@ const testCases: any[] = [ require("../common-data/issuer_next_state_transition.json"), ], proofJson: require("./data/valid_mtp_user_non_genesis.json"), - errorMessage: "Generated proof is outdated", + errorMessage: "GeneratedProofIsOutdated()", }, { name: "Validate Genesis User State. Issuer Claim IdenState is in Chain. Revocation State is in Chain", @@ -119,7 +120,7 @@ const testCases: any[] = [ proofJson: require("./data/valid_mtp_user_genesis.json"), setProofExpiration: tenYears, allowedIssuers: [123n], - errorMessage: "Issuer is not on the Allowed Issuers list", + errorMessage: "IssuerIsNotOnTheAllowedIssuersList()", }, ]; @@ -206,39 +207,15 @@ describe("Atomic MTP Validator", function () { const data = packValidatorParams(query, test.allowedIssuers); // Check verify function - if (test.errorMessage) { - await expect( - mtpValidator.verify(inputs, pi_a, pi_b, pi_c, data, senderAddress), - ).to.be.rejectedWith(test.errorMessage); - } else if (test.errorMessage === "") { - await expect(mtpValidator.verify(inputs, pi_a, pi_b, pi_c, data, senderAddress)).to.be - .reverted; - } else { - const signals = await mtpValidator.verify(inputs, pi_a, pi_b, pi_c, data, senderAddress); - const signalValues: any[] = []; - // Replace index with value to check instead of signal index - for (let i = 0; i < signals.length; i++) { - signalValues.push([signals[i][0], inputs[signals[i][1]]]); - } - checkSignals(signalValues, test.signalValues); - } - - // Check verifyV2 function const zkProof = packZKProof(inputs, pi_a, pi_b, pi_c); if (test.errorMessage) { - await expect( - mtpValidator.verifyV2(zkProof, data, senderAddress, await state.getAddress()), - ).to.be.rejectedWith(test.errorMessage); + await expect(mtpValidator.verify(senderAddress, zkProof, data, "0x")).to.be.rejectedWith( + test.errorMessage, + ); } else if (test.errorMessage === "") { - await expect(mtpValidator.verifyV2(zkProof, data, senderAddress, await state.getAddress())) - .to.be.reverted; + await expect(mtpValidator.verify(senderAddress, zkProof, data, "0x")).to.be.reverted; } else { - const signals = await mtpValidator.verifyV2( - zkProof, - data, - senderAddress, - await state.getAddress(), - ); + const signals = await mtpValidator.verify(senderAddress, zkProof, data, "0x"); checkSignals(signals, test.signalValues); } }); @@ -248,4 +225,50 @@ describe("Atomic MTP Validator", function () { const challengeIndx = await mtpValidator.inputIndexOf("challenge"); expect(challengeIndx).to.be.equal(4); }); + + it("check version", async () => { + const version = await mtpValidator.version(); + expect(version).to.be.equal(contractsInfo.VALIDATOR_MTP.version); + }); + + it("check getRequestParam", async () => { + const query: any = { + requestId: 1, + schema: 2, + claimPathKey: 3, + operator: 4, + slotIndex: 0, + queryHash: 5, + value: [20020101, ...new Array(63).fill(0)], // for operators 1-3 only first value matters + circuitIds: ["circuitName"], + skipClaimRevocationCheck: false, + claimPathNotExists: 0, + }; + + const params = packValidatorParams(query); + + let resultParam = await mtpValidator.getRequestParam(params, "groupID"); + expect(resultParam).to.deep.equal(["groupID", 0]); + resultParam = await mtpValidator.getRequestParam(params, "verifierID"); + expect(resultParam).to.deep.equal(["verifierID", 0]); + resultParam = await mtpValidator.getRequestParam(params, "nullifierSessionID"); + expect(resultParam).to.deep.equal(["nullifierSessionID", 0]); + }); + + it("Test get config params", async () => { + const oneHour = 3600; + const expirationTimeout = await mtpValidator.getProofExpirationTimeout(); + const revocationStateExpirationTimeout = + await mtpValidator.getRevocationStateExpirationTimeout(); + const gistRootExpirationTimeout = await mtpValidator.getGISTRootExpirationTimeout(); + expect(expirationTimeout).to.be.equal(oneHour); + expect(revocationStateExpirationTimeout).to.be.equal(oneHour); + expect(gistRootExpirationTimeout).to.be.equal(oneHour); + }); + + it("Test supported circuits", async () => { + const supportedCircuitIds = await mtpValidator.getSupportedCircuitIds(); + expect(supportedCircuitIds.length).to.be.equal(1); + expect(supportedCircuitIds[0]).to.be.equal(CircuitId.AtomicQueryMTPV2OnChain); + }); }); diff --git a/test/validators/sig/index.ts b/test/validators/sig/index.ts index 08d83bdf1..052471507 100644 --- a/test/validators/sig/index.ts +++ b/test/validators/sig/index.ts @@ -5,8 +5,9 @@ import { packValidatorParams } from "../../utils/validator-pack-utils"; import { CircuitId } from "@0xpolygonid/js-sdk"; import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; import { time } from "@nomicfoundation/hardhat-network-helpers"; -import { TEN_YEARS } from "../../../helpers/constants"; +import { contractsInfo, TEN_YEARS } from "../../../helpers/constants"; import { packZKProof } from "../../utils/packData"; +import { ethers } from "hardhat"; const tenYears = TEN_YEARS; const testCases: any[] = [ @@ -86,7 +87,7 @@ const testCases: any[] = [ stateTransitionDelayMs: 2000, // [1....][2....][3....][4....] - each block is 2 seconds long proofJson: require("./data/valid_sig_user_non_genesis.json"), setRevStateExpiration: 3, // [1....][2....][3..*.][4....] <-- (*) - marks where the expiration threshold is - errorMessage: "Non-Revocation state of Issuer expired", + errorMessage: "NonRevocationStateOfIssuerIsExpired()", setProofExpiration: tenYears, }, { @@ -100,7 +101,7 @@ const testCases: any[] = [ stateTransitionDelayMs: 2000, // [1....][2....][3....][4....] - each block is 2 seconds long proofJson: require("./data/valid_sig_user_non_genesis.json"), // generated on step 2 setGISTRootExpiration: 3, // [1....][2....][3..*.][4....] <-- (*) - marks where the expiration threshold is - errorMessage: "Gist root is expired", + errorMessage: "GistRootIsExpired()", setProofExpiration: tenYears, }, { @@ -111,7 +112,7 @@ const testCases: any[] = [ require("../common-data/issuer_next_state_transition.json"), ], proofJson: require("./data/valid_sig_user_non_genesis.json"), - errorMessage: "Generated proof is outdated", + errorMessage: "GeneratedProofIsOutdated()", }, { name: "Validate Genesis User State. Issuer Claim IdenState is in Chain. Revocation State is in Chain", @@ -119,7 +120,7 @@ const testCases: any[] = [ proofJson: require("./data/valid_sig_user_genesis.json"), setProofExpiration: tenYears, allowedIssuers: [123n], - errorMessage: "Issuer is not on the Allowed Issuers list", + errorMessage: "IssuerIsNotOnTheAllowedIssuersList()", }, ]; @@ -202,39 +203,15 @@ describe("Atomic Sig Validator", function () { const data = packValidatorParams(query, test.allowedIssuers); // Check verify function - if (test.errorMessage) { - await expect( - sigValidator.verify(inputs, pi_a, pi_b, pi_c, data, senderAddress), - ).to.be.rejectedWith(test.errorMessage); - } else if (test.errorMessage === "") { - await expect(sigValidator.verify(inputs, pi_a, pi_b, pi_c, data, senderAddress)).to.be - .reverted; - } else { - const signals = await sigValidator.verify(inputs, pi_a, pi_b, pi_c, data, senderAddress); - const signalValues: any[] = []; - // Replace index with value to check instead of signal index - for (let i = 0; i < signals.length; i++) { - signalValues.push([signals[i][0], inputs[signals[i][1]]]); - } - checkSignals(signalValues, test.signalValues); - } - - // Check verifyV2 function const zkProof = packZKProof(inputs, pi_a, pi_b, pi_c); if (test.errorMessage) { - await expect( - sigValidator.verifyV2(zkProof, data, senderAddress, await state.getAddress()), - ).to.be.rejectedWith(test.errorMessage); + await expect(sigValidator.verify(senderAddress, zkProof, data, "0x")).to.be.rejectedWith( + test.errorMessage, + ); } else if (test.errorMessage === "") { - await expect(sigValidator.verifyV2(zkProof, data, senderAddress, await state.getAddress())) - .to.be.reverted; + await expect(sigValidator.verify(senderAddress, zkProof, data, "0x")).to.be.reverted; } else { - const signals = await sigValidator.verifyV2( - zkProof, - data, - senderAddress, - await state.getAddress(), - ); + const signals = await sigValidator.verify(senderAddress, zkProof, data, "0x"); checkSignals(signals, test.signalValues); } }); @@ -244,4 +221,49 @@ describe("Atomic Sig Validator", function () { const challengeIndx = await sigValidator.inputIndexOf("challenge"); expect(challengeIndx).to.be.equal(5); }); + + it("check version", async () => { + const version = await sigValidator.version(); + expect(version).to.be.equal(contractsInfo.VALIDATOR_SIG.version); + }); + + it("check getRequestParam", async () => { + const query: any = { + requestId: 1, + schema: 2, + claimPathKey: 3, + operator: 4, + slotIndex: 0, + queryHash: 5, + value: [20020101, ...new Array(63).fill(0)], // for operators 1-3 only first value matters + circuitIds: ["circuitName"], + skipClaimRevocationCheck: false, + claimPathNotExists: 0, + }; + + const params = packValidatorParams(query); + let resultParam = await sigValidator.getRequestParam(params, "groupID"); + expect(resultParam).to.deep.equal(["groupID", 0]); + resultParam = await sigValidator.getRequestParam(params, "verifierID"); + expect(resultParam).to.deep.equal(["verifierID", 0]); + resultParam = await sigValidator.getRequestParam(params, "nullifierSessionID"); + expect(resultParam).to.deep.equal(["nullifierSessionID", 0]); + }); + + it("Test get config params", async () => { + const oneHour = 3600; + const expirationTimeout = await sigValidator.getProofExpirationTimeout(); + const revocationStateExpirationTimeout = + await sigValidator.getRevocationStateExpirationTimeout(); + const gistRootExpirationTimeout = await sigValidator.getGISTRootExpirationTimeout(); + expect(expirationTimeout).to.be.equal(oneHour); + expect(revocationStateExpirationTimeout).to.be.equal(oneHour); + expect(gistRootExpirationTimeout).to.be.equal(oneHour); + }); + + it("Test supported circuits", async () => { + const supportedCircuitIds = await sigValidator.getSupportedCircuitIds(); + expect(supportedCircuitIds.length).to.be.equal(1); + expect(supportedCircuitIds[0]).to.be.equal(CircuitId.AtomicQuerySigV2OnChain); + }); }); diff --git a/test/validators/v3/index.ts b/test/validators/v3/index.ts index 1d7f39a26..870c9b5b2 100644 --- a/test/validators/v3/index.ts +++ b/test/validators/v3/index.ts @@ -6,8 +6,9 @@ import { calculateQueryHashV3 } from "../../utils/query-hash-utils"; import { CircuitId } from "@0xpolygonid/js-sdk"; import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; import { time } from "@nomicfoundation/hardhat-network-helpers"; -import { TEN_YEARS } from "../../../helpers/constants"; +import { contractsInfo, TEN_YEARS } from "../../../helpers/constants"; import { packZKProof } from "../../utils/packData"; +import { ethers } from "hardhat"; const tenYears = TEN_YEARS; const testCases: any[] = [ @@ -45,7 +46,7 @@ const testCases: any[] = [ require("../common-data/issuer_from_genesis_state_to_first_transition_v3.json"), ], proofJson: require("./data/invalid_bjj_user_genesis_v3.json"), - errorMessage: "Proof is not valid", + errorMessage: "ProofIsNotValid()", setProofExpiration: tenYears, sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", }, @@ -120,7 +121,7 @@ const testCases: any[] = [ stateTransitionDelayMs: 2000, // [1....][2....][3....][4....] - each block is 2 seconds long proofJson: require("./data/valid_bjj_user_second_issuer_first_v3"), setRevStateExpiration: 3, // [1....][2....][3..*.][4....] <-- (*) - marks where the expiration threshold is - errorMessage: "Non-Revocation state of Issuer expired", + errorMessage: "NonRevocationStateOfIssuerIsExpired()", setProofExpiration: tenYears, sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", }, @@ -136,7 +137,7 @@ const testCases: any[] = [ stateTransitionDelayMs: 2000, // [1....][2....][3....][4....] - each block is 2 seconds long setGISTRootExpiration: 3, // [1....][2....][3..*.][4....] <-- (*) - marks where the expiration threshold is - errorMessage: "Gist root is expired", + errorMessage: "GistRootIsExpired()", setProofExpiration: tenYears, sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", }, @@ -148,7 +149,7 @@ const testCases: any[] = [ require("../common-data/issuer_from_first_state_to_second_transition_v3.json"), ], proofJson: require("./data/valid_bjj_user_first_v3.json"), - errorMessage: "Generated proof is outdated", + errorMessage: "GeneratedProofIsOutdated()", sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", }, { @@ -159,7 +160,7 @@ const testCases: any[] = [ proofJson: require("./data/valid_bjj_user_genesis_v3.json"), setProofExpiration: tenYears, allowedIssuers: [123n], - errorMessage: "Issuer is not on the Allowed Issuers list", + errorMessage: "IssuerIsNotOnTheAllowedIssuersList()", sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", }, { @@ -227,7 +228,7 @@ const testCases: any[] = [ require("../common-data/issuer_from_genesis_state_to_first_transition_v3.json"), ], proofJson: require("./data/invalid_mtp_user_genesis_v3.json"), - errorMessage: "Proof is not valid", + errorMessage: "ProofIsNotValid()", setProofExpiration: tenYears, isMtpProof: true, sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", @@ -304,7 +305,7 @@ const testCases: any[] = [ stateTransitionDelayMs: 2000, // [1....][2....][3....][4....] - each block is 2 seconds long proofJson: require("./data/valid_mtp_user_second_issuer_first_v3.json"), setRevStateExpiration: 3, // [1....][2....][3..*.][4....] <-- (*) - marks where the expiration threshold is - errorMessage: "Non-Revocation state of Issuer expired", + errorMessage: "NonRevocationStateOfIssuerIsExpired()", setProofExpiration: tenYears, isMtpProof: true, sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", @@ -320,7 +321,7 @@ const testCases: any[] = [ proofJson: require("./data/valid_mtp_user_first_v3"), stateTransitionDelayMs: 2000, // [1....][2....][3....][4....] - each block is 2 seconds long setGISTRootExpiration: 3, // [1....][2....][3..*.][4....] <-- (*) - marks where the expiration threshold is - errorMessage: "Gist root is expired", + errorMessage: "GistRootIsExpired()", setProofExpiration: tenYears, isMtpProof: true, sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", @@ -333,7 +334,7 @@ const testCases: any[] = [ require("../common-data/issuer_from_first_state_to_second_transition_v3.json"), ], proofJson: require("./data/valid_mtp_user_first_v3.json"), - errorMessage: "Generated proof is outdated", + errorMessage: "GeneratedProofIsOutdated()", isMtpProof: true, sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", }, @@ -345,7 +346,7 @@ const testCases: any[] = [ proofJson: require("./data/valid_mtp_user_genesis_v3.json"), setProofExpiration: tenYears, allowedIssuers: [123n], - errorMessage: "Issuer is not on the Allowed Issuers list", + errorMessage: "IssuerIsNotOnTheAllowedIssuersList()", isMtpProof: true, sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", }, @@ -387,7 +388,7 @@ const testCases: any[] = [ ], proofJson: require("./data/valid_bjj_user_genesis_auth_disabled_v3_wrong_id.json"), setProofExpiration: tenYears, - errorMessage: "UserID does not correspond to the sender", + errorMessage: "UserIDDoesNotCorrespondToTheSender()", ethereumBasedUser: true, sender: "0x6edFa588aFd58803F728AbC91984c69528C00854", }, @@ -398,7 +399,7 @@ const testCases: any[] = [ ], proofJson: require("./data/valid_mtp_user_genesis_auth_disabled_v3_wrong_id.json"), setProofExpiration: tenYears, - errorMessage: "UserID does not correspond to the sender", + errorMessage: "UserIDDoesNotCorrespondToTheSender()", ethereumBasedUser: true, isMtpProof: true, sender: "0x6edFa588aFd58803F728AbC91984c69528C00854", @@ -439,7 +440,7 @@ const testCases: any[] = [ require("../common-data/user_from_genesis_state_to_first_transition_v3.json"), ], proofJson: require("./data/valid_bjj_user_first_issuer_genesis_v3.json"), - errorMessage: "Challenge should match the sender", + errorMessage: "ChallengeShouldMatchTheSender()", setProofExpiration: tenYears, sender: "0x0000000000000000000000000000000000000000", }, @@ -452,7 +453,8 @@ const testCases: any[] = [ proofJson: require("./data/valid_bjj_user_genesis_auth_disabled_v3.json"), setProofExpiration: tenYears, ethereumBasedUser: true, - errorMessage: "Invalid Link ID pub signal", + errorMessage: + "InvalidGroupIDOrLinkID(0, 19823993270096139446564592922993947503208333537792611306066620392561342309875)", sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", groupID: 0, }, @@ -465,7 +467,7 @@ const testCases: any[] = [ proofJson: require("./data/valid_bjj_user_genesis_auth_disabled_v3.json"), setProofExpiration: tenYears, ethereumBasedUser: true, - errorMessage: "Proof type should match the requested one in query", + errorMessage: "ProofTypeShouldMatchTheRequestedOneInQuery()", sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", isMtpProof: true, }, @@ -478,7 +480,7 @@ const testCases: any[] = [ proofJson: require("./data/valid_bjj_user_genesis_auth_disabled_v3.json"), setProofExpiration: tenYears, ethereumBasedUser: true, - errorMessage: "Invalid nullify pub signal", + errorMessage: "InvalidNullifyPubSignal()", sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", nullifierSessionId: "2", }, @@ -491,14 +493,15 @@ const testCases: any[] = [ proofJson: require("./data/valid_bjj_user_genesis_auth_disabled_v3.json"), setProofExpiration: tenYears, ethereumBasedUser: true, - errorMessage: "Query hash does not match the requested one", + errorMessage: + "QueryHashDoesNotMatchTheRequestedOne(0, 19185468473610285815446195195707572856383167010831244369191309337886545428382)", sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", queryHash: BigInt(0), }, ]; describe("Atomic V3 Validator", function () { - let state: any, v3validator; + let state: any, v3Validator; async function deployContractsFixture() { const deployHelper = await DeployHelper.initialize(null, true); @@ -527,7 +530,7 @@ describe("Atomic V3 Validator", function () { } beforeEach(async () => { - ({ stateContract: state, validator: v3validator } = await loadFixture(deployContractsFixture)); + ({ stateContract: state, validator: v3Validator } = await loadFixture(deployContractsFixture)); }); for (const test of testCases) { @@ -582,57 +585,80 @@ describe("Atomic V3 Validator", function () { const { inputs, pi_a, pi_b, pi_c } = prepareInputs(test.proofJson); if (test.setProofExpiration) { - await v3validator.setProofExpirationTimeout(test.setProofExpiration); + await v3Validator.setProofExpirationTimeout(test.setProofExpiration); } if (test.setRevStateExpiration) { - await v3validator.setRevocationStateExpirationTimeout(test.setRevStateExpiration); + await v3Validator.setRevocationStateExpirationTimeout(test.setRevStateExpiration); } if (test.setGISTRootExpiration) { - await v3validator.setGISTRootExpirationTimeout(test.setGISTRootExpiration); + await v3Validator.setGISTRootExpirationTimeout(test.setGISTRootExpiration); } const data = packV3ValidatorParams(query, test.allowedIssuers); // Check verify function - if (test.errorMessage) { - await expect( - v3validator.verify(inputs, pi_a, pi_b, pi_c, data, test.sender), - ).to.be.rejectedWith(test.errorMessage); - } else if (test.errorMessage === "") { - await expect(v3validator.verify(inputs, pi_a, pi_b, pi_c, data, test.sender)).to.be - .reverted; - } else { - const signals = await v3validator.verify(inputs, pi_a, pi_b, pi_c, data, test.sender); - - const signalValues: any[] = []; - // Replace index with value to check instead of signal index - for (let i = 0; i < signals.length; i++) { - signalValues.push([signals[i][0], inputs[signals[i][1]]]); - } - - // Check if the number signals are correct. "operatorOutput" for selective disclosure is optional - checkSignals(signalValues, test.signalValues); - } - - // Check verifyV2 function const zkProof = packZKProof(inputs, pi_a, pi_b, pi_c); if (test.errorMessage) { - await expect( - v3validator.verifyV2(zkProof, data, test.sender, await state.getAddress()), - ).to.be.rejectedWith(test.errorMessage); + await expect(v3Validator.verify(test.sender, zkProof, data, "0x")).to.be.rejectedWith( + test.errorMessage, + ); } else if (test.errorMessage === "") { - await expect(v3validator.verifyV2(zkProof, data, test.sender, await state.getAddress())).to - .be.reverted; + await expect(v3Validator.verify(test.sender, zkProof, data, "0x")).to.be.reverted; } else { - const signals = await v3validator.verifyV2( - zkProof, - data, - test.sender, - await state.getAddress(), - ); + const signals = await v3Validator.verify(test.sender, zkProof, data, "0x"); checkSignals(signals, test.signalValues); } }); } + + it("check version", async () => { + const version = await v3Validator.version(); + expect(version).to.be.equal(contractsInfo.VALIDATOR_V3.version); + }); + + it("check getRequestParam", async () => { + const query: any = { + requestId: 1, + schema: 2, + claimPathKey: 3, + operator: 4, + slotIndex: 0, + queryHash: 5, + value: [20020101, ...new Array(63).fill(0)], // for operators 1-3 only first value matters + circuitIds: ["circuitName"], + skipClaimRevocationCheck: false, + claimPathNotExists: 0, + allowedIssuers: [], + verifierID: 7, + nullifierSessionID: 8, + groupID: 9, + proofType: 0, + }; + + const params = packV3ValidatorParams(query); + let resultParam = await v3Validator.getRequestParam(params, "groupID"); + expect(resultParam).to.deep.equal(["groupID", 9]); + resultParam = await v3Validator.getRequestParam(params, "verifierID"); + expect(resultParam).to.deep.equal(["verifierID", 7]); + resultParam = await v3Validator.getRequestParam(params, "nullifierSessionID"); + expect(resultParam).to.deep.equal(["nullifierSessionID", 8]); + }); + + it("Test get config params", async () => { + const oneHour = 3600; + const expirationTimeout = await v3Validator.getProofExpirationTimeout(); + const revocationStateExpirationTimeout = + await v3Validator.getRevocationStateExpirationTimeout(); + const gistRootExpirationTimeout = await v3Validator.getGISTRootExpirationTimeout(); + expect(expirationTimeout).to.be.equal(oneHour); + expect(revocationStateExpirationTimeout).to.be.equal(oneHour); + expect(gistRootExpirationTimeout).to.be.equal(oneHour); + }); + + it("Test supported circuits", async () => { + const supportedCircuitIds = await v3Validator.getSupportedCircuitIds(); + expect(supportedCircuitIds.length).to.be.equal(1); + expect(supportedCircuitIds[0]).to.be.equal(CircuitId.AtomicQueryV3OnChain); + }); }); diff --git a/test/verifier/embedded-verifier.test.ts b/test/verifier/embedded-verifier.test.ts new file mode 100644 index 000000000..e88a4af3b --- /dev/null +++ b/test/verifier/embedded-verifier.test.ts @@ -0,0 +1,99 @@ +import { ethers, upgrades } from "hardhat"; +import { beforeEach } from "mocha"; +import { DeployHelper } from "../../helpers/DeployHelper"; +import { expect } from "chai"; + +describe("EmbeddedVerifier tests", function () { + let verifier, state, validator, signer: any; + let request, paramsFromValidator, authResponse, response, crossChainProofs: any; + + async function deployContractsFixture() { + [signer] = await ethers.getSigners(); + const deployHelper = await DeployHelper.initialize(null, true); + + const { state } = await deployHelper.deployStateWithLibraries([], "Groth16VerifierStub"); + const stateAddr = await state.getAddress(); + const Verifier = await ethers.getContractFactory("EmbeddedVerifierWrapper"); + verifier = await upgrades.deployProxy(Verifier, [signer.address, stateAddr]); + + const validator = await ethers.deployContract("RequestValidatorStub"); + + const authValidator = await deployHelper.deployValidatorStub("AuthValidatorStub"); + await authValidator.stub_setVerifyResults(1); + + const authMethod = { + authMethod: "stubAuth", + validator: await authValidator.getAddress(), + params: "0x", + }; + await verifier.setAuthMethod(authMethod); + + return { state, verifier, validator }; + } + + beforeEach(async function () { + ({ state, verifier, validator } = await deployContractsFixture()); + + request = { + requestId: 0, + metadata: "0x", + validator: await validator.getAddress(), + owner: signer.address, + params: "0x", + }; + + paramsFromValidator = [ + { name: "groupID", value: 0 }, + { name: "verifierID", value: 0 }, + { name: "nullifierSessionID", value: 0 }, + ]; + + authResponse = { + authMethod: "stubAuth", + proof: "0x", + }; + response = { + requestId: 0, + proof: "0x", + metadata: "0x", + }; + + crossChainProofs = "0x"; + }); + + it("Test get state address", async () => { + let stateAddr = await verifier.getStateAddress(); + expect(stateAddr).to.be.equal(await state.getAddress()); + + await verifier.setState(await signer.getAddress()); + + stateAddr = await verifier.getStateAddress(); + expect(stateAddr).to.be.equal(await signer.getAddress()); + + await verifier.setState(await state.getAddress()); + }); + + it("beforeProofSubmit/afterProofSubmit when submitting response", async function () { + await validator.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator.stub_setInput("userID", 1); + + await verifier.setRequests([request]); + + await expect(verifier.submitResponse(authResponse, [response], crossChainProofs)).to.emit( + verifier, + "BeforeProofSubmit", + ); + + let filter = verifier.filters.BeforeProofSubmit; + let events = await verifier.queryFilter(filter, -1); + expect(events[0].eventName).to.be.equal("BeforeProofSubmit"); + expect(events[0].args.authResponse).to.deep.equal(Object.values(authResponse)); + expect(events[0].args.responses).to.deep.equal([Object.values(response)]); + + filter = verifier.filters.AfterProofSubmit; + events = await verifier.queryFilter(filter, -1); + expect(events[0].eventName).to.be.equal("AfterProofSubmit"); + expect(events[0].args.authResponse).to.deep.equal(Object.values(authResponse)); + expect(events[0].args.responses).to.deep.equal([Object.values(response)]); + }); +}); diff --git a/test/verifier/embedded-zkp-verifier.test.ts b/test/verifier/embedded-zkp-verifier.test.ts deleted file mode 100644 index 9e6991667..000000000 --- a/test/verifier/embedded-zkp-verifier.test.ts +++ /dev/null @@ -1,273 +0,0 @@ -import { expect } from "chai"; -import { DeployHelper } from "../../helpers/DeployHelper"; -import { ethers } from "hardhat"; -import { packValidatorParams } from "../utils/validator-pack-utils"; -import { prepareInputs } from "../utils/state-utils"; -import { Block, Signer } from "ethers"; -import { buildCrossChainProofs, packCrossChainProofs, packZKProof } from "../utils/packData"; -import proofJson from "../validators/sig/data/valid_sig_user_genesis.json"; -import { CircuitId } from "@0xpolygonid/js-sdk"; -import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; - -describe("Embedded ZKP Verifier", function () { - let verifier: any, validator: any; - let owner: Signer; - - const query = { - schema: BigInt("180410020913331409885634153623124536270"), - claimPathKey: BigInt( - "8566939875427719562376598811066985304309117528846759529734201066483458512800", - ), - operator: 1n, - slotIndex: 0n, - value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))], - queryHash: BigInt( - "1496222740463292783938163206931059379817846775593932664024082849882751356658", - ), - circuitIds: [CircuitId.AtomicQuerySigV2OnChain], - claimPathNotExists: 0, - }; - - const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson); - const metadatas = "0x"; - - async function deployContractsFixture() { - const deployHelper = await DeployHelper.initialize(null, true); - [owner] = await ethers.getSigners(); - - const { state } = await deployHelper.deployStateWithLibraries(["0x0112"]); - - const verifierLib = await deployHelper.deployVerifierLib(); - - verifier = await deployHelper.deployEmbeddedZKPVerifierWrapper( - owner, - await state.getAddress(), - await verifierLib.getAddress(), - ); - - validator = await deployHelper.deployValidatorStub(); - } - - async function checkStorageFields(verifier: any, requestId: number, storageFields: any[]) { - for (const field of storageFields) { - const value = await verifier.getProofStorageField( - await owner.getAddress(), - requestId, - field.name, - ); - expect(value).to.be.equal(field.value); - } - } - - beforeEach(async () => { - await loadFixture(deployContractsFixture); - }); - - it("test submit response", async () => { - await verifier.setZKPRequest(0, { - metadata: "metadata", - validator: await validator.getAddress(), - data: packValidatorParams(query), - }); - - const tx = await verifier.submitZKPResponse(0, inputs, pi_a, pi_b, pi_c); - const txRes = await tx.wait(); - const storageFields = [ - { - name: "userID", - value: inputs[1], - }, - { - name: "issuerID", - value: inputs[2], - }, - ]; - - await checkStorageFields(verifier, 0, storageFields); - const receipt = await ethers.provider.getTransactionReceipt(txRes.hash); - - // 2 events are emitted - expect(receipt?.logs.length).to.equal(2); - - const interfaceEventBeforeProofSubmit = new ethers.Interface([ - "event BeforeProofSubmit(uint64 requestId, uint256[] inputs, address validator)", - ]); - const eventBeforeProofSubmit = interfaceEventBeforeProofSubmit.decodeEventLog( - "BeforeProofSubmit", - receipt?.logs[0].data || "", - receipt?.logs[0].topics, - ); - expect(eventBeforeProofSubmit[0]).to.equal(0); - expect(eventBeforeProofSubmit[1]).to.deep.equal(inputs.map((x) => BigInt(x))); - expect(eventBeforeProofSubmit[2]).to.equal(await validator.getAddress()); - - const interfaceEventAfterProofSubmit = new ethers.Interface([ - "event AfterProofSubmit(uint64 requestId, uint256[] inputs, address validator)", - ]); - const eventAfterProofSubmit = interfaceEventAfterProofSubmit.decodeEventLog( - "AfterProofSubmit", - receipt?.logs[1].data || "", - receipt?.logs[1].topics, - ); - expect(eventAfterProofSubmit[0]).to.equal(0); - expect(eventAfterProofSubmit[1]).to.deep.equal(inputs.map((x) => BigInt(x))); - expect(eventAfterProofSubmit[2]).to.equal(await validator.getAddress()); - - const ownerAddress = await owner.getAddress(); - const requestID = 0; - const { timestamp: txResTimestamp } = (await ethers.provider.getBlock( - txRes.blockNumber, - )) as Block; - - const isProofVerified = await verifier.isProofVerified(ownerAddress, requestID); - expect(isProofVerified).to.be.equal(true); - const proofStatus = await verifier.getProofStatus(ownerAddress, requestID); - expect(proofStatus.isVerified).to.be.equal(true); - expect(proofStatus.validatorVersion).to.be.equal("2.0.2-mock"); - expect(proofStatus.blockNumber).to.be.equal(txRes.blockNumber); - expect(proofStatus.blockTimestamp).to.be.equal(txResTimestamp); - }); - - it("test submit response v2", async () => { - const globalStateMessage = { - timestamp: BigInt(Math.floor(Date.now() / 1000)), - idType: "0x01A1", - root: 0n, - replacedAtTimestamp: 0n, - }; - - const identityStateMessage1 = { - timestamp: BigInt(Math.floor(Date.now() / 1000)), - id: 25530185136167283063987925153802803371825564143650291260157676786685420033n, - state: 4595702004868323299100310062178085028712435650290319955390778053863052230284n, - replacedAtTimestamp: 0n, - }; - - const identityStateUpdate2 = { - timestamp: BigInt(Math.floor(Date.now() / 1000)), - id: 25530185136167283063987925153802803371825564143650291260157676786685420033n, - state: 16775015541053109108201708100382933592407720757224325883910784163897594100403n, - replacedAtTimestamp: 1724858009n, - }; - - await verifier.setZKPRequest(0, { - metadata: "metadata", - validator: await validator.getAddress(), - data: packValidatorParams(query), - }); - - const zkProof = packZKProof(inputs, pi_a, pi_b, pi_c); - const [signer] = await ethers.getSigners(); - - const crossChainProofs = packCrossChainProofs( - await buildCrossChainProofs( - [globalStateMessage, identityStateMessage1, identityStateUpdate2], - signer, - ), - ); - - const tx = await verifier.submitZKPResponseV2( - [ - { - requestId: 0, - zkProof: zkProof, - data: metadatas, - }, - ], - crossChainProofs, - ); - - const txRes = await tx.wait(); - - const storageFields = [ - { - name: "userID", - value: 1n, - }, - { - name: "issuerID", - value: 2n, - }, - ]; - await checkStorageFields(verifier, 0, storageFields); - - const receipt = await ethers.provider.getTransactionReceipt(txRes.hash); - - // 2 events are emitted - expect(receipt?.logs.length).to.equal(2); - - const interfaceEventBeforeProofSubmitV2 = new ethers.Interface([ - "event BeforeProofSubmitV2(tuple(uint64 requestId,bytes zkProof,bytes data)[])", - ]); - const eventBeforeProofSubmitV2 = interfaceEventBeforeProofSubmitV2.decodeEventLog( - "BeforeProofSubmitV2", - receipt?.logs[0].data || "", - receipt?.logs[0].topics, - ); - expect(eventBeforeProofSubmitV2[0][0][0]).to.equal(0); - expect(eventBeforeProofSubmitV2[0][0][1]).to.deep.equal(zkProof); - expect(eventBeforeProofSubmitV2[0][0][2]).to.equal(metadatas); - - const interfaceEventAfterProofSubmitV2 = new ethers.Interface([ - "event AfterProofSubmitV2(tuple(uint64 requestId,bytes zkProof,bytes data)[])", - ]); - const eventAfterProofSubmitV2 = interfaceEventAfterProofSubmitV2.decodeEventLog( - "AfterProofSubmitV2", - receipt?.logs[1].data || "", - receipt?.logs[1].topics, - ); - expect(eventAfterProofSubmitV2[0][0][0]).to.equal(0); - expect(eventAfterProofSubmitV2[0][0][1]).to.deep.equal(zkProof); - expect(eventAfterProofSubmitV2[0][0][2]).to.equal(metadatas); - - const ownerAddress = await owner.getAddress(); - const requestID = 0; - const { timestamp: txResTimestamp } = (await ethers.provider.getBlock( - txRes.blockNumber, - )) as Block; - - const isProofVerified = await verifier.isProofVerified(ownerAddress, requestID); - expect(isProofVerified).to.be.equal(true); - const proofStatus = await verifier.getProofStatus(ownerAddress, requestID); - expect(proofStatus.isVerified).to.be.equal(true); - expect(proofStatus.validatorVersion).to.be.equal("2.0.2-mock"); - expect(proofStatus.blockNumber).to.be.equal(txRes.blockNumber); - expect(proofStatus.blockTimestamp).to.be.equal(txResTimestamp); - }); - - it("test getZKPRequest and request id exists", async () => { - const requestsCount = 3; - for (let i = 0; i < requestsCount; i++) { - await verifier.setZKPRequest(i, { - metadata: "metadataN" + i, - validator: await validator.getAddress(), - data: "0x00", - }); - const reqeustIdExists = await verifier.requestIdExists(i); - expect(reqeustIdExists).to.be.true; - const reqeustIdDoesntExists = await verifier.requestIdExists(i + 1); - expect(reqeustIdDoesntExists).to.be.false; - - const request = await verifier.getZKPRequest(i); - expect(request.metadata).to.be.equal("metadataN" + i); - await expect(verifier.getZKPRequest(i + 1)).to.be.rejectedWith("request id doesn't exist"); - } - const count = await verifier.getZKPRequestsCount(); - expect(count).to.be.equal(requestsCount); - }); - - it("should revert if requestIds and requests length mismatch in setZKPRequests", async () => { - const validatorAddr = await validator.getAddress(); - const requestIds = [1, 2]; - const requests = [ - { - metadata: "meta1", - validator: validatorAddr, - data: "0x01", - }, - ]; - await expect(verifier.setZKPRequests(requestIds, requests)).to.be.rejectedWith( - "Request IDs and requests length mismatch", - ); - }); -}); diff --git a/test/verifier/requestDisableable.test.ts b/test/verifier/requestDisableable.test.ts new file mode 100644 index 000000000..f9a9efd84 --- /dev/null +++ b/test/verifier/requestDisableable.test.ts @@ -0,0 +1,73 @@ +import { ethers } from "hardhat"; +import { beforeEach } from "mocha"; +import { DeployHelper } from "../../helpers/DeployHelper"; +import { expect } from "chai"; + +describe("RequestDisableable tests", function () { + let verifier, validator: any; + let request, paramsFromValidator: any; + let signer: any; + + async function deployContractsFixture() { + [signer] = await ethers.getSigners(); + const deployHelper = await DeployHelper.initialize(null, true); + const verifier = await ethers.deployContract("RequestDisableableTestWrapper", []); + + const { state } = await deployHelper.deployStateWithLibraries([], "Groth16VerifierStub"); + await verifier.initialize(await state.getAddress()); + + const validator = await ethers.deployContract("RequestValidatorStub"); + return { verifier, validator }; + } + + beforeEach(async function () { + ({ verifier, validator } = await deployContractsFixture()); + + request = { + requestId: 1, + metadata: "0x", + validator: await validator.getAddress(), + owner: signer.address, + params: "0x", + }; + + paramsFromValidator = [ + { name: "groupID", value: 0 }, + { name: "verifierID", value: 0 }, + { name: "nullifierSessionID", value: 0 }, + ]; + }); + + it("disable/enable request and onlyEnabledRequest modifier", async function () { + await validator.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator.stub_setInput("userID", 1); + + await verifier.setRequests([request]); + + let isRequestEnabled = await verifier.isRequestEnabled(request.requestId); + expect(isRequestEnabled).to.be.true; + + await expect(verifier.testModifier(request.requestId)).not.to.be.reverted; + await expect(verifier.getRequestIfCanBeVerified(request.requestId)).not.to.be.reverted; + + await verifier.disableRequest(request.requestId); + + isRequestEnabled = await verifier.isRequestEnabled(request.requestId); + expect(isRequestEnabled).to.be.false; + + await expect(verifier.testModifier(request.requestId)) + .to.be.revertedWithCustomError(verifier, "RequestIsDisabled") + .withArgs(request.requestId); + + await expect(verifier.getRequestIfCanBeVerified(request.requestId)) + .to.be.revertedWithCustomError(verifier, "RequestIsDisabled") + .withArgs(request.requestId); + + await verifier.enableRequest(request.requestId); + + isRequestEnabled = await verifier.isRequestEnabled(request.requestId); + expect(isRequestEnabled).to.be.true; + + await expect(verifier.testModifier(request.requestId)).not.to.be.reverted; + }); +}); diff --git a/test/verifier/requestOwnership.test.ts b/test/verifier/requestOwnership.test.ts new file mode 100644 index 000000000..6db9285c6 --- /dev/null +++ b/test/verifier/requestOwnership.test.ts @@ -0,0 +1,55 @@ +import { ethers } from "hardhat"; +import { beforeEach } from "mocha"; +import { DeployHelper } from "../../helpers/DeployHelper"; +import { expect } from "chai"; + +describe("RequestOwnership tests", function () { + let verifier, validator: any; + let request, paramsFromValidator: any; + let signer1, signer2: any; + + async function deployContractsFixture() { + [signer1, signer2] = await ethers.getSigners(); + + const deployHelper = await DeployHelper.initialize(null, true); + const verifier = await ethers.deployContract("RequestOwnershipTestWrapper", []); + + const { state } = await deployHelper.deployStateWithLibraries([], "Groth16VerifierStub"); + await verifier.initialize(await state.getAddress()); + + const validator = await ethers.deployContract("RequestValidatorStub"); + return { verifier, validator, signer1, signer2 }; + } + + beforeEach(async function () { + ({ verifier, validator, signer1, signer2 } = await deployContractsFixture()); + + request = { + requestId: 1, + metadata: "0x", + validator: await validator.getAddress(), + owner: await signer1.getAddress(), + params: "0x", + }; + + paramsFromValidator = [ + { name: "groupID", value: 0 }, + { name: "verifierID", value: 0 }, + { name: "nullifierSessionID", value: 0 }, + ]; + }); + + it("setRequestOwner: change request ownership", async function () { + await validator.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator.stub_setInput("userID", 1); + await verifier.setRequests([request]); + + let owner = await verifier.getRequestOwner(request.requestId); + expect(owner).to.be.equal(await signer1.getAddress()); + + await verifier.setRequestOwner(request.requestId, await signer2.getAddress()); + + owner = await verifier.getRequestOwner(request.requestId); + expect(owner).to.be.equal(await signer2.getAddress()); + }); +}); diff --git a/test/verifier/universal-verifier-linked-proofs.test.ts b/test/verifier/universal-verifier-linked-proofs.test.ts deleted file mode 100644 index 8edad40c7..000000000 --- a/test/verifier/universal-verifier-linked-proofs.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { DeployHelper } from "../../helpers/DeployHelper"; -import { ethers } from "hardhat"; -import { packV3ValidatorParams } from "../utils/validator-pack-utils"; -import { prepareInputs, publishState } from "../utils/state-utils"; -import { expect } from "chai"; -import testData from "./linked-proofs-data.json"; -import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; -import { TEN_YEARS } from "../../helpers/constants"; - -describe("Universal Verifier Linked proofs", function () { - let verifier: any, v3: any, state: any; - let signer, signer2; - let signerAddress: string; - let deployHelper: DeployHelper; - - async function deployContractsFixture() { - [signer, signer2] = await ethers.getSigners(); - signerAddress = await signer.getAddress(); - - deployHelper = await DeployHelper.initialize(null, true); - ({ state } = await deployHelper.deployStateWithLibraries(["0x0112"])); - - const verifierLib = await deployHelper.deployVerifierLib(); - - verifier = await deployHelper.deployUniversalVerifier( - signer, - await state.getAddress(), - await verifierLib.getAddress(), - ); - - const contracts = await deployHelper.deployValidatorContractsWithVerifiers( - "v3", - await state.getAddress(), - ); - v3 = contracts.validator; - await verifier.addValidatorToWhitelist(await v3.getAddress()); - await verifier.connect(); - - await publishState(state, testData.state as unknown as { [key: string]: string }); - await v3.setProofExpirationTimeout(TEN_YEARS); - for (let i = 0; i < testData.queryData.zkpRequests.length; i++) { - await verifier.setZKPRequest(100 + i, { - metadata: "linkedProofN" + i, - validator: await v3.getAddress(), - data: packV3ValidatorParams(testData.queryData.zkpRequests[i].request), - }); - } - - for (let i = 0; i < testData.queryData.zkpResponses.length; i++) { - const { inputs, pi_a, pi_b, pi_c } = prepareInputs(testData.queryData.zkpResponses[i]); - await verifier.submitZKPResponse(100 + i, inputs, pi_a, pi_b, pi_c); - } - } - - beforeEach(async () => { - await loadFixture(deployContractsFixture); - }); - - it("should linked proof validation pass", async () => { - expect(await verifier.verifyLinkedProofs(signerAddress, [101, 102])).not.to.throw; - expect(await verifier.verifyLinkedProofs(signerAddress, [100, 103])).not.to.throw; - }); - - it("should linked proof validation fail", async () => { - await expect(verifier.verifyLinkedProofs(signerAddress, [100, 101])).to.be.rejectedWith( - "LinkedProofError", - ); - await expect(verifier.verifyLinkedProofs(signerAddress, [102, 103])).to.be.rejectedWith( - "LinkedProofError", - ); - - await expect(verifier.verifyLinkedProofs(signerAddress, [102])).to.be.rejectedWith( - "Linked proof verification needs more than 1 request", - ); - await expect( - verifier.verifyLinkedProofs(await signer2.getAddress(), [101, 102]), - ).to.be.rejectedWith(`Can't find linkID for given request Ids and user address`); - }); -}); diff --git a/test/verifier/universal-verifier-submit-V2.test.ts b/test/verifier/universal-verifier-submit-V2.test.ts deleted file mode 100644 index a4117be9b..000000000 --- a/test/verifier/universal-verifier-submit-V2.test.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { expect } from "chai"; -import { DeployHelper } from "../../helpers/DeployHelper"; -import { ethers } from "hardhat"; -import { packValidatorParams } from "../utils/validator-pack-utils"; -import { prepareInputs } from "../utils/state-utils"; -import { Block, Contract } from "ethers"; -import proofJson from "../validators/sig/data/valid_sig_user_genesis.json"; -import { buildCrossChainProofs, packCrossChainProofs, packZKProof } from "../utils/packData"; -import { CircuitId } from "@0xpolygonid/js-sdk"; -import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; - -describe("Universal Verifier submitZKPResponseV2 SigV2 validators", function () { - let verifier: any, sig: any; - let signer; - let signerAddress: string; - let deployHelper: DeployHelper; - let stateCrossChainStub, crossChainProofValidatorStub, validatorStub: Contract; - - const globalStateMessage = { - timestamp: BigInt(Math.floor(Date.now() / 1000)), - idType: "0x01A1", - root: 0n, - replacedAtTimestamp: 0n, - }; - - const identityStateMessage1 = { - timestamp: BigInt(Math.floor(Date.now() / 1000)), - id: 25530185136167283063987925153802803371825564143650291260157676786685420033n, - state: 4595702004868323299100310062178085028712435650290319955390778053863052230284n, - replacedAtTimestamp: 0n, - }; - - const identityStateUpdate2 = { - timestamp: BigInt(Math.floor(Date.now() / 1000)), - id: 25530185136167283063987925153802803371825564143650291260157676786685420033n, - state: 16775015541053109108201708100382933592407720757224325883910784163897594100403n, - replacedAtTimestamp: 1724858009n, - }; - - const query = { - schema: BigInt("180410020913331409885634153623124536270"), - claimPathKey: BigInt( - "8566939875427719562376598811066985304309117528846759529734201066483458512800", - ), - operator: 1n, - slotIndex: 0n, - value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))], - queryHash: BigInt( - "1496222740463292783938163206931059379817846775593932664024082849882751356658", - ), - circuitIds: [CircuitId.AtomicQuerySigV2OnChain], - claimPathNotExists: 0, - }; - - const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson); - const zkProof = packZKProof(inputs, pi_a, pi_b, pi_c); - const metadatas = "0x"; - const data = packValidatorParams(query); - - const requestIds = [0, 1, 2]; - const nonExistingRequestId = 3; - - const singleProof = [ - { - requestId: 0, - zkProof: zkProof, - data: metadatas, - }, - ]; - - const multiProof = [ - { - requestId: 1, - zkProof: zkProof, - data: metadatas, - }, - { - requestId: 2, - zkProof: zkProof, - data: metadatas, - }, - ]; - - let crossChainProofs; - - async function deployContractsFixture() { - [signer] = await ethers.getSigners(); - signerAddress = await signer.getAddress(); - - deployHelper = await DeployHelper.initialize(null, true); - crossChainProofValidatorStub = await deployHelper.deployCrossChainProofValidator(); - - const { state } = await deployHelper.deployStateWithLibraries(["0x01A1", "0x0102"]); - await state.setCrossChainProofValidator(crossChainProofValidatorStub); - stateCrossChainStub = state; - - const verifierLib = await deployHelper.deployVerifierLib(); - - verifier = await deployHelper.deployUniversalVerifier( - signer, - await stateCrossChainStub.getAddress(), - await verifierLib.getAddress(), - ); - - validatorStub = await deployHelper.deployValidatorStub(); - - sig = validatorStub; - await verifier.addValidatorToWhitelist(await sig.getAddress()); - await verifier.connect(); - - for (const requestId of requestIds) { - await verifier.setZKPRequest(requestId, { - metadata: "metadata", - validator: await sig.getAddress(), - data: data, - }); - } - } - - const storageFields = [ - { - name: "userID", - value: 1n, - }, - { - name: "issuerID", - value: 2n, - }, - ]; - - async function checkStorageFields(verifier: any, requestId: number, storageFields: any[]) { - for (const field of storageFields) { - const value = await verifier.getProofStorageField( - await signer.getAddress(), - requestId, - field.name, - ); - expect(value).to.be.equal(field.value); - } - } - - beforeEach(async () => { - await loadFixture(deployContractsFixture); - crossChainProofs = packCrossChainProofs( - await buildCrossChainProofs( - [globalStateMessage, identityStateMessage1, identityStateUpdate2], - signer, - ), - ); - }); - - it("Test submit response V2", async () => { - const requestId = 0; - const tx = await verifier.submitZKPResponseV2(singleProof, crossChainProofs); - - const txRes = await tx.wait(); - await checkStorageFields(verifier, requestId, storageFields); - const filter = verifier.filters.ZKPResponseSubmitted; - - const events = await verifier.queryFilter(filter, -1); - expect(events[0].eventName).to.be.equal("ZKPResponseSubmitted"); - expect(events[0].args.requestId).to.be.equal(0); - expect(events[0].args.caller).to.be.equal(signerAddress); - - const { timestamp: txResTimestamp } = (await ethers.provider.getBlock( - txRes.blockNumber, - )) as Block; - - const status = await verifier.getProofStatus(signerAddress, requestId); - expect(status.isVerified).to.be.true; - expect(status.validatorVersion).to.be.equal("2.0.2-mock"); - expect(status.blockNumber).to.be.equal(txRes.blockNumber); - expect(status.blockTimestamp).to.be.equal(txResTimestamp); - - await expect(verifier.getProofStatus(signerAddress, nonExistingRequestId)).to.be.rejectedWith( - "request id doesn't exist", - ); - - const requestIdsMulti = requestIds.slice(1, 3); - const txMulti = await verifier.submitZKPResponseV2(multiProof, crossChainProofs); - - const txResMulti = await txMulti.wait(); - - const eventsMulti = await verifier.queryFilter(filter, txRes.blockNumber + 1); - expect(eventsMulti[0].eventName).to.be.equal("ZKPResponseSubmitted"); - expect(eventsMulti[0].args.requestId).to.be.equal(1); - expect(eventsMulti[0].args.caller).to.be.equal(signerAddress); - - const { timestamp: txResTimestampMuti } = (await ethers.provider.getBlock( - txResMulti.blockNumber, - )) as Block; - - for (const requestId of requestIdsMulti) { - const status = await verifier.getProofStatus(signerAddress, requestId); - expect(status.isVerified).to.be.true; - expect(status.validatorVersion).to.be.equal("2.0.2-mock"); - expect(status.blockNumber).to.be.equal(txResMulti.blockNumber); - expect(status.blockTimestamp).to.be.equal(txResTimestampMuti); - await checkStorageFields(verifier, requestId, storageFields); - } - }); - - it("Test submit response V2 with disable/enable functionality", async () => { - await verifier.disableZKPRequest(0); - await expect(verifier.submitZKPResponseV2(singleProof, crossChainProofs)).to.be.rejectedWith( - "Request is disabled", - ); - - await verifier.disableZKPRequest(1); - await expect(verifier.submitZKPResponseV2(multiProof, crossChainProofs)).to.be.rejectedWith( - "Request is disabled", - ); - - await verifier.enableZKPRequest(0); - await expect(verifier.submitZKPResponseV2(singleProof, crossChainProofs)).not.to.be.rejected; - - await verifier.enableZKPRequest(1); - await expect(verifier.submitZKPResponseV2(multiProof, crossChainProofs)).not.to.be.rejected; - }); - - it("Test submit response V2 check whitelisted functionality", async () => { - await verifier.removeValidatorFromWhitelist(await sig.getAddress()); - await expect(verifier.submitZKPResponseV2(singleProof, crossChainProofs)).to.be.rejectedWith( - "Validator is not whitelisted", - ); - await expect(verifier.submitZKPResponseV2(multiProof, crossChainProofs)).to.be.rejectedWith( - "Validator is not whitelisted", - ); - - await verifier.addValidatorToWhitelist(await sig.getAddress()); - await expect(verifier.submitZKPResponseV2(singleProof, crossChainProofs)).not.to.be.rejected; - await expect(verifier.submitZKPResponseV2(multiProof, crossChainProofs)).not.to.be.rejected; - }); -}); diff --git a/test/verifier/universal-verifier.events.test.ts b/test/verifier/universal-verifier.events.test.ts deleted file mode 100644 index fa5441e94..000000000 --- a/test/verifier/universal-verifier.events.test.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { expect } from "chai"; -import { DeployHelper } from "../../helpers/DeployHelper"; -import { ethers } from "hardhat"; -import { packValidatorParams } from "../utils/validator-pack-utils"; -import { AbiCoder } from "ethers"; -import { CircuitId } from "@0xpolygonid/js-sdk"; - -describe("Universal Verifier events", function () { - let verifier: any, sig: any; - let signer; - - const queries = [ - { - schema: 111n, - claimPathKey: 8566939875427719562376598811066985304309117528846759529734201066483458512800n, - operator: 1n, - slotIndex: 0n, - value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))], - queryHash: BigInt( - "1496222740463292783938163206931059379817846775593932664024082849882751356658", - ), - circuitIds: [CircuitId.AtomicQuerySigV2OnChain], - skipClaimRevocationCheck: false, - claimPathNotExists: 0n, - }, - { - schema: BigInt("222"), - claimPathKey: BigInt( - "8566939875427719562376598811066985304309117528846759529734201066483458512800", - ), - operator: 1n, - slotIndex: 0n, - value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))], - queryHash: BigInt( - "1496222740463292783938163206931059379817846775593932664024082849882751356658", - ), - circuitIds: [CircuitId.AtomicQuerySigV2OnChain], - skipClaimRevocationCheck: true, - claimPathNotExists: 0n, - }, - { - schema: 333n, - claimPathKey: BigInt( - "8566939875427719562376598811066985304309117528846759529734201066483458512800", - ), - operator: 1n, - slotIndex: 0n, - value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))], - queryHash: BigInt( - "1496222740463292783938163206931059379817846775593932664024082849882751356658", - ), - circuitIds: [CircuitId.AtomicQuerySigV2OnChain], - skipClaimRevocationCheck: false, - claimPathNotExists: 0n, - }, - ]; - - const encodedDataAbi = [ - { - components: [ - { name: "schema", type: "uint256" }, - { name: "claimPathKey", type: "uint256" }, - { name: "operator", type: "uint256" }, - { name: "slotIndex", type: "uint256" }, - { name: "value", type: "uint256[]" }, - { name: "queryHash", type: "uint256" }, - { name: "allowedIssuers", type: "uint256[]" }, - { name: "circuitIds", type: "string[]" }, - { name: "skipClaimRevocationCheck", type: "bool" }, - { name: "claimPathNotExists", type: "uint256" }, - ], - name: "", - type: "tuple", - }, - ]; - - beforeEach(async () => { - [signer] = await ethers.getSigners(); - - const deployHelper = await DeployHelper.initialize(null, true); - const { state } = await deployHelper.deployStateWithLibraries(["0x0112"]); - - const verifierLib = await deployHelper.deployVerifierLib(); - verifier = await deployHelper.deployUniversalVerifier( - signer, - await state.getAddress(), - await verifierLib.getAddress(), - ); - - const contracts = await deployHelper.deployValidatorContractsWithVerifiers( - "sigV2", - await state.getAddress(), - ); - sig = contracts.validator; - await verifier.addValidatorToWhitelist(await sig.getAddress()); - await verifier.connect(); - }); - - it("Check ZKPRequestSet event", async () => { - const requestsCount = 3; - const data = [ - packValidatorParams(queries[0]), - packValidatorParams(queries[1]), - packValidatorParams(queries[2]), - ]; - - for (let i = 0; i < requestsCount; i++) { - await verifier.setZKPRequest(i, { - metadata: "metadataN" + i, - validator: await sig.getAddress(), - data: data[i], - }); - } - const filter = verifier.filters.ZKPRequestSet(null, null); - const logs = await verifier.queryFilter(filter, 0, "latest"); - - const coder = AbiCoder.defaultAbiCoder(); - logs.map((log, index) => { - const [decodedData] = coder.decode(encodedDataAbi as any, log.args.data); - expect(decodedData.schema).to.equal(queries[index].schema); - expect(decodedData.claimPathKey).to.equal(queries[index].claimPathKey); - expect(decodedData.operator).to.equal(queries[index].operator); - expect(decodedData.slotIndex).to.equal(queries[index].slotIndex); - decodedData.value.forEach((v, i) => { - expect(v).to.equal(queries[index].value[i]); - }); - expect(decodedData.queryHash).to.equal(queries[index].queryHash); - decodedData.circuitIds.forEach((circuitId, i) => { - expect(circuitId).to.equal(queries[index].circuitIds[i]); - }); - expect(decodedData.skipClaimRevocationCheck).to.equal( - queries[index].skipClaimRevocationCheck, - ); - expect(decodedData.claimPathNotExists).to.equal(queries[index].claimPathNotExists); - }); - }); - - it("Check ZKPRequestUpdate event", async () => { - const originalRequestData = packValidatorParams(queries[0]); - const updatedRequestData = packValidatorParams(queries[1]); - - await verifier.setZKPRequest(0, { - metadata: "metadataN0", - validator: await sig.getAddress(), - data: originalRequestData, - }); - - await verifier.updateZKPRequest(0, { - metadata: "metadataN1", - validator: await sig.getAddress(), - data: updatedRequestData, - }); - - const filter = verifier.filters.ZKPRequestUpdate(null, null); - const logs = await verifier.queryFilter(filter, 0, "latest"); - - const coder = AbiCoder.defaultAbiCoder(); - logs.map((log) => { - const [decodedData] = coder.decode(encodedDataAbi as any, log.args.data); - expect(decodedData.schema).to.equal(queries[1].schema); - expect(decodedData.claimPathKey).to.equal(queries[1].claimPathKey); - expect(decodedData.operator).to.equal(queries[1].operator); - expect(decodedData.slotIndex).to.equal(queries[1].slotIndex); - decodedData.value.forEach((v, i) => { - expect(v).to.equal(queries[1].value[i]); - }); - expect(decodedData.queryHash).to.equal(queries[1].queryHash); - decodedData.circuitIds.forEach((circuitId, i) => { - expect(circuitId).to.equal(queries[1].circuitIds[i]); - }); - expect(decodedData.skipClaimRevocationCheck).to.equal(queries[1].skipClaimRevocationCheck); - expect(decodedData.claimPathNotExists).to.equal(queries[1].claimPathNotExists); - }); - }); -}); diff --git a/test/verifier/universal-verifier.test.ts b/test/verifier/universal-verifier.test.ts index 3b9b86bb6..e0225c53d 100644 --- a/test/verifier/universal-verifier.test.ts +++ b/test/verifier/universal-verifier.test.ts @@ -2,426 +2,699 @@ import { expect } from "chai"; import { DeployHelper } from "../../helpers/DeployHelper"; import { ethers } from "hardhat"; import { packValidatorParams } from "../utils/validator-pack-utils"; -import { prepareInputs } from "../utils/state-utils"; -import { Block } from "ethers"; -import proofJson from "../validators/mtp/data/valid_mtp_user_genesis.json"; -import { CircuitId } from "@0xpolygonid/js-sdk"; +import { AbiCoder, Block } from "ethers"; +import { byteEncoder, CircuitId } from "@0xpolygonid/js-sdk"; import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; +import { contractsInfo } from "../../helpers/constants"; +import { calculateMultiRequestId } from "../utils/id-calculation-utils"; -describe("Universal Verifier MTP & SIG validators", function () { - let verifier: any, validator: any, state: any; +describe("Universal Verifier tests", function () { + let request, paramsFromValidator, multiRequest, authResponse, response: any; + let verifier: any, validator: any, authValidator: any, state: any; let signer, signer2, signer3; let signerAddress: string; let deployHelper: DeployHelper; + let authMethod; - const query = { - schema: BigInt("180410020913331409885634153623124536270"), - claimPathKey: BigInt( - "8566939875427719562376598811066985304309117528846759529734201066483458512800", - ), - operator: 1n, - slotIndex: 0n, - value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))], - queryHash: BigInt( - "1496222740463292783938163206931059379817846775593932664024082849882751356658", - ), - circuitIds: [CircuitId.AtomicQuerySigV2OnChain], - claimPathNotExists: 0, - }; + const storageFields = [ + { + name: "userID", + value: 1n, + }, + { + name: "issuerID", + value: 2n, + }, + ]; + + const crossChainProofs = "0x"; async function deployContractsFixture() { const [ethSigner, ethSigner2, ethSigner3] = await ethers.getSigners(); deployHelper = await DeployHelper.initialize(null, true); const { state: stateContract } = await deployHelper.deployStateWithLibraries(["0x0112"]); - const verifierLib = await deployHelper.deployVerifierLib(); - const verifier: any = await deployHelper.deployUniversalVerifier( + const validator = await deployHelper.deployValidatorStub("RequestValidatorStub"); + await validator.stub_setVerifyResults([ + { name: "userID", value: 1, rawValue: "0x" }, + { name: "issuerID", value: 2, rawValue: "0x" }, + ]); + + const universalVerifier: any = await deployHelper.deployUniversalVerifier( ethSigner, await stateContract.getAddress(), - await verifierLib.getAddress(), ); - const validator = await deployHelper.deployValidatorStub(); - await verifier.addValidatorToWhitelist(await validator.getAddress()); - await verifier.connect(); + await universalVerifier.addValidatorToWhitelist(await validator.getAddress()); + await universalVerifier.connect(); + + const authValidator = await deployHelper.deployValidatorStub("AuthValidatorStub"); + await authValidator.stub_setVerifyResults(1); + + authMethod = { + authMethod: "stubAuth", + validator: await authValidator.getAddress(), + params: "0x", + }; + await universalVerifier.setAuthMethod(authMethod); - return { ethSigner, ethSigner2, ethSigner3, stateContract, verifier, validator }; + return { + ethSigner, + ethSigner2, + ethSigner3, + stateContract, + universalVerifier, + validator, + authValidator, + }; } - async function checkStorageFields(verifier: any, requestId: number, storageFields: any[]) { + async function checkStorageFields(verifier: any, requestId: bigint, storageFields: any[]) { for (const field of storageFields) { - const value = await verifier.getProofStorageField( - await signer.getAddress(), + const value = await verifier.getResponseFieldValue( requestId, + await signer.getAddress(), field.name, ); expect(value).to.be.equal(field.value); } } - beforeEach(async () => { - ({ - ethSigner: signer, - ethSigner2: signer2, - ethSigner3: signer3, - stateContract: state, - verifier, - validator, - } = await loadFixture(deployContractsFixture)); - signerAddress = await signer.getAddress(); - }); + describe("Methods", function () { + beforeEach(async () => { + ({ + ethSigner: signer, + ethSigner2: signer2, + ethSigner3: signer3, + stateContract: state, + universalVerifier: verifier, + validator: validator, + } = await loadFixture(deployContractsFixture)); + request = { + requestId: 0, + metadata: "0x", + validator: await validator.getAddress(), + owner: signer.address, + params: "0x", + }; + + authResponse = { + authMethod: authMethod.authMethod, + proof: "0x", + }; + response = { + requestId: 0, + proof: "0x", + metadata: "0x", + }; + paramsFromValidator = [ + { name: "groupID", value: 0 }, + { name: "verifierID", value: 0 }, + { name: "nullifierSessionID", value: 0 }, + ]; + multiRequest = { + multiRequestId: calculateMultiRequestId([request.requestId], [], signer.address), + requestIds: [request.requestId], + groupIds: [], + metadata: "0x", + }; + await validator.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator.stub_setInput("userID", 1); + + signerAddress = await signer.getAddress(); + }); - it("Test get state address", async () => { - const stateAddr = await verifier.getStateAddress(); - expect(stateAddr).to.be.equal(await state.getAddress()); - }); + it("Test get version", async () => { + const version = await verifier.version(); + expect(version).to.be.equal(contractsInfo.UNIVERSAL_VERIFIER.version); + }); - it("Test add, get ZKPRequest, requestIdExists, getZKPRequestsCount", async () => { - const requestsCount = 3; - const validatorAddr = await validator.getAddress(); + it("Test get state address", async () => { + let stateAddr = await verifier.getStateAddress(); + expect(stateAddr).to.be.equal(await state.getAddress()); - for (let i = 0; i < requestsCount; i++) { - await expect( - verifier.setZKPRequest(i, { - metadata: "metadataN" + i, - validator: validatorAddr, - data: "0x0" + i, - }), - ) - .to.emit(verifier, "ZKPRequestSet") - .withArgs(i, signerAddress, "metadataN" + i, validatorAddr, "0x0" + i); - const request = await verifier.getZKPRequest(i); - expect(request.metadata).to.be.equal("metadataN" + i); - expect(request.validator).to.be.equal(validatorAddr); - expect(request.data).to.be.equal("0x0" + i); - - const requestIdExists = await verifier.requestIdExists(i); - expect(requestIdExists).to.be.true; - const requestIdDoesntExists = await verifier.requestIdExists(i + 1); - expect(requestIdDoesntExists).to.be.false; - - await expect(verifier.getZKPRequest(i + 1)).to.be.rejectedWith("request id doesn't exist"); - } + await verifier.setState(await signer.getAddress()); - const count = await verifier.getZKPRequestsCount(); - expect(count).to.be.equal(requestsCount); - }); + stateAddr = await verifier.getStateAddress(); + expect(stateAddr).to.be.equal(await signer.getAddress()); - it("Test add, get ZKPRequest, requestIdExists, getZKPRequestsCount with multiple set", async () => { - const requestsCount = 3; - const validatorAddr = await validator.getAddress(); - - const requestIds: number[] = []; - const requests: any[] = []; - for (let i = 0; i < requestsCount; i++) { - requestIds.push(i); - requests.push({ - metadata: "metadataN" + i, - validator: validatorAddr, - data: "0x0" + i, - }); - } + await verifier.setState(await state.getAddress()); + }); + + it("Test add, getRequest, requestIdExists, getRequestsCount", async () => { + const requestsCount = 3; + for (let i = 0; i < requestsCount; i++) { + request.requestId = i; + request.metadata = "metadataN" + i; + request.params = "0x0" + i; + + await validator.stub_setRequestParams([request.params], [paramsFromValidator]); + + await expect(verifier.setRequests([request])) + .to.emit(verifier, "RequestSet") + .withArgs(i, signerAddress, "metadataN" + i, request.validator, "0x0" + i); + const requestFromContract = await verifier.getRequest(i); + expect(requestFromContract.metadata).to.be.equal("metadataN" + i); + expect(requestFromContract.validator).to.be.equal(request.validator); + expect(requestFromContract.params).to.be.equal("0x0" + i); + + const requestIdExists = await verifier.requestIdExists(i); + expect(requestIdExists).to.be.true; + const requestIdDoesntExists = await verifier.requestIdExists(i + 1); + expect(requestIdDoesntExists).to.be.false; + + await expect(verifier.getRequest(i + 1)) + .to.be.revertedWithCustomError(verifier, "RequestIdNotFound") + .withArgs(i + 1); + } + + const count = await verifier.getRequestsCount(); + expect(count).to.be.equal(requestsCount); + }); - await expect(verifier.setZKPRequests(requestIds, requests)) - .to.emit(verifier, "ZKPRequestSet") - .withArgs(0, signerAddress, "metadataN" + 0, validatorAddr, "0x0" + 0); + it("Test submit response single request", async () => { + const nonExistingRequestId = 1; + await verifier.setRequests([request]); - for (let i = 1; i < requestsCount; i++) { - const request = await verifier.getZKPRequest(i); - expect(request.metadata).to.be.equal("metadataN" + i); - expect(request.validator).to.be.equal(validatorAddr); - expect(request.data).to.be.equal("0x0" + i); + const tx = await verifier.submitResponse(authResponse, [response], crossChainProofs); - const requestIdExists = await verifier.requestIdExists(i); - expect(requestIdExists).to.be.true; - } + const txRes = await tx.wait(); + await checkStorageFields(verifier, BigInt(request.requestId), storageFields); - const count = await verifier.getZKPRequestsCount(); - expect(count).to.be.equal(requestsCount); - }); + let filter = verifier.filters.ResponseSubmitted; + let events = await verifier.queryFilter(filter, -1); + expect(events[0].eventName).to.be.equal("ResponseSubmitted"); + expect(events[0].args.requestId).to.be.equal(request.requestId); + expect(events[0].args.caller).to.be.equal(signerAddress); - it("Test submit response", async () => { - const requestId = 0; - const nonExistingRequestId = 1; - const data = packValidatorParams(query); + filter = verifier.filters.AuthResponseSubmitted; + events = await verifier.queryFilter(filter, -1); + expect(events[0].eventName).to.be.equal("AuthResponseSubmitted"); + expect(events[0].args.authMethod.hash).to.be.equal( + ethers.keccak256(byteEncoder.encode(authResponse.authMethod)), + ); + expect(events[0].args.caller).to.be.equal(signerAddress); + + const { timestamp: txResTimestamp } = (await ethers.provider.getBlock( + txRes.blockNumber, + )) as Block; - await verifier.setZKPRequest(0, { - metadata: "metadata", - validator: await validator.getAddress(), - data: data, + const status = await verifier.getRequestProofStatus(signerAddress, request.requestId); + expect(status.isVerified).to.be.true; + expect(status.validatorVersion).to.be.equal("1.0.0-stub"); + expect(status.timestamp).to.be.equal(txResTimestamp); + + await expect(verifier.getRequestProofStatus(signerAddress, nonExistingRequestId)) + .to.be.revertedWithCustomError(verifier, "RequestIdNotFound") + .withArgs(nonExistingRequestId); }); - const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson); - const tx = await verifier.submitZKPResponse(0, inputs, pi_a, pi_b, pi_c); - const txRes = await tx.wait(); - const storageFields = [ - { - name: "userID", - value: inputs[1], - }, - { - name: "issuerID", - value: inputs[2], - }, - ]; - await checkStorageFields(verifier, requestId, storageFields); - const filter = verifier.filters.ZKPResponseSubmitted; - - const events = await verifier.queryFilter(filter, -1); - expect(events[0].eventName).to.be.equal("ZKPResponseSubmitted"); - expect(events[0].args.requestId).to.be.equal(0); - expect(events[0].args.caller).to.be.equal(signerAddress); - - const { timestamp: txResTimestamp } = (await ethers.provider.getBlock( - txRes.blockNumber, - )) as Block; - - await expect( - verifier.verifyZKPResponse( - 0, - inputs, - pi_a, - pi_b, - pi_c, - "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", - ), - ).not.to.be.rejected; - - const status = await verifier.getProofStatus(signerAddress, requestId); - expect(status.isVerified).to.be.true; - expect(status.validatorVersion).to.be.equal("2.0.2-mock"); - expect(status.blockNumber).to.be.equal(txRes.blockNumber); - expect(status.blockTimestamp).to.be.equal(txResTimestamp); - - await expect(verifier.getProofStatus(signerAddress, nonExistingRequestId)).to.be.rejectedWith( - "request id doesn't exist", - ); - }); + it("Test submit response multiple request", async () => { + const requestIds = [1, 2]; + await verifier.setRequests([ + { + ...request, + requestId: requestIds[0], + }, + { + ...request, + requestId: requestIds[1], + }, + ]); + + const tx = await verifier.submitResponse( + authResponse, + [ + { + ...response, + requestId: requestIds[0], + }, + { + ...response, + requestId: requestIds[1], + }, + ], + crossChainProofs, + ); - it("Check access control", async () => { - const owner = signer; - const requestOwner = signer2; - const someSigner = signer3; - const requestId = 0; - const nonExistentRequestId = 1; - const requestOwnerAddr = await requestOwner.getAddress(); - const someSignerAddress = await someSigner.getAddress(); - - await expect(verifier.getRequestOwner(requestId)).to.be.rejectedWith( - "request id doesn't exist", - ); - await verifier.connect(requestOwner).setZKPRequest(requestId, { - metadata: "metadata", - validator: await validator.getAddress(), - data: packValidatorParams(query), + const txRes = await tx.wait(); + + for (const requestId of requestIds) { + await checkStorageFields(verifier, BigInt(requestId), storageFields); + } + + let filter = verifier.filters.ResponseSubmitted; + let events = await verifier.queryFilter(filter, -1); + expect(events[0].eventName).to.be.equal("ResponseSubmitted"); + expect(events[0].args.requestId).to.be.equal(requestIds[0]); + expect(events[0].args.caller).to.be.equal(signerAddress); + + filter = verifier.filters.AuthResponseSubmitted; + events = await verifier.queryFilter(filter, -1); + expect(events[0].eventName).to.be.equal("AuthResponseSubmitted"); + expect(events[0].args.authMethod.hash).to.be.equal( + ethers.keccak256(byteEncoder.encode(authResponse.authMethod)), + ); + expect(events[0].args.caller).to.be.equal(signerAddress); + + const { timestamp: txResTimestamp } = (await ethers.provider.getBlock( + txRes.blockNumber, + )) as Block; + + for (const requestId of requestIds) { + const status = await verifier.getRequestProofStatus(signerAddress, requestId); + expect(status.isVerified).to.be.true; + expect(status.validatorVersion).to.be.equal("1.0.0-stub"); + expect(status.timestamp).to.be.equal(txResTimestamp); + } }); - expect(await verifier.getRequestOwner(requestId)).to.be.equal(requestOwnerAddr); - await expect( - verifier.connect(someSigner).setRequestOwner(requestId, someSigner), - ).to.be.rejectedWith("Not an owner or request owner"); + it("Check access control", async () => { + const owner = signer; + const requestOwner = signer2; + const someSigner = signer3; + const nonExistentRequestId = 1; + const requestOwnerAddr = await requestOwner.getAddress(); + const someSignerAddress = await someSigner.getAddress(); - await verifier.connect(requestOwner).setRequestOwner(requestId, someSigner); - expect(await verifier.getRequestOwner(requestId)).to.be.equal(someSignerAddress); + const request2 = { ...request, owner: requestOwnerAddr }; - await expect( - verifier.connect(requestOwner).setRequestOwner(requestId, requestOwnerAddr), - ).to.be.rejectedWith("Not an owner or request owner"); - await verifier.connect(owner).setRequestOwner(requestId, requestOwnerAddr); - expect(await verifier.getRequestOwner(requestId)).to.be.equal(requestOwnerAddr); + await expect(verifier.getRequestOwner(request.requestId)) + .to.be.revertedWithCustomError(verifier, "RequestIdNotFound") + .withArgs(request.requestId); - await expect(verifier.getRequestOwner(nonExistentRequestId)).to.be.rejectedWith( - "request id doesn't exist", - ); - await expect( - verifier.setRequestOwner(nonExistentRequestId, someSignerAddress), - ).to.be.rejectedWith("request id doesn't exist"); - }); + await verifier.connect(requestOwner).setRequests([request2]); - it("Check disable/enable functionality", async () => { - const owner = signer; - const requestOwner = signer2; - const someSigner = signer3; - const requestId = 0; - const nonExistentRequestId = 1; + expect(await verifier.getRequestOwner(request.requestId)).to.be.equal(requestOwnerAddr); + await expect(verifier.connect(someSigner).setRequestOwner(request.requestId, someSigner)) + .to.be.revertedWithCustomError(verifier, "NotAnOwnerOrRequestOwner") + .withArgs(someSigner); - await expect(verifier.isZKPRequestEnabled(requestId)).to.be.rejectedWith( - "request id doesn't exist", - ); + await verifier.connect(requestOwner).setRequestOwner(request.requestId, someSigner); + expect(await verifier.getRequestOwner(request.requestId)).to.be.equal(someSignerAddress); - await verifier.connect(requestOwner).setZKPRequest(requestId, { - metadata: "metadata", - validator: await validator.getAddress(), - data: packValidatorParams(query), + await expect( + verifier.connect(requestOwner).setRequestOwner(request.requestId, requestOwnerAddr), + ) + .to.be.revertedWithCustomError(verifier, "NotAnOwnerOrRequestOwner") + .withArgs(requestOwner); + + await verifier.connect(owner).setRequestOwner(request.requestId, requestOwnerAddr); + expect(await verifier.getRequestOwner(request.requestId)).to.be.equal(requestOwnerAddr); + + await expect(verifier.getRequestOwner(nonExistentRequestId)) + .to.be.revertedWithCustomError(verifier, "RequestIdNotFound") + .withArgs(nonExistentRequestId); + await expect(verifier.setRequestOwner(nonExistentRequestId, someSignerAddress)) + .to.be.revertedWithCustomError(verifier, "RequestIdNotFound") + .withArgs(nonExistentRequestId); }); - expect(await verifier.isZKPRequestEnabled(requestId)).to.be.true; - await expect(verifier.connect(someSigner).disableZKPRequest(requestId)).to.be.rejectedWith( - "Not an owner or request owner", - ); - expect(await verifier.isZKPRequestEnabled(requestId)).to.be.true; + it("Test submit response with disable/enable functionality", async () => { + const requestIds = [0, 1, 2]; + + const singleResponse = [response]; + + const multiResponses = [ + { + ...response, + requestId: 1, + }, + { + ...response, + requestId: 2, + }, + ]; + + for (const requestId of requestIds) { + await verifier.setRequests([ + { + ...request, + requestId: requestId, + }, + ]); + } + + await verifier.disableRequest(singleResponse[0].requestId); + await expect(verifier.submitResponse(authResponse, singleResponse, crossChainProofs)) + .to.be.revertedWithCustomError(verifier, "RequestIsDisabled") + .withArgs(singleResponse[0].requestId); + + await verifier.disableRequest(multiResponses[0].requestId); + await expect(verifier.submitResponse(authResponse, multiResponses, crossChainProofs)) + .to.be.revertedWithCustomError(verifier, "RequestIsDisabled") + .withArgs(multiResponses[0].requestId); + + await verifier.enableRequest(singleResponse[0].requestId); + await expect(verifier.submitResponse(authResponse, singleResponse, crossChainProofs)).not.to + .be.rejected; + + await verifier.enableRequest(multiResponses[0].requestId); + await expect(verifier.submitResponse(authResponse, multiResponses, crossChainProofs)).not.to + .be.rejected; + }); - await verifier.connect(owner).disableZKPRequest(requestId); - expect(await verifier.isZKPRequestEnabled(requestId)).to.be.false; + it("Test submit response check whitelisted functionality", async () => { + const requestIds = [0, 1, 2]; + const singleResponse = [response]; + + const multiResponses = [ + { + ...response, + requestId: 1, + }, + { + ...response, + requestId: 2, + }, + ]; + + for (const requestId of requestIds) { + await verifier.setRequests([ + { + ...request, + requestId: requestId, + }, + ]); + } + + await verifier.removeValidatorFromWhitelist(await validator.getAddress()); + await expect(verifier.submitResponse(authResponse, singleResponse, crossChainProofs)) + .to.be.revertedWithCustomError(verifier, "ValidatorIsNotWhitelisted") + .withArgs(await validator.getAddress()); + await expect(verifier.submitResponse(authResponse, multiResponses, crossChainProofs)) + .to.be.revertedWithCustomError(verifier, "ValidatorIsNotWhitelisted") + .withArgs(await validator.getAddress()); + + await verifier.addValidatorToWhitelist(await validator.getAddress()); + await expect(verifier.submitResponse(authResponse, singleResponse, crossChainProofs)).not.to + .be.rejected; + await expect(verifier.submitResponse(authResponse, multiResponses, crossChainProofs)).not.to + .be.rejected; + }); - await expect(verifier.connect(someSigner).enableZKPRequest(requestId)).to.be.rejectedWith( - "Not an owner or request owner", - ); - await verifier.connect(requestOwner).enableZKPRequest(requestId); - expect(await verifier.isZKPRequestEnabled(requestId)).to.be.true; + it("Check InvalidRequestOwner", async () => { + const requestOwner = signer2; + const owner = signer; + + await expect(verifier.connect(requestOwner).setRequests([request])) + .to.be.revertedWithCustomError(verifier, "InvalidRequestOwner") + .withArgs(request.owner, await requestOwner.getAddress()); + + // Request owner different from the owner of the contract. + const request2 = { ...request, owner: await requestOwner.getAddress() }; + // Owner of the contract is the sender to set the request with different owner + await expect(verifier.connect(owner).setRequests([request2])).not.to.be.reverted; + + // Request owner the same as the sender + const request3 = { + ...request, + requestId: request.requestId + 1, + owner: await requestOwner.getAddress(), + }; + await expect(verifier.connect(requestOwner).setRequests([request3])).not.to.be.reverted; + }); - const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson); - await verifier.submitZKPResponse(0, inputs, pi_a, pi_b, pi_c); + it("Check updateRequest", async () => { + const owner = signer; + const requestOwner = signer2; + const requestId = 0; - await verifier.connect(requestOwner).disableZKPRequest(requestId); - await expect(verifier.submitZKPResponse(0, inputs, pi_a, pi_b, pi_c)).to.be.rejectedWith( - "Request is disabled", - ); - await expect( - verifier.verifyZKPResponse( - 0, - inputs, - pi_a, - pi_b, - pi_c, - "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", - ), - ).to.be.rejectedWith("Request is disabled"); - - await expect(verifier.isZKPRequestEnabled(nonExistentRequestId)).to.be.rejectedWith( - "request id doesn't exist", - ); - await expect(verifier.disableZKPRequest(nonExistentRequestId)).to.be.rejectedWith( - "request id doesn't exist", - ); - await expect(verifier.enableZKPRequest(nonExistentRequestId)).to.be.rejectedWith( - "request id doesn't exist", - ); - }); + const request2 = { ...request, owner: await requestOwner.getAddress() }; + await verifier.connect(requestOwner).setRequests([request2]); - it("Check whitelisted validators", async () => { - const owner = signer; - const someAddress = signer2; - const requestId = 1; - const otherRequestId = 2; - const { validator: mtp } = await deployHelper.deployValidatorContractsWithVerifiers( - "mtpV2", - await state.getAddress(), - ); - const mtpValAddr = await mtp.getAddress(); - expect(await verifier.isWhitelistedValidator(mtpValAddr)).to.be.false; - - await expect( - verifier.setZKPRequest(requestId, { - metadata: "metadata", - validator: mtpValAddr, - data: "0x00", - }), - ).to.be.rejectedWith("Validator is not whitelisted"); - - await expect(verifier.connect(someAddress).addValidatorToWhitelist(mtpValAddr)) - .to.be.revertedWithCustomError(verifier, "OwnableUnauthorizedAccount") - .withArgs(someAddress); - expect(await verifier.isWhitelistedValidator(mtpValAddr)).to.be.false; - - await verifier.connect(owner).addValidatorToWhitelist(mtpValAddr); - expect(await verifier.isWhitelistedValidator(mtpValAddr)).to.be.true; - - await expect( - verifier.setZKPRequest(requestId, { - metadata: "metadata", - validator: mtpValAddr, - data: "0x00", - }), - ).not.to.be.rejected; - - // can't whitelist validator, which does not support ICircuitValidator interface - await expect(verifier.addValidatorToWhitelist(someAddress)).to.be.rejected; - - await expect( - verifier.setZKPRequest(otherRequestId, { - metadata: "metadata", - validator: someAddress, - data: "0x00", - }), - ).to.be.rejectedWith("Validator is not whitelisted"); - - await verifier.removeValidatorFromWhitelist(mtpValAddr); - - await expect( - verifier.submitZKPResponse( - requestId, - [], - [0, 0], - [ - [0, 0], - [0, 0], - ], - [0, 0], - ), - ).to.be.rejectedWith("Validator is not whitelisted"); - }); + let requestStored = await verifier.getRequest(requestId); + expect(requestStored.metadata).to.be.equal(request.metadata); + await expect( + verifier.connect(requestOwner).updateRequest(request2), + ).to.be.revertedWithCustomError(verifier, "OwnableUnauthorizedAccount"); - it("Check updateZKPRequest", async () => { - const owner = signer; - const requestOwner = signer2; - const requestId = 0; - const data = packValidatorParams(query); + await verifier.connect(owner).updateRequest({ + ...request, + metadata: "metadata2", + }); - await verifier.connect(requestOwner).setZKPRequest(requestId, { - metadata: "metadata", - validator: await validator.getAddress(), - data: data, + requestStored = await verifier.getRequest(requestId); + expect(requestStored.metadata).to.be.equal("metadata2"); }); - let request = await verifier.getZKPRequest(requestId); - expect(request.metadata).to.be.equal("metadata"); + it("updateRequest - not existed request", async () => { + const owner = signer; + const requestId = 0; - await expect( - verifier.connect(requestOwner).updateZKPRequest(requestId, { - metadata: "metadata", - validator: await validator.getAddress(), - data: data, - }), - ).to.be.revertedWithCustomError(verifier, "OwnableUnauthorizedAccount"); - - await verifier.connect(owner).updateZKPRequest(requestId, { - metadata: "metadata2", - validator: await validator.getAddress(), - data: data, + await expect(verifier.connect(owner).updateRequest(request)) + .to.be.revertedWithCustomError(verifier, "RequestIdNotFound") + .withArgs(requestId); }); - request = await verifier.getZKPRequest(requestId); - expect(request.metadata).to.be.equal("metadata2"); - }); + it("Test set request fails with VerifierIDIsNotValid", async () => { + ({ + ethSigner: signer, + ethSigner2: signer2, + stateContract: state, + validator: validator, + universalVerifier: verifier, + } = await loadFixture(deployContractsFixture)); + + paramsFromValidator = [ + { name: "groupID", value: 0 }, + { name: "verifierID", value: 2 }, + { name: "nullifierSessionID", value: 0 }, + ]; + + const requestId = 40; + + const request = { + requestId: requestId, + metadata: "0x", + validator: await validator.getAddress(), + owner: signer.address, + params: "0x", + }; + await validator.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator.stub_setInput("userID", 1); + await verifier.setVerifierID(1); + + await expect(verifier.setRequests([request])) + .to.be.revertedWithCustomError(verifier, "VerifierIDIsNotValid") + .withArgs(2, 1); + }); - it("updateZKPRequest - not existed request", async () => { - const owner = signer; - const requestId = 0; - const data = packValidatorParams(query); + it("Check if auth method can be enabled/disabled by only owner", async () => { + await expect( + verifier.connect(signer2).disableAuthMethod(authMethod.authMethod), + ).to.be.revertedWithCustomError(verifier, "OwnableUnauthorizedAccount"); - await expect( - verifier.connect(owner).updateZKPRequest(requestId, { - metadata: "metadata", - validator: await validator.getAddress(), - data: data, - }), - ).to.be.rejectedWith("request id doesn't exist"); + await verifier.connect(signer).disableAuthMethod(authMethod.authMethod); + await verifier.connect(signer).enableAuthMethod(authMethod.authMethod); + }); }); - it("should revert if requestIds and requests length mismatch in setZKPRequests", async () => { - const validatorAddr = await validator.getAddress(); - const requestIds = [1, 2]; - const requests = [ + describe("Events", function () { + const queries = [ { - metadata: "metadata-1", - validator: validatorAddr, - data: "0x01", + schema: 111n, + claimPathKey: 8566939875427719562376598811066985304309117528846759529734201066483458512800n, + operator: 1n, + slotIndex: 0n, + value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))], + queryHash: BigInt( + "1496222740463292783938163206931059379817846775593932664024082849882751356658", + ), + circuitIds: [CircuitId.AtomicQuerySigV2OnChain], + skipClaimRevocationCheck: false, + claimPathNotExists: 0n, + }, + { + schema: 222n, + claimPathKey: BigInt( + "8566939875427719562376598811066985304309117528846759529734201066483458512800", + ), + operator: 1n, + slotIndex: 0n, + value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))], + queryHash: BigInt( + "1496222740463292783938163206931059379817846775593932664024082849882751356658", + ), + circuitIds: [CircuitId.AtomicQuerySigV2OnChain], + skipClaimRevocationCheck: true, + claimPathNotExists: 0n, + }, + { + schema: 333n, + claimPathKey: BigInt( + "8566939875427719562376598811066985304309117528846759529734201066483458512800", + ), + operator: 1n, + slotIndex: 0n, + value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))], + queryHash: BigInt( + "1496222740463292783938163206931059379817846775593932664024082849882751356658", + ), + circuitIds: [CircuitId.AtomicQuerySigV2OnChain], + skipClaimRevocationCheck: false, + claimPathNotExists: 0n, }, ]; - await expect(verifier.setZKPRequests(requestIds, requests)).to.be.rejectedWith( - "Request IDs and requests length mismatch", - ); + + const encodedDataAbi = [ + { + components: [ + { name: "schema", type: "uint256" }, + { name: "claimPathKey", type: "uint256" }, + { name: "operator", type: "uint256" }, + { name: "slotIndex", type: "uint256" }, + { name: "value", type: "uint256[]" }, + { name: "queryHash", type: "uint256" }, + { name: "allowedIssuers", type: "uint256[]" }, + { name: "circuitIds", type: "string[]" }, + { name: "skipClaimRevocationCheck", type: "bool" }, + { name: "claimPathNotExists", type: "uint256" }, + ], + name: "", + type: "tuple", + }, + ]; + + beforeEach(async () => { + ({ + ethSigner: signer, + ethSigner2: signer2, + ethSigner3: signer3, + stateContract: state, + universalVerifier: verifier, + validator: validator, + authValidator: authValidator, + } = await loadFixture(deployContractsFixture)); + signerAddress = await signer.getAddress(); + }); + + it("Check RequestSet event", async () => { + const requestsCount = 3; + const params = [ + packValidatorParams(queries[0]), + packValidatorParams(queries[1]), + packValidatorParams(queries[2]), + ]; + + paramsFromValidator = [ + { name: "groupID", value: 0 }, + { name: "verifierID", value: 0 }, + { name: "nullifierSessionID", value: 0 }, + ]; + + for (let i = 0; i < requestsCount; i++) { + await validator.stub_setRequestParams([params[i]], [paramsFromValidator]); + await validator.stub_setInput("userID", 1); + await expect( + verifier.setRequests([ + { + ...request, + requestId: i, + params: params[i], + }, + ]), + ).to.emit(verifier, "RequestSet"); + } + const filter = verifier.filters.RequestSet(null, null); + const logs = await verifier.queryFilter(filter, 0, "latest"); + + const coder = AbiCoder.defaultAbiCoder(); + logs.map((log, index) => { + const [decodedData] = coder.decode(encodedDataAbi as any, log.args.params); + expect(decodedData.schema).to.equal(queries[index].schema); + expect(decodedData.claimPathKey).to.equal(queries[index].claimPathKey); + expect(decodedData.operator).to.equal(queries[index].operator); + expect(decodedData.slotIndex).to.equal(queries[index].slotIndex); + decodedData.value.forEach((v, i) => { + expect(v).to.equal(queries[index].value[i]); + }); + expect(decodedData.queryHash).to.equal(queries[index].queryHash); + decodedData.circuitIds.forEach((circuitId, i) => { + expect(circuitId).to.equal(queries[index].circuitIds[i]); + }); + expect(decodedData.skipClaimRevocationCheck).to.equal( + queries[index].skipClaimRevocationCheck, + ); + expect(decodedData.claimPathNotExists).to.equal(queries[index].claimPathNotExists); + }); + }); + + it("Check RequestUpdate event", async () => { + const originalRequestData = packValidatorParams(queries[0]); + const updatedRequestData = packValidatorParams(queries[1]); + + await validator.stub_setRequestParams([originalRequestData], [paramsFromValidator]); + await validator.stub_setRequestParams([updatedRequestData], [paramsFromValidator]); + await validator.stub_setInput("userID", 1); + + await verifier.setRequests([ + { + ...request, + params: originalRequestData, + }, + ]); + + await verifier.updateRequest({ + ...request, + metadata: "metadataN1", + params: updatedRequestData, + }); + + const filter = verifier.filters.RequestUpdate(null, null); + const logs = await verifier.queryFilter(filter, 0, "latest"); + + const coder = AbiCoder.defaultAbiCoder(); + logs.map((log) => { + const [decodedData] = coder.decode(encodedDataAbi as any, log.args.params); + expect(decodedData.schema).to.equal(queries[1].schema); + expect(decodedData.claimPathKey).to.equal(queries[1].claimPathKey); + expect(decodedData.operator).to.equal(queries[1].operator); + expect(decodedData.slotIndex).to.equal(queries[1].slotIndex); + decodedData.value.forEach((v, i) => { + expect(v).to.equal(queries[1].value[i]); + }); + expect(decodedData.queryHash).to.equal(queries[1].queryHash); + decodedData.circuitIds.forEach((circuitId, i) => { + expect(circuitId).to.equal(queries[1].circuitIds[i]); + }); + expect(decodedData.skipClaimRevocationCheck).to.equal(queries[1].skipClaimRevocationCheck); + expect(decodedData.claimPathNotExists).to.equal(queries[1].claimPathNotExists); + }); + }); + + it("Check AuthMethodSet event", async () => { + const nonExistingAuthMethod = { + authMethod: "stubAuth2", + validator: await authValidator.getAddress(), + params: "0x", + }; + const tx = await verifier.setAuthMethod(nonExistingAuthMethod); + + const filter = verifier.filters.AuthMethodSet; + const events = await verifier.queryFilter(filter, tx.blockNumber); + expect(events[0].eventName).to.be.equal("AuthMethodSet"); + expect(events[0].args.authMethod.hash).to.be.equal( + ethers.keccak256(byteEncoder.encode(nonExistingAuthMethod.authMethod)), + ); + expect(events[0].args.validator).to.be.equal(nonExistingAuthMethod.validator); + expect(events[0].args.params).to.be.equal(nonExistingAuthMethod.params); + }); + + it("Check MultiRequestSet event", async function () { + await validator.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator.stub_setInput("userID", 1); + await verifier.setRequests([request]); + + await expect(verifier.setMultiRequest(multiRequest)).to.emit(verifier, "MultiRequestSet"); + + const filter = verifier.filters.MultiRequestSet; + const events = await verifier.queryFilter(filter, -1); + expect(events[0].eventName).to.be.equal("MultiRequestSet"); + expect(events[0].args.multiRequestId).to.be.equal(multiRequest.multiRequestId); + expect(events[0].args.requestIds).to.deep.equal(multiRequest.requestIds); + expect(events[0].args.groupIds).to.deep.equal(multiRequest.groupIds); + }); }); }); diff --git a/test/verifier/universal-verifier.v3.test.ts b/test/verifier/universal-verifier.v3.test.ts deleted file mode 100644 index 08c840c57..000000000 --- a/test/verifier/universal-verifier.v3.test.ts +++ /dev/null @@ -1,312 +0,0 @@ -import { DeployHelper } from "../../helpers/DeployHelper"; -import { ethers } from "hardhat"; -import { packV3ValidatorParams } from "../utils/validator-pack-utils"; -import { prepareInputs, publishState } from "../utils/state-utils"; -import { calculateQueryHashV3 } from "../utils/query-hash-utils"; -import { expect } from "chai"; -import { CircuitId } from "@0xpolygonid/js-sdk"; -import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; -import proofJson from "../validators/v3/data/valid_bjj_user_genesis_auth_disabled_v3.json"; -import stateTransition1 from "../validators/common-data/issuer_from_genesis_state_to_first_auth_disabled_transition_v3.json"; -import stateTransition11 from "../validators/common-data/issuer_from_genesis_state_to_first_transition_v3.json"; -import stateTransition12 from "../validators/common-data/user_from_genesis_state_to_first_transition_v3.json"; -import stateTransition13 from "../validators/common-data/issuer_from_first_state_to_second_transition_v3.json"; -import { packZKProof } from "../utils/packData"; -import { TEN_YEARS } from "../../helpers/constants"; - -const storageFields = [ - { - name: "issuerID", - value: 22057981499787921734624217749308316644136637822444794206796063681866502657n, - }, - { - name: "userID", - value: 23013175891893363078841232968022302880776034013620341061794940968520126978n, - }, - { name: "timestamp", value: 1642074362n }, - { - name: "linkID", - value: 19823993270096139446564592922993947503208333537792611306066620392561342309875n, - }, - { name: "nullifier", value: 0 }, -]; - -describe("Universal Verifier V3 validator", function () { - let verifier: any, v3Validator: any, state: any; - let signer, signer2; - let deployHelper: DeployHelper; - - const value = ["20010101", ...new Array(63).fill("0")]; - - const schema = "267831521922558027206082390043321796944"; - const slotIndex = 0; // 0 for signature - const operator = 2; - const claimPathKey = - "20376033832371109177683048456014525905119173674985843915445634726167450989630"; - const [merklized, isRevocationChecked, valueArrSize] = [1, 1, 1]; - const nullifierSessionId = "0"; - const verifierId = "21929109382993718606847853573861987353620810345503358891473103689157378049"; - const queryHash = calculateQueryHashV3( - value, - schema, - slotIndex, - operator, - claimPathKey, - valueArrSize, - merklized, - isRevocationChecked, - verifierId, - nullifierSessionId, - ); - - const query = { - schema, - claimPathKey, - operator, - slotIndex, - value, - circuitIds: [CircuitId.AtomicQueryV3OnChain], - skipClaimRevocationCheck: false, - queryHash, - groupID: 1, - nullifierSessionID: nullifierSessionId, // for ethereum based user - proofType: 1, // 1 for BJJ - verifierID: verifierId, - }; - - const initializeState = async () => { - deployHelper = await DeployHelper.initialize(null, true); - - const { state: stateContract } = await deployHelper.deployStateWithLibraries(["0x0212"]); - const verifierLib = await deployHelper.deployVerifierLib(); - const contracts = await deployHelper.deployValidatorContractsWithVerifiers( - "v3", - await stateContract.getAddress(), - ); - const validator = contracts.validator; - const universalVerifier: any = await deployHelper.deployUniversalVerifier( - signer, - await stateContract.getAddress(), - await verifierLib.getAddress(), - ); - await universalVerifier.addValidatorToWhitelist(await validator.getAddress()); - await universalVerifier.connect(); - - return { stateContract, validator, universalVerifier }; - }; - - async function deployContractsFixture() { - const [ethSigner, ethSigner2] = await ethers.getSigners(); - const { stateContract, validator, universalVerifier } = await initializeState(); - return { ethSigner, ethSigner2, stateContract, universalVerifier, validator }; - } - - async function checkStorageFields(verifier: any, requestId: number, storageFields: any[]) { - for (const field of storageFields) { - const value = await verifier.getProofStorageField( - await signer.getAddress(), - requestId, - field.name, - ); - expect(value).to.be.equal(field.value); - } - } - - before(async () => { - ({ - ethSigner: signer, - ethSigner2: signer2, - stateContract: state, - validator: v3Validator, - universalVerifier: verifier, - } = await loadFixture(deployContractsFixture)); - await v3Validator.setProofExpirationTimeout(TEN_YEARS); - }); - - it("Test submit response", async () => { - await publishState(state, stateTransition1 as any); - const data = packV3ValidatorParams(query); - const requestId = 32; - await verifier.setZKPRequest(requestId, { - metadata: "metadata", - validator: await v3Validator.getAddress(), - data: data, - }); - await v3Validator.setProofExpirationTimeout(TEN_YEARS); - - const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson); - - await verifier.verifyZKPResponse( - requestId, - inputs, - pi_a, - pi_b, - pi_c, - "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", - ); - - await expect(verifier.submitZKPResponse(requestId, inputs, pi_a, pi_b, pi_c)).not.to.be - .rejected; - - await checkStorageFields(verifier, requestId, storageFields); - }); - - it("Test submit response V2", async () => { - const requestId = 32; - - const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson); - - const zkProof = packZKProof(inputs, pi_a, pi_b, pi_c); - - const crossChainProofs = "0x"; - - const metadatas = "0x"; - - await expect( - verifier.submitZKPResponseV2( - [ - { - requestId, - zkProof: zkProof, - data: metadatas, - }, - ], - crossChainProofs, - ), - ).not.to.be.rejected; - - await checkStorageFields(verifier, requestId, storageFields); - }); - - it("Test submit response fails with UserID does not correspond to the sender", async () => { - const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson); - const requestId = 32; - await expect( - verifier.connect(signer2).submitZKPResponse(requestId, inputs, pi_a, pi_b, pi_c), - ).to.be.rejectedWith("UserID does not correspond to the sender"); - }); - - it("Test submit response fails with Issuer is not on the Allowed Issuers list", async () => { - const data = packV3ValidatorParams(query, ["1"]); - const requestId = 33; - await verifier.setZKPRequest(requestId, { - metadata: "metadata", - validator: await v3Validator.getAddress(), - data: data, - }); - - const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson); - - await expect( - verifier.connect(signer).submitZKPResponse(requestId, inputs, pi_a, pi_b, pi_c), - ).to.be.rejectedWith("Issuer is not on the Allowed Issuers list"); - }); - - it("Test submit response fails with Invalid Link ID pub signal", async () => { - const query2 = { - ...query, - }; - query2.groupID = 0; - const requestId = 34; - const data = packV3ValidatorParams(query2); - await verifier.setZKPRequest(requestId, { - metadata: "metadata", - validator: await v3Validator.getAddress(), - data: data, - }); - - const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson); - - await expect( - verifier.connect(signer).submitZKPResponse(requestId, inputs, pi_a, pi_b, pi_c), - ).to.be.rejectedWith("Invalid Link ID pub signal"); - }); - - it("Test submit response fails with Proof type should match the requested one in query", async () => { - const query2 = { - ...query, - }; - query2.proofType = 2; - const requestId = 35; - const data = packV3ValidatorParams(query2); - await verifier.setZKPRequest(requestId, { - metadata: "metadata", - validator: await v3Validator.getAddress(), - data: data, - }); - - const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson); - - await expect( - verifier.connect(signer).submitZKPResponse(requestId, inputs, pi_a, pi_b, pi_c), - ).to.be.rejectedWith("Proof type should match the requested one in query"); - }); - - it("Test submit response fails with Invalid nullify pub signal", async () => { - const query2 = { - ...query, - }; - query2.nullifierSessionID = "2"; - const requestId = 36; - const data = packV3ValidatorParams(query2); - await verifier.setZKPRequest(requestId, { - metadata: "metadata", - validator: await v3Validator.getAddress(), - data: data, - }); - - const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson); - - await expect( - verifier.connect(signer).submitZKPResponse(requestId, inputs, pi_a, pi_b, pi_c), - ).to.be.rejectedWith("Invalid nullify pub signal"); - }); - - it("Test submit response fails with Query hash does not match the requested one", async () => { - const query2 = { - ...query, - }; - query2.queryHash = BigInt(0); - const requestId = 37; - const data = packV3ValidatorParams(query2); - await verifier.setZKPRequest(requestId, { - metadata: "metadata", - validator: await v3Validator.getAddress(), - data: data, - }); - - const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson); - - await expect( - verifier.connect(signer).submitZKPResponse(requestId, inputs, pi_a, pi_b, pi_c), - ).to.be.rejectedWith("Query hash does not match the requested one"); - }); - - it("Test submit response fails with Generated proof is outdated", async () => { - ({ - ethSigner: signer, - ethSigner2: signer2, - stateContract: state, - validator: v3Validator, - universalVerifier: verifier, - } = await loadFixture(deployContractsFixture)); - - await publishState(state, stateTransition11 as any); - await publishState(state, stateTransition12 as any); - await publishState(state, stateTransition13 as any); - - const data = packV3ValidatorParams(query); - const requestId = 37; - await verifier.setZKPRequest(requestId, { - metadata: "metadata", - validator: await v3Validator.getAddress(), - data: data, - }); - - const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson); - - await expect( - verifier.connect(signer).submitZKPResponse(requestId, inputs, pi_a, pi_b, pi_c), - ).to.be.rejectedWith("Generated proof is outdated"); - }); -}); diff --git a/test/verifier/validatorWhitelist.test.ts b/test/verifier/validatorWhitelist.test.ts new file mode 100644 index 000000000..f71661d36 --- /dev/null +++ b/test/verifier/validatorWhitelist.test.ts @@ -0,0 +1,77 @@ +import { ethers } from "hardhat"; +import { beforeEach } from "mocha"; +import { DeployHelper } from "../../helpers/DeployHelper"; +import { expect } from "chai"; + +describe("ValidatorWhitelist tests", function () { + let verifier, validator: any; + let signer1, signer2: any; + let request, paramsFromValidator: any; + + async function deployContractsFixture() { + [signer1, signer2] = await ethers.getSigners(); + + const deployHelper = await DeployHelper.initialize(null, true); + const verifier = await ethers.deployContract("ValidatorWhitelistTestWrapper", []); + + const { state } = await deployHelper.deployStateWithLibraries([], "Groth16VerifierStub"); + await verifier.initialize(await state.getAddress()); + + const validator = await ethers.deployContract("RequestValidatorStub"); + return { verifier, validator, signer1, signer2 }; + } + + beforeEach(async function () { + ({ verifier, validator, signer1, signer2 } = await deployContractsFixture()); + + request = { + requestId: 1, + metadata: "0x", + validator: await validator.getAddress(), + owner: await signer1.getAddress(), + params: "0x", + }; + + paramsFromValidator = [ + { name: "groupID", value: 0 }, + { name: "verifierID", value: 0 }, + { name: "nullifierSessionID", value: 0 }, + ]; + }); + + it("whitelist/remove Validators and modifier onlyWhitelistedValidator", async function () { + let isWhitelistedValidator = await verifier.isWhitelistedValidator( + await validator.getAddress(), + ); + expect(isWhitelistedValidator).to.be.false; + + await expect(verifier.testModifier(await validator.getAddress())).to.be.revertedWithCustomError( + verifier, + "ValidatorIsNotWhitelisted", + ); + + await verifier.addValidatorToWhitelist(await validator.getAddress()); + + await validator.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator.stub_setInput("userID", 1); + await verifier.setRequests([request]); + + await expect(verifier.testModifier(await validator.getAddress())).not.to.be.reverted; + await expect(verifier.getRequestIfCanBeVerified(request.requestId)).not.to.be.reverted; + + isWhitelistedValidator = await verifier.isWhitelistedValidator(await validator.getAddress()); + expect(isWhitelistedValidator).to.be.true; + + await verifier.removeValidatorFromWhitelist(await validator.getAddress()); + + await expect(verifier.testModifier(await validator.getAddress())) + .to.be.revertedWithCustomError(verifier, "ValidatorIsNotWhitelisted") + .withArgs(await validator.getAddress()); + await expect(verifier.getRequestIfCanBeVerified(request.requestId)) + .to.be.revertedWithCustomError(verifier, "ValidatorIsNotWhitelisted") + .withArgs(await validator.getAddress()); + + isWhitelistedValidator = await verifier.isWhitelistedValidator(await validator.getAddress()); + expect(isWhitelistedValidator).to.be.false; + }); +}); diff --git a/test/verifier/verifier.test.ts b/test/verifier/verifier.test.ts new file mode 100644 index 000000000..ad3905f0f --- /dev/null +++ b/test/verifier/verifier.test.ts @@ -0,0 +1,763 @@ +import { ethers } from "hardhat"; +import { beforeEach } from "mocha"; +import { DeployHelper } from "../../helpers/DeployHelper"; +import { expect } from "chai"; +import { + calculateGroupID, + calculateMultiRequestId, + calculateRequestID, +} from "../utils/id-calculation-utils"; + +describe("Verifier tests", function () { + let sender: any; + let verifier, validator1, validator2: any; + let request, paramsFromValidator, authMethod: any; + let multiRequest: any; + let signer: any; + let signerAddress: string; + let verifierId: any; + + async function deployContractsFixture() { + [signer] = await ethers.getSigners(); + signerAddress = await signer.getAddress(); + + const deployHelper = await DeployHelper.initialize(null, true); + const verifier = await ethers.deployContract("VerifierTestWrapper", []); + + const { state } = await deployHelper.deployStateWithLibraries([], "Groth16VerifierStub"); + await verifier.initialize(await state.getAddress()); + + const authValidatorStub = await ethers.deployContract("AuthValidatorStub"); + await authValidatorStub.stub_setVerifyResults(1); + + authMethod = { + authMethod: "stubAuth", + validator: await authValidatorStub.getAddress(), + params: "0x", + }; + + await verifier.setAuthMethod(authMethod); + + const validator1 = await ethers.deployContract("RequestValidatorStub"); + const validator2 = await ethers.deployContract("RequestValidatorStub"); + return { verifier, validator1, validator2 }; + } + + describe("Single request tests", function () { + beforeEach(async function () { + [sender] = await ethers.getSigners(); + ({ verifier, validator1, validator2 } = await deployContractsFixture()); + + verifierId = await verifier.getVerifierID(); + + request = { + requestId: 1, + metadata: "0x", + validator: await validator1.getAddress(), + owner: await sender.getAddress(), + params: "0x", + }; + + paramsFromValidator = [ + { name: "groupID", value: 0 }, + { name: "verifierID", value: 0 }, + { name: "nullifierSessionID", value: 0 }, + ]; + + multiRequest = { + multiRequestId: calculateMultiRequestId([request.requestId], [], signerAddress), + requestIds: [request.requestId], + groupIds: [], + metadata: "0x", + }; + }); + + it("setRequests: should not exist when creating", async function () { + await validator1.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator1.stub_setInput("userID", 1); + + let requestIdExists = await verifier.requestIdExists(request.requestId); + expect(requestIdExists).to.be.false; + let requestsCount = await verifier.getRequestsCount(); + expect(requestsCount).to.be.equal(0); + + await expect(verifier.setRequests([request])).not.to.be.rejected; + await expect(verifier.setRequests([request])) + .to.be.revertedWithCustomError(verifier, "RequestIdAlreadyExists") + .withArgs(request.requestId); + + requestIdExists = await verifier.requestIdExists(request.requestId); + expect(requestIdExists).to.be.true; + requestsCount = await verifier.getRequestsCount(); + expect(requestsCount).to.be.equal(1); + }); + + it("setRequests: should revert with MissingUserIDInRequest", async function () { + await validator1.stub_setRequestParams([request.params], [paramsFromValidator]); + + await expect(verifier.setRequests([request])) + .to.be.revertedWithCustomError(verifier, "MissingUserIDInRequest") + .withArgs(request.requestId); + }); + + it("setRequests: nullifierSessionID may be not unique if EQUAL to 0", async function () { + await validator1.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator1.stub_setInput("userID", 1); + + await verifier.setRequests([request]); + request.requestId = 2; + await verifier.setRequests([request]); + }); + + it("setRequests: nullifierSessionID must be unique if NOT EQUAL to 0", async function () { + paramsFromValidator = [ + { name: "groupID", value: 0 }, + { name: "verifierID", value: 0 }, + { name: "nullifierSessionID", value: 1 }, + ]; + await validator1.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator1.stub_setInput("userID", 1); + + await verifier.setRequests([request]); + request.requestId = 2; + await expect(verifier.setRequests([request])) + .to.be.revertedWithCustomError(verifier, "NullifierSessionIDAlreadyExists") + .withArgs(1); + }); + + it("Check InvalidRequestOwner", async () => { + await validator1.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator1.stub_setInput("userID", 1); + + const requestOwner = (await ethers.getSigners())[2]; + + await expect(verifier.connect(requestOwner).setRequests([request])) + .to.be.revertedWithCustomError(verifier, "InvalidRequestOwner") + .withArgs(request.owner, await requestOwner.getAddress()); + + // Request owner the same as the sender + const request3 = { + ...request, + requestId: request.requestId + 1, + owner: await requestOwner.getAddress(), + }; + await expect(verifier.connect(requestOwner).setRequests([request3])).not.to.be.reverted; + }); + + it("setRequests: requestId should be valid", async function () { + await validator1.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator1.stub_setInput("userID", 1); + + request.requestId = BigInt( + "0x0002000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + ); // requestId without valid prefix 0x00000000000000_00 or 0x00000000000000_01 (eigth byte) + + await expect(verifier.setRequests([request])).to.be.revertedWithCustomError( + verifier, + "RequestIdTypeNotValid", + ); + + request.requestId = BigInt( + "0x0000000001000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + ); // requestId uses reserved bytes (firt to seventh byte) 0x00000000000000 + await expect(verifier.setRequests([request])).to.be.revertedWithCustomError( + verifier, + "RequestIdUsesReservedBytes", + ); + + const expectedRequestId = calculateRequestID(request.params, sender.address); + request.requestId = BigInt( + "0x0001000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + ); // requestId idType is valid but calculation from hash params is not valid + await expect(verifier.setRequests([request])) + .to.be.revertedWithCustomError(verifier, "RequestIdNotValid") + .withArgs(expectedRequestId, request.requestId); + + // requestId is valid; + request.requestId = expectedRequestId; + await expect(verifier.setRequests([request])).not.to.be.rejected; + }); + + it("setRequests: a group should be formed by the groupID encoded in requests params", async function () { + const requestId2 = 2; + const groupID = calculateGroupID([request.requestId, BigInt(requestId2)]); + + const request1 = { ...request, groupID }; + const request2 = { ...request, requestId: requestId2, groupID }; + paramsFromValidator = [ + { name: "groupID", value: groupID }, + { name: "verifierID", value: 0 }, + { name: "nullifierSessionID", value: 0 }, + ]; + await validator1.stub_setRequestParams([request1.params], [paramsFromValidator]); + await validator1.stub_setRequestParams([request2.params], [paramsFromValidator]); + await validator1.stub_setInput("userID", 1); + + let groupExists = await verifier.groupIdExists(groupID); + expect(groupExists).to.be.false; + let groupsCount = await verifier.getGroupsCount(); + expect(groupsCount).to.be.equal(0); + + await verifier.setRequests([request1, request2]); + + groupExists = await verifier.groupIdExists(groupID); + expect(groupExists).to.be.true; + groupsCount = await verifier.getGroupsCount(); + expect(groupsCount).to.be.equal(1); + + const groupedRequests = await verifier.getGroupedRequests(groupID); + expect(groupedRequests.length).to.be.equal(2); + expect(groupedRequests[0].requestId).to.be.equal(request1.requestId); + expect(groupedRequests[1].requestId).to.be.equal(request2.requestId); + }); + + it("setRequests: a group should not exist previously", async function () { + const requestId2 = 2; + const groupID = calculateGroupID([BigInt(request.requestId), BigInt(requestId2)]); + + const request1 = { ...request, groupID }; + const request2 = { ...request, requestId: requestId2, groupID }; + + paramsFromValidator = [ + { name: "groupID", value: groupID }, + { name: "verifierID", value: 0 }, + { name: "nullifierSessionID", value: 0 }, + ]; + await validator1.stub_setRequestParams([request1.params], [paramsFromValidator]); + await validator1.stub_setRequestParams([request2.params], [paramsFromValidator]); + await validator1.stub_setInput("userID", 1); + + await verifier.setRequests([request1, request2]); + + await expect(verifier.setRequests([request1, request2])) + .to.be.revertedWithCustomError(verifier, "GroupIdAlreadyExists") + .withArgs(groupID); + }); + + it("getRequest: requestId should exist", async function () { + await expect(verifier.getRequest(request.requestId)) + .to.be.revertedWithCustomError(verifier, "RequestIdNotFound") + .withArgs(request.requestId); + + paramsFromValidator = [ + { name: "groupID", value: 0 }, + { name: "verifierID", value: verifierId }, + { name: "nullifierSessionID", value: 0 }, + ]; + + await validator1.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator1.stub_setInput("userID", 1); + await verifier.setRequests([request]); + + const requestObject = await verifier.getRequest(request.requestId); + + expect(requestObject.requestId).to.be.equal(request.requestId); + expect(requestObject.metadata).to.be.equal(request.metadata); + expect(requestObject.validator).to.be.equal(request.validator); + expect(requestObject.params).to.be.equal(request.params); + expect(requestObject.creator).to.be.equal(await signer.getAddress()); + }); + + it("getRequestProofStatus: requestId should exist", async function () { + const nonExistingRequestId = 2; + + await expect(verifier.getRequestProofStatus(signerAddress, nonExistingRequestId)) + .to.be.revertedWithCustomError(verifier, "RequestIdNotFound") + .withArgs(nonExistingRequestId); + }); + + it("getAuthMethod: authMethod should exist", async function () { + const authMethod2 = { ...authMethod, authMethod: "stubAuth2" }; + + await expect(verifier.getAuthMethod(authMethod2.authMethod)) + .to.be.revertedWithCustomError(verifier, "AuthMethodNotFound") + .withArgs(authMethod2.authMethod); + + await expect(verifier.setAuthMethod(authMethod)) + .to.be.revertedWithCustomError(verifier, "AuthMethodAlreadyExists") + .withArgs(authMethod.authMethod); + + await expect(verifier.setAuthMethod(authMethod2)).not.to.be.reverted; + + const authMethodObject = await verifier.getAuthMethod(authMethod.authMethod); + expect(authMethodObject.validator).to.be.equal(authMethod2.validator); + expect(authMethodObject.params).to.be.equal(authMethod2.params); + }); + + it("enableAuthMethod/disableAuthMethod", async function () { + let authMethodObject = await verifier.getAuthMethod(authMethod.authMethod); + expect(authMethodObject.isActive).to.be.true; + + await verifier.disableAuthMethod(authMethod.authMethod); + + authMethodObject = await verifier.getAuthMethod(authMethod.authMethod); + expect(authMethodObject.isActive).to.be.false; + + await validator1.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator1.stub_setInput("userID", 1); + await verifier.setRequests([request]); + + const authResponse = { + authMethod: authMethod.authMethod, + proof: "0x", + }; + const response = { + requestId: request.requestId, + proof: "0x", + metadata: "0x", + }; + const crossChainProofs = "0x"; + + await expect(verifier.submitResponse(authResponse, [response], crossChainProofs)) + .to.be.revertedWithCustomError(verifier, "AuthMethodIsNotActive") + .withArgs(authMethod.authMethod); + + await verifier.enableAuthMethod(authMethod.authMethod); + + authMethodObject = await verifier.getAuthMethod(authMethod.authMethod); + expect(authMethodObject.isActive).to.be.true; + + await expect(verifier.submitResponse(authResponse, [response], crossChainProofs)).not.to.be + .reverted; + }); + + it("submitResponse: not repeated responseFields from validator", async function () { + await validator1.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator1.stub_setInput("userID", 1); + await verifier.setRequests([request]); + await validator1.stub_setVerifyResults([ + { + name: "someFieldName1", + value: 1, + rawValue: "0x", + }, + { + name: "someFieldName2", + value: 2, + rawValue: "0x", + }, + ]); + + const authResponse = { + authMethod: authMethod.authMethod, + proof: "0x", + }; + const response = { + requestId: request.requestId, + proof: "0x", + metadata: "0x", + }; + const crossChainProofs = "0x"; + + let isRequestProofVerified = await verifier.isRequestProofVerified(sender, request.requestId); + expect(isRequestProofVerified).to.be.false; + + await verifier.submitResponse(authResponse, [response], crossChainProofs); + + isRequestProofVerified = await verifier.isRequestProofVerified(sender, request.requestId); + expect(isRequestProofVerified).to.be.true; + + const responseField1 = await verifier.getResponseFieldValue( + request.requestId, + sender, + "someFieldName1", + ); + expect(responseField1).to.be.equal(1); + const responseField2 = await verifier.getResponseFieldValue( + request.requestId, + sender, + "someFieldName2", + ); + expect(responseField2).to.be.equal(2); + + const responseFields = await verifier.getResponseFields(request.requestId, sender); + expect(responseFields.length).to.be.equal(2); + expect(responseFields[0].name).to.be.equal("someFieldName1"); + expect(responseFields[0].value).to.be.equal(1); + expect(responseFields[1].name).to.be.equal("someFieldName2"); + expect(responseFields[1].value).to.be.equal(2); + }); + + it("submitResponse: should throw if repeated responseFields from validator", async function () { + await validator1.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator1.stub_setInput("userID", 1); + await verifier.setRequests([request]); + await validator1.stub_setVerifyResults([ + { + name: "someFieldName1", + value: 1, + rawValue: "0x", + }, + { + name: "someFieldName1", + value: 1, + rawValue: "0x", + }, + ]); + + const authResponse = { + authMethod: authMethod.authMethod, + proof: "0x", + }; + const response = { + requestId: request.requestId, + proof: "0x", + metadata: "0x", + }; + const crossChainProofs = "0x"; + await expect(verifier.submitResponse(authResponse, [response], crossChainProofs)) + .to.revertedWithCustomError(verifier, "ResponseFieldAlreadyExists") + .withArgs("someFieldName1"); + }); + + it("submitResponse: userID in response fields should match auth userID", async function () { + await validator1.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator1.stub_setInput("userID", 1); + await verifier.setRequests([request]); + + let userID = 1; // we assume that userID is hardcoded to 1 in the auth stub contract + await validator1.stub_setVerifyResults([ + { + name: "userID", + value: userID, + rawValue: "0x", + }, + ]); + + const authResponse = { + authMethod: authMethod.authMethod, + proof: "0x", + }; + const response = { + requestId: request.requestId, + proof: "0x", + metadata: "0x", + }; + const crossChainProofs = "0x"; + + await verifier.submitResponse(authResponse, [response], crossChainProofs); + + userID = 2; + await validator1.stub_setVerifyResults([ + { + name: "userID", + value: userID, + rawValue: "0x", + }, + ]); + + await expect(verifier.submitResponse(authResponse, [response], crossChainProofs)) + .to.revertedWithCustomError(verifier, "UserIDMismatch") + .withArgs(1, 2); + }); + }); + + describe("Multi request tests", function () { + before(async function () { + [sender] = await ethers.getSigners(); + ({ verifier, validator1, validator2 } = await deployContractsFixture()); + + request = { + requestId: 1, + metadata: "0x", + validator: await validator1.getAddress(), + owner: await sender.getAddress(), + params: "0x", + }; + + paramsFromValidator = [ + { name: "groupID", value: 0 }, + { name: "verifierID", value: 0 }, + { name: "nullifierSessionID", value: 0 }, + ]; + + multiRequest = { + multiRequestId: calculateMultiRequestId([request.requestId], [], signerAddress), + requestIds: [request.requestId], + groupIds: [], + metadata: "0x", + }; + }); + + it("setMultiRequest: should not exist when creating", async function () { + await validator1.stub_setRequestParams([request.params], [paramsFromValidator]); + await validator1.stub_setInput("userID", 1); + await verifier.setRequests([request]); + + let multiRequestIdExists = await verifier.multiRequestIdExists(multiRequest.multiRequestId); + expect(multiRequestIdExists).to.be.false; + await expect(verifier.setMultiRequest(multiRequest)).not.to.be.rejected; + await expect(verifier.setMultiRequest(multiRequest)) + .revertedWithCustomError(verifier, "MultiRequestIdAlreadyExists") + .withArgs(multiRequest.multiRequestId); + multiRequestIdExists = await verifier.multiRequestIdExists(multiRequest.multiRequestId); + expect(multiRequestIdExists).to.be.true; + }); + + it("setMultiRequest: should only create multi request with correct id", async function () { + await expect(verifier.setMultiRequest({ ...multiRequest, multiRequestId: 1 })) + .to.be.revertedWithCustomError(verifier, "MultiRequestIdNotValid") + .withArgs(multiRequest.multiRequestId, 1); + }); + + it("setMultiRequest: requestIds and groupIds should exist", async function () { + const multiRequest2 = { + multiRequestId: calculateMultiRequestId([2n], [], signerAddress), + requestIds: [2], + groupIds: [], + metadata: "0x", + }; + + await expect(verifier.setMultiRequest(multiRequest2)) + .revertedWithCustomError(verifier, "RequestIdNotFound") + .withArgs(multiRequest2.requestIds[0]); + + const multiRequest3 = { + multiRequestId: calculateMultiRequestId([], [2n], signerAddress), + requestIds: [], + groupIds: [2], + metadata: "0x", + }; + + await expect(verifier.setMultiRequest(multiRequest3)) + .revertedWithCustomError(verifier, "GroupIdNotFound") + .withArgs(multiRequest3.groupIds[0]); + }); + + it("getMultiRequest: multiRequestId should exist", async function () { + const nonExistingMultiRequestId = 5; + await expect(verifier.getMultiRequest(nonExistingMultiRequestId)) + .to.be.revertedWithCustomError(verifier, "MultiRequestIdNotFound") + .withArgs(nonExistingMultiRequestId); + const multiRequestObject = await verifier.getMultiRequest(multiRequest.multiRequestId); + expect(multiRequestObject.multiRequestId).to.be.equal(multiRequest.multiRequestId); + expect(multiRequestObject.metadata).to.be.equal(multiRequest.metadata); + expect(multiRequestObject.requestIds.length).to.be.equal(multiRequest.requestIds.length); + expect(multiRequestObject.groupIds.length).to.be.equal(multiRequest.groupIds.length); + }); + + it("setMultiRequest: check statuses of two different multiRequests pointing to the same requests", async function () { + const signer2 = (await ethers.getSigners())[1]; + const multiRequest2 = { + ...multiRequest, + multiRequestId: calculateMultiRequestId( + multiRequest.requestIds, + multiRequest.groupIds, + signer2.address, + ), + }; + await verifier.connect(signer2).setMultiRequest(multiRequest2); + + let areMultiRequestProofsVerified = await verifier.areMultiRequestProofsVerified( + multiRequest.multiRequestId, + signerAddress, + ); + expect(areMultiRequestProofsVerified).to.be.false; + + let isMultiRequest2Verified = await verifier.areMultiRequestProofsVerified( + multiRequest2.multiRequestId, + signerAddress, + ); + expect(isMultiRequest2Verified).to.be.false; + + const userID = 1; // we assume that userID is hardcoded to 1 in the auth stub contract + await validator1.stub_setVerifyResults([ + { + name: "userID", + value: userID, + rawValue: "0x", + }, + ]); + + const authResponse = { + authMethod: authMethod.authMethod, + proof: "0x", + }; + const response = { + requestId: request.requestId, + proof: "0x", + metadata: "0x", + }; + const crossChainProofs = "0x"; + + await verifier.submitResponse(authResponse, [response], crossChainProofs); + + //check statuses of two different multiRequests pointing to the same requests after response + areMultiRequestProofsVerified = await verifier.areMultiRequestProofsVerified( + multiRequest.multiRequestId, + signerAddress, + ); + expect(areMultiRequestProofsVerified).to.be.true; + + isMultiRequest2Verified = await verifier.areMultiRequestProofsVerified( + multiRequest2.multiRequestId, + signerAddress, + ); + expect(isMultiRequest2Verified).to.be.true; + }); + + it("getMultiRequestProofsStatus: multi request should exist", async function () { + const nonExistingMultiRequestId = 5; + await expect(verifier.getMultiRequestProofsStatus(nonExistingMultiRequestId, signerAddress)) + .to.be.revertedWithCustomError(verifier, "MultiRequestIdNotFound") + .withArgs(nonExistingMultiRequestId); + await expect(verifier.getMultiRequestProofsStatus(multiRequest.multiRequestId, signerAddress)) + .not.to.be.rejected; + }); + + it("getMultiRequestProofsStatus: linkID should be equal to all requests in a group, otherwise multiRequest pointing to it returns false", async function () { + const requestId1 = 5; + const requestId2 = 6; + const groupID = calculateGroupID([BigInt(requestId1), BigInt(requestId2)]); + const groupRequest1 = { ...request, requestId: requestId1, groupID }; + const groupRequest2 = { + ...request, + validator: await validator2.getAddress(), + requestId: requestId2, + groupID, + }; + const paramsFromValidator1 = [ + { name: "groupID", value: groupID }, + { name: "verifierID", value: 0 }, + { name: "nullifierSessionID", value: 0 }, + ]; + const paramsFromValidator2 = [ + { name: "groupID", value: groupID }, + { name: "verifierID", value: 0 }, + { name: "nullifierSessionID", value: 0 }, + ]; + await validator1.stub_setRequestParams([groupRequest1.params], [paramsFromValidator1]); + await validator2.stub_setRequestParams([groupRequest2.params], [paramsFromValidator2]); + await validator1.stub_setInput("userID", 1); + await validator2.stub_setInput("userID", 1); + + await verifier.setRequests([groupRequest1, groupRequest2]); + + const multiRequest3 = { + multiRequestId: calculateMultiRequestId([], [groupID], signerAddress), + requestIds: [], + groupIds: [groupID], + metadata: "0x", + }; + await verifier.setMultiRequest(multiRequest3); + + const userID = 1; + await validator1.stub_setVerifyResults([ + { name: "userID", value: userID, rawValue: "0x" }, + { name: "issuerID", value: 2, rawValue: "0x" }, + { name: "linkID", value: 3, rawValue: "0x" }, + ]); + await validator2.stub_setVerifyResults([ + { name: "userID", value: userID, rawValue: "0x" }, + { name: "issuerID", value: 2, rawValue: "0x" }, + { name: "linkID", value: 4, rawValue: "0x" }, + ]); + + const authResponse = { + authMethod: authMethod.authMethod, + proof: "0x", + }; + const response1 = { + requestId: groupRequest1.requestId, + proof: "0x", + metadata: "0x", + }; + const response2 = { + requestId: groupRequest2.requestId, + proof: "0x", + metadata: "0x", + }; + const crossChainProofs = "0x"; + + await verifier.submitResponse(authResponse, [response1, response2], crossChainProofs); + await expect( + verifier.getMultiRequestProofsStatus(multiRequest3.multiRequestId, signerAddress), + ).to.be.revertedWithCustomError(verifier, "LinkIDNotTheSameForGroupedRequests"); + + const areMultiRequestProofsVerified = await verifier.areMultiRequestProofsVerified( + multiRequest3.multiRequestId, + signerAddress, + ); + expect(areMultiRequestProofsVerified).to.be.false; + }); + + it("getMultiRequestProofsStatus: all request with same linkID in a group already verified returns true", async function () { + const requestId1 = 10; + const requestId2 = 11; + const groupID = calculateGroupID([BigInt(requestId1), BigInt(requestId2)]); + const request1 = { ...request, requestId: requestId1, groupID: groupID }; + const request2 = { + ...request, + requestId: requestId2, + groupID: groupID, + }; + paramsFromValidator = [ + { name: "groupID", value: groupID }, + { name: "verifierID", value: 0 }, + { name: "nullifierSessionID", value: 0 }, + ]; + await validator1.stub_setRequestParams([request1.params], [paramsFromValidator]); + await validator1.stub_setRequestParams([request2.params], [paramsFromValidator]); + await validator1.stub_setInput("userID", 1); + + await verifier.setRequests([request1, request2]); + + const multiRequest4 = { + multiRequestId: calculateMultiRequestId([], [groupID], signerAddress), + requestIds: [], + groupIds: [groupID], + metadata: "0x", + }; + await verifier.setMultiRequest(multiRequest4); + + const userID = 1; + await validator1.stub_setVerifyResults([ + { name: "userID", value: userID, rawValue: "0x" }, + { name: "issuerID", value: 2, rawValue: "0x" }, + { name: "linkID", value: 3, rawValue: "0x" }, + ]); + + const authResponse = { + authMethod: authMethod.authMethod, + proof: "0x", + }; + const response1 = { + requestId: request1.requestId, + proof: "0x", + metadata: "0x", + }; + const response2 = { + requestId: request2.requestId, + proof: "0x", + metadata: "0x", + }; + const crossChainProofs = "0x"; + + // partial responses of the multiRequest group + await verifier.submitResponse(authResponse, [response1], crossChainProofs); + + await expect( + verifier.getMultiRequestProofsStatus(multiRequest4.multiRequestId, signerAddress), + ).to.be.revertedWithCustomError(verifier, "LinkIDNotTheSameForGroupedRequests"); + + let areMultiRequestProofsVerified = await verifier.areMultiRequestProofsVerified( + multiRequest4.multiRequestId, + signerAddress, + ); + expect(areMultiRequestProofsVerified).to.be.false; + + // all responses of the multiRequest group completed + await verifier.submitResponse(authResponse, [response2], crossChainProofs); + + await expect( + verifier.getMultiRequestProofsStatus(multiRequest4.multiRequestId, signerAddress), + ).not.to.be.rejected; + + areMultiRequestProofsVerified = await verifier.areMultiRequestProofsVerified( + multiRequest4.multiRequestId, + signerAddress, + ); + expect(areMultiRequestProofsVerified).to.be.true; + }); + }); +});