diff --git a/.github/workflows/coordinator-build-and-publish.yml b/.github/workflows/coordinator-build-and-publish.yml index 310c6f508..33a718f0d 100644 --- a/.github/workflows/coordinator-build-and-publish.yml +++ b/.github/workflows/coordinator-build-and-publish.yml @@ -51,7 +51,7 @@ concurrency: jobs: build-and-publish: - runs-on: gha-runner-scale-set-ubuntu-22.04-amd64-med + runs-on: gha-runner-scale-set-ubuntu-22.04-amd64-large name: Coordinator build env: COMMIT_TAG: ${{ inputs.commit_tag }} @@ -78,7 +78,7 @@ jobs: uses: gradle/actions/setup-gradle@cc4fc85e6b35bafd578d5ffbc76a5518407e1af0 #v4.2.1 - name: Build dist run: | - ./gradlew coordinator:app:installDist --no-daemon + ./gradlew coordinator:app:installDist - name: Login to Docker Hub if: ${{ env.DOCKERHUB_USERNAME != '' && env.DOCKERHUB_TOKEN != '' }} uses: docker/login-action@v3 diff --git a/.husky/pre-commit.js b/.husky/pre-commit.js index 86d60c090..0c1728a1d 100644 --- a/.husky/pre-commit.js +++ b/.husky/pre-commit.js @@ -43,12 +43,17 @@ const FILE_EXTENSION_FILTERS = { [FILE_EXTENSION.SOLIDITY]: "\.sol$", }; -// File extension => script in package.json to run +// File extension => script in package.json to run for linting const FILE_EXTENSION_LINTING_COMMAND = { [FILE_EXTENSION.TYPESCRIPT]: "pnpm run lint:ts:fix", [FILE_EXTENSION.SOLIDITY]: "pnpm run lint:sol:fix", }; +// File extension => script in package.json to run for documentation generation +const FILE_EXTENSION_DOCUMENTATION_UPDATING_COMMAND = { + [FILE_EXTENSION.SOLIDITY]: "pnpm run solidity:docgen", +}; + // Project => Path in monorepo const FOLDER_PATH = { [FOLDER.BRIDGEUI]: "bridge-ui/", @@ -95,7 +100,8 @@ function main() { process.exit(1); } const changedFileExtensions = getChangedFileExtensions(folder); - executeLinting(folder, changedFileExtensions); + executeCommand(folder, changedFileExtensions, FILE_EXTENSION_LINTING_COMMAND); + executeCommand(folder, changedFileExtensions, FILE_EXTENSION_DOCUMENTATION_UPDATING_COMMAND); } updateGitIndex(); @@ -180,14 +186,15 @@ function getChangedFileExtensions(_folder) { } /** - * Execute linting command - * @param {FOLDER, FILE_EXTENSION[]} + * Execute command based on file extension + * @param {FOLDER, FILE_EXTENSION[], FILE_EXTENSION_LINTING_COMMAND | FILE_EXTENSION_DOCUMENTATION_UPDATING_COMMAND} */ -function executeLinting(_folder, _changedFileExtensions) { +function executeCommand(_folder, _changedFileExtensions, _command) { for (const fileExtension of _changedFileExtensions) { const path = FOLDER_PATH[_folder]; - const cmd = FILE_EXTENSION_LINTING_COMMAND[fileExtension]; - console.log(`${fileExtension} change found in ${path}, linting...`); + const cmd = _command[fileExtension]; + if (!cmd) return; + console.log(`${fileExtension} change found in ${path}, executing command ${cmd}`); try { // Execute command synchronously and stream output directly to the current stdout execSync(` diff --git a/Makefile b/Makefile index 554ae443d..0621cca0b 100644 --- a/Makefile +++ b/Makefile @@ -111,7 +111,7 @@ deploy-token-bridge-l1: RPC_URL=http:\\localhost:8445/ \ REMOTE_CHAIN_ID=1337 \ TOKEN_BRIDGE_L1=true \ - TOKEN_BRIDGE_SECURITY_COUNCIL=0x90F79bf6EB2c4f870365E785982E1f101E93b906 \ + L1_TOKEN_BRIDGE_SECURITY_COUNCIL=0x90F79bf6EB2c4f870365E785982E1f101E93b906 \ L2MESSAGESERVICE_ADDRESS=0xe537D669CA013d86EBeF1D64e40fC74CADC91987 \ LINEA_ROLLUP_ADDRESS=0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 \ npx ts-node local-deployments-artifacts/deployBridgedTokenAndTokenBridge.ts @@ -124,7 +124,7 @@ deploy-token-bridge-l2: RPC_URL=http:\\localhost:8545/ \ REMOTE_CHAIN_ID=31648428 \ TOKEN_BRIDGE_L1=false \ - TOKEN_BRIDGE_SECURITY_COUNCIL=0xf17f52151EbEF6C7334FAD080c5704D77216b732 \ + L2_TOKEN_BRIDGE_SECURITY_COUNCIL=0xf17f52151EbEF6C7334FAD080c5704D77216b732 \ L2MESSAGESERVICE_ADDRESS=0xe537D669CA013d86EBeF1D64e40fC74CADC91987 \ LINEA_ROLLUP_ADDRESS=0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 \ npx ts-node local-deployments-artifacts/deployBridgedTokenAndTokenBridge.ts diff --git a/buildSrc/src/main/groovy/net.consensys.zkevm.kotlin-common-minimal-conventions.gradle b/buildSrc/src/main/groovy/net.consensys.zkevm.kotlin-common-minimal-conventions.gradle index 34fb71301..69f37d430 100644 --- a/buildSrc/src/main/groovy/net.consensys.zkevm.kotlin-common-minimal-conventions.gradle +++ b/buildSrc/src/main/groovy/net.consensys.zkevm.kotlin-common-minimal-conventions.gradle @@ -20,6 +20,12 @@ repositories { url "https://hyperledger.jfrog.io/artifactory/besu-maven/" content { includeGroupAndSubgroups('org.hyperledger.besu') } } + maven { + url "https://artifacts.consensys.net/public/linea-besu/maven/" + content { + includeGroupAndSubgroups('io.consensys') + } + } maven { url "https://artifacts.consensys.net/public/maven/maven/" } diff --git a/contracts/abi/LineaRollupV6.0.abi b/contracts/abi/LineaRollupV6.0.abi index 481271af0..5bf3bb4ed 100644 --- a/contracts/abi/LineaRollupV6.0.abi +++ b/contracts/abi/LineaRollupV6.0.abi @@ -983,19 +983,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "GENESIS_SHNARF", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "INBOX_STATUS_RECEIVED", diff --git a/contracts/contracts/LineaRollup.sol b/contracts/contracts/LineaRollup.sol index bdc28b863..17b7526c2 100644 --- a/contracts/contracts/LineaRollup.sol +++ b/contracts/contracts/LineaRollup.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.26; -import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import { L1MessageService } from "./messageService/l1/L1MessageService.sol"; import { ZkEvmV2 } from "./ZkEvmV2.sol"; @@ -14,14 +13,7 @@ import { Utils } from "./lib/Utils.sol"; * @author ConsenSys Software Inc. * @custom:security-contact security-report@linea.build */ -contract LineaRollup is - Initializable, - AccessControlUpgradeable, - ZkEvmV2, - L1MessageService, - PermissionsManager, - ILineaRollup -{ +contract LineaRollup is AccessControlUpgradeable, ZkEvmV2, L1MessageService, PermissionsManager, ILineaRollup { using Utils for *; /// @notice This is the ABI version and not the reinitialize version. @@ -33,18 +25,6 @@ contract LineaRollup is /// @notice The role required to set/remove proof verifiers by type. bytes32 public constant VERIFIER_UNSETTER_ROLE = keccak256("VERIFIER_UNSETTER_ROLE"); - /// @notice The default genesis shnarf using empty/default hashes and a default state. - bytes32 public constant GENESIS_SHNARF = - keccak256( - abi.encode( - EMPTY_HASH, - EMPTY_HASH, - 0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd, - EMPTY_HASH, - EMPTY_HASH - ) - ); - /// @dev Value indicating a shnarf exists. uint256 internal constant SHNARF_EXISTS_DEFAULT_VALUE = 1; @@ -122,6 +102,10 @@ contract LineaRollup is __MessageService_init(_initializationData.rateLimitPeriodInSeconds, _initializationData.rateLimitAmountInWei); + if (_initializationData.defaultAdmin == address(0)) { + revert ZeroAddressNotAllowed(); + } + /** * @dev DEFAULT_ADMIN_ROLE is set for the security council explicitly, * as the permissions init purposefully does not allow DEFAULT_ADMIN_ROLE to be set. @@ -132,15 +116,26 @@ contract LineaRollup is verifiers[0] = _initializationData.defaultVerifier; + if (_initializationData.fallbackOperator == address(0)) { + revert ZeroAddressNotAllowed(); + } + fallbackOperator = _initializationData.fallbackOperator; emit FallbackOperatorAddressSet(msg.sender, _initializationData.fallbackOperator); currentL2BlockNumber = _initializationData.initialL2BlockNumber; stateRootHashes[_initializationData.initialL2BlockNumber] = _initializationData.initialStateRootHash; - blobShnarfExists[GENESIS_SHNARF] = SHNARF_EXISTS_DEFAULT_VALUE; + bytes32 genesisShnarf = _computeShnarf( + EMPTY_HASH, + EMPTY_HASH, + _initializationData.initialStateRootHash, + EMPTY_HASH, + EMPTY_HASH + ); - currentFinalizedShnarf = GENESIS_SHNARF; + blobShnarfExists[genesisShnarf] = SHNARF_EXISTS_DEFAULT_VALUE; + currentFinalizedShnarf = genesisShnarf; currentFinalizedState = _computeLastFinalizedState(0, EMPTY_HASH, _initializationData.genesisTimestamp); } @@ -487,8 +482,7 @@ contract LineaRollup is _finalizationData, lastFinalizedShnarf, finalShnarf, - lastFinalizedBlockNumber, - _finalizationData.endBlockNumber + lastFinalizedBlockNumber ); _verifyProof(publicInput, _proofType, _aggregatedProof); @@ -504,10 +498,6 @@ contract LineaRollup is FinalizationDataV3 calldata _finalizationData, uint256 _lastFinalizedBlock ) internal returns (bytes32 finalShnarf) { - if (_finalizationData.endBlockNumber <= _lastFinalizedBlock) { - revert FinalBlockNumberLessThanOrEqualToLastFinalizedBlock(_finalizationData.endBlockNumber, _lastFinalizedBlock); - } - _validateL2ComputedRollingHash(_finalizationData.l1RollingHashMessageNumber, _finalizationData.l1RollingHash); if ( @@ -678,14 +668,12 @@ contract LineaRollup is * @param _finalizationData The full finalization data. * @param _finalShnarf The final shnarf in the finalization. * @param _lastFinalizedBlockNumber The last finalized block number. - * @param _endBlockNumber End block number being finalized. */ function _computePublicInput( FinalizationDataV3 calldata _finalizationData, bytes32 _lastFinalizedShnarf, bytes32 _finalShnarf, - uint256 _lastFinalizedBlockNumber, - uint256 _endBlockNumber + uint256 _lastFinalizedBlockNumber ) private pure returns (uint256 publicInput) { assembly { let mPtr := mload(0x40) @@ -701,7 +689,7 @@ contract LineaRollup is mstore(add(mPtr, 0x80), _lastFinalizedBlockNumber) // _finalizationData.endBlockNumber - mstore(add(mPtr, 0xA0), _endBlockNumber) + calldatacopy(add(mPtr, 0xA0), add(_finalizationData, 0x20), 0x20) /** * _finalizationData.lastFinalizedL1RollingHash diff --git a/contracts/contracts/ZkEvmV2.sol b/contracts/contracts/ZkEvmV2.sol index 2fb702236..24a1fef1d 100644 --- a/contracts/contracts/ZkEvmV2.sol +++ b/contracts/contracts/ZkEvmV2.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.26; -import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import { L1MessageServiceV1 } from "./messageService/l1/v1/L1MessageServiceV1.sol"; import { IZkEvmV2 } from "./interfaces/l1/IZkEvmV2.sol"; @@ -11,7 +10,7 @@ import { IPlonkVerifier } from "./interfaces/l1/IPlonkVerifier.sol"; * @author ConsenSys Software Inc. * @custom:security-contact security-report@linea.build */ -abstract contract ZkEvmV2 is Initializable, AccessControlUpgradeable, L1MessageServiceV1, IZkEvmV2 { +abstract contract ZkEvmV2 is AccessControlUpgradeable, L1MessageServiceV1, IZkEvmV2 { uint256 internal constant MODULO_R = 21888242871839275222246405745257275088548364400416034343698204186575808495617; bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); @@ -49,7 +48,7 @@ abstract contract ZkEvmV2 is Initializable, AccessControlUpgradeable, L1MessageS } (bool callSuccess, bytes memory result) = verifierToUse.call( - abi.encodeWithSelector(IPlonkVerifier.Verify.selector, _proof, publicInput) + abi.encodeCall(IPlonkVerifier.Verify, (_proof, publicInput)) ); if (!callSuccess) { diff --git a/contracts/contracts/interfaces/IPauseManager.sol b/contracts/contracts/interfaces/IPauseManager.sol index f0609f022..d475694b6 100644 --- a/contracts/contracts/interfaces/IPauseManager.sol +++ b/contracts/contracts/interfaces/IPauseManager.sol @@ -57,6 +57,14 @@ interface IPauseManager { */ event PauseTypeRoleSet(PauseType indexed pauseType, bytes32 indexed role); + /** + * @notice Emitted when a pause type and its associated role are updated in the `_PauseTypeRoles` mapping. + * @param pauseType The indexed type of pause. + * @param role The indexed role associated with the pause type. + * @param previousRole The indexed previously found role associated with the pause type. + */ + event PauseTypeRoleUpdated(PauseType indexed pauseType, bytes32 indexed role, bytes32 indexed previousRole); + /** * @notice Emitted when an unpause type and its associated role are set in the `_unPauseTypeRoles` mapping. * @param unPauseType The indexed type of unpause. @@ -64,6 +72,14 @@ interface IPauseManager { */ event UnPauseTypeRoleSet(PauseType indexed unPauseType, bytes32 indexed role); + /** + * @notice Emitted when an unpause type and its associated role are updated in the `_unPauseTypeRoles` mapping. + * @param unPauseType The indexed type of unpause. + * @param role The indexed role associated with the unpause type. + * @param previousRole The indexed previously found role associated with the unpause type. + */ + event UnPauseTypeRoleUpdated(PauseType indexed unPauseType, bytes32 indexed role, bytes32 indexed previousRole); + /** * @dev Thrown when a specific pause type is paused. */ @@ -74,8 +90,19 @@ interface IPauseManager { */ error IsNotPaused(PauseType pauseType); + /** + * @dev Thrown when the unused paused type is used. + */ + error PauseTypeNotUsed(); + + /** + * @dev Thrown when trying to update a pause/unpause type role mapping to the existing role. + */ + error RolesNotDifferent(); + /** * @notice Pauses functionality by specific type. + * @dev Throws if UNUSED pause type is used. * @dev Requires the role mapped in pauseTypeRoles for the pauseType. * @param _pauseType The pause type value. */ @@ -83,6 +110,7 @@ interface IPauseManager { /** * @notice Unpauses functionality by specific type. + * @dev Throws if UNUSED pause type is used. * @dev Requires the role mapped in unPauseTypeRoles for the pauseType. * @param _pauseType The pause type value. */ @@ -94,4 +122,24 @@ interface IPauseManager { * @return pauseTypeIsPaused Returns true if the pause type if paused, false otherwise. */ function isPaused(PauseType _pauseType) external view returns (bool pauseTypeIsPaused); + + /** + * @notice Update the pause type role mapping. + * @dev Throws if UNUSED pause type is used. + * @dev Throws if role not different. + * @dev PAUSE_ALL_ROLE role is required to execute this function. + * @param _pauseType The pause type value to update. + * @param _newRole The role to update to. + */ + function updatePauseTypeRole(PauseType _pauseType, bytes32 _newRole) external; + + /** + * @notice Update the unpause type role mapping. + * @dev Throws if UNUSED pause type is used. + * @dev Throws if role not different. + * @dev UNPAUSE_ALL_ROLE role is required to execute this function. + * @param _pauseType The pause type value to update. + * @param _newRole The role to update to. + */ + function updateUnpauseTypeRole(PauseType _pauseType, bytes32 _newRole) external; } diff --git a/contracts/contracts/interfaces/l1/ILineaRollup.sol b/contracts/contracts/interfaces/l1/ILineaRollup.sol index d7d31c4b4..841143ecb 100644 --- a/contracts/contracts/interfaces/l1/ILineaRollup.sol +++ b/contracts/contracts/interfaces/l1/ILineaRollup.sol @@ -232,11 +232,6 @@ interface ILineaRollup { */ error FinalizationStateIncorrect(bytes32 expected, bytes32 value); - /** - * @dev Thrown when the final block number in finalization data is less than or equal to the last finalized block during finalization. - */ - error FinalBlockNumberLessThanOrEqualToLastFinalizedBlock(uint256 finalBlockNumber, uint256 lastFinalizedBlock); - /** * @dev Thrown when the final block state equals the zero hash during finalization. */ diff --git a/contracts/contracts/lib/PauseManager.sol b/contracts/contracts/lib/PauseManager.sol index 55be8f03b..d6c151411 100644 --- a/contracts/contracts/lib/PauseManager.sol +++ b/contracts/contracts/lib/PauseManager.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.19 <=0.8.26; -import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import { IPauseManager } from "../interfaces/IPauseManager.sol"; @@ -10,7 +9,7 @@ import { IPauseManager } from "../interfaces/IPauseManager.sol"; * @author ConsenSys Software Inc. * @custom:security-contact security-report@linea.build */ -abstract contract PauseManager is Initializable, IPauseManager, AccessControlUpgradeable { +abstract contract PauseManager is IPauseManager, AccessControlUpgradeable { /// @notice This is used to pause all pausable functions. bytes32 public constant PAUSE_ALL_ROLE = keccak256("PAUSE_ALL_ROLE"); @@ -34,6 +33,20 @@ abstract contract PauseManager is Initializable, IPauseManager, AccessControlUpg /// @dev Note: This was reduced previously to cater for new functionality. uint256[7] private __gap; + /** + * @dev Modifier to prevent usage of unused PauseType. + * @param _pauseType The PauseType value being checked. + * Requirements: + * + * - The type must not be UNUSED. + */ + modifier onlyUsedPausedTypes(PauseType _pauseType) { + if (_pauseType == PauseType.UNUSED) { + revert PauseTypeNotUsed(); + } + _; + } + /** * @dev Modifier to make a function callable only when the specific and general types are not paused. * @param _pauseType The pause type value being checked. @@ -109,10 +122,13 @@ abstract contract PauseManager is Initializable, IPauseManager, AccessControlUpg /** * @notice Pauses functionality by specific type. + * @dev Throws if UNUSED pause type is used. * @dev Requires the role mapped in `_pauseTypeRoles` for the pauseType. * @param _pauseType The pause type value. */ - function pauseByType(PauseType _pauseType) external onlyRole(_pauseTypeRoles[_pauseType]) { + function pauseByType( + PauseType _pauseType + ) external onlyUsedPausedTypes(_pauseType) onlyRole(_pauseTypeRoles[_pauseType]) { if (isPaused(_pauseType)) { revert IsPaused(_pauseType); } @@ -123,10 +139,13 @@ abstract contract PauseManager is Initializable, IPauseManager, AccessControlUpg /** * @notice Unpauses functionality by specific type. + * @dev Throws if UNUSED pause type is used. * @dev Requires the role mapped in `_unPauseTypeRoles` for the pauseType. * @param _pauseType The pause type value. */ - function unPauseByType(PauseType _pauseType) external onlyRole(_unPauseTypeRoles[_pauseType]) { + function unPauseByType( + PauseType _pauseType + ) external onlyUsedPausedTypes(_pauseType) onlyRole(_unPauseTypeRoles[_pauseType]) { if (!isPaused(_pauseType)) { revert IsNotPaused(_pauseType); } @@ -143,4 +162,46 @@ abstract contract PauseManager is Initializable, IPauseManager, AccessControlUpg function isPaused(PauseType _pauseType) public view returns (bool pauseTypeIsPaused) { pauseTypeIsPaused = (_pauseTypeStatusesBitMap & (1 << uint256(_pauseType))) != 0; } + + /** + * @notice Update the pause type role mapping. + * @dev Throws if UNUSED pause type is used. + * @dev Throws if role not different. + * @dev PAUSE_ALL_ROLE role is required to execute this function. + * @param _pauseType The pause type value to update. + * @param _newRole The role to update to. + */ + function updatePauseTypeRole( + PauseType _pauseType, + bytes32 _newRole + ) external onlyUsedPausedTypes(_pauseType) onlyRole(PAUSE_ALL_ROLE) { + bytes32 previousRole = _pauseTypeRoles[_pauseType]; + if(previousRole == _newRole){ + revert RolesNotDifferent(); + } + + _pauseTypeRoles[_pauseType] = _newRole; + emit PauseTypeRoleUpdated(_pauseType, _newRole, previousRole); + } + + /** + * @notice Update the unpause type role mapping. + * @dev Throws if UNUSED pause type is used. + * @dev Throws if role not different. + * @dev UNPAUSE_ALL_ROLE role is required to execute this function. + * @param _pauseType The pause type value to update. + * @param _newRole The role to update to. + */ + function updateUnpauseTypeRole( + PauseType _pauseType, + bytes32 _newRole + ) external onlyUsedPausedTypes(_pauseType) onlyRole(UNPAUSE_ALL_ROLE) { + bytes32 previousRole = _unPauseTypeRoles[_pauseType]; + if(previousRole == _newRole){ + revert RolesNotDifferent(); + } + + _unPauseTypeRoles[_pauseType] = _newRole; + emit UnPauseTypeRoleUpdated(_pauseType, _newRole, previousRole); + } } diff --git a/contracts/contracts/lib/PermissionsManager.sol b/contracts/contracts/lib/PermissionsManager.sol index 477628c29..0e19cf849 100644 --- a/contracts/contracts/lib/PermissionsManager.sol +++ b/contracts/contracts/lib/PermissionsManager.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.19 <=0.8.26; -import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import { IGenericErrors } from "../interfaces/IGenericErrors.sol"; import { IPermissionsManager } from "../interfaces/IPermissionsManager.sol"; @@ -11,7 +10,7 @@ import { IPermissionsManager } from "../interfaces/IPermissionsManager.sol"; * @author ConsenSys Software Inc. * @custom:security-contact security-report@linea.build */ -abstract contract PermissionsManager is Initializable, AccessControlUpgradeable, IPermissionsManager, IGenericErrors { +abstract contract PermissionsManager is AccessControlUpgradeable, IPermissionsManager, IGenericErrors { /** * @notice Sets permissions for a list of addresses and their roles. * @param _roleAddresses The list of addresses and roles to assign permissions to. diff --git a/contracts/contracts/lib/TokenBridgePauseManager.sol b/contracts/contracts/lib/TokenBridgePauseManager.sol index ec9f4f4fb..ca46f8bb7 100644 --- a/contracts/contracts/lib/TokenBridgePauseManager.sol +++ b/contracts/contracts/lib/TokenBridgePauseManager.sol @@ -9,8 +9,15 @@ import { PauseManager } from "./PauseManager.sol"; * @custom:security-contact security-report@linea.build */ abstract contract TokenBridgePauseManager is PauseManager { + /// @notice This is used to pause token bridging initiation. bytes32 public constant PAUSE_INITIATE_TOKEN_BRIDGING_ROLE = keccak256("PAUSE_INITIATE_TOKEN_BRIDGING_ROLE"); + + /// @notice This is used to unpause token bridging initiation. bytes32 public constant UNPAUSE_INITIATE_TOKEN_BRIDGING_ROLE = keccak256("UNPAUSE_INITIATE_TOKEN_BRIDGING_ROLE"); + + /// @notice This is used to pause token bridging completion. bytes32 public constant PAUSE_COMPLETE_TOKEN_BRIDGING_ROLE = keccak256("PAUSE_COMPLETE_TOKEN_BRIDGING_ROLE"); + + /// @notice This is used to unpause token bridging completion. bytes32 public constant UNPAUSE_COMPLETE_TOKEN_BRIDGING_ROLE = keccak256("UNPAUSE_COMPLETE_TOKEN_BRIDGING_ROLE"); } diff --git a/contracts/contracts/messageService/l1/v1/L1MessageServiceV1.sol b/contracts/contracts/messageService/l1/v1/L1MessageServiceV1.sol index 06cce7834..fce768940 100644 --- a/contracts/contracts/messageService/l1/v1/L1MessageServiceV1.sol +++ b/contracts/contracts/messageService/l1/v1/L1MessageServiceV1.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.26; -import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { LineaRollupPauseManager } from "../../../lib/LineaRollupPauseManager.sol"; import { RateLimiter } from "../../lib/RateLimiter.sol"; import { L1MessageManagerV1 } from "./L1MessageManagerV1.sol"; @@ -16,7 +15,6 @@ import { MessageHashing } from "../../lib/MessageHashing.sol"; * @custom:security-contact security-report@linea.build */ abstract contract L1MessageServiceV1 is - Initializable, RateLimiter, L1MessageManagerV1, TransientStorageReentrancyGuardUpgradeable, diff --git a/contracts/contracts/messageService/l2/v1/L2MessageServiceV1.sol b/contracts/contracts/messageService/l2/v1/L2MessageServiceV1.sol index 975cce51f..c14969cef 100644 --- a/contracts/contracts/messageService/l2/v1/L2MessageServiceV1.sol +++ b/contracts/contracts/messageService/l2/v1/L2MessageServiceV1.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.19; -import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import { IMessageService } from "../../../interfaces/IMessageService.sol"; import { IL2MessageServiceV1 } from "../../../interfaces/l2/IL2MessageServiceV1.sol"; @@ -16,7 +15,6 @@ import { MessageHashing } from "../../lib/MessageHashing.sol"; * @custom:security-contact security-report@linea.build */ abstract contract L2MessageServiceV1 is - Initializable, RateLimiter, L2MessageManagerV1, ReentrancyGuardUpgradeable, diff --git a/contracts/contracts/messageService/lib/RateLimiter.sol b/contracts/contracts/messageService/lib/RateLimiter.sol index b2b3637fc..b6eb3bf31 100644 --- a/contracts/contracts/messageService/lib/RateLimiter.sol +++ b/contracts/contracts/messageService/lib/RateLimiter.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.19 <=0.8.26; -import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import { IRateLimiter } from "../../interfaces/IRateLimiter.sol"; @@ -11,7 +10,7 @@ import { IRateLimiter } from "../../interfaces/IRateLimiter.sol"; * @notice You can use this control numeric limits over a period using timestamp. * @custom:security-contact security-report@linea.build */ -contract RateLimiter is Initializable, IRateLimiter, AccessControlUpgradeable { +contract RateLimiter is IRateLimiter, AccessControlUpgradeable { bytes32 public constant RATE_LIMIT_SETTER_ROLE = keccak256("RATE_LIMIT_SETTER_ROLE"); bytes32 public constant USED_RATE_LIMIT_RESETTER_ROLE = keccak256("USED_RATE_LIMIT_RESETTER_ROLE"); diff --git a/contracts/contracts/test-contracts/OpcodeTestContract.sol b/contracts/contracts/test-contracts/OpcodeTestContract.sol index c9ef96b3e..8366f0f4e 100644 --- a/contracts/contracts/test-contracts/OpcodeTestContract.sol +++ b/contracts/contracts/test-contracts/OpcodeTestContract.sol @@ -9,8 +9,7 @@ contract OpcodeTestContract { } // keccak256(abi.encode(uint256(keccak256("opcodeTestContract.main")) - 1)) & ~bytes32(uint256(0xff)) - bytes32 private constant MAIN_STORAGE_SLOT = - 0xb69ece048aea1886497badfc9449787df15ad9606ca8687d17308088ee555100; + bytes32 private constant MAIN_STORAGE_SLOT = 0xb69ece048aea1886497badfc9449787df15ad9606ca8687d17308088ee555100; function _getMainStorage() private pure returns (MainStorage storage $) { assembly { diff --git a/contracts/contracts/tokenBridge/TokenBridge.sol b/contracts/contracts/tokenBridge/TokenBridge.sol index c2d1f49ac..8c0bad578 100644 --- a/contracts/contracts/tokenBridge/TokenBridge.sol +++ b/contracts/contracts/tokenBridge/TokenBridge.sol @@ -11,8 +11,6 @@ import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ import { BeaconProxy } from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; -import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; - import { BridgedToken } from "./BridgedToken.sol"; import { MessageServiceBase } from "../messageService/MessageServiceBase.sol"; @@ -30,7 +28,6 @@ import { Utils } from "../lib/Utils.sol"; */ contract TokenBridge is ITokenBridge, - Initializable, ReentrancyGuardUpgradeable, AccessControlUpgradeable, MessageServiceBase, @@ -116,6 +113,7 @@ contract TokenBridge is if (_addr == EMPTY) revert ZeroAddressNotAllowed(); _; } + /** * @dev Ensures the amount is not 0. * @param _amount amount to check. @@ -125,6 +123,15 @@ contract TokenBridge is _; } + /** + * @dev Ensures the chainId is not 0. + * @param _chainId chainId to check. + */ + modifier nonZeroChainId(uint256 _chainId) { + if (_chainId == 0) revert ZeroChainIdNotAllowed(); + _; + } + /// @dev Disable constructor for safety /// @custom:oz-upgrades-unsafe-allow constructor constructor() { @@ -142,12 +149,18 @@ contract TokenBridge is external nonZeroAddress(_initializationData.messageService) nonZeroAddress(_initializationData.tokenBeacon) + nonZeroChainId(_initializationData.sourceChainId) + nonZeroChainId(_initializationData.targetChainId) initializer { __PauseManager_init(_initializationData.pauseTypeRoles, _initializationData.unpauseTypeRoles); __MessageServiceBase_init(_initializationData.messageService); __ReentrancyGuard_init(); + if (_initializationData.defaultAdmin == address(0)) { + revert ZeroAddressNotAllowed(); + } + /** * @dev DEFAULT_ADMIN_ROLE is set for the security council explicitly, * as the permissions init purposefully does not allow DEFAULT_ADMIN_ROLE to be set. @@ -157,6 +170,7 @@ contract TokenBridge is __Permissions_init(_initializationData.roleAddresses); tokenBeacon = _initializationData.tokenBeacon; + if (_initializationData.sourceChainId == _initializationData.targetChainId) revert SourceChainSameAsTargetChain(); sourceChainId = _initializationData.sourceChainId; targetChainId = _initializationData.targetChainId; diff --git a/contracts/contracts/tokenBridge/interfaces/ITokenBridge.sol b/contracts/contracts/tokenBridge/interfaces/ITokenBridge.sol index 330d6ba4f..7efdfd817 100644 --- a/contracts/contracts/tokenBridge/interfaces/ITokenBridge.sol +++ b/contracts/contracts/tokenBridge/interfaces/ITokenBridge.sol @@ -219,6 +219,16 @@ interface ITokenBridge { */ error TokenListEmpty(); + /** + * @dev Thrown when a chainId provided during initialization is zero. + */ + error ZeroChainIdNotAllowed(); + + /** + * @dev Thrown when sourceChainId is the same as targetChainId during initialization. + */ + error SourceChainSameAsTargetChain(); + /** * @notice Similar to `bridgeToken` function but allows to pass additional * permit data to do the ERC20 approval in a single transaction. diff --git a/contracts/docs/api/LineaRollup.mdx b/contracts/docs/api/LineaRollup.mdx index 96990127c..9604dfa5b 100644 --- a/contracts/docs/api/LineaRollup.mdx +++ b/contracts/docs/api/LineaRollup.mdx @@ -24,14 +24,6 @@ bytes32 VERIFIER_UNSETTER_ROLE The role required to set/remove proof verifiers by type. -### GENESIS_SHNARF - -```solidity -bytes32 GENESIS_SHNARF -``` - -The default genesis shnarf using empty/default hashes and a default state. - ### SHNARF_EXISTS_DEFAULT_VALUE ```solidity diff --git a/contracts/docs/api/interfaces/IPauseManager.mdx b/contracts/docs/api/interfaces/IPauseManager.mdx index d09f221c0..e8dbf6129 100644 --- a/contracts/docs/api/interfaces/IPauseManager.mdx +++ b/contracts/docs/api/interfaces/IPauseManager.mdx @@ -70,6 +70,22 @@ Emitted when a pause type and its associated role are set in the `_pauseTypeRole | pauseType | enum IPauseManager.PauseType | The indexed type of pause. | | role | bytes32 | The indexed role associated with the pause type. | +### PauseTypeRoleUpdated + +```solidity +event PauseTypeRoleUpdated(enum IPauseManager.PauseType pauseType, bytes32 role, bytes32 previousRole) +``` + +Emitted when a pause type and its associated role are updated in the `_PauseTypeRoles` mapping. + +#### Parameters + +| Name | Type | Description | +| ---- | ---- | ----------- | +| pauseType | enum IPauseManager.PauseType | The indexed type of pause. | +| role | bytes32 | The indexed role associated with the pause type. | +| previousRole | bytes32 | The indexed previously found role associated with the pause type. | + ### UnPauseTypeRoleSet ```solidity @@ -85,6 +101,22 @@ Emitted when an unpause type and its associated role are set in the `_unPauseTyp | unPauseType | enum IPauseManager.PauseType | The indexed type of unpause. | | role | bytes32 | The indexed role associated with the unpause type. | +### UnPauseTypeRoleUpdated + +```solidity +event UnPauseTypeRoleUpdated(enum IPauseManager.PauseType unPauseType, bytes32 role, bytes32 previousRole) +``` + +Emitted when an unpause type and its associated role are updated in the `_unPauseTypeRoles` mapping. + +#### Parameters + +| Name | Type | Description | +| ---- | ---- | ----------- | +| unPauseType | enum IPauseManager.PauseType | The indexed type of unpause. | +| role | bytes32 | The indexed role associated with the unpause type. | +| previousRole | bytes32 | The indexed previously found role associated with the unpause type. | + ### IsPaused ```solidity @@ -101,6 +133,22 @@ error IsNotPaused(enum IPauseManager.PauseType pauseType) _Thrown when a specific pause type is not paused and expected to be._ +### PauseTypeNotUsed + +```solidity +error PauseTypeNotUsed() +``` + +_Thrown when the unused paused type is used._ + +### RolesNotDifferent + +```solidity +error RolesNotDifferent() +``` + +_Thrown when trying to update a pause/unpause type role mapping to the existing role._ + ### pauseByType ```solidity @@ -109,7 +157,8 @@ function pauseByType(enum IPauseManager.PauseType _pauseType) external Pauses functionality by specific type. -_Requires the role mapped in pauseTypeRoles for the pauseType._ +_Throws if UNUSED pause type is used. +Requires the role mapped in pauseTypeRoles for the pauseType._ #### Parameters @@ -125,7 +174,8 @@ function unPauseByType(enum IPauseManager.PauseType _pauseType) external Unpauses functionality by specific type. -_Requires the role mapped in unPauseTypeRoles for the pauseType._ +_Throws if UNUSED pause type is used. +Requires the role mapped in unPauseTypeRoles for the pauseType._ #### Parameters @@ -153,3 +203,41 @@ Check if a pause type is enabled. | ---- | ---- | ----------- | | pauseTypeIsPaused | bool | Returns true if the pause type if paused, false otherwise. | +### updatePauseTypeRole + +```solidity +function updatePauseTypeRole(enum IPauseManager.PauseType _pauseType, bytes32 _newRole) external +``` + +Update the pause type role mapping. + +_Throws if UNUSED pause type is used. +Throws if role not different. +PAUSE_ALL_ROLE role is required to execute this function._ + +#### Parameters + +| Name | Type | Description | +| ---- | ---- | ----------- | +| _pauseType | enum IPauseManager.PauseType | The pause type value to update. | +| _newRole | bytes32 | The role to update to. | + +### updateUnpauseTypeRole + +```solidity +function updateUnpauseTypeRole(enum IPauseManager.PauseType _pauseType, bytes32 _newRole) external +``` + +Update the unpause type role mapping. + +_Throws if UNUSED pause type is used. +Throws if role not different. +UNPAUSE_ALL_ROLE role is required to execute this function._ + +#### Parameters + +| Name | Type | Description | +| ---- | ---- | ----------- | +| _pauseType | enum IPauseManager.PauseType | The pause type value to update. | +| _newRole | bytes32 | The role to update to. | + diff --git a/contracts/docs/api/interfaces/l1/ILineaRollup.mdx b/contracts/docs/api/interfaces/l1/ILineaRollup.mdx index 62e8e3944..5e53f2a61 100644 --- a/contracts/docs/api/interfaces/l1/ILineaRollup.mdx +++ b/contracts/docs/api/interfaces/l1/ILineaRollup.mdx @@ -308,14 +308,6 @@ error FinalizationStateIncorrect(bytes32 expected, bytes32 value) _Thrown when finalization state does not match._ -### FinalBlockNumberLessThanOrEqualToLastFinalizedBlock - -```solidity -error FinalBlockNumberLessThanOrEqualToLastFinalizedBlock(uint256 finalBlockNumber, uint256 lastFinalizedBlock) -``` - -_Thrown when the final block number in finalization data is less than or equal to the last finalized block during finalization._ - ### FinalBlockStateEqualsZeroHash ```solidity diff --git a/contracts/docs/api/lib/CallForwardingProxy.md b/contracts/docs/api/lib/CallForwardingProxy.md new file mode 100644 index 000000000..57483a27d --- /dev/null +++ b/contracts/docs/api/lib/CallForwardingProxy.md @@ -0,0 +1,26 @@ +# Solidity API + +## CallForwardingProxy + +### target + +```solidity +address target +``` + +The underlying target address that is called. + +### constructor + +```solidity +constructor(address _target) public +``` + +### fallback + +```solidity +fallback() external payable +``` + +Defaults to, and forwards all calls to the target address. + diff --git a/contracts/docs/api/lib/CallForwardingProxy.mdx b/contracts/docs/api/lib/CallForwardingProxy.mdx index 0464089fd..1b008bce6 100644 --- a/contracts/docs/api/lib/CallForwardingProxy.mdx +++ b/contracts/docs/api/lib/CallForwardingProxy.mdx @@ -1,9 +1,9 @@ # `CallForwardingProxy` -### target +### TARGET ```solidity -address target +address TARGET ``` The underlying target address that is called. @@ -22,3 +22,9 @@ fallback() external payable Defaults to, and forwards all calls to the target address. +### receive + +```solidity +receive() external payable +``` + diff --git a/contracts/docs/api/lib/PauseManager.mdx b/contracts/docs/api/lib/PauseManager.mdx index 8b85b7d9b..470c720b2 100644 --- a/contracts/docs/api/lib/PauseManager.mdx +++ b/contracts/docs/api/lib/PauseManager.mdx @@ -22,6 +22,20 @@ This is used to unpause all unpausable functions. mapping(bytes32 => bool) pauseTypeStatuses ``` +### onlyUsedPausedTypes + +```solidity +modifier onlyUsedPausedTypes(enum IPauseManager.PauseType _pauseType) +``` + +_Modifier to prevent usage of unused PauseType._ + +#### Parameters + +| Name | Type | Description | +| ---- | ---- | ----------- | +| _pauseType | enum IPauseManager.PauseType | The PauseType value being checked. Requirements: - The type must not be UNUSED. | + ### whenTypeAndGeneralNotPaused ```solidity @@ -105,7 +119,8 @@ function pauseByType(enum IPauseManager.PauseType _pauseType) external Pauses functionality by specific type. -_Requires the role mapped in `_pauseTypeRoles` for the pauseType._ +_Throws if UNUSED pause type is used. +Requires the role mapped in `_pauseTypeRoles` for the pauseType._ #### Parameters @@ -121,7 +136,8 @@ function unPauseByType(enum IPauseManager.PauseType _pauseType) external Unpauses functionality by specific type. -_Requires the role mapped in `_unPauseTypeRoles` for the pauseType._ +_Throws if UNUSED pause type is used. +Requires the role mapped in `_unPauseTypeRoles` for the pauseType._ #### Parameters @@ -149,3 +165,41 @@ Check if a pause type is enabled. | ---- | ---- | ----------- | | pauseTypeIsPaused | bool | Returns true if the pause type if paused, false otherwise. | +### updatePauseTypeRole + +```solidity +function updatePauseTypeRole(enum IPauseManager.PauseType _pauseType, bytes32 _newRole) external +``` + +Update the pause type role mapping. + +_Throws if UNUSED pause type is used. +Throws if role not different. +PAUSE_ALL_ROLE role is required to execute this function._ + +#### Parameters + +| Name | Type | Description | +| ---- | ---- | ----------- | +| _pauseType | enum IPauseManager.PauseType | The pause type value to update. | +| _newRole | bytes32 | The role to update to. | + +### updateUnpauseTypeRole + +```solidity +function updateUnpauseTypeRole(enum IPauseManager.PauseType _pauseType, bytes32 _newRole) external +``` + +Update the unpause type role mapping. + +_Throws if UNUSED pause type is used. +Throws if role not different. +UNPAUSE_ALL_ROLE role is required to execute this function._ + +#### Parameters + +| Name | Type | Description | +| ---- | ---- | ----------- | +| _pauseType | enum IPauseManager.PauseType | The pause type value to update. | +| _newRole | bytes32 | The role to update to. | + diff --git a/contracts/docs/api/lib/TokenBridgePauseManager.mdx b/contracts/docs/api/lib/TokenBridgePauseManager.mdx index b0047aa76..af36bb313 100644 --- a/contracts/docs/api/lib/TokenBridgePauseManager.mdx +++ b/contracts/docs/api/lib/TokenBridgePauseManager.mdx @@ -6,21 +6,29 @@ bytes32 PAUSE_INITIATE_TOKEN_BRIDGING_ROLE ``` +This is used to pause token bridging initiation. + ### UNPAUSE_INITIATE_TOKEN_BRIDGING_ROLE ```solidity bytes32 UNPAUSE_INITIATE_TOKEN_BRIDGING_ROLE ``` +This is used to unpause token bridging initiation. + ### PAUSE_COMPLETE_TOKEN_BRIDGING_ROLE ```solidity bytes32 PAUSE_COMPLETE_TOKEN_BRIDGING_ROLE ``` +This is used to pause token bridging completion. + ### UNPAUSE_COMPLETE_TOKEN_BRIDGING_ROLE ```solidity bytes32 UNPAUSE_COMPLETE_TOKEN_BRIDGING_ROLE ``` +This is used to unpause token bridging completion. + diff --git a/contracts/docs/api/tokenBridge/TokenBridge.mdx b/contracts/docs/api/tokenBridge/TokenBridge.mdx index f333b32e7..3445a9c35 100644 --- a/contracts/docs/api/tokenBridge/TokenBridge.mdx +++ b/contracts/docs/api/tokenBridge/TokenBridge.mdx @@ -166,6 +166,20 @@ _Ensures the amount is not 0._ | ---- | ---- | ----------- | | _amount | uint256 | amount to check. | +### nonZeroChainId + +```solidity +modifier nonZeroChainId(uint256 _chainId) +``` + +_Ensures the chainId is not 0._ + +#### Parameters + +| Name | Type | Description | +| ---- | ---- | ----------- | +| _chainId | uint256 | chainId to check. | + ### constructor ```solidity diff --git a/contracts/docs/api/tokenBridge/interfaces/ITokenBridge.mdx b/contracts/docs/api/tokenBridge/interfaces/ITokenBridge.mdx index 2225d9481..267ae0cc4 100644 --- a/contracts/docs/api/tokenBridge/interfaces/ITokenBridge.mdx +++ b/contracts/docs/api/tokenBridge/interfaces/ITokenBridge.mdx @@ -337,6 +337,22 @@ error TokenListEmpty() _Thrown when the token list is empty._ +### ZeroChainIdNotAllowed + +```solidity +error ZeroChainIdNotAllowed() +``` + +_Thrown when a chainId provided during initialization is zero._ + +### SourceChainSameAsTargetChain + +```solidity +error SourceChainSameAsTargetChain() +``` + +_Thrown when sourceChainId is the same as targetChainId during initialization._ + ### bridgeTokenWithPermit ```solidity diff --git a/contracts/docs/scripts/updateSidebar.js b/contracts/docs/scripts/updateSidebar.js index ccfda3389..a362f8610 100644 --- a/contracts/docs/scripts/updateSidebar.js +++ b/contracts/docs/scripts/updateSidebar.js @@ -1,10 +1,10 @@ /* eslint-disable */ // This script is meant to be executed in the root directory of https://github.com/Consensys/doc.linea, which has different linting rules -// The purpose of this script is to modify the sidebars.js file to correctly include the autogenerated smart contract documentation +// The purpose of this script is to modify the sidebars.js file to correctly include the autogenerated smart contract documentation /** * PURPOSE - * + * * Modifies sidebars.js in the root directory of https://github.com/Consensys/doc.linea to correctly include smart contract documentation pages. * The sidebars.js file configures the sidebar for the documentation website @ https://docs.linea.build/ */ @@ -70,7 +70,9 @@ function main() { */ function removeExistingSmartContractSidebar(sidebarObject) { if (sidebarObject?.apiSidebar) { - sidebarObject.apiSidebar = sidebarObject?.apiSidebar.filter(sidebarSection => sidebarSection?.label !== SMART_CONTRACT_SIDEBAR_LABEL); + sidebarObject.apiSidebar = sidebarObject?.apiSidebar.filter( + (sidebarSection) => sidebarSection?.label !== SMART_CONTRACT_SIDEBAR_LABEL, + ); } } @@ -80,12 +82,7 @@ function removeExistingSmartContractSidebar(sidebarObject) { */ function getSmartContractSidebar() { // Create and populate smart contract sidebar - const smartContractsPath = path.join( - __dirname, - "docs", - "api", - "linea-smart-contracts", - ); + const smartContractsPath = path.join(__dirname, "docs", "api", "linea-smart-contracts"); let smartContractSidebar = new FolderSidebar( SMART_CONTRACT_SIDEBAR_LABEL, @@ -93,11 +90,7 @@ function getSmartContractSidebar() { false, ); - populateFolderSidebar( - smartContractSidebar, - smartContractsPath, - ".mdx", - ); + populateFolderSidebar(smartContractSidebar, smartContractsPath, ".mdx"); return smartContractSidebar; } @@ -120,10 +113,7 @@ function populateFolderSidebar(folderSidebar, subdirectoryPath, fileExtension) { // Base case => *.mdx file => Add relative path to sidebar if (fileMetadata.isFile() && fileNode.endsWith(fileExtension)) { - const relativePath = path.relative( - path.join(__dirname, "docs"), - filePath.split(fileExtension)[0], - ); + const relativePath = path.relative(path.join(__dirname, "docs"), filePath.split(fileExtension)[0]); folderSidebar?.items.push(relativePath); } } @@ -137,7 +127,7 @@ function populateFolderSidebar(folderSidebar, subdirectoryPath, fileExtension) { if (fileMetadata.isDirectory()) { let newFolderNode = new FolderSidebar(fileNode); populateFolderSidebar(newFolderNode, filePath, fileExtension); - // Add populated child FolderSidebar to current sidebar section + // Add populated child FolderSidebar to current sidebar section folderSidebar?.items.push(newFolderNode); } } @@ -153,8 +143,7 @@ function populateFolderSidebar(folderSidebar, subdirectoryPath, fileExtension) { */ function createNewSidebarFile(sidebarObject) { // Create new sidebars.js file content - const sidebarFileLine1 = - "/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */"; + const sidebarFileLine1 = "/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */"; const sidebarFileLine2 = "const sidebars ="; const sidebarFileLineFinal = "module.exports = sidebars;"; const newSidebarFileContent = `${sidebarFileLine1}\n${sidebarFileLine2}\n${JSON.stringify(sidebarObject, null, 2)}\n\n${sidebarFileLineFinal}`; diff --git a/contracts/local-deployments-artifacts/deployBridgedTokenAndTokenBridge.ts b/contracts/local-deployments-artifacts/deployBridgedTokenAndTokenBridge.ts index 0e4570e51..1f4a9e8e5 100644 --- a/contracts/local-deployments-artifacts/deployBridgedTokenAndTokenBridge.ts +++ b/contracts/local-deployments-artifacts/deployBridgedTokenAndTokenBridge.ts @@ -37,15 +37,22 @@ async function main() { const ORDERED_NONCE_POST_L2MESSAGESERVICE = 3; const ORDERED_NONCE_POST_LINEAROLLUP = 4; + let securityCouncilAddress; + + if (process.env.TOKEN_BRIDGE_L1 === "true") { + securityCouncilAddress = getRequiredEnvVar("L1_TOKEN_BRIDGE_SECURITY_COUNCIL"); + } else { + securityCouncilAddress = getRequiredEnvVar("L2_TOKEN_BRIDGE_SECURITY_COUNCIL"); + } + const l2MessageServiceAddress = process.env.L2MESSAGESERVICE_ADDRESS; const lineaRollupAddress = process.env.LINEA_ROLLUP_ADDRESS; const remoteChainId = getRequiredEnvVar("REMOTE_CHAIN_ID"); - const tokenBridgeSecurityCouncil = getRequiredEnvVar("TOKEN_BRIDGE_SECURITY_COUNCIL"); const pauseTypeRoles = getEnvVarOrDefault("TOKEN_BRIDGE_PAUSE_TYPES_ROLES", TOKEN_BRIDGE_PAUSE_TYPES_ROLES); const unpauseTypeRoles = getEnvVarOrDefault("TOKEN_BRIDGE_UNPAUSE_TYPES_ROLES", TOKEN_BRIDGE_UNPAUSE_TYPES_ROLES); - const defaultRoleAddresses = generateRoleAssignments(TOKEN_BRIDGE_ROLES, tokenBridgeSecurityCouncil, []); + const defaultRoleAddresses = generateRoleAssignments(TOKEN_BRIDGE_ROLES, securityCouncilAddress, []); const roleAddresses = getEnvVarOrDefault("TOKEN_BRIDGE_ROLE_ADDRESSES", defaultRoleAddresses); const provider = new ethers.JsonRpcProvider(process.env.RPC_URL); const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider); @@ -53,13 +60,13 @@ async function main() { let walletNonce; if (process.env.TOKEN_BRIDGE_L1 === "true") { - if (process.env.L1_NONCE === undefined) { + if (!process.env.L1_NONCE) { walletNonce = await wallet.getNonce(); } else { walletNonce = parseInt(process.env.L1_NONCE) + ORDERED_NONCE_POST_LINEAROLLUP; } } else { - if (process.env.L2_NONCE === undefined) { + if (!process.env.L2_NONCE) { walletNonce = await wallet.getNonce(); } else { walletNonce = parseInt(process.env.L2_NONCE) + ORDERED_NONCE_POST_L2MESSAGESERVICE; @@ -119,7 +126,7 @@ async function main() { const initializer = getInitializerData(TokenBridgeAbi, "initialize", [ { - defaultAdmin: tokenBridgeSecurityCouncil, + defaultAdmin: securityCouncilAddress, messageService: deployingChainMessageService, tokenBeacon: beaconProxyAddress, sourceChainId: chainId, diff --git a/contracts/local-deployments-artifacts/dynamic-artifacts/LineaRollupV6.json b/contracts/local-deployments-artifacts/dynamic-artifacts/LineaRollupV6.json index cd78b1e27..a938a4f49 100644 --- a/contracts/local-deployments-artifacts/dynamic-artifacts/LineaRollupV6.json +++ b/contracts/local-deployments-artifacts/dynamic-artifacts/LineaRollupV6.json @@ -987,19 +987,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "GENESIS_SHNARF", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "INBOX_STATUS_RECEIVED", @@ -2447,8 +2434,8 @@ "type": "function" } ], - "bytecode": "0x6080604052348015600e575f80fd5b5060156019565b60d3565b5f54610100900460ff161560835760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff9081161460d1575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b615462806100e05f395ff3fe60806040526004361061049d575f3560e01c806373bd07b71161026b578063b837dbe911610156578063cc5782f6116100d1578063d5d4b83511610087578063e196fb5d1161006d578063e196fb5d14610ea0578063e97a1e9e14610ebf578063f5b541a614610f31575f80fd5b8063d5d4b83514610e57578063d722bbfc14610e6d575f80fd5b8063cd9b9e9a116100b7578063cd9b9e9a14610e02578063cf5b276414610e18578063d547741f14610e38575f80fd5b8063cc5782f614610da1578063cc6f725114610dcf575f80fd5b8063bf3e750511610126578063c0c4e5841161010c578063c0c4e58414610d4e578063c1dc0f0714610d6d578063c211697414610d82575f80fd5b8063bf3e750514610d06578063c0729ab114610d39575f80fd5b8063b837dbe914610c80578063b9174ba314610c95578063bc61e73314610cc8578063bcc3003d14610ce7575f80fd5b80639ac25d08116101e6578063a98e773d116101b6578063ad422ff01161019c578063ad422ff014610c24578063aea4f74514610c39578063b59faa6014610c4d575f80fd5b8063a98e773d14610bd0578063ac1eff6814610bef575f80fd5b80639ac25d0814610b585780639ee8b21114610b8b5780639f3ce55a14610baa578063a217fddf14610bbd575f80fd5b8063914e57eb1161023b578063921b278e11610221578063921b278e14610b23578063986fcddd14610a4157806399467a3514610b39575f80fd5b8063914e57eb14610ab357806391d1485414610adf575f80fd5b806373bd07b714610a2d5780637d1e8c5514610a415780638be745d114610a545780638de4948714610a80575f80fd5b80634cdd389b1161038b57806360e83cf31161030657806367e404ce116102d6578063695378f5116102bc578063695378f5146109b15780636a906b80146109c75780636e673843146109fa575f80fd5b806367e404ce146109665780636854f6bc14610992575f80fd5b806360e83cf3146108bc57806363213155146108e85780636463fb2a1461091b57806366f96e981461093a575f80fd5b8063587944561161035b5780635c721a0c116103415780635c721a0c146108395780635ed73ceb146108645780636078bfd814610890575f80fd5b806358794456146108245780635b7eb4bd14610742575f80fd5b80634cdd389b146107875780635230eef2146107b3578063557eac73146107e65780635603c65f14610805575f80fd5b8063289581741161041b57806338b90333116103eb5780633fc08b65116103d15780633fc08b651461071757806348922ab714610742578063491e093614610768575f80fd5b806338b903331461068f5780633b12eccb146106e4575f80fd5b8063289581741461061c5780632c70645c1461063b5780632f2ff15d1461065157806336568abe14610670575f80fd5b806312d3fa9a116104705780631f443da0116104565780631f443da0146105965780632130d812146105c2578063248a9ca3146105ee575f80fd5b806312d3fa9a1461054d5780631e2ff94f14610580575f80fd5b806301ffc9a7146104a157806303134d1d146104d557806305861180146105165780631065a3991461052c575b5f80fd5b3480156104ac575f80fd5b506104c06104bb3660046147a5565b610f64565b60405190151581526020015b60405180910390f35b3480156104e0575f80fd5b506105087f1ab87f7458c0e3d07e9881c14ee67f0141703614fd48ea5b15ed987e5f4b030e81565b6040519081526020016104cc565b348015610521575f80fd5b506105086101bb5481565b348015610537575f80fd5b5061054b6105463660046147e4565b610ffc565b005b348015610558575f80fd5b506105087f67c2dca7476ee0fe1dd3cba13428c6760bfe2599a6dfe26a9ad7ef27317c6e7781565b34801561058b575f80fd5b506105086101185481565b3480156105a1575f80fd5b506105086105b0366004614802565b6101b96020525f908152604090205481565b3480156105cd575f80fd5b506105086105dc366004614802565b6101be6020525f908152604090205481565b3480156105f9575f80fd5b50610508610608366004614802565b5f9081526065602052604090206001015490565b348015610627575f80fd5b5061054b610636366004614802565b6110f8565b348015610646575f80fd5b506105086101835481565b34801561065c575f80fd5b5061054b61066b36600461482d565b6111ab565b34801561067b575f80fd5b5061054b61068a36600461482d565b6111d4565b34801561069a575f80fd5b506106d76040518060400160405280600381526020017f362e30000000000000000000000000000000000000000000000000000000000081525081565b6040516104cc919061485b565b3480156106ef575f80fd5b506105087fb6cc65f42901ed602aec1619cc1ead29d487cd489094a37615153eaeb991d77081565b348015610722575f80fd5b50610508610731366004614802565b60a56020525f908152604090205481565b34801561074d575f80fd5b50610756600181565b60405160ff90911681526020016104cc565b348015610773575f80fd5b5061054b6107823660046148d5565b61122b565b348015610792575f80fd5b506105086107a1366004614802565b6101b76020525f908152604090205481565b3480156107be575f80fd5b506105087f0cf0d2deb70d7bdac2fa48c4ac99bc558170be0ce5fcb994caefa4bf7b96edf981565b3480156107f1575f80fd5b5061054b610800366004614802565b6114e1565b348015610810575f80fd5b5061054b61081f366004614965565b6115a7565b34801561082f575f80fd5b5061050860995481565b348015610844575f80fd5b50610508610853366004614802565b60a66020525f908152604090205481565b34801561086f575f80fd5b5061050861087e366004614802565b6101ba6020525f908152604090205481565b34801561089b575f80fd5b506105086108aa366004614802565b6101b66020525f908152604090205481565b3480156108c7575f80fd5b506105086108d6366004614802565b6101506020525f908152604090205481565b3480156108f3575f80fd5b506105087fe37c272ea30e2bb381ad7cf89ae754b49153250609f36d0cbdad8b64c184bb5c81565b348015610926575f80fd5b5061054b6109353660046149dd565b61169f565b348015610945575f80fd5b50610508610954366004614802565b6101b86020525f908152604090205481565b348015610971575f80fd5b5061097a611af8565b6040516001600160a01b0390911681526020016104cc565b34801561099d575f80fd5b5061054b6109ac366004614a15565b611b30565b3480156109bc575f80fd5b506105086101195481565b3480156109d2575f80fd5b506105087fd8b4c34c2ec1f3194471108c64ad2beda340c0337ee4ca35592f9ef270f4228b81565b348015610a05575f80fd5b506105087f32937fd5162e282df7e9a14a5073a2425321c7966eaf70ed6c838a1006d84c4c81565b348015610a38575f80fd5b50610756600281565b348015610a4c575f80fd5b506107565f81565b348015610a5f575f80fd5b50610508610a6e366004614802565b61011a6020525f908152604090205481565b348015610a8b575f80fd5b506105087fe1fce82838dd7a42cfe783f60dc6233c8aa2c4fc66e77817805e767ec5e349b681565b348015610abe575f80fd5b50610508610acd366004614802565b61014e6020525f908152604090205481565b348015610aea575f80fd5b506104c0610af936600461482d565b5f9182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b348015610b2e575f80fd5b506105086101bf5481565b348015610b44575f80fd5b5061054b610b53366004614a63565b611d70565b348015610b63575f80fd5b506105087f56bdc3c9ec86cb7db110a7699b2ade72f0b8819727d9f7d906b012641505fa7781565b348015610b96575f80fd5b506104c0610ba5366004614802565b612054565b61054b610bb8366004614ae0565b612077565b348015610bc8575f80fd5b506105085f81565b348015610bdb575f80fd5b5061054b610bea366004614b38565b612199565b348015610bfa575f80fd5b5061097a610c09366004614802565b61011b6020525f90815260409020546001600160a01b031681565b348015610c2f575f80fd5b5061050860985481565b348015610c44575f80fd5b5061054b6125cb565b348015610c58575f80fd5b506105087fe4831f9e4316ac2c65117d1f602fbf56d38128a9973d5e3fdbc5b77265c18d4081565b348015610c8b575f80fd5b5061050860e45481565b348015610ca0575f80fd5b506105087f430a7f0cb00b5ebbe63cecc96e82cf959a883e7c13a95110854f1fa6b3fbf59881565b348015610cd3575f80fd5b506104c0610ce23660046147e4565b612626565b348015610cf2575f80fd5b5061054b610d01366004614b70565b61264a565b348015610d11575f80fd5b506105087f1185e52d62bfbbea270e57d3d09733d221b53ab7a18bae82bb3c6c74bab16d8281565b348015610d44575f80fd5b50610508609a5481565b348015610d59575f80fd5b5061054b610d68366004614bda565b61277a565b348015610d78575f80fd5b5061050860975481565b348015610d8d575f80fd5b5061054b610d9c366004614c8c565b6129e0565b348015610dac575f80fd5b506104c0610dbb366004614802565b60d96020525f908152604090205460ff1681565b348015610dda575f80fd5b506105087fe8cb6172fcf5cbaae022b7c910224a4f0c20d53227e630056efff182155a5abc81565b348015610e0d575f80fd5b506105086101bd5481565b348015610e23575f80fd5b506101c05461097a906001600160a01b031681565b348015610e43575f80fd5b5061054b610e5236600461482d565b612ae6565b348015610e62575f80fd5b506105086101bc5481565b348015610e78575f80fd5b506105087f6b5661ddfbd1fbd525c902a513e0f47d9c74f1c1ee8a2d4f1937ad305fb8f41a81565b348015610eab575f80fd5b5061054b610eba3660046147e4565b612b0a565b348015610eca575f80fd5b50610508604080515f602082018190529181018290527f072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd60608201526080810182905260a081019190915260c0016040516020818303038152906040528051906020012081565b348015610f3c575f80fd5b506105087f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92981565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610ff657507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60dc5f82600881111561101157611011614cb6565b600881111561102257611022614cb6565b81526020019081526020015f205461103981612be2565b61104282612626565b61108357816040517f1865965400000000000000000000000000000000000000000000000000000000815260040161107a9190614ce3565b60405180910390fd5b81600881111561109557611095614cb6565b60da8054600190921b1990911690558160088111156110b6576110b6614cb6565b7fd071d2b85dec4489435b541d2f0e2570db09b09db9efd8703948d44a433df65a335b6040516001600160a01b03909116815260200160405180910390a25050565b7f6b5661ddfbd1fbd525c902a513e0f47d9c74f1c1ee8a2d4f1937ad305fb8f41a61112281612be2565b5f82815261011b602090815260408083205490516001600160a01b0390911681523392859290917f4a29db3fc6b42bda201e4b4d69ce8d575eeeba5f153509c0d0a342af0f1bd021910160405180910390a4505f90815261011b6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b5f828152606560205260409020600101546111c581612be2565b6111cf8383612bec565b505050565b6101c0546001600160a01b039081169082160361121d576040517f7f7497e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112278282612caa565b5050565b611233612d4c565b85878484875f5a90506112466003612de9565b61127a61127460017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614d4f565b8f612e7b565b5f61128a8f8f8f8f8c8f8f612e82565b905061129581612edb565b6112a76112a28d8f614d62565b612f35565b5f808f6001600160a01b03168e8d8d6040516112c4929190614d75565b5f6040518083038185875af1925050503d805f81146112fe576040519150601f19603f3d011682016040523d82523d5f602084013e611303565b606091505b5091509150816113605780511561131d5780518082602001fd5b8f6040517f5461344300000000000000000000000000000000000000000000000000000000815260040161107a91906001600160a01b0391909116815260200190565b61139461138e60017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614d4f565b5f612e7b565b60405183907fa4c827e719e911e8f19393ccdb85b5102f08f0910604d340ba38390b7ff2ab0e905f90a25050861590506114c957855f84900361143f57853b15801561143d573a5a6113e861bc7c86614d62565b6113f29190614d4f565b6113fc9190614d84565b915081881115611439576001600160a01b0387166108fc61141d848b614d4f565b6040518115909202915f818181858888f193505050505061143d565b8791505b505b5f6001600160a01b038416156114555783611457565b335b90505f816001600160a01b03166108fc8490811502906040515f60405180830381858888f193505050509050806114c5576040517fa57c4df40000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260240161107a565b5050505b5050505050506114d7612fab565b5050505050505050565b7f1185e52d62bfbbea270e57d3d09733d221b53ab7a18bae82bb3c6c74bab16d8261150b81612be2565b5f805f426099541015611530576097546115259042614d62565b609955506001611542565b609a5485101561154257849250600191505b609885905580806115505750815b1561155b57609a8390555b60408051868152831515602082015282151581830152905133917fbc3dc0cb5c15c51c81316450d44048838bb478b9809447d01c766a06f3e9f2c8919081900360600190a25050505050565b60066115b281612de9565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b9296115dc81612be2565b5f859003611616576040517f7907d79b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610119545f81815261011a6020526040902054843514611662576040517fead4c30e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101bd545f6116718684612fd9565b90505f611685878484878b602001356132c6565b905061169381898c8c61334e565b50505050505050505050565b6116a7612d4c565b60a081018035906116bb9060808401614d9b565b6116c9610120840184614db6565b6116da610100860160e08701614d9b565b5f5a90506116e86003612de9565b6101008701355f908152610150602052604081205490819003611737576040517f4e68667500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117418880614e17565b9050811461179057806117548980614e17565b6040517f5e3fd6ad000000000000000000000000000000000000000000000000000000008152600481019390935260248301525060440161107a565b61179d88602001356135b2565b6117b26112a260c08a013560a08b0135614d62565b5f6117fb6117c660808b0160608c01614d9b565b6117d660a08c0160808d01614d9b565b8b60a001358c60c001358d602001358e8061012001906117f69190614db6565b612e82565b90506118268161180b8b80614e17565b61181b60608e0160408f01614e7b565b8d610100013561362a565b61185c576040517fb05e92fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61189f61188a60017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614d4f565b61189a60808c0160608d01614d9b565b612e7b565b5f806118b160a08c0160808d01614d9b565b6001600160a01b031660c08c01356118cd6101208e018e614db6565b6040516118db929190614d75565b5f6040518083038185875af1925050503d805f8114611915576040519150601f19603f3d011682016040523d82523d5f602084013e61191a565b606091505b509150915081611982578051156119345780518082602001fd5b61194460a08c0160808d01614d9b565b6040517f546134430000000000000000000000000000000000000000000000000000000081526001600160a01b03909116600482015260240161107a565b6119b061138e60017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614d4f565b60405183907fa4c827e719e911e8f19393ccdb85b5102f08f0910604d340ba38390b7ff2ab0e905f90a2505050505f861115611ae757855f849003611a5d57853b158015611a5b573a5a611a0661bc7c86614d62565b611a109190614d4f565b611a1a9190614d84565b915081881115611a57576001600160a01b0387166108fc611a3b848b614d4f565b6040518115909202915f818181858888f1935050505050611a5b565b8791505b505b5f6001600160a01b03841615611a735783611a75565b335b90505f816001600160a01b03166108fc8490811502906040515f60405180830381858888f19350505050905080611ae3576040517fa57c4df40000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260240161107a565b5050505b505050505050611af5612fab565b50565b5f611b2b611b2760017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614d4f565b5c90565b905090565b6005611b3b81612de9565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929611b6581612be2565b611b726040860186614db6565b90505f03611bac576040517fc01eab5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8381526101be602052604090205415611bf5576040517f0f06cd150000000000000000000000000000000000000000000000000000000081526004810184905260240161107a565b5f8481526101be60205260408120549003611c3f576040517f6e5424c20000000000000000000000000000000000000000000000000000000081526004810185905260240161107a565b5f611c4d6040870187614db6565b604051611c5b929190614d75565b604051809103902090505f611c7d8760200135835f9182526020526040902090565b90505f611cc98760208a01358a3585611ca2611c9c60408f018f614db6565b89613737565b604080519586526020860194909452928401919091526060830152608082015260a0902090565b9050808614611d0e576040517fd3664fb3000000000000000000000000000000000000000000000000000000008152600481018790526024810182905260440161107a565b5f8181526101be602052604090819020600190555181907f55f4c645c36aa5cd3f443d6be44d7a7a5df9d2100d7139dfc69d4289ee07231990611d5e908a908c3590918252602082015260400190565b60405180910390a25050505050505050565b6004611d7b81612de9565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929611da581612be2565b5f859003611ddf576040517fb1504a5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b844915611e1b576040517f8019aff70000000000000000000000000000000000000000000000000000000081526004810186905260240161107a565b5f8481526101be60205260408120549003611e65576040517f6e5424c20000000000000000000000000000000000000000000000000000000081526004810185905260240161107a565b5f8381526101be602052604090205415611eae576040517f0f06cd150000000000000000000000000000000000000000000000000000000081526004810184905260240161107a565b6040805160a0810182525f808252606060208301819052928201839052918101829052608081018290528190865f5b89811015611fb3578a8a82818110611ef757611ef7614e9e565b9050602002810190611f099190614ecb565b611f1290614fe8565b81499450925083611f52576040517fc0e41e1d0000000000000000000000000000000000000000000000000000000081526004810182905260240161107a565b60808301515f8181526020869052604090209550611f8085875f1c865f015187602001518860400151613838565b6060848101518551604080519687526020870194909452928501528301869052608083015260a090912090600101611edd565b50808714611ff7576040517fd3664fb3000000000000000000000000000000000000000000000000000000008152600481018890526024810182905260440161107a565b5f8181526101be602090815260409182902060019055606084015182518b81529182015282917f55f4c645c36aa5cd3f443d6be44d7a7a5df9d2100d7139dfc69d4289ee072319910160405180910390a250505050505050505050565b600881901c5f90815261014f6020526040812054600160ff84161b161515610ff6565b600261208281612de9565b6001600160a01b0385166120c2576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b348411156120fc576040517fb03b693200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60e480545f918261210c83615075565b9091555090505f61211d8634614d4f565b90505f61212f33898985878b8b612e82565b905061213b83826139da565b80886001600160a01b0316336001600160a01b03167fe856c2b8bd4eb0027ce32eeaf595c21b0b6b4644b326e5b7bd80a1cf8db72e6c8a86888c8c6040516121879594939291906150d5565b60405180910390a45050505050505050565b5f54610100900460ff16158080156121b757505f54600160ff909116105b806121d05750303b1580156121d057505f5460ff166001145b61225c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161107a565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156122b8575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b5f6122c96080840160608501614d9b565b6001600160a01b031603612309576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61232c61231960e0840184615105565b612327610100860186615105565b613a56565b61233e82608001358360a00135613d04565b6123595f61235461016085016101408601614d9b565b612bec565b61236e61236960c0840184615105565b613dc5565b61237e6080830160608401614d9b565b5f805261011b6020527f033d11f27e62ab919708ec716731da80d261a6e4253259b7acde9bf89d28ec1880547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03929092169190911790556123f061014083016101208401614d9b565b6101c080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039290921691909117905561243b61014083016101208401614d9b565b6001600160a01b0316336001600160a01b03167f1f82add12d98b5eaed4d6a6d5f74cfc7a85e5c90c335ab5562f77f220ed45d5f60405160405180910390a36020828101356101198190555f90815261011a825260408082208535905580518084018390528082018390527f072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd60608083018290526080830185905260a08084018690528451808503909101815260c08401855280519087012085526101be86528385206001905560e0830185905261010083018590526101208301919091526101408201849052610160808301859052835180840390910181526101808301808552815191909601206101bd558385526101a0820193909352908501356101c09091015290206101bf558015611227575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15050565b7f0cf0d2deb70d7bdac2fa48c4ac99bc558170be0ce5fcb994caefa4bf7b96edf96125f581612be2565b5f609a81905560405133917fba88c025b0cbb77022c0c487beef24f759f1e4be2f51a205bc427cee19c2eaa691a250565b5f81600881111561263957612639614cb6565b60da54600190911b16151592915050565b61265762f099c082614d62565b421015612690576040517f4306cbb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805184815260208101849052908101829052606090206101bf5414612708576101bf546040805185815260208101859052908101839052606090206040517fbc5aad110000000000000000000000000000000000000000000000000000000081526004810192909252602482015260440161107a565b6101c0546001600160a01b031661273f7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92982612bec565b6040516001600160a01b0382169033907f9fc8868f8577b31b805ee65bb52325782b5e2708dbdb7f04c7467c6785fccb30905f90a350505050565b5f54600690610100900460ff1615801561279a57505f5460ff8083169116105b612826576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161107a565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001790556128608888613dc5565b61286c86868686613a56565b6001600160a01b0382166128ac576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101c080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03841690811790915560405133907f1f82add12d98b5eaed4d6a6d5f74cfc7a85e5c90c335ab5562f77f220ed45d5f905f90a36040517f362e300000000000000000000000000000000000000000000000000000000000907f352e300000000000000000000000000000000000000000000000000000000000907f2f8492a7a430cf917798dfb60bc5af634f68e6c40287947df0ea6f7ec0669bd8905f90a35f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050505050565b7f32937fd5162e282df7e9a14a5073a2425321c7966eaf70ed6c838a1006d84c4c612a0a81612be2565b6001600160a01b038316612a4a576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815261011b60209081526040918290205491516001600160a01b03928316815233928592908716917f4a29db3fc6b42bda201e4b4d69ce8d575eeeba5f153509c0d0a342af0f1bd021910160405180910390a4505f90815261011b6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b5f82815260656020526040902060010154612b0081612be2565b6111cf8383613f73565b60db5f826008811115612b1f57612b1f614cb6565b6008811115612b3057612b30614cb6565b81526020019081526020015f2054612b4781612be2565b612b5082612626565b15612b8957816040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040161107a9190614ce3565b816008811115612b9b57612b9b614cb6565b60da8054600190921b9091179055816008811115612bbb57612bbb614cb6565b7f534f879afd40abb4e39f8e1b77a316be4c8e3521d9cf5a3a3db8959d574d4559336110d9565b611af58133614012565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff16611227575f8281526065602090815260408083206001600160a01b0385168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055612c663390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b0381163314612d42576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c660000000000000000000000000000000000606482015260840161107a565b6112278282613f73565b5f612d7b611b2760017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614d4f565b14612db2576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612de7612de060017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614d4f565b6001612e7b565b565b60da54816008811115612dfe57612dfe614cb6565b6001901b811615612e3d57816040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040161107a9190614ce3565b60028116156112275760016040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040161107a9190614ce3565b80825d5050565b5f60405188815287602082015286604082015285606082015284608082015260c060a08201528260c0820152602083065f8115612ec0578160200390505b848660e085013790930160e001902098975050505050505050565b5f81815260a66020526040902054600114612f25576040517f992d87c30000000000000000000000000000000000000000000000000000000081526004810182905260240161107a565b5f90815260a66020526040812055565b8015611af557426099541015612f5a57609754612f529042614d62565b609955612f6a565b609a54612f679082614d62565b90505b609854811115612fa6576040517fa74c1c5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609a55565b612de761138e60017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614d4f565b5f81836020013511613024576040517f70614405000000000000000000000000000000000000000000000000000000008152602084013560048201526024810183905260440161107a565b6130388361018001358461014001356140a0565b6101bf54604080516101608601358152610120860135602082015260e08601359181019190915260609020146130ce57604080516101608501358152610120850135602082015260e085013591810191909152606090206101bf546040517fbc5aad110000000000000000000000000000000000000000000000000000000081526004810192909252602482015260440161107a565b4283610100013510613119576040517fbf81c6e0000000000000000000000000000000000000000000000000000000008152610100840135600482015242602482015260440161107a565b6080830135613154576040517f2898482a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61319760408401356060850135608086013560a087013560c0880135604080519586526020860194909452928401919091526060830152608082015260a0902090565b5f8181526101be6020526040812054919250036131e3576040517fedeae83c0000000000000000000000000000000000000000000000000000000081526004810182905260240161107a565b6131ff6131f46101c0850185614e17565b856101a0013561416d565b6132166132106101e0850185614db6565b84614279565b6020808401355f81815261011a909252604090912060808501359055610119556101bd81905561326b610180840135610140850135610100860135604080519384526020840192909252908201526060902090565b6101bf5580602084013561327e84615075565b60408051873581526080880135602082015291955085917fa0262dc79e4ccb71ceac8574ae906311ae338aa4a2044fd4ec4b99fad5ab60cb910160405180910390a492915050565b5f604051858152846020820152604060e0880160408301378360808201528260a082015260a0610120880160c083013761018081016101c088013588018035602081026020830184376020029091206101608301525061018090207f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000190069695505050505050565b6040805160018082528183019092525f916020808301908036833701905050905084815f8151811061338257613382614e9e565b6020908102919091018101919091525f85815261011b90915260409020546001600160a01b0316806133e0576040517f69ed70ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80826001600160a01b0316637e4f7a8a60e01b87878760405160240161340993929190615169565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161347491906151da565b5f604051808303815f865af19150503d805f81146134ad576040519150601f19603f3d011682016040523d82523d5f602084013e6134b2565b606091505b509150915081613559578051156134f757602081017bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81511663ca389c4460e01b178152815181fd5b6040517fca389c4400000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f556e6b6e6f776e00000000000000000000000000000000000000000000000000604482015260640161107a565b5f8180602001905181019061356e91906151e5565b9050806135a7576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050565b600881901c5f90815261014f6020526040902054600160ff83161b1615613608576040517f335a4a900000000000000000000000000000000000000000000000000000000081526004810182905260240161107a565b600881901c5f90815261014f602052604090208054600160ff84161b17905550565b5f8061364b600161363c876002615325565b6136469190614d4f565b614306565b90508063ffffffff168463ffffffff1611156136a3576040517ff7ec909700000000000000000000000000000000000000000000000000000000815263ffffffff80861660048301528216602482015260440161107a565b865f5b8681101561372957600163ffffffff8716821c811690036136f3576136ec8888838181106136d6576136d6614e9e565b90506020020135835f9182526020526040902090565b9150613721565b61371e8289898481811061370957613709614e9e565b905060200201355f9182526020526040902090565b91505b6001016136a6565b509092149695505050505050565b5f613743602084615330565b1561377a576040517f6426c6c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f729eebce00000000000000000000000000000000000000000000000000000000835b801561382f57602081039050808601357fff000000000000000000000000000000000000000000000000000000000000008116156137e057604051838152600481fd5b7f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001817f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff000000018787090893505061379d565b50509392505050565b7f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001840693505f80600a6001600160a01b03168787878787604051602001613883959493929190615368565b60408051601f198184030181529082905261389d916151da565b5f60405180830381855afa9150503d805f81146138d5576040519150601f19603f3d011682016040523d82523d5f602084013e6138da565b606091505b509150915081613916576040517fa71194af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604081511461395e578051604080517ff75db38100000000000000000000000000000000000000000000000000000000815261107a9290600401918252602082015260400190565b602081015160408201516110008214158061399957507f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff000000018114155b156135a7576040517f68dcad5f000000000000000000000000000000000000000000000000000000008152600481018390526024810182905260440161107a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82015f90815261014e60208181526040808420548452848252808420868552929091528083208290555190918391839186917fea3b023b4c8680d4b4824f0143132c95476359a2bb70a81d6c5a36f6918f63399190a4505050565b5f54610100900460ff16613aec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161107a565b5f5b83811015613bf457848482818110613b0857613b08614e9e565b9050604002016020013560db5f878785818110613b2757613b27614e9e565b613b3d92602060409092020190810191506147e4565b6008811115613b4e57613b4e614cb6565b6008811115613b5f57613b5f614cb6565b815260208101919091526040015f2055848482818110613b8157613b81614e9e565b90506040020160200135858583818110613b9d57613b9d614e9e565b613bb392602060409092020190810191506147e4565b6008811115613bc457613bc4614cb6565b6040517f33aa8fd1ce49e1761bc8d27fd53414bfefc45d690feed0ce55019d7d3aec6091905f90a3600101613aee565b505f5b81811015613cfd57828282818110613c1157613c11614e9e565b9050604002016020013560dc5f858585818110613c3057613c30614e9e565b613c4692602060409092020190810191506147e4565b6008811115613c5757613c57614cb6565b6008811115613c6857613c68614cb6565b815260208101919091526040015f2055828282818110613c8a57613c8a614e9e565b90506040020160200135838383818110613ca657613ca6614e9e565b613cbc92602060409092020190810191506147e4565b6008811115613ccd57613ccd614cb6565b6040517fe7bf4b8dc0c17a52dc9e52323a3ab61cb2079db35f969125b1f8a3d984c6f6c2905f90a3600101613bf7565b5050505050565b5f54610100900460ff16613d9a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161107a565b613da2614353565b613daa614353565b613db2614353565b613dbc82826143e9565b5050600160e455565b5f54610100900460ff16613e5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161107a565b5f5b818110156111cf575f838383818110613e7857613e78614e9e565b613e8e9260206040909202019081019150614d9b565b6001600160a01b031603613ece576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b828282818110613ee057613ee0614e9e565b905060400201602001355f801b03613f24576040517f0742d05300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613f6b838383818110613f3957613f39614e9e565b90506040020160200135848484818110613f5557613f55614e9e565b6123549260206040909202019081019150614d9b565b600101613e5d565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff1615611227575f8281526065602090815260408083206001600160a01b038516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff16611227576140448161454f565b61404f836020614561565b60405160200161406092919061538e565b60408051601f19818403018152908290527f08c379a000000000000000000000000000000000000000000000000000000000825261107a9160040161485b565b815f036140e2578015611227576040517f0c2565920000000000000000000000000000000000000000000000000000000081526004810182905260240161107a565b8061411c576040517f5228f4c80000000000000000000000000000000000000000000000000000000081526004810183905260240161107a565b5f82815261014e60205260409020548114611227576040517f36459fa0000000000000000000000000000000000000000000000000000000008152600481018390526024810182905260440161107a565b5f5b82811015614273576101505f85858481811061418d5761418d614e9e565b9050602002013581526020019081526020015f20545f146141f6578383828181106141ba576141ba614e9e565b905060200201356040517fe5d1442500000000000000000000000000000000000000000000000000000000815260040161107a91815260200190565b816101505f86868581811061420d5761420d614e9e565b9050602002013581526020019081526020015f20819055508184848381811061423857614238614e9e565b905060200201357f300e6f978eee6a4b0bba78dd8400dc64fd5652dbfc868a2258e16d0977be222b60405160405180910390a360010161416f565b50505050565b614284600283615330565b156142be576040517f0c91d7760000000000000000000000000000000000000000000000000000000081526004810183905260240161107a565b5f805b83811015613cfd576040518582013560f01c9250838301907f3c116827db9db3a30c1a25db8b0ee4bab9d2b223560209cfd839601b621c726d905f90a26002016142c1565b5f63ffffffff82111561434f576040517f6dfcc650000000000000000000000000000000000000000000000000000000008152602060048201526024810183905260440161107a565b5090565b5f54610100900460ff16612de7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161107a565b5f54610100900460ff1661447f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161107a565b815f036144b8576040517fb5ed5a3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805f036144f1576040517fd10d72bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609782905560988190556145058242614d62565b60998190556097546098546040805192835260208301919091528101919091527f8f805c372b66240792580418b7328c0c554ae235f0932475c51b026887fe26a9906060016125bf565b6060610ff66001600160a01b03831660145b60605f61456f836002614d84565b61457a906002614d62565b67ffffffffffffffff81111561459257614592614f07565b6040519080825280601f01601f1916602001820160405280156145bc576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000815f815181106145f2576145f2614e9e565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061465457614654614e9e565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f61468e846002614d84565b614699906001614d62565b90505b6001811115614735577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106146da576146da614e9e565b1a60f81b8282815181106146f0576146f0614e9e565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060049490941c9361472e816153f8565b905061469c565b50831561479e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640161107a565b9392505050565b5f602082840312156147b5575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461479e575f80fd5b5f602082840312156147f4575f80fd5b81356009811061479e575f80fd5b5f60208284031215614812575f80fd5b5035919050565b6001600160a01b0381168114611af5575f80fd5b5f806040838503121561483e575f80fd5b82359150602083013561485081614819565b809150509250929050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f8083601f8401126148a0575f80fd5b50813567ffffffffffffffff8111156148b7575f80fd5b6020830191508360208285010111156148ce575f80fd5b9250929050565b5f805f805f805f8060e0898b0312156148ec575f80fd5b88356148f781614819565b9750602089013561490781614819565b96506040890135955060608901359450608089013561492581614819565b935060a089013567ffffffffffffffff811115614940575f80fd5b61494c8b828c01614890565b999c989b50969995989497949560c00135949350505050565b5f805f8060608587031215614978575f80fd5b843567ffffffffffffffff81111561498e575f80fd5b61499a87828801614890565b90955093505060208501359150604085013567ffffffffffffffff8111156149c0575f80fd5b850161020081880312156149d2575f80fd5b939692955090935050565b5f602082840312156149ed575f80fd5b813567ffffffffffffffff811115614a03575f80fd5b8201610140818503121561479e575f80fd5b5f805f60608486031215614a27575f80fd5b833567ffffffffffffffff811115614a3d575f80fd5b840160608187031215614a4e575f80fd5b95602085013595506040909401359392505050565b5f805f8060608587031215614a76575f80fd5b843567ffffffffffffffff811115614a8c575f80fd5b8501601f81018713614a9c575f80fd5b803567ffffffffffffffff811115614ab2575f80fd5b8760208260051b8401011115614ac6575f80fd5b602091820198909750908601359560400135945092505050565b5f805f8060608587031215614af3575f80fd5b8435614afe81614819565b935060208501359250604085013567ffffffffffffffff811115614b20575f80fd5b614b2c87828801614890565b95989497509550505050565b5f60208284031215614b48575f80fd5b813567ffffffffffffffff811115614b5e575f80fd5b8201610160818503121561479e575f80fd5b5f805f60608486031215614b82575f80fd5b505081359360208301359350604090920135919050565b5f8083601f840112614ba9575f80fd5b50813567ffffffffffffffff811115614bc0575f80fd5b6020830191508360208260061b85010111156148ce575f80fd5b5f805f805f805f6080888a031215614bf0575f80fd5b873567ffffffffffffffff811115614c06575f80fd5b614c128a828b01614b99565b909850965050602088013567ffffffffffffffff811115614c31575f80fd5b614c3d8a828b01614b99565b909650945050604088013567ffffffffffffffff811115614c5c575f80fd5b614c688a828b01614b99565b9094509250506060880135614c7c81614819565b8091505092959891949750929550565b5f8060408385031215614c9d575f80fd5b8235614ca881614819565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6020810160098310614d1c577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b91905290565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115610ff657610ff6614d22565b80820180821115610ff657610ff6614d22565b818382375f9101908152919050565b8082028115828204841417610ff657610ff6614d22565b5f60208284031215614dab575f80fd5b813561479e81614819565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614de9575f80fd5b83018035915067ffffffffffffffff821115614e03575f80fd5b6020019150368190038213156148ce575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614e4a575f80fd5b83018035915067ffffffffffffffff821115614e64575f80fd5b6020019150600581901b36038213156148ce575f80fd5b5f60208284031215614e8b575f80fd5b813563ffffffff8116811461479e575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61833603018112614efd575f80fd5b9190910192915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405160a0810167ffffffffffffffff81118282101715614f5757614f57614f07565b60405290565b5f82601f830112614f6c575f80fd5b813567ffffffffffffffff811115614f8657614f86614f07565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715614fb557614fb5614f07565b604052818152838201602001851015614fcc575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60a08236031215614ff8575f80fd5b615000614f34565b82358152602083013567ffffffffffffffff81111561501d575f80fd5b61502936828601614f5d565b602083015250604083013567ffffffffffffffff811115615048575f80fd5b61505436828601614f5d565b60408301525060608381013590820152608092830135928101929092525090565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036150a5576150a5614d22565b5060010190565b81835281816020850137505f602082840101525f6020601f19601f840116840101905092915050565b858152846020820152836040820152608060608201525f6150fa6080830184866150ac565b979650505050505050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615138575f80fd5b83018035915067ffffffffffffffff821115615152575f80fd5b6020019150600681901b36038213156148ce575f80fd5b604081525f61517c6040830185876150ac565b82810360208401528084518083526020830191506020860192505f5b818110156151b6578351835260209384019390920191600101615198565b5090979650505050505050565b5f81518060208401855e5f93019283525090919050565b5f61479e82846151c3565b5f602082840312156151f5575f80fd5b8151801515811461479e575f80fd5b6001815b600184111561523f5780850481111561522357615223614d22565b600184161561523157908102905b60019390931c928002615208565b935093915050565b5f8261525557506001610ff6565b8161526157505f610ff6565b816001811461527757600281146152815761529d565b6001915050610ff6565b60ff84111561529257615292614d22565b50506001821b610ff6565b5060208310610133831016604e8410600b84101617156152c0575081810a610ff6565b6152eb7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484615204565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561531d5761531d614d22565b029392505050565b5f61479e8383615247565b5f82615363577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500690565b8581528460208201528360408201525f6150fa61538860608401866151c3565b846151c3565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f6153bf60178301856151c3565b7f206973206d697373696e6720726f6c652000000000000000000000000000000081526153ef60118201856151c3565b95945050505050565b5f8161540657615406614d22565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea264697066735822122017fa9362d0392993ac5f756a12c21940cf721259b8b8bc02053fb03e1c986a6364736f6c634300081a0033", - "deployedBytecode": "0x60806040526004361061049d575f3560e01c806373bd07b71161026b578063b837dbe911610156578063cc5782f6116100d1578063d5d4b83511610087578063e196fb5d1161006d578063e196fb5d14610ea0578063e97a1e9e14610ebf578063f5b541a614610f31575f80fd5b8063d5d4b83514610e57578063d722bbfc14610e6d575f80fd5b8063cd9b9e9a116100b7578063cd9b9e9a14610e02578063cf5b276414610e18578063d547741f14610e38575f80fd5b8063cc5782f614610da1578063cc6f725114610dcf575f80fd5b8063bf3e750511610126578063c0c4e5841161010c578063c0c4e58414610d4e578063c1dc0f0714610d6d578063c211697414610d82575f80fd5b8063bf3e750514610d06578063c0729ab114610d39575f80fd5b8063b837dbe914610c80578063b9174ba314610c95578063bc61e73314610cc8578063bcc3003d14610ce7575f80fd5b80639ac25d08116101e6578063a98e773d116101b6578063ad422ff01161019c578063ad422ff014610c24578063aea4f74514610c39578063b59faa6014610c4d575f80fd5b8063a98e773d14610bd0578063ac1eff6814610bef575f80fd5b80639ac25d0814610b585780639ee8b21114610b8b5780639f3ce55a14610baa578063a217fddf14610bbd575f80fd5b8063914e57eb1161023b578063921b278e11610221578063921b278e14610b23578063986fcddd14610a4157806399467a3514610b39575f80fd5b8063914e57eb14610ab357806391d1485414610adf575f80fd5b806373bd07b714610a2d5780637d1e8c5514610a415780638be745d114610a545780638de4948714610a80575f80fd5b80634cdd389b1161038b57806360e83cf31161030657806367e404ce116102d6578063695378f5116102bc578063695378f5146109b15780636a906b80146109c75780636e673843146109fa575f80fd5b806367e404ce146109665780636854f6bc14610992575f80fd5b806360e83cf3146108bc57806363213155146108e85780636463fb2a1461091b57806366f96e981461093a575f80fd5b8063587944561161035b5780635c721a0c116103415780635c721a0c146108395780635ed73ceb146108645780636078bfd814610890575f80fd5b806358794456146108245780635b7eb4bd14610742575f80fd5b80634cdd389b146107875780635230eef2146107b3578063557eac73146107e65780635603c65f14610805575f80fd5b8063289581741161041b57806338b90333116103eb5780633fc08b65116103d15780633fc08b651461071757806348922ab714610742578063491e093614610768575f80fd5b806338b903331461068f5780633b12eccb146106e4575f80fd5b8063289581741461061c5780632c70645c1461063b5780632f2ff15d1461065157806336568abe14610670575f80fd5b806312d3fa9a116104705780631f443da0116104565780631f443da0146105965780632130d812146105c2578063248a9ca3146105ee575f80fd5b806312d3fa9a1461054d5780631e2ff94f14610580575f80fd5b806301ffc9a7146104a157806303134d1d146104d557806305861180146105165780631065a3991461052c575b5f80fd5b3480156104ac575f80fd5b506104c06104bb3660046147a5565b610f64565b60405190151581526020015b60405180910390f35b3480156104e0575f80fd5b506105087f1ab87f7458c0e3d07e9881c14ee67f0141703614fd48ea5b15ed987e5f4b030e81565b6040519081526020016104cc565b348015610521575f80fd5b506105086101bb5481565b348015610537575f80fd5b5061054b6105463660046147e4565b610ffc565b005b348015610558575f80fd5b506105087f67c2dca7476ee0fe1dd3cba13428c6760bfe2599a6dfe26a9ad7ef27317c6e7781565b34801561058b575f80fd5b506105086101185481565b3480156105a1575f80fd5b506105086105b0366004614802565b6101b96020525f908152604090205481565b3480156105cd575f80fd5b506105086105dc366004614802565b6101be6020525f908152604090205481565b3480156105f9575f80fd5b50610508610608366004614802565b5f9081526065602052604090206001015490565b348015610627575f80fd5b5061054b610636366004614802565b6110f8565b348015610646575f80fd5b506105086101835481565b34801561065c575f80fd5b5061054b61066b36600461482d565b6111ab565b34801561067b575f80fd5b5061054b61068a36600461482d565b6111d4565b34801561069a575f80fd5b506106d76040518060400160405280600381526020017f362e30000000000000000000000000000000000000000000000000000000000081525081565b6040516104cc919061485b565b3480156106ef575f80fd5b506105087fb6cc65f42901ed602aec1619cc1ead29d487cd489094a37615153eaeb991d77081565b348015610722575f80fd5b50610508610731366004614802565b60a56020525f908152604090205481565b34801561074d575f80fd5b50610756600181565b60405160ff90911681526020016104cc565b348015610773575f80fd5b5061054b6107823660046148d5565b61122b565b348015610792575f80fd5b506105086107a1366004614802565b6101b76020525f908152604090205481565b3480156107be575f80fd5b506105087f0cf0d2deb70d7bdac2fa48c4ac99bc558170be0ce5fcb994caefa4bf7b96edf981565b3480156107f1575f80fd5b5061054b610800366004614802565b6114e1565b348015610810575f80fd5b5061054b61081f366004614965565b6115a7565b34801561082f575f80fd5b5061050860995481565b348015610844575f80fd5b50610508610853366004614802565b60a66020525f908152604090205481565b34801561086f575f80fd5b5061050861087e366004614802565b6101ba6020525f908152604090205481565b34801561089b575f80fd5b506105086108aa366004614802565b6101b66020525f908152604090205481565b3480156108c7575f80fd5b506105086108d6366004614802565b6101506020525f908152604090205481565b3480156108f3575f80fd5b506105087fe37c272ea30e2bb381ad7cf89ae754b49153250609f36d0cbdad8b64c184bb5c81565b348015610926575f80fd5b5061054b6109353660046149dd565b61169f565b348015610945575f80fd5b50610508610954366004614802565b6101b86020525f908152604090205481565b348015610971575f80fd5b5061097a611af8565b6040516001600160a01b0390911681526020016104cc565b34801561099d575f80fd5b5061054b6109ac366004614a15565b611b30565b3480156109bc575f80fd5b506105086101195481565b3480156109d2575f80fd5b506105087fd8b4c34c2ec1f3194471108c64ad2beda340c0337ee4ca35592f9ef270f4228b81565b348015610a05575f80fd5b506105087f32937fd5162e282df7e9a14a5073a2425321c7966eaf70ed6c838a1006d84c4c81565b348015610a38575f80fd5b50610756600281565b348015610a4c575f80fd5b506107565f81565b348015610a5f575f80fd5b50610508610a6e366004614802565b61011a6020525f908152604090205481565b348015610a8b575f80fd5b506105087fe1fce82838dd7a42cfe783f60dc6233c8aa2c4fc66e77817805e767ec5e349b681565b348015610abe575f80fd5b50610508610acd366004614802565b61014e6020525f908152604090205481565b348015610aea575f80fd5b506104c0610af936600461482d565b5f9182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b348015610b2e575f80fd5b506105086101bf5481565b348015610b44575f80fd5b5061054b610b53366004614a63565b611d70565b348015610b63575f80fd5b506105087f56bdc3c9ec86cb7db110a7699b2ade72f0b8819727d9f7d906b012641505fa7781565b348015610b96575f80fd5b506104c0610ba5366004614802565b612054565b61054b610bb8366004614ae0565b612077565b348015610bc8575f80fd5b506105085f81565b348015610bdb575f80fd5b5061054b610bea366004614b38565b612199565b348015610bfa575f80fd5b5061097a610c09366004614802565b61011b6020525f90815260409020546001600160a01b031681565b348015610c2f575f80fd5b5061050860985481565b348015610c44575f80fd5b5061054b6125cb565b348015610c58575f80fd5b506105087fe4831f9e4316ac2c65117d1f602fbf56d38128a9973d5e3fdbc5b77265c18d4081565b348015610c8b575f80fd5b5061050860e45481565b348015610ca0575f80fd5b506105087f430a7f0cb00b5ebbe63cecc96e82cf959a883e7c13a95110854f1fa6b3fbf59881565b348015610cd3575f80fd5b506104c0610ce23660046147e4565b612626565b348015610cf2575f80fd5b5061054b610d01366004614b70565b61264a565b348015610d11575f80fd5b506105087f1185e52d62bfbbea270e57d3d09733d221b53ab7a18bae82bb3c6c74bab16d8281565b348015610d44575f80fd5b50610508609a5481565b348015610d59575f80fd5b5061054b610d68366004614bda565b61277a565b348015610d78575f80fd5b5061050860975481565b348015610d8d575f80fd5b5061054b610d9c366004614c8c565b6129e0565b348015610dac575f80fd5b506104c0610dbb366004614802565b60d96020525f908152604090205460ff1681565b348015610dda575f80fd5b506105087fe8cb6172fcf5cbaae022b7c910224a4f0c20d53227e630056efff182155a5abc81565b348015610e0d575f80fd5b506105086101bd5481565b348015610e23575f80fd5b506101c05461097a906001600160a01b031681565b348015610e43575f80fd5b5061054b610e5236600461482d565b612ae6565b348015610e62575f80fd5b506105086101bc5481565b348015610e78575f80fd5b506105087f6b5661ddfbd1fbd525c902a513e0f47d9c74f1c1ee8a2d4f1937ad305fb8f41a81565b348015610eab575f80fd5b5061054b610eba3660046147e4565b612b0a565b348015610eca575f80fd5b50610508604080515f602082018190529181018290527f072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd60608201526080810182905260a081019190915260c0016040516020818303038152906040528051906020012081565b348015610f3c575f80fd5b506105087f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92981565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610ff657507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60dc5f82600881111561101157611011614cb6565b600881111561102257611022614cb6565b81526020019081526020015f205461103981612be2565b61104282612626565b61108357816040517f1865965400000000000000000000000000000000000000000000000000000000815260040161107a9190614ce3565b60405180910390fd5b81600881111561109557611095614cb6565b60da8054600190921b1990911690558160088111156110b6576110b6614cb6565b7fd071d2b85dec4489435b541d2f0e2570db09b09db9efd8703948d44a433df65a335b6040516001600160a01b03909116815260200160405180910390a25050565b7f6b5661ddfbd1fbd525c902a513e0f47d9c74f1c1ee8a2d4f1937ad305fb8f41a61112281612be2565b5f82815261011b602090815260408083205490516001600160a01b0390911681523392859290917f4a29db3fc6b42bda201e4b4d69ce8d575eeeba5f153509c0d0a342af0f1bd021910160405180910390a4505f90815261011b6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b5f828152606560205260409020600101546111c581612be2565b6111cf8383612bec565b505050565b6101c0546001600160a01b039081169082160361121d576040517f7f7497e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112278282612caa565b5050565b611233612d4c565b85878484875f5a90506112466003612de9565b61127a61127460017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614d4f565b8f612e7b565b5f61128a8f8f8f8f8c8f8f612e82565b905061129581612edb565b6112a76112a28d8f614d62565b612f35565b5f808f6001600160a01b03168e8d8d6040516112c4929190614d75565b5f6040518083038185875af1925050503d805f81146112fe576040519150601f19603f3d011682016040523d82523d5f602084013e611303565b606091505b5091509150816113605780511561131d5780518082602001fd5b8f6040517f5461344300000000000000000000000000000000000000000000000000000000815260040161107a91906001600160a01b0391909116815260200190565b61139461138e60017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614d4f565b5f612e7b565b60405183907fa4c827e719e911e8f19393ccdb85b5102f08f0910604d340ba38390b7ff2ab0e905f90a25050861590506114c957855f84900361143f57853b15801561143d573a5a6113e861bc7c86614d62565b6113f29190614d4f565b6113fc9190614d84565b915081881115611439576001600160a01b0387166108fc61141d848b614d4f565b6040518115909202915f818181858888f193505050505061143d565b8791505b505b5f6001600160a01b038416156114555783611457565b335b90505f816001600160a01b03166108fc8490811502906040515f60405180830381858888f193505050509050806114c5576040517fa57c4df40000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260240161107a565b5050505b5050505050506114d7612fab565b5050505050505050565b7f1185e52d62bfbbea270e57d3d09733d221b53ab7a18bae82bb3c6c74bab16d8261150b81612be2565b5f805f426099541015611530576097546115259042614d62565b609955506001611542565b609a5485101561154257849250600191505b609885905580806115505750815b1561155b57609a8390555b60408051868152831515602082015282151581830152905133917fbc3dc0cb5c15c51c81316450d44048838bb478b9809447d01c766a06f3e9f2c8919081900360600190a25050505050565b60066115b281612de9565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b9296115dc81612be2565b5f859003611616576040517f7907d79b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610119545f81815261011a6020526040902054843514611662576040517fead4c30e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101bd545f6116718684612fd9565b90505f611685878484878b602001356132c6565b905061169381898c8c61334e565b50505050505050505050565b6116a7612d4c565b60a081018035906116bb9060808401614d9b565b6116c9610120840184614db6565b6116da610100860160e08701614d9b565b5f5a90506116e86003612de9565b6101008701355f908152610150602052604081205490819003611737576040517f4e68667500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117418880614e17565b9050811461179057806117548980614e17565b6040517f5e3fd6ad000000000000000000000000000000000000000000000000000000008152600481019390935260248301525060440161107a565b61179d88602001356135b2565b6117b26112a260c08a013560a08b0135614d62565b5f6117fb6117c660808b0160608c01614d9b565b6117d660a08c0160808d01614d9b565b8b60a001358c60c001358d602001358e8061012001906117f69190614db6565b612e82565b90506118268161180b8b80614e17565b61181b60608e0160408f01614e7b565b8d610100013561362a565b61185c576040517fb05e92fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61189f61188a60017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614d4f565b61189a60808c0160608d01614d9b565b612e7b565b5f806118b160a08c0160808d01614d9b565b6001600160a01b031660c08c01356118cd6101208e018e614db6565b6040516118db929190614d75565b5f6040518083038185875af1925050503d805f8114611915576040519150601f19603f3d011682016040523d82523d5f602084013e61191a565b606091505b509150915081611982578051156119345780518082602001fd5b61194460a08c0160808d01614d9b565b6040517f546134430000000000000000000000000000000000000000000000000000000081526001600160a01b03909116600482015260240161107a565b6119b061138e60017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614d4f565b60405183907fa4c827e719e911e8f19393ccdb85b5102f08f0910604d340ba38390b7ff2ab0e905f90a2505050505f861115611ae757855f849003611a5d57853b158015611a5b573a5a611a0661bc7c86614d62565b611a109190614d4f565b611a1a9190614d84565b915081881115611a57576001600160a01b0387166108fc611a3b848b614d4f565b6040518115909202915f818181858888f1935050505050611a5b565b8791505b505b5f6001600160a01b03841615611a735783611a75565b335b90505f816001600160a01b03166108fc8490811502906040515f60405180830381858888f19350505050905080611ae3576040517fa57c4df40000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260240161107a565b5050505b505050505050611af5612fab565b50565b5f611b2b611b2760017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614d4f565b5c90565b905090565b6005611b3b81612de9565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929611b6581612be2565b611b726040860186614db6565b90505f03611bac576040517fc01eab5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8381526101be602052604090205415611bf5576040517f0f06cd150000000000000000000000000000000000000000000000000000000081526004810184905260240161107a565b5f8481526101be60205260408120549003611c3f576040517f6e5424c20000000000000000000000000000000000000000000000000000000081526004810185905260240161107a565b5f611c4d6040870187614db6565b604051611c5b929190614d75565b604051809103902090505f611c7d8760200135835f9182526020526040902090565b90505f611cc98760208a01358a3585611ca2611c9c60408f018f614db6565b89613737565b604080519586526020860194909452928401919091526060830152608082015260a0902090565b9050808614611d0e576040517fd3664fb3000000000000000000000000000000000000000000000000000000008152600481018790526024810182905260440161107a565b5f8181526101be602052604090819020600190555181907f55f4c645c36aa5cd3f443d6be44d7a7a5df9d2100d7139dfc69d4289ee07231990611d5e908a908c3590918252602082015260400190565b60405180910390a25050505050505050565b6004611d7b81612de9565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929611da581612be2565b5f859003611ddf576040517fb1504a5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b844915611e1b576040517f8019aff70000000000000000000000000000000000000000000000000000000081526004810186905260240161107a565b5f8481526101be60205260408120549003611e65576040517f6e5424c20000000000000000000000000000000000000000000000000000000081526004810185905260240161107a565b5f8381526101be602052604090205415611eae576040517f0f06cd150000000000000000000000000000000000000000000000000000000081526004810184905260240161107a565b6040805160a0810182525f808252606060208301819052928201839052918101829052608081018290528190865f5b89811015611fb3578a8a82818110611ef757611ef7614e9e565b9050602002810190611f099190614ecb565b611f1290614fe8565b81499450925083611f52576040517fc0e41e1d0000000000000000000000000000000000000000000000000000000081526004810182905260240161107a565b60808301515f8181526020869052604090209550611f8085875f1c865f015187602001518860400151613838565b6060848101518551604080519687526020870194909452928501528301869052608083015260a090912090600101611edd565b50808714611ff7576040517fd3664fb3000000000000000000000000000000000000000000000000000000008152600481018890526024810182905260440161107a565b5f8181526101be602090815260409182902060019055606084015182518b81529182015282917f55f4c645c36aa5cd3f443d6be44d7a7a5df9d2100d7139dfc69d4289ee072319910160405180910390a250505050505050505050565b600881901c5f90815261014f6020526040812054600160ff84161b161515610ff6565b600261208281612de9565b6001600160a01b0385166120c2576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b348411156120fc576040517fb03b693200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60e480545f918261210c83615075565b9091555090505f61211d8634614d4f565b90505f61212f33898985878b8b612e82565b905061213b83826139da565b80886001600160a01b0316336001600160a01b03167fe856c2b8bd4eb0027ce32eeaf595c21b0b6b4644b326e5b7bd80a1cf8db72e6c8a86888c8c6040516121879594939291906150d5565b60405180910390a45050505050505050565b5f54610100900460ff16158080156121b757505f54600160ff909116105b806121d05750303b1580156121d057505f5460ff166001145b61225c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161107a565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156122b8575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b5f6122c96080840160608501614d9b565b6001600160a01b031603612309576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61232c61231960e0840184615105565b612327610100860186615105565b613a56565b61233e82608001358360a00135613d04565b6123595f61235461016085016101408601614d9b565b612bec565b61236e61236960c0840184615105565b613dc5565b61237e6080830160608401614d9b565b5f805261011b6020527f033d11f27e62ab919708ec716731da80d261a6e4253259b7acde9bf89d28ec1880547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03929092169190911790556123f061014083016101208401614d9b565b6101c080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039290921691909117905561243b61014083016101208401614d9b565b6001600160a01b0316336001600160a01b03167f1f82add12d98b5eaed4d6a6d5f74cfc7a85e5c90c335ab5562f77f220ed45d5f60405160405180910390a36020828101356101198190555f90815261011a825260408082208535905580518084018390528082018390527f072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd60608083018290526080830185905260a08084018690528451808503909101815260c08401855280519087012085526101be86528385206001905560e0830185905261010083018590526101208301919091526101408201849052610160808301859052835180840390910181526101808301808552815191909601206101bd558385526101a0820193909352908501356101c09091015290206101bf558015611227575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15050565b7f0cf0d2deb70d7bdac2fa48c4ac99bc558170be0ce5fcb994caefa4bf7b96edf96125f581612be2565b5f609a81905560405133917fba88c025b0cbb77022c0c487beef24f759f1e4be2f51a205bc427cee19c2eaa691a250565b5f81600881111561263957612639614cb6565b60da54600190911b16151592915050565b61265762f099c082614d62565b421015612690576040517f4306cbb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805184815260208101849052908101829052606090206101bf5414612708576101bf546040805185815260208101859052908101839052606090206040517fbc5aad110000000000000000000000000000000000000000000000000000000081526004810192909252602482015260440161107a565b6101c0546001600160a01b031661273f7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92982612bec565b6040516001600160a01b0382169033907f9fc8868f8577b31b805ee65bb52325782b5e2708dbdb7f04c7467c6785fccb30905f90a350505050565b5f54600690610100900460ff1615801561279a57505f5460ff8083169116105b612826576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161107a565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001790556128608888613dc5565b61286c86868686613a56565b6001600160a01b0382166128ac576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101c080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03841690811790915560405133907f1f82add12d98b5eaed4d6a6d5f74cfc7a85e5c90c335ab5562f77f220ed45d5f905f90a36040517f362e300000000000000000000000000000000000000000000000000000000000907f352e300000000000000000000000000000000000000000000000000000000000907f2f8492a7a430cf917798dfb60bc5af634f68e6c40287947df0ea6f7ec0669bd8905f90a35f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050505050565b7f32937fd5162e282df7e9a14a5073a2425321c7966eaf70ed6c838a1006d84c4c612a0a81612be2565b6001600160a01b038316612a4a576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815261011b60209081526040918290205491516001600160a01b03928316815233928592908716917f4a29db3fc6b42bda201e4b4d69ce8d575eeeba5f153509c0d0a342af0f1bd021910160405180910390a4505f90815261011b6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b5f82815260656020526040902060010154612b0081612be2565b6111cf8383613f73565b60db5f826008811115612b1f57612b1f614cb6565b6008811115612b3057612b30614cb6565b81526020019081526020015f2054612b4781612be2565b612b5082612626565b15612b8957816040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040161107a9190614ce3565b816008811115612b9b57612b9b614cb6565b60da8054600190921b9091179055816008811115612bbb57612bbb614cb6565b7f534f879afd40abb4e39f8e1b77a316be4c8e3521d9cf5a3a3db8959d574d4559336110d9565b611af58133614012565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff16611227575f8281526065602090815260408083206001600160a01b0385168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055612c663390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b0381163314612d42576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c660000000000000000000000000000000000606482015260840161107a565b6112278282613f73565b5f612d7b611b2760017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614d4f565b14612db2576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612de7612de060017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614d4f565b6001612e7b565b565b60da54816008811115612dfe57612dfe614cb6565b6001901b811615612e3d57816040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040161107a9190614ce3565b60028116156112275760016040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040161107a9190614ce3565b80825d5050565b5f60405188815287602082015286604082015285606082015284608082015260c060a08201528260c0820152602083065f8115612ec0578160200390505b848660e085013790930160e001902098975050505050505050565b5f81815260a66020526040902054600114612f25576040517f992d87c30000000000000000000000000000000000000000000000000000000081526004810182905260240161107a565b5f90815260a66020526040812055565b8015611af557426099541015612f5a57609754612f529042614d62565b609955612f6a565b609a54612f679082614d62565b90505b609854811115612fa6576040517fa74c1c5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609a55565b612de761138e60017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614d4f565b5f81836020013511613024576040517f70614405000000000000000000000000000000000000000000000000000000008152602084013560048201526024810183905260440161107a565b6130388361018001358461014001356140a0565b6101bf54604080516101608601358152610120860135602082015260e08601359181019190915260609020146130ce57604080516101608501358152610120850135602082015260e085013591810191909152606090206101bf546040517fbc5aad110000000000000000000000000000000000000000000000000000000081526004810192909252602482015260440161107a565b4283610100013510613119576040517fbf81c6e0000000000000000000000000000000000000000000000000000000008152610100840135600482015242602482015260440161107a565b6080830135613154576040517f2898482a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61319760408401356060850135608086013560a087013560c0880135604080519586526020860194909452928401919091526060830152608082015260a0902090565b5f8181526101be6020526040812054919250036131e3576040517fedeae83c0000000000000000000000000000000000000000000000000000000081526004810182905260240161107a565b6131ff6131f46101c0850185614e17565b856101a0013561416d565b6132166132106101e0850185614db6565b84614279565b6020808401355f81815261011a909252604090912060808501359055610119556101bd81905561326b610180840135610140850135610100860135604080519384526020840192909252908201526060902090565b6101bf5580602084013561327e84615075565b60408051873581526080880135602082015291955085917fa0262dc79e4ccb71ceac8574ae906311ae338aa4a2044fd4ec4b99fad5ab60cb910160405180910390a492915050565b5f604051858152846020820152604060e0880160408301378360808201528260a082015260a0610120880160c083013761018081016101c088013588018035602081026020830184376020029091206101608301525061018090207f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000190069695505050505050565b6040805160018082528183019092525f916020808301908036833701905050905084815f8151811061338257613382614e9e565b6020908102919091018101919091525f85815261011b90915260409020546001600160a01b0316806133e0576040517f69ed70ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80826001600160a01b0316637e4f7a8a60e01b87878760405160240161340993929190615169565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161347491906151da565b5f604051808303815f865af19150503d805f81146134ad576040519150601f19603f3d011682016040523d82523d5f602084013e6134b2565b606091505b509150915081613559578051156134f757602081017bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81511663ca389c4460e01b178152815181fd5b6040517fca389c4400000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f556e6b6e6f776e00000000000000000000000000000000000000000000000000604482015260640161107a565b5f8180602001905181019061356e91906151e5565b9050806135a7576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050565b600881901c5f90815261014f6020526040902054600160ff83161b1615613608576040517f335a4a900000000000000000000000000000000000000000000000000000000081526004810182905260240161107a565b600881901c5f90815261014f602052604090208054600160ff84161b17905550565b5f8061364b600161363c876002615325565b6136469190614d4f565b614306565b90508063ffffffff168463ffffffff1611156136a3576040517ff7ec909700000000000000000000000000000000000000000000000000000000815263ffffffff80861660048301528216602482015260440161107a565b865f5b8681101561372957600163ffffffff8716821c811690036136f3576136ec8888838181106136d6576136d6614e9e565b90506020020135835f9182526020526040902090565b9150613721565b61371e8289898481811061370957613709614e9e565b905060200201355f9182526020526040902090565b91505b6001016136a6565b509092149695505050505050565b5f613743602084615330565b1561377a576040517f6426c6c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f729eebce00000000000000000000000000000000000000000000000000000000835b801561382f57602081039050808601357fff000000000000000000000000000000000000000000000000000000000000008116156137e057604051838152600481fd5b7f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001817f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff000000018787090893505061379d565b50509392505050565b7f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001840693505f80600a6001600160a01b03168787878787604051602001613883959493929190615368565b60408051601f198184030181529082905261389d916151da565b5f60405180830381855afa9150503d805f81146138d5576040519150601f19603f3d011682016040523d82523d5f602084013e6138da565b606091505b509150915081613916576040517fa71194af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604081511461395e578051604080517ff75db38100000000000000000000000000000000000000000000000000000000815261107a9290600401918252602082015260400190565b602081015160408201516110008214158061399957507f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff000000018114155b156135a7576040517f68dcad5f000000000000000000000000000000000000000000000000000000008152600481018390526024810182905260440161107a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82015f90815261014e60208181526040808420548452848252808420868552929091528083208290555190918391839186917fea3b023b4c8680d4b4824f0143132c95476359a2bb70a81d6c5a36f6918f63399190a4505050565b5f54610100900460ff16613aec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161107a565b5f5b83811015613bf457848482818110613b0857613b08614e9e565b9050604002016020013560db5f878785818110613b2757613b27614e9e565b613b3d92602060409092020190810191506147e4565b6008811115613b4e57613b4e614cb6565b6008811115613b5f57613b5f614cb6565b815260208101919091526040015f2055848482818110613b8157613b81614e9e565b90506040020160200135858583818110613b9d57613b9d614e9e565b613bb392602060409092020190810191506147e4565b6008811115613bc457613bc4614cb6565b6040517f33aa8fd1ce49e1761bc8d27fd53414bfefc45d690feed0ce55019d7d3aec6091905f90a3600101613aee565b505f5b81811015613cfd57828282818110613c1157613c11614e9e565b9050604002016020013560dc5f858585818110613c3057613c30614e9e565b613c4692602060409092020190810191506147e4565b6008811115613c5757613c57614cb6565b6008811115613c6857613c68614cb6565b815260208101919091526040015f2055828282818110613c8a57613c8a614e9e565b90506040020160200135838383818110613ca657613ca6614e9e565b613cbc92602060409092020190810191506147e4565b6008811115613ccd57613ccd614cb6565b6040517fe7bf4b8dc0c17a52dc9e52323a3ab61cb2079db35f969125b1f8a3d984c6f6c2905f90a3600101613bf7565b5050505050565b5f54610100900460ff16613d9a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161107a565b613da2614353565b613daa614353565b613db2614353565b613dbc82826143e9565b5050600160e455565b5f54610100900460ff16613e5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161107a565b5f5b818110156111cf575f838383818110613e7857613e78614e9e565b613e8e9260206040909202019081019150614d9b565b6001600160a01b031603613ece576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b828282818110613ee057613ee0614e9e565b905060400201602001355f801b03613f24576040517f0742d05300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613f6b838383818110613f3957613f39614e9e565b90506040020160200135848484818110613f5557613f55614e9e565b6123549260206040909202019081019150614d9b565b600101613e5d565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff1615611227575f8281526065602090815260408083206001600160a01b038516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff16611227576140448161454f565b61404f836020614561565b60405160200161406092919061538e565b60408051601f19818403018152908290527f08c379a000000000000000000000000000000000000000000000000000000000825261107a9160040161485b565b815f036140e2578015611227576040517f0c2565920000000000000000000000000000000000000000000000000000000081526004810182905260240161107a565b8061411c576040517f5228f4c80000000000000000000000000000000000000000000000000000000081526004810183905260240161107a565b5f82815261014e60205260409020548114611227576040517f36459fa0000000000000000000000000000000000000000000000000000000008152600481018390526024810182905260440161107a565b5f5b82811015614273576101505f85858481811061418d5761418d614e9e565b9050602002013581526020019081526020015f20545f146141f6578383828181106141ba576141ba614e9e565b905060200201356040517fe5d1442500000000000000000000000000000000000000000000000000000000815260040161107a91815260200190565b816101505f86868581811061420d5761420d614e9e565b9050602002013581526020019081526020015f20819055508184848381811061423857614238614e9e565b905060200201357f300e6f978eee6a4b0bba78dd8400dc64fd5652dbfc868a2258e16d0977be222b60405160405180910390a360010161416f565b50505050565b614284600283615330565b156142be576040517f0c91d7760000000000000000000000000000000000000000000000000000000081526004810183905260240161107a565b5f805b83811015613cfd576040518582013560f01c9250838301907f3c116827db9db3a30c1a25db8b0ee4bab9d2b223560209cfd839601b621c726d905f90a26002016142c1565b5f63ffffffff82111561434f576040517f6dfcc650000000000000000000000000000000000000000000000000000000008152602060048201526024810183905260440161107a565b5090565b5f54610100900460ff16612de7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161107a565b5f54610100900460ff1661447f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161107a565b815f036144b8576040517fb5ed5a3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805f036144f1576040517fd10d72bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609782905560988190556145058242614d62565b60998190556097546098546040805192835260208301919091528101919091527f8f805c372b66240792580418b7328c0c554ae235f0932475c51b026887fe26a9906060016125bf565b6060610ff66001600160a01b03831660145b60605f61456f836002614d84565b61457a906002614d62565b67ffffffffffffffff81111561459257614592614f07565b6040519080825280601f01601f1916602001820160405280156145bc576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000815f815181106145f2576145f2614e9e565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061465457614654614e9e565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f61468e846002614d84565b614699906001614d62565b90505b6001811115614735577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106146da576146da614e9e565b1a60f81b8282815181106146f0576146f0614e9e565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060049490941c9361472e816153f8565b905061469c565b50831561479e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640161107a565b9392505050565b5f602082840312156147b5575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461479e575f80fd5b5f602082840312156147f4575f80fd5b81356009811061479e575f80fd5b5f60208284031215614812575f80fd5b5035919050565b6001600160a01b0381168114611af5575f80fd5b5f806040838503121561483e575f80fd5b82359150602083013561485081614819565b809150509250929050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f8083601f8401126148a0575f80fd5b50813567ffffffffffffffff8111156148b7575f80fd5b6020830191508360208285010111156148ce575f80fd5b9250929050565b5f805f805f805f8060e0898b0312156148ec575f80fd5b88356148f781614819565b9750602089013561490781614819565b96506040890135955060608901359450608089013561492581614819565b935060a089013567ffffffffffffffff811115614940575f80fd5b61494c8b828c01614890565b999c989b50969995989497949560c00135949350505050565b5f805f8060608587031215614978575f80fd5b843567ffffffffffffffff81111561498e575f80fd5b61499a87828801614890565b90955093505060208501359150604085013567ffffffffffffffff8111156149c0575f80fd5b850161020081880312156149d2575f80fd5b939692955090935050565b5f602082840312156149ed575f80fd5b813567ffffffffffffffff811115614a03575f80fd5b8201610140818503121561479e575f80fd5b5f805f60608486031215614a27575f80fd5b833567ffffffffffffffff811115614a3d575f80fd5b840160608187031215614a4e575f80fd5b95602085013595506040909401359392505050565b5f805f8060608587031215614a76575f80fd5b843567ffffffffffffffff811115614a8c575f80fd5b8501601f81018713614a9c575f80fd5b803567ffffffffffffffff811115614ab2575f80fd5b8760208260051b8401011115614ac6575f80fd5b602091820198909750908601359560400135945092505050565b5f805f8060608587031215614af3575f80fd5b8435614afe81614819565b935060208501359250604085013567ffffffffffffffff811115614b20575f80fd5b614b2c87828801614890565b95989497509550505050565b5f60208284031215614b48575f80fd5b813567ffffffffffffffff811115614b5e575f80fd5b8201610160818503121561479e575f80fd5b5f805f60608486031215614b82575f80fd5b505081359360208301359350604090920135919050565b5f8083601f840112614ba9575f80fd5b50813567ffffffffffffffff811115614bc0575f80fd5b6020830191508360208260061b85010111156148ce575f80fd5b5f805f805f805f6080888a031215614bf0575f80fd5b873567ffffffffffffffff811115614c06575f80fd5b614c128a828b01614b99565b909850965050602088013567ffffffffffffffff811115614c31575f80fd5b614c3d8a828b01614b99565b909650945050604088013567ffffffffffffffff811115614c5c575f80fd5b614c688a828b01614b99565b9094509250506060880135614c7c81614819565b8091505092959891949750929550565b5f8060408385031215614c9d575f80fd5b8235614ca881614819565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6020810160098310614d1c577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b91905290565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115610ff657610ff6614d22565b80820180821115610ff657610ff6614d22565b818382375f9101908152919050565b8082028115828204841417610ff657610ff6614d22565b5f60208284031215614dab575f80fd5b813561479e81614819565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614de9575f80fd5b83018035915067ffffffffffffffff821115614e03575f80fd5b6020019150368190038213156148ce575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614e4a575f80fd5b83018035915067ffffffffffffffff821115614e64575f80fd5b6020019150600581901b36038213156148ce575f80fd5b5f60208284031215614e8b575f80fd5b813563ffffffff8116811461479e575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61833603018112614efd575f80fd5b9190910192915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405160a0810167ffffffffffffffff81118282101715614f5757614f57614f07565b60405290565b5f82601f830112614f6c575f80fd5b813567ffffffffffffffff811115614f8657614f86614f07565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715614fb557614fb5614f07565b604052818152838201602001851015614fcc575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60a08236031215614ff8575f80fd5b615000614f34565b82358152602083013567ffffffffffffffff81111561501d575f80fd5b61502936828601614f5d565b602083015250604083013567ffffffffffffffff811115615048575f80fd5b61505436828601614f5d565b60408301525060608381013590820152608092830135928101929092525090565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036150a5576150a5614d22565b5060010190565b81835281816020850137505f602082840101525f6020601f19601f840116840101905092915050565b858152846020820152836040820152608060608201525f6150fa6080830184866150ac565b979650505050505050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615138575f80fd5b83018035915067ffffffffffffffff821115615152575f80fd5b6020019150600681901b36038213156148ce575f80fd5b604081525f61517c6040830185876150ac565b82810360208401528084518083526020830191506020860192505f5b818110156151b6578351835260209384019390920191600101615198565b5090979650505050505050565b5f81518060208401855e5f93019283525090919050565b5f61479e82846151c3565b5f602082840312156151f5575f80fd5b8151801515811461479e575f80fd5b6001815b600184111561523f5780850481111561522357615223614d22565b600184161561523157908102905b60019390931c928002615208565b935093915050565b5f8261525557506001610ff6565b8161526157505f610ff6565b816001811461527757600281146152815761529d565b6001915050610ff6565b60ff84111561529257615292614d22565b50506001821b610ff6565b5060208310610133831016604e8410600b84101617156152c0575081810a610ff6565b6152eb7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484615204565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561531d5761531d614d22565b029392505050565b5f61479e8383615247565b5f82615363577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500690565b8581528460208201528360408201525f6150fa61538860608401866151c3565b846151c3565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f6153bf60178301856151c3565b7f206973206d697373696e6720726f6c652000000000000000000000000000000081526153ef60118201856151c3565b95945050505050565b5f8161540657615406614d22565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea264697066735822122017fa9362d0392993ac5f756a12c21940cf721259b8b8bc02053fb03e1c986a6364736f6c634300081a0033", + "bytecode": "0x6080604052348015600e575f80fd5b5060156019565b60d3565b5f54610100900460ff161560835760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff9081161460d1575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61535e806100e05f395ff3fe608060405260043610610483575f3560e01c806373bd07b711610251578063b837dbe91161013c578063cc5782f6116100b7578063d547741f11610087578063d722bbfc1161006d578063d722bbfc14610e53578063e196fb5d14610e86578063f5b541a614610ea5575f80fd5b8063d547741f14610e1e578063d5d4b83514610e3d575f80fd5b8063cc5782f614610d87578063cc6f725114610db5578063cd9b9e9a14610de8578063cf5b276414610dfe575f80fd5b8063bf3e75051161010c578063c0c4e584116100f2578063c0c4e58414610d34578063c1dc0f0714610d53578063c211697414610d68575f80fd5b8063bf3e750514610cec578063c0729ab114610d1f575f80fd5b8063b837dbe914610c66578063b9174ba314610c7b578063bc61e73314610cae578063bcc3003d14610ccd575f80fd5b80639ac25d08116101cc578063a98e773d1161019c578063ad422ff011610182578063ad422ff014610c0a578063aea4f74514610c1f578063b59faa6014610c33575f80fd5b8063a98e773d14610bb6578063ac1eff6814610bd5575f80fd5b80639ac25d0814610b3e5780639ee8b21114610b715780639f3ce55a14610b90578063a217fddf14610ba3575f80fd5b8063914e57eb11610221578063921b278e11610207578063921b278e14610b09578063986fcddd14610a2757806399467a3514610b1f575f80fd5b8063914e57eb14610a9957806391d1485414610ac5575f80fd5b806373bd07b714610a135780637d1e8c5514610a275780638be745d114610a3a5780638de4948714610a66575f80fd5b80634cdd389b1161037157806360e83cf3116102ec57806367e404ce116102bc578063695378f5116102a2578063695378f5146109975780636a906b80146109ad5780636e673843146109e0575f80fd5b806367e404ce1461094c5780636854f6bc14610978575f80fd5b806360e83cf3146108a257806363213155146108ce5780636463fb2a1461090157806366f96e9814610920575f80fd5b806358794456116103415780635c721a0c116103275780635c721a0c1461081f5780635ed73ceb1461084a5780636078bfd814610876575f80fd5b8063587944561461080a5780635b7eb4bd14610728575f80fd5b80634cdd389b1461076d5780635230eef214610799578063557eac73146107cc5780635603c65f146107eb575f80fd5b8063289581741161040157806338b90333116103d15780633fc08b65116103b75780633fc08b65146106fd57806348922ab714610728578063491e09361461074e575f80fd5b806338b90333146106755780633b12eccb146106ca575f80fd5b806328958174146106025780632c70645c146106215780632f2ff15d1461063757806336568abe14610656575f80fd5b806312d3fa9a116104565780631f443da01161043c5780631f443da01461057c5780632130d812146105a8578063248a9ca3146105d4575f80fd5b806312d3fa9a146105335780631e2ff94f14610566575f80fd5b806301ffc9a71461048757806303134d1d146104bb57806305861180146104fc5780631065a39914610512575b5f80fd5b348015610492575f80fd5b506104a66104a13660046146a1565b610ed8565b60405190151581526020015b60405180910390f35b3480156104c6575f80fd5b506104ee7f1ab87f7458c0e3d07e9881c14ee67f0141703614fd48ea5b15ed987e5f4b030e81565b6040519081526020016104b2565b348015610507575f80fd5b506104ee6101bb5481565b34801561051d575f80fd5b5061053161052c3660046146e0565b610f70565b005b34801561053e575f80fd5b506104ee7f67c2dca7476ee0fe1dd3cba13428c6760bfe2599a6dfe26a9ad7ef27317c6e7781565b348015610571575f80fd5b506104ee6101185481565b348015610587575f80fd5b506104ee6105963660046146fe565b6101b96020525f908152604090205481565b3480156105b3575f80fd5b506104ee6105c23660046146fe565b6101be6020525f908152604090205481565b3480156105df575f80fd5b506104ee6105ee3660046146fe565b5f9081526065602052604090206001015490565b34801561060d575f80fd5b5061053161061c3660046146fe565b61106c565b34801561062c575f80fd5b506104ee6101835481565b348015610642575f80fd5b50610531610651366004614729565b61111f565b348015610661575f80fd5b50610531610670366004614729565b611148565b348015610680575f80fd5b506106bd6040518060400160405280600381526020017f362e30000000000000000000000000000000000000000000000000000000000081525081565b6040516104b29190614757565b3480156106d5575f80fd5b506104ee7fb6cc65f42901ed602aec1619cc1ead29d487cd489094a37615153eaeb991d77081565b348015610708575f80fd5b506104ee6107173660046146fe565b60a56020525f908152604090205481565b348015610733575f80fd5b5061073c600181565b60405160ff90911681526020016104b2565b348015610759575f80fd5b506105316107683660046147d1565b61119f565b348015610778575f80fd5b506104ee6107873660046146fe565b6101b76020525f908152604090205481565b3480156107a4575f80fd5b506104ee7f0cf0d2deb70d7bdac2fa48c4ac99bc558170be0ce5fcb994caefa4bf7b96edf981565b3480156107d7575f80fd5b506105316107e63660046146fe565b611455565b3480156107f6575f80fd5b50610531610805366004614861565b61151b565b348015610815575f80fd5b506104ee60995481565b34801561082a575f80fd5b506104ee6108393660046146fe565b60a66020525f908152604090205481565b348015610855575f80fd5b506104ee6108643660046146fe565b6101ba6020525f908152604090205481565b348015610881575f80fd5b506104ee6108903660046146fe565b6101b66020525f908152604090205481565b3480156108ad575f80fd5b506104ee6108bc3660046146fe565b6101506020525f908152604090205481565b3480156108d9575f80fd5b506104ee7fe37c272ea30e2bb381ad7cf89ae754b49153250609f36d0cbdad8b64c184bb5c81565b34801561090c575f80fd5b5061053161091b3660046148d9565b611613565b34801561092b575f80fd5b506104ee61093a3660046146fe565b6101b86020525f908152604090205481565b348015610957575f80fd5b50610960611a6c565b6040516001600160a01b0390911681526020016104b2565b348015610983575f80fd5b50610531610992366004614911565b611aa4565b3480156109a2575f80fd5b506104ee6101195481565b3480156109b8575f80fd5b506104ee7fd8b4c34c2ec1f3194471108c64ad2beda340c0337ee4ca35592f9ef270f4228b81565b3480156109eb575f80fd5b506104ee7f32937fd5162e282df7e9a14a5073a2425321c7966eaf70ed6c838a1006d84c4c81565b348015610a1e575f80fd5b5061073c600281565b348015610a32575f80fd5b5061073c5f81565b348015610a45575f80fd5b506104ee610a543660046146fe565b61011a6020525f908152604090205481565b348015610a71575f80fd5b506104ee7fe1fce82838dd7a42cfe783f60dc6233c8aa2c4fc66e77817805e767ec5e349b681565b348015610aa4575f80fd5b506104ee610ab33660046146fe565b61014e6020525f908152604090205481565b348015610ad0575f80fd5b506104a6610adf366004614729565b5f9182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b348015610b14575f80fd5b506104ee6101bf5481565b348015610b2a575f80fd5b50610531610b3936600461495f565b611ce4565b348015610b49575f80fd5b506104ee7f56bdc3c9ec86cb7db110a7699b2ade72f0b8819727d9f7d906b012641505fa7781565b348015610b7c575f80fd5b506104a6610b8b3660046146fe565b611fc8565b610531610b9e3660046149dc565b611feb565b348015610bae575f80fd5b506104ee5f81565b348015610bc1575f80fd5b50610531610bd0366004614a34565b61210d565b348015610be0575f80fd5b50610960610bef3660046146fe565b61011b6020525f90815260409020546001600160a01b031681565b348015610c15575f80fd5b506104ee60985481565b348015610c2a575f80fd5b506105316124c7565b348015610c3e575f80fd5b506104ee7fe4831f9e4316ac2c65117d1f602fbf56d38128a9973d5e3fdbc5b77265c18d4081565b348015610c71575f80fd5b506104ee60e45481565b348015610c86575f80fd5b506104ee7f430a7f0cb00b5ebbe63cecc96e82cf959a883e7c13a95110854f1fa6b3fbf59881565b348015610cb9575f80fd5b506104a6610cc83660046146e0565b612522565b348015610cd8575f80fd5b50610531610ce7366004614a6c565b612546565b348015610cf7575f80fd5b506104ee7f1185e52d62bfbbea270e57d3d09733d221b53ab7a18bae82bb3c6c74bab16d8281565b348015610d2a575f80fd5b506104ee609a5481565b348015610d3f575f80fd5b50610531610d4e366004614ad6565b612676565b348015610d5e575f80fd5b506104ee60975481565b348015610d73575f80fd5b50610531610d82366004614b88565b6128dc565b348015610d92575f80fd5b506104a6610da13660046146fe565b60d96020525f908152604090205460ff1681565b348015610dc0575f80fd5b506104ee7fe8cb6172fcf5cbaae022b7c910224a4f0c20d53227e630056efff182155a5abc81565b348015610df3575f80fd5b506104ee6101bd5481565b348015610e09575f80fd5b506101c054610960906001600160a01b031681565b348015610e29575f80fd5b50610531610e38366004614729565b6129e2565b348015610e48575f80fd5b506104ee6101bc5481565b348015610e5e575f80fd5b506104ee7f6b5661ddfbd1fbd525c902a513e0f47d9c74f1c1ee8a2d4f1937ad305fb8f41a81565b348015610e91575f80fd5b50610531610ea03660046146e0565b612a06565b348015610eb0575f80fd5b506104ee7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92981565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610f6a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60dc5f826008811115610f8557610f85614bb2565b6008811115610f9657610f96614bb2565b81526020019081526020015f2054610fad81612ade565b610fb682612522565b610ff757816040517f18659654000000000000000000000000000000000000000000000000000000008152600401610fee9190614bdf565b60405180910390fd5b81600881111561100957611009614bb2565b60da8054600190921b19909116905581600881111561102a5761102a614bb2565b7fd071d2b85dec4489435b541d2f0e2570db09b09db9efd8703948d44a433df65a335b6040516001600160a01b03909116815260200160405180910390a25050565b7f6b5661ddfbd1fbd525c902a513e0f47d9c74f1c1ee8a2d4f1937ad305fb8f41a61109681612ade565b5f82815261011b602090815260408083205490516001600160a01b0390911681523392859290917f4a29db3fc6b42bda201e4b4d69ce8d575eeeba5f153509c0d0a342af0f1bd021910160405180910390a4505f90815261011b6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b5f8281526065602052604090206001015461113981612ade565b6111438383612ae8565b505050565b6101c0546001600160a01b0390811690821603611191576040517f7f7497e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61119b8282612ba6565b5050565b6111a7612c48565b85878484875f5a90506111ba6003612ce5565b6111ee6111e860017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b8f612d77565b5f6111fe8f8f8f8f8c8f8f612d7e565b905061120981612dd7565b61121b6112168d8f614c5e565b612e31565b5f808f6001600160a01b03168e8d8d604051611238929190614c71565b5f6040518083038185875af1925050503d805f8114611272576040519150601f19603f3d011682016040523d82523d5f602084013e611277565b606091505b5091509150816112d4578051156112915780518082602001fd5b8f6040517f54613443000000000000000000000000000000000000000000000000000000008152600401610fee91906001600160a01b0391909116815260200190565b61130861130260017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b5f612d77565b60405183907fa4c827e719e911e8f19393ccdb85b5102f08f0910604d340ba38390b7ff2ab0e905f90a250508615905061143d57855f8490036113b357853b1580156113b1573a5a61135c61bc7c86614c5e565b6113669190614c4b565b6113709190614c80565b9150818811156113ad576001600160a01b0387166108fc611391848b614c4b565b6040518115909202915f818181858888f19350505050506113b1565b8791505b505b5f6001600160a01b038416156113c957836113cb565b335b90505f816001600160a01b03166108fc8490811502906040515f60405180830381858888f19350505050905080611439576040517fa57c4df40000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610fee565b5050505b50505050505061144b612ea7565b5050505050505050565b7f1185e52d62bfbbea270e57d3d09733d221b53ab7a18bae82bb3c6c74bab16d8261147f81612ade565b5f805f4260995410156114a4576097546114999042614c5e565b6099555060016114b6565b609a548510156114b657849250600191505b609885905580806114c45750815b156114cf57609a8390555b60408051868152831515602082015282151581830152905133917fbc3dc0cb5c15c51c81316450d44048838bb478b9809447d01c766a06f3e9f2c8919081900360600190a25050505050565b600661152681612ce5565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92961155081612ade565b5f85900361158a576040517f7907d79b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610119545f81815261011a60205260409020548435146115d6576040517fead4c30e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101bd545f6115e58684612ed5565b90505f6115f9878484878b602001356131c2565b905061160781898c8c61324a565b50505050505050505050565b61161b612c48565b60a0810180359061162f9060808401614c97565b61163d610120840184614cb2565b61164e610100860160e08701614c97565b5f5a905061165c6003612ce5565b6101008701355f9081526101506020526040812054908190036116ab576040517f4e68667500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116b58880614d13565b9050811461170457806116c88980614d13565b6040517f5e3fd6ad0000000000000000000000000000000000000000000000000000000081526004810193909352602483015250604401610fee565b61171188602001356134ae565b61172661121660c08a013560a08b0135614c5e565b5f61176f61173a60808b0160608c01614c97565b61174a60a08c0160808d01614c97565b8b60a001358c60c001358d602001358e80610120019061176a9190614cb2565b612d7e565b905061179a8161177f8b80614d13565b61178f60608e0160408f01614d77565b8d6101000135613526565b6117d0576040517fb05e92fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6118136117fe60017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b61180e60808c0160608d01614c97565b612d77565b5f8061182560a08c0160808d01614c97565b6001600160a01b031660c08c01356118416101208e018e614cb2565b60405161184f929190614c71565b5f6040518083038185875af1925050503d805f8114611889576040519150601f19603f3d011682016040523d82523d5f602084013e61188e565b606091505b5091509150816118f6578051156118a85780518082602001fd5b6118b860a08c0160808d01614c97565b6040517f546134430000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610fee565b61192461130260017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b60405183907fa4c827e719e911e8f19393ccdb85b5102f08f0910604d340ba38390b7ff2ab0e905f90a2505050505f861115611a5b57855f8490036119d157853b1580156119cf573a5a61197a61bc7c86614c5e565b6119849190614c4b565b61198e9190614c80565b9150818811156119cb576001600160a01b0387166108fc6119af848b614c4b565b6040518115909202915f818181858888f19350505050506119cf565b8791505b505b5f6001600160a01b038416156119e757836119e9565b335b90505f816001600160a01b03166108fc8490811502906040515f60405180830381858888f19350505050905080611a57576040517fa57c4df40000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610fee565b5050505b505050505050611a69612ea7565b50565b5f611a9f611a9b60017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b5c90565b905090565b6005611aaf81612ce5565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929611ad981612ade565b611ae66040860186614cb2565b90505f03611b20576040517fc01eab5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8381526101be602052604090205415611b69576040517f0f06cd1500000000000000000000000000000000000000000000000000000000815260048101849052602401610fee565b5f8481526101be60205260408120549003611bb3576040517f6e5424c200000000000000000000000000000000000000000000000000000000815260048101859052602401610fee565b5f611bc16040870187614cb2565b604051611bcf929190614c71565b604051809103902090505f611bf18760200135835f9182526020526040902090565b90505f611c3d8760208a01358a3585611c16611c1060408f018f614cb2565b89613633565b604080519586526020860194909452928401919091526060830152608082015260a0902090565b9050808614611c82576040517fd3664fb30000000000000000000000000000000000000000000000000000000081526004810187905260248101829052604401610fee565b5f8181526101be602052604090819020600190555181907f55f4c645c36aa5cd3f443d6be44d7a7a5df9d2100d7139dfc69d4289ee07231990611cd2908a908c3590918252602082015260400190565b60405180910390a25050505050505050565b6004611cef81612ce5565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929611d1981612ade565b5f859003611d53576040517fb1504a5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b844915611d8f576040517f8019aff700000000000000000000000000000000000000000000000000000000815260048101869052602401610fee565b5f8481526101be60205260408120549003611dd9576040517f6e5424c200000000000000000000000000000000000000000000000000000000815260048101859052602401610fee565b5f8381526101be602052604090205415611e22576040517f0f06cd1500000000000000000000000000000000000000000000000000000000815260048101849052602401610fee565b6040805160a0810182525f808252606060208301819052928201839052918101829052608081018290528190865f5b89811015611f27578a8a82818110611e6b57611e6b614d9a565b9050602002810190611e7d9190614dc7565b611e8690614ee4565b81499450925083611ec6576040517fc0e41e1d00000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b60808301515f8181526020869052604090209550611ef485875f1c865f015187602001518860400151613734565b6060848101518551604080519687526020870194909452928501528301869052608083015260a090912090600101611e51565b50808714611f6b576040517fd3664fb30000000000000000000000000000000000000000000000000000000081526004810188905260248101829052604401610fee565b5f8181526101be602090815260409182902060019055606084015182518b81529182015282917f55f4c645c36aa5cd3f443d6be44d7a7a5df9d2100d7139dfc69d4289ee072319910160405180910390a250505050505050505050565b600881901c5f90815261014f6020526040812054600160ff84161b161515610f6a565b6002611ff681612ce5565b6001600160a01b038516612036576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b34841115612070576040517fb03b693200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60e480545f918261208083614f71565b9091555090505f6120918634614c4b565b90505f6120a333898985878b8b612d7e565b90506120af83826138d6565b80886001600160a01b0316336001600160a01b03167fe856c2b8bd4eb0027ce32eeaf595c21b0b6b4644b326e5b7bd80a1cf8db72e6c8a86888c8c6040516120fb959493929190614fd1565b60405180910390a45050505050505050565b5f54610100900460ff161580801561212b57505f54600160ff909116105b806121445750303b15801561214457505f5460ff166001145b6121d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610fee565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561222c575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b5f61223d6080840160608501614c97565b6001600160a01b03160361227d576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122a061228d60e0840184615001565b61229b610100860186615001565b613952565b6122b282608001358360a00135613c00565b6122cd5f6122c861016085016101408601614c97565b612ae8565b6122e26122dd60c0840184615001565b613cc1565b6122f26080830160608401614c97565b5f805261011b6020527f033d11f27e62ab919708ec716731da80d261a6e4253259b7acde9bf89d28ec1880547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039290921691909117905561236461014083016101208401614c97565b6101c080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03929092169190911790556123af61014083016101208401614c97565b6001600160a01b0316336001600160a01b03167f1f82add12d98b5eaed4d6a6d5f74cfc7a85e5c90c335ab5562f77f220ed45d5f60405160405180910390a36020828101356101198190555f90815261011a8252604080822085359081905581518381528085018490528083019190915260608082018490526080820184905260a09091208084526101be8552828420600190556101bd55815183815293840192909252808501359083015290206101bf55801561119b575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15050565b7f0cf0d2deb70d7bdac2fa48c4ac99bc558170be0ce5fcb994caefa4bf7b96edf96124f181612ade565b5f609a81905560405133917fba88c025b0cbb77022c0c487beef24f759f1e4be2f51a205bc427cee19c2eaa691a250565b5f81600881111561253557612535614bb2565b60da54600190911b16151592915050565b61255362f099c082614c5e565b42101561258c576040517f4306cbb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805184815260208101849052908101829052606090206101bf5414612604576101bf546040805185815260208101859052908101839052606090206040517fbc5aad1100000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401610fee565b6101c0546001600160a01b031661263b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92982612ae8565b6040516001600160a01b0382169033907f9fc8868f8577b31b805ee65bb52325782b5e2708dbdb7f04c7467c6785fccb30905f90a350505050565b5f54600690610100900460ff1615801561269657505f5460ff8083169116105b612722576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610fee565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff83161761010017905561275c8888613cc1565b61276886868686613952565b6001600160a01b0382166127a8576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101c080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03841690811790915560405133907f1f82add12d98b5eaed4d6a6d5f74cfc7a85e5c90c335ab5562f77f220ed45d5f905f90a36040517f362e300000000000000000000000000000000000000000000000000000000000907f352e300000000000000000000000000000000000000000000000000000000000907f2f8492a7a430cf917798dfb60bc5af634f68e6c40287947df0ea6f7ec0669bd8905f90a35f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050505050565b7f32937fd5162e282df7e9a14a5073a2425321c7966eaf70ed6c838a1006d84c4c61290681612ade565b6001600160a01b038316612946576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815261011b60209081526040918290205491516001600160a01b03928316815233928592908716917f4a29db3fc6b42bda201e4b4d69ce8d575eeeba5f153509c0d0a342af0f1bd021910160405180910390a4505f90815261011b6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b5f828152606560205260409020600101546129fc81612ade565b6111438383613e6f565b60db5f826008811115612a1b57612a1b614bb2565b6008811115612a2c57612a2c614bb2565b81526020019081526020015f2054612a4381612ade565b612a4c82612522565b15612a8557816040517fc0a71b58000000000000000000000000000000000000000000000000000000008152600401610fee9190614bdf565b816008811115612a9757612a97614bb2565b60da8054600190921b9091179055816008811115612ab757612ab7614bb2565b7f534f879afd40abb4e39f8e1b77a316be4c8e3521d9cf5a3a3db8959d574d45593361104d565b611a698133613f0e565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff1661119b575f8281526065602090815260408083206001600160a01b0385168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055612b623390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b0381163314612c3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610fee565b61119b8282613e6f565b5f612c77611a9b60017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614c4b565b14612cae576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612ce3612cdc60017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614c4b565b6001612d77565b565b60da54816008811115612cfa57612cfa614bb2565b6001901b811615612d3957816040517fc0a71b58000000000000000000000000000000000000000000000000000000008152600401610fee9190614bdf565b600281161561119b5760016040517fc0a71b58000000000000000000000000000000000000000000000000000000008152600401610fee9190614bdf565b80825d5050565b5f60405188815287602082015286604082015285606082015284608082015260c060a08201528260c0820152602083065f8115612dbc578160200390505b848660e085013790930160e001902098975050505050505050565b5f81815260a66020526040902054600114612e21576040517f992d87c300000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b5f90815260a66020526040812055565b8015611a6957426099541015612e5657609754612e4e9042614c5e565b609955612e66565b609a54612e639082614c5e565b90505b609854811115612ea2576040517fa74c1c5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609a55565b612ce361130260017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614c4b565b5f81836020013511612f20576040517f706144050000000000000000000000000000000000000000000000000000000081526020840135600482015260248101839052604401610fee565b612f34836101800135846101400135613f9c565b6101bf54604080516101608601358152610120860135602082015260e0860135918101919091526060902014612fca57604080516101608501358152610120850135602082015260e085013591810191909152606090206101bf546040517fbc5aad1100000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401610fee565b4283610100013510613015576040517fbf81c6e00000000000000000000000000000000000000000000000000000000081526101008401356004820152426024820152604401610fee565b6080830135613050576040517f2898482a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61309360408401356060850135608086013560a087013560c0880135604080519586526020860194909452928401919091526060830152608082015260a0902090565b5f8181526101be6020526040812054919250036130df576040517fedeae83c00000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b6130fb6130f06101c0850185614d13565b856101a00135614069565b61311261310c6101e0850185614cb2565b84614175565b6020808401355f81815261011a909252604090912060808501359055610119556101bd819055613167610180840135610140850135610100860135604080519384526020840192909252908201526060902090565b6101bf5580602084013561317a84614f71565b60408051873581526080880135602082015291955085917fa0262dc79e4ccb71ceac8574ae906311ae338aa4a2044fd4ec4b99fad5ab60cb910160405180910390a492915050565b5f604051858152846020820152604060e0880160408301378360808201528260a082015260a0610120880160c083013761018081016101c088013588018035602081026020830184376020029091206101608301525061018090207f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000190069695505050505050565b6040805160018082528183019092525f916020808301908036833701905050905084815f8151811061327e5761327e614d9a565b6020908102919091018101919091525f85815261011b90915260409020546001600160a01b0316806132dc576040517f69ed70ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80826001600160a01b0316637e4f7a8a60e01b87878760405160240161330593929190615065565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161337091906150d6565b5f604051808303815f865af19150503d805f81146133a9576040519150601f19603f3d011682016040523d82523d5f602084013e6133ae565b606091505b509150915081613455578051156133f357602081017bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81511663ca389c4460e01b178152815181fd5b6040517fca389c4400000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f556e6b6e6f776e000000000000000000000000000000000000000000000000006044820152606401610fee565b5f8180602001905181019061346a91906150e1565b9050806134a3576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050565b600881901c5f90815261014f6020526040902054600160ff83161b1615613504576040517f335a4a9000000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b600881901c5f90815261014f602052604090208054600160ff84161b17905550565b5f806135476001613538876002615221565b6135429190614c4b565b614202565b90508063ffffffff168463ffffffff16111561359f576040517ff7ec909700000000000000000000000000000000000000000000000000000000815263ffffffff808616600483015282166024820152604401610fee565b865f5b8681101561362557600163ffffffff8716821c811690036135ef576135e88888838181106135d2576135d2614d9a565b90506020020135835f9182526020526040902090565b915061361d565b61361a8289898481811061360557613605614d9a565b905060200201355f9182526020526040902090565b91505b6001016135a2565b509092149695505050505050565b5f61363f60208461522c565b15613676576040517f6426c6c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f729eebce00000000000000000000000000000000000000000000000000000000835b801561372b57602081039050808601357fff000000000000000000000000000000000000000000000000000000000000008116156136dc57604051838152600481fd5b7f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001817f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff0000000187870908935050613699565b50509392505050565b7f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001840693505f80600a6001600160a01b0316878787878760405160200161377f959493929190615264565b60408051601f1981840301815290829052613799916150d6565b5f60405180830381855afa9150503d805f81146137d1576040519150601f19603f3d011682016040523d82523d5f602084013e6137d6565b606091505b509150915081613812576040517fa71194af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604081511461385a578051604080517ff75db381000000000000000000000000000000000000000000000000000000008152610fee9290600401918252602082015260400190565b602081015160408201516110008214158061389557507f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff000000018114155b156134a3576040517f68dcad5f0000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401610fee565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82015f90815261014e60208181526040808420548452848252808420868552929091528083208290555190918391839186917fea3b023b4c8680d4b4824f0143132c95476359a2bb70a81d6c5a36f6918f63399190a4505050565b5f54610100900460ff166139e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b5f5b83811015613af057848482818110613a0457613a04614d9a565b9050604002016020013560db5f878785818110613a2357613a23614d9a565b613a3992602060409092020190810191506146e0565b6008811115613a4a57613a4a614bb2565b6008811115613a5b57613a5b614bb2565b815260208101919091526040015f2055848482818110613a7d57613a7d614d9a565b90506040020160200135858583818110613a9957613a99614d9a565b613aaf92602060409092020190810191506146e0565b6008811115613ac057613ac0614bb2565b6040517f33aa8fd1ce49e1761bc8d27fd53414bfefc45d690feed0ce55019d7d3aec6091905f90a36001016139ea565b505f5b81811015613bf957828282818110613b0d57613b0d614d9a565b9050604002016020013560dc5f858585818110613b2c57613b2c614d9a565b613b4292602060409092020190810191506146e0565b6008811115613b5357613b53614bb2565b6008811115613b6457613b64614bb2565b815260208101919091526040015f2055828282818110613b8657613b86614d9a565b90506040020160200135838383818110613ba257613ba2614d9a565b613bb892602060409092020190810191506146e0565b6008811115613bc957613bc9614bb2565b6040517fe7bf4b8dc0c17a52dc9e52323a3ab61cb2079db35f969125b1f8a3d984c6f6c2905f90a3600101613af3565b5050505050565b5f54610100900460ff16613c96576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b613c9e61424f565b613ca661424f565b613cae61424f565b613cb882826142e5565b5050600160e455565b5f54610100900460ff16613d57576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b5f5b81811015611143575f838383818110613d7457613d74614d9a565b613d8a9260206040909202019081019150614c97565b6001600160a01b031603613dca576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b828282818110613ddc57613ddc614d9a565b905060400201602001355f801b03613e20576040517f0742d05300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613e67838383818110613e3557613e35614d9a565b90506040020160200135848484818110613e5157613e51614d9a565b6122c89260206040909202019081019150614c97565b600101613d59565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff161561119b575f8281526065602090815260408083206001600160a01b038516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff1661119b57613f408161444b565b613f4b83602061445d565b604051602001613f5c92919061528a565b60408051601f19818403018152908290527f08c379a0000000000000000000000000000000000000000000000000000000008252610fee91600401614757565b815f03613fde57801561119b576040517f0c25659200000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b80614018576040517f5228f4c800000000000000000000000000000000000000000000000000000000815260048101839052602401610fee565b5f82815261014e6020526040902054811461119b576040517f36459fa00000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401610fee565b5f5b8281101561416f576101505f85858481811061408957614089614d9a565b9050602002013581526020019081526020015f20545f146140f2578383828181106140b6576140b6614d9a565b905060200201356040517fe5d14425000000000000000000000000000000000000000000000000000000008152600401610fee91815260200190565b816101505f86868581811061410957614109614d9a565b9050602002013581526020019081526020015f20819055508184848381811061413457614134614d9a565b905060200201357f300e6f978eee6a4b0bba78dd8400dc64fd5652dbfc868a2258e16d0977be222b60405160405180910390a360010161406b565b50505050565b61418060028361522c565b156141ba576040517f0c91d77600000000000000000000000000000000000000000000000000000000815260048101839052602401610fee565b5f805b83811015613bf9576040518582013560f01c9250838301907f3c116827db9db3a30c1a25db8b0ee4bab9d2b223560209cfd839601b621c726d905f90a26002016141bd565b5f63ffffffff82111561424b576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526020600482015260248101839052604401610fee565b5090565b5f54610100900460ff16612ce3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b5f54610100900460ff1661437b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b815f036143b4576040517fb5ed5a3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805f036143ed576040517fd10d72bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609782905560988190556144018242614c5e565b60998190556097546098546040805192835260208301919091528101919091527f8f805c372b66240792580418b7328c0c554ae235f0932475c51b026887fe26a9906060016124bb565b6060610f6a6001600160a01b03831660145b60605f61446b836002614c80565b614476906002614c5e565b67ffffffffffffffff81111561448e5761448e614e03565b6040519080825280601f01601f1916602001820160405280156144b8576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000815f815181106144ee576144ee614d9a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061455057614550614d9a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f61458a846002614c80565b614595906001614c5e565b90505b6001811115614631577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106145d6576145d6614d9a565b1a60f81b8282815181106145ec576145ec614d9a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060049490941c9361462a816152f4565b9050614598565b50831561469a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610fee565b9392505050565b5f602082840312156146b1575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461469a575f80fd5b5f602082840312156146f0575f80fd5b81356009811061469a575f80fd5b5f6020828403121561470e575f80fd5b5035919050565b6001600160a01b0381168114611a69575f80fd5b5f806040838503121561473a575f80fd5b82359150602083013561474c81614715565b809150509250929050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f8083601f84011261479c575f80fd5b50813567ffffffffffffffff8111156147b3575f80fd5b6020830191508360208285010111156147ca575f80fd5b9250929050565b5f805f805f805f8060e0898b0312156147e8575f80fd5b88356147f381614715565b9750602089013561480381614715565b96506040890135955060608901359450608089013561482181614715565b935060a089013567ffffffffffffffff81111561483c575f80fd5b6148488b828c0161478c565b999c989b50969995989497949560c00135949350505050565b5f805f8060608587031215614874575f80fd5b843567ffffffffffffffff81111561488a575f80fd5b6148968782880161478c565b90955093505060208501359150604085013567ffffffffffffffff8111156148bc575f80fd5b850161020081880312156148ce575f80fd5b939692955090935050565b5f602082840312156148e9575f80fd5b813567ffffffffffffffff8111156148ff575f80fd5b8201610140818503121561469a575f80fd5b5f805f60608486031215614923575f80fd5b833567ffffffffffffffff811115614939575f80fd5b84016060818703121561494a575f80fd5b95602085013595506040909401359392505050565b5f805f8060608587031215614972575f80fd5b843567ffffffffffffffff811115614988575f80fd5b8501601f81018713614998575f80fd5b803567ffffffffffffffff8111156149ae575f80fd5b8760208260051b84010111156149c2575f80fd5b602091820198909750908601359560400135945092505050565b5f805f80606085870312156149ef575f80fd5b84356149fa81614715565b935060208501359250604085013567ffffffffffffffff811115614a1c575f80fd5b614a288782880161478c565b95989497509550505050565b5f60208284031215614a44575f80fd5b813567ffffffffffffffff811115614a5a575f80fd5b8201610160818503121561469a575f80fd5b5f805f60608486031215614a7e575f80fd5b505081359360208301359350604090920135919050565b5f8083601f840112614aa5575f80fd5b50813567ffffffffffffffff811115614abc575f80fd5b6020830191508360208260061b85010111156147ca575f80fd5b5f805f805f805f6080888a031215614aec575f80fd5b873567ffffffffffffffff811115614b02575f80fd5b614b0e8a828b01614a95565b909850965050602088013567ffffffffffffffff811115614b2d575f80fd5b614b398a828b01614a95565b909650945050604088013567ffffffffffffffff811115614b58575f80fd5b614b648a828b01614a95565b9094509250506060880135614b7881614715565b8091505092959891949750929550565b5f8060408385031215614b99575f80fd5b8235614ba481614715565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6020810160098310614c18577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b91905290565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115610f6a57610f6a614c1e565b80820180821115610f6a57610f6a614c1e565b818382375f9101908152919050565b8082028115828204841417610f6a57610f6a614c1e565b5f60208284031215614ca7575f80fd5b813561469a81614715565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614ce5575f80fd5b83018035915067ffffffffffffffff821115614cff575f80fd5b6020019150368190038213156147ca575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614d46575f80fd5b83018035915067ffffffffffffffff821115614d60575f80fd5b6020019150600581901b36038213156147ca575f80fd5b5f60208284031215614d87575f80fd5b813563ffffffff8116811461469a575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61833603018112614df9575f80fd5b9190910192915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405160a0810167ffffffffffffffff81118282101715614e5357614e53614e03565b60405290565b5f82601f830112614e68575f80fd5b813567ffffffffffffffff811115614e8257614e82614e03565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715614eb157614eb1614e03565b604052818152838201602001851015614ec8575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60a08236031215614ef4575f80fd5b614efc614e30565b82358152602083013567ffffffffffffffff811115614f19575f80fd5b614f2536828601614e59565b602083015250604083013567ffffffffffffffff811115614f44575f80fd5b614f5036828601614e59565b60408301525060608381013590820152608092830135928101929092525090565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614fa157614fa1614c1e565b5060010190565b81835281816020850137505f602082840101525f6020601f19601f840116840101905092915050565b858152846020820152836040820152608060608201525f614ff6608083018486614fa8565b979650505050505050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615034575f80fd5b83018035915067ffffffffffffffff82111561504e575f80fd5b6020019150600681901b36038213156147ca575f80fd5b604081525f615078604083018587614fa8565b82810360208401528084518083526020830191506020860192505f5b818110156150b2578351835260209384019390920191600101615094565b5090979650505050505050565b5f81518060208401855e5f93019283525090919050565b5f61469a82846150bf565b5f602082840312156150f1575f80fd5b8151801515811461469a575f80fd5b6001815b600184111561513b5780850481111561511f5761511f614c1e565b600184161561512d57908102905b60019390931c928002615104565b935093915050565b5f8261515157506001610f6a565b8161515d57505f610f6a565b8160018114615173576002811461517d57615199565b6001915050610f6a565b60ff84111561518e5761518e614c1e565b50506001821b610f6a565b5060208310610133831016604e8410600b84101617156151bc575081810a610f6a565b6151e77fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484615100565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561521957615219614c1e565b029392505050565b5f61469a8383615143565b5f8261525f577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500690565b8581528460208201528360408201525f614ff661528460608401866150bf565b846150bf565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f6152bb60178301856150bf565b7f206973206d697373696e6720726f6c652000000000000000000000000000000081526152eb60118201856150bf565b95945050505050565b5f8161530257615302614c1e565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea2646970667358221220f37ab9d49b246192cc1f4c0273d18fcd431dc83c67e6b7fb35993ccad3328d4e64736f6c634300081a0033", + "deployedBytecode": "0x608060405260043610610483575f3560e01c806373bd07b711610251578063b837dbe91161013c578063cc5782f6116100b7578063d547741f11610087578063d722bbfc1161006d578063d722bbfc14610e53578063e196fb5d14610e86578063f5b541a614610ea5575f80fd5b8063d547741f14610e1e578063d5d4b83514610e3d575f80fd5b8063cc5782f614610d87578063cc6f725114610db5578063cd9b9e9a14610de8578063cf5b276414610dfe575f80fd5b8063bf3e75051161010c578063c0c4e584116100f2578063c0c4e58414610d34578063c1dc0f0714610d53578063c211697414610d68575f80fd5b8063bf3e750514610cec578063c0729ab114610d1f575f80fd5b8063b837dbe914610c66578063b9174ba314610c7b578063bc61e73314610cae578063bcc3003d14610ccd575f80fd5b80639ac25d08116101cc578063a98e773d1161019c578063ad422ff011610182578063ad422ff014610c0a578063aea4f74514610c1f578063b59faa6014610c33575f80fd5b8063a98e773d14610bb6578063ac1eff6814610bd5575f80fd5b80639ac25d0814610b3e5780639ee8b21114610b715780639f3ce55a14610b90578063a217fddf14610ba3575f80fd5b8063914e57eb11610221578063921b278e11610207578063921b278e14610b09578063986fcddd14610a2757806399467a3514610b1f575f80fd5b8063914e57eb14610a9957806391d1485414610ac5575f80fd5b806373bd07b714610a135780637d1e8c5514610a275780638be745d114610a3a5780638de4948714610a66575f80fd5b80634cdd389b1161037157806360e83cf3116102ec57806367e404ce116102bc578063695378f5116102a2578063695378f5146109975780636a906b80146109ad5780636e673843146109e0575f80fd5b806367e404ce1461094c5780636854f6bc14610978575f80fd5b806360e83cf3146108a257806363213155146108ce5780636463fb2a1461090157806366f96e9814610920575f80fd5b806358794456116103415780635c721a0c116103275780635c721a0c1461081f5780635ed73ceb1461084a5780636078bfd814610876575f80fd5b8063587944561461080a5780635b7eb4bd14610728575f80fd5b80634cdd389b1461076d5780635230eef214610799578063557eac73146107cc5780635603c65f146107eb575f80fd5b8063289581741161040157806338b90333116103d15780633fc08b65116103b75780633fc08b65146106fd57806348922ab714610728578063491e09361461074e575f80fd5b806338b90333146106755780633b12eccb146106ca575f80fd5b806328958174146106025780632c70645c146106215780632f2ff15d1461063757806336568abe14610656575f80fd5b806312d3fa9a116104565780631f443da01161043c5780631f443da01461057c5780632130d812146105a8578063248a9ca3146105d4575f80fd5b806312d3fa9a146105335780631e2ff94f14610566575f80fd5b806301ffc9a71461048757806303134d1d146104bb57806305861180146104fc5780631065a39914610512575b5f80fd5b348015610492575f80fd5b506104a66104a13660046146a1565b610ed8565b60405190151581526020015b60405180910390f35b3480156104c6575f80fd5b506104ee7f1ab87f7458c0e3d07e9881c14ee67f0141703614fd48ea5b15ed987e5f4b030e81565b6040519081526020016104b2565b348015610507575f80fd5b506104ee6101bb5481565b34801561051d575f80fd5b5061053161052c3660046146e0565b610f70565b005b34801561053e575f80fd5b506104ee7f67c2dca7476ee0fe1dd3cba13428c6760bfe2599a6dfe26a9ad7ef27317c6e7781565b348015610571575f80fd5b506104ee6101185481565b348015610587575f80fd5b506104ee6105963660046146fe565b6101b96020525f908152604090205481565b3480156105b3575f80fd5b506104ee6105c23660046146fe565b6101be6020525f908152604090205481565b3480156105df575f80fd5b506104ee6105ee3660046146fe565b5f9081526065602052604090206001015490565b34801561060d575f80fd5b5061053161061c3660046146fe565b61106c565b34801561062c575f80fd5b506104ee6101835481565b348015610642575f80fd5b50610531610651366004614729565b61111f565b348015610661575f80fd5b50610531610670366004614729565b611148565b348015610680575f80fd5b506106bd6040518060400160405280600381526020017f362e30000000000000000000000000000000000000000000000000000000000081525081565b6040516104b29190614757565b3480156106d5575f80fd5b506104ee7fb6cc65f42901ed602aec1619cc1ead29d487cd489094a37615153eaeb991d77081565b348015610708575f80fd5b506104ee6107173660046146fe565b60a56020525f908152604090205481565b348015610733575f80fd5b5061073c600181565b60405160ff90911681526020016104b2565b348015610759575f80fd5b506105316107683660046147d1565b61119f565b348015610778575f80fd5b506104ee6107873660046146fe565b6101b76020525f908152604090205481565b3480156107a4575f80fd5b506104ee7f0cf0d2deb70d7bdac2fa48c4ac99bc558170be0ce5fcb994caefa4bf7b96edf981565b3480156107d7575f80fd5b506105316107e63660046146fe565b611455565b3480156107f6575f80fd5b50610531610805366004614861565b61151b565b348015610815575f80fd5b506104ee60995481565b34801561082a575f80fd5b506104ee6108393660046146fe565b60a66020525f908152604090205481565b348015610855575f80fd5b506104ee6108643660046146fe565b6101ba6020525f908152604090205481565b348015610881575f80fd5b506104ee6108903660046146fe565b6101b66020525f908152604090205481565b3480156108ad575f80fd5b506104ee6108bc3660046146fe565b6101506020525f908152604090205481565b3480156108d9575f80fd5b506104ee7fe37c272ea30e2bb381ad7cf89ae754b49153250609f36d0cbdad8b64c184bb5c81565b34801561090c575f80fd5b5061053161091b3660046148d9565b611613565b34801561092b575f80fd5b506104ee61093a3660046146fe565b6101b86020525f908152604090205481565b348015610957575f80fd5b50610960611a6c565b6040516001600160a01b0390911681526020016104b2565b348015610983575f80fd5b50610531610992366004614911565b611aa4565b3480156109a2575f80fd5b506104ee6101195481565b3480156109b8575f80fd5b506104ee7fd8b4c34c2ec1f3194471108c64ad2beda340c0337ee4ca35592f9ef270f4228b81565b3480156109eb575f80fd5b506104ee7f32937fd5162e282df7e9a14a5073a2425321c7966eaf70ed6c838a1006d84c4c81565b348015610a1e575f80fd5b5061073c600281565b348015610a32575f80fd5b5061073c5f81565b348015610a45575f80fd5b506104ee610a543660046146fe565b61011a6020525f908152604090205481565b348015610a71575f80fd5b506104ee7fe1fce82838dd7a42cfe783f60dc6233c8aa2c4fc66e77817805e767ec5e349b681565b348015610aa4575f80fd5b506104ee610ab33660046146fe565b61014e6020525f908152604090205481565b348015610ad0575f80fd5b506104a6610adf366004614729565b5f9182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b348015610b14575f80fd5b506104ee6101bf5481565b348015610b2a575f80fd5b50610531610b3936600461495f565b611ce4565b348015610b49575f80fd5b506104ee7f56bdc3c9ec86cb7db110a7699b2ade72f0b8819727d9f7d906b012641505fa7781565b348015610b7c575f80fd5b506104a6610b8b3660046146fe565b611fc8565b610531610b9e3660046149dc565b611feb565b348015610bae575f80fd5b506104ee5f81565b348015610bc1575f80fd5b50610531610bd0366004614a34565b61210d565b348015610be0575f80fd5b50610960610bef3660046146fe565b61011b6020525f90815260409020546001600160a01b031681565b348015610c15575f80fd5b506104ee60985481565b348015610c2a575f80fd5b506105316124c7565b348015610c3e575f80fd5b506104ee7fe4831f9e4316ac2c65117d1f602fbf56d38128a9973d5e3fdbc5b77265c18d4081565b348015610c71575f80fd5b506104ee60e45481565b348015610c86575f80fd5b506104ee7f430a7f0cb00b5ebbe63cecc96e82cf959a883e7c13a95110854f1fa6b3fbf59881565b348015610cb9575f80fd5b506104a6610cc83660046146e0565b612522565b348015610cd8575f80fd5b50610531610ce7366004614a6c565b612546565b348015610cf7575f80fd5b506104ee7f1185e52d62bfbbea270e57d3d09733d221b53ab7a18bae82bb3c6c74bab16d8281565b348015610d2a575f80fd5b506104ee609a5481565b348015610d3f575f80fd5b50610531610d4e366004614ad6565b612676565b348015610d5e575f80fd5b506104ee60975481565b348015610d73575f80fd5b50610531610d82366004614b88565b6128dc565b348015610d92575f80fd5b506104a6610da13660046146fe565b60d96020525f908152604090205460ff1681565b348015610dc0575f80fd5b506104ee7fe8cb6172fcf5cbaae022b7c910224a4f0c20d53227e630056efff182155a5abc81565b348015610df3575f80fd5b506104ee6101bd5481565b348015610e09575f80fd5b506101c054610960906001600160a01b031681565b348015610e29575f80fd5b50610531610e38366004614729565b6129e2565b348015610e48575f80fd5b506104ee6101bc5481565b348015610e5e575f80fd5b506104ee7f6b5661ddfbd1fbd525c902a513e0f47d9c74f1c1ee8a2d4f1937ad305fb8f41a81565b348015610e91575f80fd5b50610531610ea03660046146e0565b612a06565b348015610eb0575f80fd5b506104ee7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92981565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610f6a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60dc5f826008811115610f8557610f85614bb2565b6008811115610f9657610f96614bb2565b81526020019081526020015f2054610fad81612ade565b610fb682612522565b610ff757816040517f18659654000000000000000000000000000000000000000000000000000000008152600401610fee9190614bdf565b60405180910390fd5b81600881111561100957611009614bb2565b60da8054600190921b19909116905581600881111561102a5761102a614bb2565b7fd071d2b85dec4489435b541d2f0e2570db09b09db9efd8703948d44a433df65a335b6040516001600160a01b03909116815260200160405180910390a25050565b7f6b5661ddfbd1fbd525c902a513e0f47d9c74f1c1ee8a2d4f1937ad305fb8f41a61109681612ade565b5f82815261011b602090815260408083205490516001600160a01b0390911681523392859290917f4a29db3fc6b42bda201e4b4d69ce8d575eeeba5f153509c0d0a342af0f1bd021910160405180910390a4505f90815261011b6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b5f8281526065602052604090206001015461113981612ade565b6111438383612ae8565b505050565b6101c0546001600160a01b0390811690821603611191576040517f7f7497e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61119b8282612ba6565b5050565b6111a7612c48565b85878484875f5a90506111ba6003612ce5565b6111ee6111e860017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b8f612d77565b5f6111fe8f8f8f8f8c8f8f612d7e565b905061120981612dd7565b61121b6112168d8f614c5e565b612e31565b5f808f6001600160a01b03168e8d8d604051611238929190614c71565b5f6040518083038185875af1925050503d805f8114611272576040519150601f19603f3d011682016040523d82523d5f602084013e611277565b606091505b5091509150816112d4578051156112915780518082602001fd5b8f6040517f54613443000000000000000000000000000000000000000000000000000000008152600401610fee91906001600160a01b0391909116815260200190565b61130861130260017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b5f612d77565b60405183907fa4c827e719e911e8f19393ccdb85b5102f08f0910604d340ba38390b7ff2ab0e905f90a250508615905061143d57855f8490036113b357853b1580156113b1573a5a61135c61bc7c86614c5e565b6113669190614c4b565b6113709190614c80565b9150818811156113ad576001600160a01b0387166108fc611391848b614c4b565b6040518115909202915f818181858888f19350505050506113b1565b8791505b505b5f6001600160a01b038416156113c957836113cb565b335b90505f816001600160a01b03166108fc8490811502906040515f60405180830381858888f19350505050905080611439576040517fa57c4df40000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610fee565b5050505b50505050505061144b612ea7565b5050505050505050565b7f1185e52d62bfbbea270e57d3d09733d221b53ab7a18bae82bb3c6c74bab16d8261147f81612ade565b5f805f4260995410156114a4576097546114999042614c5e565b6099555060016114b6565b609a548510156114b657849250600191505b609885905580806114c45750815b156114cf57609a8390555b60408051868152831515602082015282151581830152905133917fbc3dc0cb5c15c51c81316450d44048838bb478b9809447d01c766a06f3e9f2c8919081900360600190a25050505050565b600661152681612ce5565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92961155081612ade565b5f85900361158a576040517f7907d79b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610119545f81815261011a60205260409020548435146115d6576040517fead4c30e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101bd545f6115e58684612ed5565b90505f6115f9878484878b602001356131c2565b905061160781898c8c61324a565b50505050505050505050565b61161b612c48565b60a0810180359061162f9060808401614c97565b61163d610120840184614cb2565b61164e610100860160e08701614c97565b5f5a905061165c6003612ce5565b6101008701355f9081526101506020526040812054908190036116ab576040517f4e68667500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116b58880614d13565b9050811461170457806116c88980614d13565b6040517f5e3fd6ad0000000000000000000000000000000000000000000000000000000081526004810193909352602483015250604401610fee565b61171188602001356134ae565b61172661121660c08a013560a08b0135614c5e565b5f61176f61173a60808b0160608c01614c97565b61174a60a08c0160808d01614c97565b8b60a001358c60c001358d602001358e80610120019061176a9190614cb2565b612d7e565b905061179a8161177f8b80614d13565b61178f60608e0160408f01614d77565b8d6101000135613526565b6117d0576040517fb05e92fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6118136117fe60017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b61180e60808c0160608d01614c97565b612d77565b5f8061182560a08c0160808d01614c97565b6001600160a01b031660c08c01356118416101208e018e614cb2565b60405161184f929190614c71565b5f6040518083038185875af1925050503d805f8114611889576040519150601f19603f3d011682016040523d82523d5f602084013e61188e565b606091505b5091509150816118f6578051156118a85780518082602001fd5b6118b860a08c0160808d01614c97565b6040517f546134430000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610fee565b61192461130260017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b60405183907fa4c827e719e911e8f19393ccdb85b5102f08f0910604d340ba38390b7ff2ab0e905f90a2505050505f861115611a5b57855f8490036119d157853b1580156119cf573a5a61197a61bc7c86614c5e565b6119849190614c4b565b61198e9190614c80565b9150818811156119cb576001600160a01b0387166108fc6119af848b614c4b565b6040518115909202915f818181858888f19350505050506119cf565b8791505b505b5f6001600160a01b038416156119e757836119e9565b335b90505f816001600160a01b03166108fc8490811502906040515f60405180830381858888f19350505050905080611a57576040517fa57c4df40000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610fee565b5050505b505050505050611a69612ea7565b50565b5f611a9f611a9b60017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b5c90565b905090565b6005611aaf81612ce5565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929611ad981612ade565b611ae66040860186614cb2565b90505f03611b20576040517fc01eab5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8381526101be602052604090205415611b69576040517f0f06cd1500000000000000000000000000000000000000000000000000000000815260048101849052602401610fee565b5f8481526101be60205260408120549003611bb3576040517f6e5424c200000000000000000000000000000000000000000000000000000000815260048101859052602401610fee565b5f611bc16040870187614cb2565b604051611bcf929190614c71565b604051809103902090505f611bf18760200135835f9182526020526040902090565b90505f611c3d8760208a01358a3585611c16611c1060408f018f614cb2565b89613633565b604080519586526020860194909452928401919091526060830152608082015260a0902090565b9050808614611c82576040517fd3664fb30000000000000000000000000000000000000000000000000000000081526004810187905260248101829052604401610fee565b5f8181526101be602052604090819020600190555181907f55f4c645c36aa5cd3f443d6be44d7a7a5df9d2100d7139dfc69d4289ee07231990611cd2908a908c3590918252602082015260400190565b60405180910390a25050505050505050565b6004611cef81612ce5565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929611d1981612ade565b5f859003611d53576040517fb1504a5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b844915611d8f576040517f8019aff700000000000000000000000000000000000000000000000000000000815260048101869052602401610fee565b5f8481526101be60205260408120549003611dd9576040517f6e5424c200000000000000000000000000000000000000000000000000000000815260048101859052602401610fee565b5f8381526101be602052604090205415611e22576040517f0f06cd1500000000000000000000000000000000000000000000000000000000815260048101849052602401610fee565b6040805160a0810182525f808252606060208301819052928201839052918101829052608081018290528190865f5b89811015611f27578a8a82818110611e6b57611e6b614d9a565b9050602002810190611e7d9190614dc7565b611e8690614ee4565b81499450925083611ec6576040517fc0e41e1d00000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b60808301515f8181526020869052604090209550611ef485875f1c865f015187602001518860400151613734565b6060848101518551604080519687526020870194909452928501528301869052608083015260a090912090600101611e51565b50808714611f6b576040517fd3664fb30000000000000000000000000000000000000000000000000000000081526004810188905260248101829052604401610fee565b5f8181526101be602090815260409182902060019055606084015182518b81529182015282917f55f4c645c36aa5cd3f443d6be44d7a7a5df9d2100d7139dfc69d4289ee072319910160405180910390a250505050505050505050565b600881901c5f90815261014f6020526040812054600160ff84161b161515610f6a565b6002611ff681612ce5565b6001600160a01b038516612036576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b34841115612070576040517fb03b693200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60e480545f918261208083614f71565b9091555090505f6120918634614c4b565b90505f6120a333898985878b8b612d7e565b90506120af83826138d6565b80886001600160a01b0316336001600160a01b03167fe856c2b8bd4eb0027ce32eeaf595c21b0b6b4644b326e5b7bd80a1cf8db72e6c8a86888c8c6040516120fb959493929190614fd1565b60405180910390a45050505050505050565b5f54610100900460ff161580801561212b57505f54600160ff909116105b806121445750303b15801561214457505f5460ff166001145b6121d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610fee565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561222c575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b5f61223d6080840160608501614c97565b6001600160a01b03160361227d576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122a061228d60e0840184615001565b61229b610100860186615001565b613952565b6122b282608001358360a00135613c00565b6122cd5f6122c861016085016101408601614c97565b612ae8565b6122e26122dd60c0840184615001565b613cc1565b6122f26080830160608401614c97565b5f805261011b6020527f033d11f27e62ab919708ec716731da80d261a6e4253259b7acde9bf89d28ec1880547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039290921691909117905561236461014083016101208401614c97565b6101c080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03929092169190911790556123af61014083016101208401614c97565b6001600160a01b0316336001600160a01b03167f1f82add12d98b5eaed4d6a6d5f74cfc7a85e5c90c335ab5562f77f220ed45d5f60405160405180910390a36020828101356101198190555f90815261011a8252604080822085359081905581518381528085018490528083019190915260608082018490526080820184905260a09091208084526101be8552828420600190556101bd55815183815293840192909252808501359083015290206101bf55801561119b575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15050565b7f0cf0d2deb70d7bdac2fa48c4ac99bc558170be0ce5fcb994caefa4bf7b96edf96124f181612ade565b5f609a81905560405133917fba88c025b0cbb77022c0c487beef24f759f1e4be2f51a205bc427cee19c2eaa691a250565b5f81600881111561253557612535614bb2565b60da54600190911b16151592915050565b61255362f099c082614c5e565b42101561258c576040517f4306cbb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805184815260208101849052908101829052606090206101bf5414612604576101bf546040805185815260208101859052908101839052606090206040517fbc5aad1100000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401610fee565b6101c0546001600160a01b031661263b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92982612ae8565b6040516001600160a01b0382169033907f9fc8868f8577b31b805ee65bb52325782b5e2708dbdb7f04c7467c6785fccb30905f90a350505050565b5f54600690610100900460ff1615801561269657505f5460ff8083169116105b612722576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610fee565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff83161761010017905561275c8888613cc1565b61276886868686613952565b6001600160a01b0382166127a8576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101c080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03841690811790915560405133907f1f82add12d98b5eaed4d6a6d5f74cfc7a85e5c90c335ab5562f77f220ed45d5f905f90a36040517f362e300000000000000000000000000000000000000000000000000000000000907f352e300000000000000000000000000000000000000000000000000000000000907f2f8492a7a430cf917798dfb60bc5af634f68e6c40287947df0ea6f7ec0669bd8905f90a35f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050505050565b7f32937fd5162e282df7e9a14a5073a2425321c7966eaf70ed6c838a1006d84c4c61290681612ade565b6001600160a01b038316612946576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815261011b60209081526040918290205491516001600160a01b03928316815233928592908716917f4a29db3fc6b42bda201e4b4d69ce8d575eeeba5f153509c0d0a342af0f1bd021910160405180910390a4505f90815261011b6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b5f828152606560205260409020600101546129fc81612ade565b6111438383613e6f565b60db5f826008811115612a1b57612a1b614bb2565b6008811115612a2c57612a2c614bb2565b81526020019081526020015f2054612a4381612ade565b612a4c82612522565b15612a8557816040517fc0a71b58000000000000000000000000000000000000000000000000000000008152600401610fee9190614bdf565b816008811115612a9757612a97614bb2565b60da8054600190921b9091179055816008811115612ab757612ab7614bb2565b7f534f879afd40abb4e39f8e1b77a316be4c8e3521d9cf5a3a3db8959d574d45593361104d565b611a698133613f0e565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff1661119b575f8281526065602090815260408083206001600160a01b0385168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055612b623390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b0381163314612c3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610fee565b61119b8282613e6f565b5f612c77611a9b60017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614c4b565b14612cae576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612ce3612cdc60017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614c4b565b6001612d77565b565b60da54816008811115612cfa57612cfa614bb2565b6001901b811615612d3957816040517fc0a71b58000000000000000000000000000000000000000000000000000000008152600401610fee9190614bdf565b600281161561119b5760016040517fc0a71b58000000000000000000000000000000000000000000000000000000008152600401610fee9190614bdf565b80825d5050565b5f60405188815287602082015286604082015285606082015284608082015260c060a08201528260c0820152602083065f8115612dbc578160200390505b848660e085013790930160e001902098975050505050505050565b5f81815260a66020526040902054600114612e21576040517f992d87c300000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b5f90815260a66020526040812055565b8015611a6957426099541015612e5657609754612e4e9042614c5e565b609955612e66565b609a54612e639082614c5e565b90505b609854811115612ea2576040517fa74c1c5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609a55565b612ce361130260017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614c4b565b5f81836020013511612f20576040517f706144050000000000000000000000000000000000000000000000000000000081526020840135600482015260248101839052604401610fee565b612f34836101800135846101400135613f9c565b6101bf54604080516101608601358152610120860135602082015260e0860135918101919091526060902014612fca57604080516101608501358152610120850135602082015260e085013591810191909152606090206101bf546040517fbc5aad1100000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401610fee565b4283610100013510613015576040517fbf81c6e00000000000000000000000000000000000000000000000000000000081526101008401356004820152426024820152604401610fee565b6080830135613050576040517f2898482a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61309360408401356060850135608086013560a087013560c0880135604080519586526020860194909452928401919091526060830152608082015260a0902090565b5f8181526101be6020526040812054919250036130df576040517fedeae83c00000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b6130fb6130f06101c0850185614d13565b856101a00135614069565b61311261310c6101e0850185614cb2565b84614175565b6020808401355f81815261011a909252604090912060808501359055610119556101bd819055613167610180840135610140850135610100860135604080519384526020840192909252908201526060902090565b6101bf5580602084013561317a84614f71565b60408051873581526080880135602082015291955085917fa0262dc79e4ccb71ceac8574ae906311ae338aa4a2044fd4ec4b99fad5ab60cb910160405180910390a492915050565b5f604051858152846020820152604060e0880160408301378360808201528260a082015260a0610120880160c083013761018081016101c088013588018035602081026020830184376020029091206101608301525061018090207f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000190069695505050505050565b6040805160018082528183019092525f916020808301908036833701905050905084815f8151811061327e5761327e614d9a565b6020908102919091018101919091525f85815261011b90915260409020546001600160a01b0316806132dc576040517f69ed70ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80826001600160a01b0316637e4f7a8a60e01b87878760405160240161330593929190615065565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161337091906150d6565b5f604051808303815f865af19150503d805f81146133a9576040519150601f19603f3d011682016040523d82523d5f602084013e6133ae565b606091505b509150915081613455578051156133f357602081017bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81511663ca389c4460e01b178152815181fd5b6040517fca389c4400000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f556e6b6e6f776e000000000000000000000000000000000000000000000000006044820152606401610fee565b5f8180602001905181019061346a91906150e1565b9050806134a3576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050565b600881901c5f90815261014f6020526040902054600160ff83161b1615613504576040517f335a4a9000000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b600881901c5f90815261014f602052604090208054600160ff84161b17905550565b5f806135476001613538876002615221565b6135429190614c4b565b614202565b90508063ffffffff168463ffffffff16111561359f576040517ff7ec909700000000000000000000000000000000000000000000000000000000815263ffffffff808616600483015282166024820152604401610fee565b865f5b8681101561362557600163ffffffff8716821c811690036135ef576135e88888838181106135d2576135d2614d9a565b90506020020135835f9182526020526040902090565b915061361d565b61361a8289898481811061360557613605614d9a565b905060200201355f9182526020526040902090565b91505b6001016135a2565b509092149695505050505050565b5f61363f60208461522c565b15613676576040517f6426c6c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f729eebce00000000000000000000000000000000000000000000000000000000835b801561372b57602081039050808601357fff000000000000000000000000000000000000000000000000000000000000008116156136dc57604051838152600481fd5b7f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001817f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff0000000187870908935050613699565b50509392505050565b7f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001840693505f80600a6001600160a01b0316878787878760405160200161377f959493929190615264565b60408051601f1981840301815290829052613799916150d6565b5f60405180830381855afa9150503d805f81146137d1576040519150601f19603f3d011682016040523d82523d5f602084013e6137d6565b606091505b509150915081613812576040517fa71194af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604081511461385a578051604080517ff75db381000000000000000000000000000000000000000000000000000000008152610fee9290600401918252602082015260400190565b602081015160408201516110008214158061389557507f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff000000018114155b156134a3576040517f68dcad5f0000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401610fee565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82015f90815261014e60208181526040808420548452848252808420868552929091528083208290555190918391839186917fea3b023b4c8680d4b4824f0143132c95476359a2bb70a81d6c5a36f6918f63399190a4505050565b5f54610100900460ff166139e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b5f5b83811015613af057848482818110613a0457613a04614d9a565b9050604002016020013560db5f878785818110613a2357613a23614d9a565b613a3992602060409092020190810191506146e0565b6008811115613a4a57613a4a614bb2565b6008811115613a5b57613a5b614bb2565b815260208101919091526040015f2055848482818110613a7d57613a7d614d9a565b90506040020160200135858583818110613a9957613a99614d9a565b613aaf92602060409092020190810191506146e0565b6008811115613ac057613ac0614bb2565b6040517f33aa8fd1ce49e1761bc8d27fd53414bfefc45d690feed0ce55019d7d3aec6091905f90a36001016139ea565b505f5b81811015613bf957828282818110613b0d57613b0d614d9a565b9050604002016020013560dc5f858585818110613b2c57613b2c614d9a565b613b4292602060409092020190810191506146e0565b6008811115613b5357613b53614bb2565b6008811115613b6457613b64614bb2565b815260208101919091526040015f2055828282818110613b8657613b86614d9a565b90506040020160200135838383818110613ba257613ba2614d9a565b613bb892602060409092020190810191506146e0565b6008811115613bc957613bc9614bb2565b6040517fe7bf4b8dc0c17a52dc9e52323a3ab61cb2079db35f969125b1f8a3d984c6f6c2905f90a3600101613af3565b5050505050565b5f54610100900460ff16613c96576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b613c9e61424f565b613ca661424f565b613cae61424f565b613cb882826142e5565b5050600160e455565b5f54610100900460ff16613d57576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b5f5b81811015611143575f838383818110613d7457613d74614d9a565b613d8a9260206040909202019081019150614c97565b6001600160a01b031603613dca576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b828282818110613ddc57613ddc614d9a565b905060400201602001355f801b03613e20576040517f0742d05300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613e67838383818110613e3557613e35614d9a565b90506040020160200135848484818110613e5157613e51614d9a565b6122c89260206040909202019081019150614c97565b600101613d59565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff161561119b575f8281526065602090815260408083206001600160a01b038516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff1661119b57613f408161444b565b613f4b83602061445d565b604051602001613f5c92919061528a565b60408051601f19818403018152908290527f08c379a0000000000000000000000000000000000000000000000000000000008252610fee91600401614757565b815f03613fde57801561119b576040517f0c25659200000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b80614018576040517f5228f4c800000000000000000000000000000000000000000000000000000000815260048101839052602401610fee565b5f82815261014e6020526040902054811461119b576040517f36459fa00000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401610fee565b5f5b8281101561416f576101505f85858481811061408957614089614d9a565b9050602002013581526020019081526020015f20545f146140f2578383828181106140b6576140b6614d9a565b905060200201356040517fe5d14425000000000000000000000000000000000000000000000000000000008152600401610fee91815260200190565b816101505f86868581811061410957614109614d9a565b9050602002013581526020019081526020015f20819055508184848381811061413457614134614d9a565b905060200201357f300e6f978eee6a4b0bba78dd8400dc64fd5652dbfc868a2258e16d0977be222b60405160405180910390a360010161406b565b50505050565b61418060028361522c565b156141ba576040517f0c91d77600000000000000000000000000000000000000000000000000000000815260048101839052602401610fee565b5f805b83811015613bf9576040518582013560f01c9250838301907f3c116827db9db3a30c1a25db8b0ee4bab9d2b223560209cfd839601b621c726d905f90a26002016141bd565b5f63ffffffff82111561424b576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526020600482015260248101839052604401610fee565b5090565b5f54610100900460ff16612ce3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b5f54610100900460ff1661437b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b815f036143b4576040517fb5ed5a3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805f036143ed576040517fd10d72bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609782905560988190556144018242614c5e565b60998190556097546098546040805192835260208301919091528101919091527f8f805c372b66240792580418b7328c0c554ae235f0932475c51b026887fe26a9906060016124bb565b6060610f6a6001600160a01b03831660145b60605f61446b836002614c80565b614476906002614c5e565b67ffffffffffffffff81111561448e5761448e614e03565b6040519080825280601f01601f1916602001820160405280156144b8576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000815f815181106144ee576144ee614d9a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061455057614550614d9a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f61458a846002614c80565b614595906001614c5e565b90505b6001811115614631577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106145d6576145d6614d9a565b1a60f81b8282815181106145ec576145ec614d9a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060049490941c9361462a816152f4565b9050614598565b50831561469a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610fee565b9392505050565b5f602082840312156146b1575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461469a575f80fd5b5f602082840312156146f0575f80fd5b81356009811061469a575f80fd5b5f6020828403121561470e575f80fd5b5035919050565b6001600160a01b0381168114611a69575f80fd5b5f806040838503121561473a575f80fd5b82359150602083013561474c81614715565b809150509250929050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f8083601f84011261479c575f80fd5b50813567ffffffffffffffff8111156147b3575f80fd5b6020830191508360208285010111156147ca575f80fd5b9250929050565b5f805f805f805f8060e0898b0312156147e8575f80fd5b88356147f381614715565b9750602089013561480381614715565b96506040890135955060608901359450608089013561482181614715565b935060a089013567ffffffffffffffff81111561483c575f80fd5b6148488b828c0161478c565b999c989b50969995989497949560c00135949350505050565b5f805f8060608587031215614874575f80fd5b843567ffffffffffffffff81111561488a575f80fd5b6148968782880161478c565b90955093505060208501359150604085013567ffffffffffffffff8111156148bc575f80fd5b850161020081880312156148ce575f80fd5b939692955090935050565b5f602082840312156148e9575f80fd5b813567ffffffffffffffff8111156148ff575f80fd5b8201610140818503121561469a575f80fd5b5f805f60608486031215614923575f80fd5b833567ffffffffffffffff811115614939575f80fd5b84016060818703121561494a575f80fd5b95602085013595506040909401359392505050565b5f805f8060608587031215614972575f80fd5b843567ffffffffffffffff811115614988575f80fd5b8501601f81018713614998575f80fd5b803567ffffffffffffffff8111156149ae575f80fd5b8760208260051b84010111156149c2575f80fd5b602091820198909750908601359560400135945092505050565b5f805f80606085870312156149ef575f80fd5b84356149fa81614715565b935060208501359250604085013567ffffffffffffffff811115614a1c575f80fd5b614a288782880161478c565b95989497509550505050565b5f60208284031215614a44575f80fd5b813567ffffffffffffffff811115614a5a575f80fd5b8201610160818503121561469a575f80fd5b5f805f60608486031215614a7e575f80fd5b505081359360208301359350604090920135919050565b5f8083601f840112614aa5575f80fd5b50813567ffffffffffffffff811115614abc575f80fd5b6020830191508360208260061b85010111156147ca575f80fd5b5f805f805f805f6080888a031215614aec575f80fd5b873567ffffffffffffffff811115614b02575f80fd5b614b0e8a828b01614a95565b909850965050602088013567ffffffffffffffff811115614b2d575f80fd5b614b398a828b01614a95565b909650945050604088013567ffffffffffffffff811115614b58575f80fd5b614b648a828b01614a95565b9094509250506060880135614b7881614715565b8091505092959891949750929550565b5f8060408385031215614b99575f80fd5b8235614ba481614715565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6020810160098310614c18577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b91905290565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115610f6a57610f6a614c1e565b80820180821115610f6a57610f6a614c1e565b818382375f9101908152919050565b8082028115828204841417610f6a57610f6a614c1e565b5f60208284031215614ca7575f80fd5b813561469a81614715565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614ce5575f80fd5b83018035915067ffffffffffffffff821115614cff575f80fd5b6020019150368190038213156147ca575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614d46575f80fd5b83018035915067ffffffffffffffff821115614d60575f80fd5b6020019150600581901b36038213156147ca575f80fd5b5f60208284031215614d87575f80fd5b813563ffffffff8116811461469a575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61833603018112614df9575f80fd5b9190910192915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405160a0810167ffffffffffffffff81118282101715614e5357614e53614e03565b60405290565b5f82601f830112614e68575f80fd5b813567ffffffffffffffff811115614e8257614e82614e03565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715614eb157614eb1614e03565b604052818152838201602001851015614ec8575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60a08236031215614ef4575f80fd5b614efc614e30565b82358152602083013567ffffffffffffffff811115614f19575f80fd5b614f2536828601614e59565b602083015250604083013567ffffffffffffffff811115614f44575f80fd5b614f5036828601614e59565b60408301525060608381013590820152608092830135928101929092525090565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614fa157614fa1614c1e565b5060010190565b81835281816020850137505f602082840101525f6020601f19601f840116840101905092915050565b858152846020820152836040820152608060608201525f614ff6608083018486614fa8565b979650505050505050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615034575f80fd5b83018035915067ffffffffffffffff82111561504e575f80fd5b6020019150600681901b36038213156147ca575f80fd5b604081525f615078604083018587614fa8565b82810360208401528084518083526020830191506020860192505f5b818110156150b2578351835260209384019390920191600101615094565b5090979650505050505050565b5f81518060208401855e5f93019283525090919050565b5f61469a82846150bf565b5f602082840312156150f1575f80fd5b8151801515811461469a575f80fd5b6001815b600184111561513b5780850481111561511f5761511f614c1e565b600184161561512d57908102905b60019390931c928002615104565b935093915050565b5f8261515157506001610f6a565b8161515d57505f610f6a565b8160018114615173576002811461517d57615199565b6001915050610f6a565b60ff84111561518e5761518e614c1e565b50506001821b610f6a565b5060208310610133831016604e8410600b84101617156151bc575081810a610f6a565b6151e77fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484615100565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561521957615219614c1e565b029392505050565b5f61469a8383615143565b5f8261525f577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500690565b8581528460208201528360408201525f614ff661528460608401866150bf565b846150bf565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f6152bb60178301856150bf565b7f206973206d697373696e6720726f6c652000000000000000000000000000000081526152eb60118201856150bf565b95945050505050565b5f8161530257615302614c1e565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea2646970667358221220f37ab9d49b246192cc1f4c0273d18fcd431dc83c67e6b7fb35993ccad3328d4e64736f6c634300081a0033", "linkReferences": {}, "deployedLinkReferences": {} } diff --git a/contracts/local-deployments-artifacts/dynamic-artifacts/TokenBridge.json b/contracts/local-deployments-artifacts/dynamic-artifacts/TokenBridge.json index 878f0dd7b..42a0081c1 100644 --- a/contracts/local-deployments-artifacts/dynamic-artifacts/TokenBridge.json +++ b/contracts/local-deployments-artifacts/dynamic-artifacts/TokenBridge.json @@ -160,6 +160,11 @@ "name": "SenderNotAuthorized", "type": "error" }, + { + "inputs": [], + "name": "SourceChainSameAsTargetChain", + "type": "error" + }, { "inputs": [ { @@ -203,6 +208,11 @@ "name": "ZeroAmountNotAllowed", "type": "error" }, + { + "inputs": [], + "name": "ZeroChainIdNotAllowed", + "type": "error" + }, { "inputs": [], "name": "ZeroHashNotAllowed", @@ -1472,8 +1482,8 @@ "type": "function" } ], - "bytecode": "0x60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e1576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6155b380620000f36000396000f3fe6080604052600436106200030b5760003560e01c806391d148541162000197578063ca41a24711620000e7578063d547741f1162000095578063e4d27451116200006c578063e4d2745114620009f3578063edc42a221462000a18578063fe3c50a01462000a3d57600080fd5b8063d547741f1462000992578063dfa96efb14620009b7578063e196fb5d14620009ce57600080fd5b8063ccf5a77c11620000ca578063ccf5a77c1462000914578063cdd914c51462000937578063cf4a7208146200095c57600080fd5b8063ca41a24714620008a5578063cc5782f614620008e057600080fd5b8063b3232bdf1162000145578063be46096f1162000128578063be46096f1462000814578063c483d8381462000839578063c986752a146200086f57600080fd5b8063b3232bdf14620007ca578063bc61e73314620007ef57600080fd5b8063a217fddf116200017a578063a217fddf146200076c578063a676e8ab1462000783578063a6ef995f14620007a857600080fd5b806391d1485414620006ec5780639ac25d08146200073657600080fd5b80632f2ff15d116200025f578063522ea81a116200020d5780636a906b8011620001e45780636a906b80146200065e57806380efb43a14620006945780638dae45dd14620006ca57600080fd5b8063522ea81a14620005db5780635626fc2514620005f25780635a06a42a146200062857600080fd5b806336568abe116200024257806336568abe146200054557806338b90333146200056a5780634bf98dce14620005c457600080fd5b80632f2ff15d14620004ea5780633551237b146200050f57600080fd5b80631544298e11620002bd578063248a9ca311620002a0578063248a9ca3146200045b5780632a564f34146200048f5780632e4c3fff14620004b457600080fd5b80631544298e146200041d5780631754f301146200043657600080fd5b80630f6f86ec11620002f25780630f6f86ec14620003715780631065a39914620003d0578063146ffb2614620003f557600080fd5b806301941d39146200031057806301ffc9a71462000337575b600080fd5b3480156200031d57600080fd5b50620003356200032f36600462004212565b62000a73565b005b3480156200034457600080fd5b506200035c62000356366004620042cb565b62000c0a565b60405190151581526020015b60405180910390f35b3480156200037e57600080fd5b50620003b7620003903660046200430f565b6101086020908152600092835260408084209091529082529020546001600160a01b031681565b6040516001600160a01b03909116815260200162000368565b348015620003dd57600080fd5b5062000335620003ef36600462004342565b62000ca4565b3480156200040257600080fd5b506200040e61010b5481565b60405190815260200162000368565b3480156200042a57600080fd5b506200040e61010a5481565b3480156200044357600080fd5b50620003356200045536600462004365565b62000dad565b3480156200046857600080fd5b506200040e6200047a36600462004398565b60009081526097602052604090206001015490565b3480156200049c57600080fd5b5062000335620004ae366004620043b2565b620010a8565b348015620004c157600080fd5b506200040e7f8a7b208fd13ab36d18025be4f62b53d46aeb2cbe8958d2e13de74c040dddcddd81565b348015620004f757600080fd5b5062000335620005093660046200430f565b620012c7565b3480156200051c57600080fd5b506200040e7f19bf281d118073c159a713666aba52e0d403520cd01e03f42e0f62a0b3bd4a3581565b3480156200055257600080fd5b5062000335620005643660046200430f565b620012f5565b3480156200057757600080fd5b50620005b56040518060400160405280600381526020017f312e30000000000000000000000000000000000000000000000000000000000081525081565b60405162000368919062004480565b62000335620005d5366004620044f8565b62001385565b62000335620005ec366004620045b7565b620015f4565b348015620005ff57600080fd5b506200040e7f46e34517dc946faf87aabe65eb5b4fa06b974e5c8d72c5df73b9fb6ff7b6d80281565b3480156200063557600080fd5b506200040e7f50962b2d10066f5051f78d5ea04a3ab09b9c87dd1002962f0b1e30e66eeb80a581565b3480156200066b57600080fd5b506200040e7fd8b4c34c2ec1f3194471108c64ad2beda340c0337ee4ca35592f9ef270f4228b81565b348015620006a157600080fd5b506200040e7fbf094fe3c005c553ff0d33c7dff9d1273add12fb3f258b992f8d36224dd35b2481565b348015620006d757600080fd5b5060c954620003b7906001600160a01b031681565b348015620006f957600080fd5b506200035c6200070b3660046200430f565b60009182526097602090815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156200074357600080fd5b506200040e7f56bdc3c9ec86cb7db110a7699b2ade72f0b8819727d9f7d906b012641505fa7781565b3480156200077957600080fd5b506200040e600081565b3480156200079057600080fd5b5062000335620007a2366004620045fe565b62001ba2565b348015620007b557600080fd5b5060ca54620003b7906001600160a01b031681565b348015620007d757600080fd5b5062000335620007e93660046200461e565b62001c67565b348015620007fc57600080fd5b506200035c6200080e36600462004342565b620020c5565b3480156200082157600080fd5b506200033562000833366004620045fe565b620020ed565b3480156200084657600080fd5b506200040e7feaf25fcc6b7d45bda16c56628df3f435e20319ef53b065c11ee4510083f0ae2d81565b3480156200087c57600080fd5b506200040e7f550554a677c8e7b73b62db78b0ef06c5f237da4ef30b88196a899ccf591041fe81565b348015620008b257600080fd5b50620003b7620008c4366004620045fe565b610109602052600090815260409020546001600160a01b031681565b348015620008ed57600080fd5b506200035c620008ff36600462004398565b60d56020526000908152604090205460ff1681565b3480156200092157600080fd5b5061010754620003b7906001600160a01b031681565b3480156200094457600080fd5b506200033562000956366004620045fe565b620021b0565b3480156200096957600080fd5b506200040e7f3900d9d72d5177a154375317154fdc0e08377e3134a8a5d21cadccf831cc231c81565b3480156200099f57600080fd5b5062000335620009b13660046200430f565b6200231b565b62000335620009c8366004620046a2565b62002344565b348015620009db57600080fd5b5062000335620009ed36600462004342565b6200236c565b34801562000a0057600080fd5b506200033562000a123660046200471d565b6200245a565b34801562000a2557600080fd5b506200033562000a37366004620045fe565b6200279d565b34801562000a4a57600080fd5b506200040e7f77974cc9cb5bafc9bb265be792d93fa46355c05701895b82f6d3b4b448c8ce0081565b600054600290610100900460ff1615801562000a96575060005460ff8083169116105b62000b0e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001790556001600160a01b03881662000b67576040516342bcdf7f60e11b815260040160405180910390fd5b62000b74600089620028d9565b6000606555600060d55562000b886200299b565b62000b968585858562002a26565b62000ba2878762002d0c565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148062000c9e57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60d8600082600881111562000cbd5762000cbd620047a1565b600881111562000cd15762000cd1620047a1565b81526020019081526020016000205462000ceb8162002eae565b62000cf682620020c5565b62000d3157816040517f1865965400000000000000000000000000000000000000000000000000000000815260040162000b059190620047d0565b81600881111562000d465762000d46620047a1565b60d68054600190921b19909116905581600881111562000d6a5762000d6a620047a1565b7fd071d2b85dec4489435b541d2f0e2570db09b09db9efd8703948d44a433df65a335b6040516001600160a01b0390911681526020015b60405180910390a25050565b816001600160a01b03811662000dd6576040516342bcdf7f60e11b815260040160405180910390fd5b816001600160a01b03811662000dff576040516342bcdf7f60e11b815260040160405180910390fd5b7f550554a677c8e7b73b62db78b0ef06c5f237da4ef30b88196a899ccf591041fe62000e2b8162002eae565b6001600160a01b038086166000908152610109602052604090205486911615158062000e7f575061010a546000908152610108602090815260408083206001600160a01b0385811685529252909120541615155b1562000ec3576040517f12f3df090000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260240162000b05565b6001600160a01b0385811660009081526101096020526040902054161562000f23576040517ff8fb7c270000000000000000000000000000000000000000000000000000000081526001600160a01b038616600482015260240162000b05565b6001600160a01b038516610222148062000f4757506001600160a01b038516610333145b8062000f5d57506001600160a01b038516610111145b1562000fa1576040517fd8ce8acb0000000000000000000000000000000000000000000000000000000081526001600160a01b038616600482015260240162000b05565b61010b546000818152610108602090815260408083206001600160a01b038b8116855292529091205416156200100f576040517f022bc8410000000000000000000000000000000000000000000000000000000081526001600160a01b038816600482015260240162000b05565b6000818152610108602090815260408083206001600160a01b03808c168086529184528285208054918c167fffffffffffffffffffffffff00000000000000000000000000000000000000009283168117909155808652610109909452828520805490911682179055905133937f844cb5c635052898ad92bea4ece14519111765d835105e76aa1f77ad0d0aa81f91a450505050505050565b60c9546001600160a01b03163314620010ed576040517f8c56efb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ca5460c954604080517f67e404ce00000000000000000000000000000000000000000000000000000000815290516001600160a01b0393841693909216916367e404ce916004808201926020929091908290030181865afa15801562001158573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200117e919062004812565b6001600160a01b031614620011bf576040517f79d1e58f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61010a5460005b82811015620012c15760008281526101086020526040812061033391868685818110620011f757620011f762004832565b90506020020160208101906200120e9190620045fe565b6001600160a01b039081168252602082019290925260400160002080547fffffffffffffffffffffffff000000000000000000000000000000000000000016929091169190911790558383828181106200126c576200126c62004832565b9050602002016020810190620012839190620045fe565b6001600160a01b03167f91d24864a084ab70b268a1f865e757ca12006cf298d763b6be697302ef86498c60405160405180910390a2600101620011c6565b50505050565b600082815260976020526040902060010154620012e48162002eae565b620012f08383620028d9565b505050565b6001600160a01b0381163314620013755760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c660000000000000000000000000000000000606482015260840162000b05565b62001381828262002ebd565b5050565b80516000819003620013c3576040517f10cbd58300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015620014bf5760006101096000858481518110620013eb57620013eb62004832565b6020908102919091018101516001600160a01b0390811683529082019290925260400160002054169050806200147b5783828151811062001430576200143062004832565b60200260200101516040517fa5ea89da00000000000000000000000000000000000000000000000000000000815260040162000b0591906001600160a01b0391909116815260200190565b8084838151811062001491576200149162004832565b6001600160a01b03909216602092830291909101909101525080620014b68162004890565b915050620013c6565b5060c95460ca546040516001600160a01b0392831692639f3ce55a9234929116908290620014f2908890602401620048cb565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f2a564f3400000000000000000000000000000000000000000000000000000000179052517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815262001585939291906004016200491a565b6000604051808303818588803b1580156200159f57600080fd5b505af1158015620015b4573d6000803e3d6000fd5b5050505050336001600160a01b03167f59eab5b5f813ac9e0c10035dfb55b5e3419eff53c0f7a869fb3c22400ea036d68360405162000da19190620048cb565b826001600160a01b0381166200161d576040516342bcdf7f60e11b815260040160405180910390fd5b816001600160a01b03811662001646576040516342bcdf7f60e11b815260040160405180910390fd5b838060000362001686576040517f4618044a0000000000000000000000000000000000000000000000000000000081526004810182905260240162000b05565b6200169062002f5f565b6200169c600762002fba565b61010a546000818152610108602090815260408083206001600160a01b03808c168552925290912054167ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeef81016200172c576040517f6dad9c780000000000000000000000000000000000000000000000000000000081526001600160a01b038916600482015260240162000b05565b6001600160a01b03808916600090815261010960205260408120549091169060608215620017db576040517f9dc29fac000000000000000000000000000000000000000000000000000000008152336004820152602481018b90526001600160a01b038c1690639dc29fac90604401600060405180830381600087803b158015620017b657600080fd5b505af1158015620017cb573d6000803e3d6000fd5b5050505061010b54915062001a15565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000906001600160a01b038d16906370a0823190602401602060405180830381865afa1580156200183c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200186291906200494d565b90506200187b6001600160a01b038d1633308e62003055565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038e16906370a0823190602401602060405180830381865afa158015620018db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200190191906200494d565b6200190d919062004967565b9a508b93506001600160a01b038516620019b657610222610108600088815260200190815260200160002060008e6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508b6001600160a01b03167f0f53e2a811b6fd2d6cd965fd6c27b44fb924ca39f7a7f321115705c22366d62360405160405180910390a25b6001600160a01b0385166103331462001a1057620019d48c62003108565b620019df8d6200321b565b620019ea8e6200331b565b604051602001620019fe939291906200497d565b60405160208183030381529060405291505b859250505b60c960009054906101000a90046001600160a01b03166001600160a01b0316639f3ce55a3460ca60009054906101000a90046001600160a01b031634878f8f898960405160240162001a6c959493929190620049ba565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe4d2745100000000000000000000000000000000000000000000000000000000179052517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815262001aff939291906004016200491a565b6000604051808303818588803b15801562001b1957600080fd5b505af115801562001b2e573d6000803e3d6000fd5b50505050508a6001600160a01b0316896001600160a01b0316336001600160a01b03167f8780a94875b70464f8ac6c28851501d32e7fd4ee574e4b94beb28923a3c42d9c8d60405162001b8391815260200190565b60405180910390a4505050505062001b9a60018055565b505050505050565b7fbf094fe3c005c553ff0d33c7dff9d1273add12fb3f258b992f8d36224dd35b2462001bce8162002eae565b60ca546001600160a01b03161562001c225760ca546040517f94fbfd2e0000000000000000000000000000000000000000000000000000000081526001600160a01b03909116600482015260240162000b05565b62001c2d8262003447565b60405133906001600160a01b038416907fb044c1a1a05a729c402def784b4e4cb01612ff03eee6f0beb3eba0f0606260a190600090a35050565b62001c796040820160208301620045fe565b6001600160a01b03811662001ca1576040516342bcdf7f60e11b815260040160405180910390fd5b62001cb36060830160408401620045fe565b6001600160a01b03811662001cdb576040516342bcdf7f60e11b815260040160405180910390fd5b600054610100900460ff161580801562001cfc5750600054600160ff909116105b8062001d185750303b15801562001d18575060005460ff166001145b62001d8c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840162000b05565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801562001deb57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b62001e1462001dfe60e0860186620049f4565b62001e0e610100880188620049f4565b62002a26565b62001e3062001e2a6040860160208701620045fe565b620034d4565b62001e3a6200299b565b62001e55600062001e4f6020870187620045fe565b620028d9565b62001e6e62001e6860c0860186620049f4565b62002d0c565b62001e806060850160408601620045fe565b61010780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055606084013561010a55608084013561010b5560005b62001edd60a086018662004a5f565b90508110156200205b57600062001ef860a087018762004a5f565b8381811062001f0b5762001f0b62004832565b905060200201602081019062001f229190620045fe565b6001600160a01b03160362001f4a576040516342bcdf7f60e11b815260040160405180910390fd5b60608501356000908152610108602052604081206101119162001f7160a089018962004a5f565b8581811062001f845762001f8462004832565b905060200201602081019062001f9b9190620045fe565b6001600160a01b039081168252602082019290925260400160002080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169290911691909117905562001ff360a086018662004a5f565b8281811062002006576200200662004832565b90506020020160208101906200201d9190620045fe565b6001600160a01b03167f5e023c7a09fa0534ce3199f65fc3e635a5e851c5adc88ebda3b9d332ae07cbe960405160405180910390a260010162001ece565b508015620012c157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050565b6000816008811115620020dc57620020dc620047a1565b60d654600190911b16151592915050565b806001600160a01b03811662002116576040516342bcdf7f60e11b815260040160405180910390fd5b7f77974cc9cb5bafc9bb265be792d93fa46355c05701895b82f6d3b4b448c8ce00620021428162002eae565b60c980546001600160a01b038581167fffffffffffffffffffffffff00000000000000000000000000000000000000008316811790935560405191169133918391907fc96d462e42a71473da49a1d58c1754b9b2d319786692d621dc7f921331c517e990600090a450505050565b806001600160a01b038116620021d9576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b03808316600090815261010960205260409020548391161515806200222d575061010a546000908152610108602090815260408083206001600160a01b0385811685529252909120541615155b1562002271576040517f12f3df090000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260240162000b05565b7feaf25fcc6b7d45bda16c56628df3f435e20319ef53b065c11ee4510083f0ae2d6200229d8162002eae565b61010a546000908152610108602090815260408083206001600160a01b038816808552925280832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166101111790555190917f5e023c7a09fa0534ce3199f65fc3e635a5e851c5adc88ebda3b9d332ae07cbe991a250505050565b600082815260976020526040902060010154620023388162002eae565b620012f0838362002ebd565b8015620023585762002358858383620035b5565b62002365858585620015f4565b5050505050565b60d76000826008811115620023855762002385620047a1565b6008811115620023995762002399620047a1565b815260200190815260200160002054620023b38162002eae565b620023be82620020c5565b15620023fa57816040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040162000b059190620047d0565b8160088111156200240f576200240f620047a1565b60d68054600190921b9091179055816008811115620024325762002432620047a1565b7f534f879afd40abb4e39f8e1b77a316be4c8e3521d9cf5a3a3db8959d574d45593362000d8d565b6200246462002f5f565b60c9546001600160a01b03163314620024a9576040517f8c56efb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ca5460c954604080517f67e404ce00000000000000000000000000000000000000000000000000000000815290516001600160a01b0393841693909216916367e404ce916004808201926020929091908290030181865afa15801562002514573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200253a919062004812565b6001600160a01b0316146200257b576040517f79d1e58f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6008620025888162002fba565b6000848152610108602090815260408083206001600160a01b03808c16855292528220541690610222821480620025c957506001600160a01b038216610333145b15620025eb57620025e56001600160a01b038a16888a620038d1565b62002738565b50806001600160a01b038116620026ba576200260d89868661010a546200391c565b9050886101096000836001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555080610108600061010b54815260200190815260200160002060008b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b038881166004830152602482018a90528216906340c10f1990604401600060405180830381600087803b1580156200271e57600080fd5b505af115801562002733573d6000803e3d6000fd5b505050505b866001600160a01b0316816001600160a01b03168a6001600160a01b03167f6ed06519caca659cdefa71015c79a561928d3cf8cc4a3e9739fde9fb5fb38d648b6040516200278891815260200190565b60405180910390a450505062001b9a60018055565b806001600160a01b038116620027c6576040516342bcdf7f60e11b815260040160405180910390fd5b7f19bf281d118073c159a713666aba52e0d403520cd01e03f42e0f62a0b3bd4a35620027f28162002eae565b61010a546000818152610108602090815260408083206001600160a01b038881168552925290912054166101111462002863576040517f82f5d0a50000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240162000b05565b6000818152610108602090815260408083206001600160a01b038816808552925280832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555190917f0145163d8d460d1ab21463758d147fdfe79d4b57c81ca3d1439996104ae6895991a250505050565b60008281526097602090815260408083206001600160a01b038516845290915290205460ff16620013815760008281526097602090815260408083206001600160a01b0385168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055620029573390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600054610100900460ff1662002a1a5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b62002a2462003a4c565b565b600054610100900460ff1662002aa55760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b60005b8381101562002bd85784848281811062002ac65762002ac662004832565b9050604002016020013560d7600087878581811062002ae95762002ae962004832565b62002b01926020604090920201908101915062004342565b600881111562002b155762002b15620047a1565b600881111562002b295762002b29620047a1565b815260208101919091526040016000205584848281811062002b4f5762002b4f62004832565b9050604002016020013585858381811062002b6e5762002b6e62004832565b62002b86926020604090920201908101915062004342565b600881111562002b9a5762002b9a620047a1565b6040517f33aa8fd1ce49e1761bc8d27fd53414bfefc45d690feed0ce55019d7d3aec609190600090a38062002bcf8162004890565b91505062002aa8565b5060005b81811015620023655782828281811062002bfa5762002bfa62004832565b9050604002016020013560d8600085858581811062002c1d5762002c1d62004832565b62002c35926020604090920201908101915062004342565b600881111562002c495762002c49620047a1565b600881111562002c5d5762002c5d620047a1565b815260208101919091526040016000205582828281811062002c835762002c8362004832565b9050604002016020013583838381811062002ca25762002ca262004832565b62002cba926020604090920201908101915062004342565b600881111562002cce5762002cce620047a1565b6040517fe7bf4b8dc0c17a52dc9e52323a3ab61cb2079db35f969125b1f8a3d984c6f6c290600090a38062002d038162004890565b91505062002bdc565b600054610100900460ff1662002d8b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b60005b81811015620012f057600083838381811062002dae5762002dae62004832565b62002dc69260206040909202019081019150620045fe565b6001600160a01b03160362002dee576040516342bcdf7f60e11b815260040160405180910390fd5b82828281811062002e035762002e0362004832565b905060400201602001356000801b0362002e49576040517f0742d05300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62002e9983838381811062002e625762002e6262004832565b9050604002016020013584848481811062002e815762002e8162004832565b62001e4f9260206040909202019081019150620045fe565b8062002ea58162004890565b91505062002d8e565b62002eba813362003acb565b50565b60008281526097602090815260408083206001600160a01b038516845290915290205460ff1615620013815760008281526097602090815260408083206001600160a01b038516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60026001540362002fb35760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640162000b05565b6002600155565b60d65481600881111562002fd25762002fd2620047a1565b6001901b8116156200301457816040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040162000b059190620047d0565b6002811615620013815760016040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040162000b059190620047d0565b6040516001600160a01b0380851660248301528316604482015260648101829052620012c19085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915262003b49565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f06fdde0300000000000000000000000000000000000000000000000000000000179052905160609160009182916001600160a01b038616916200317f919062004aca565b600060405180830381855afa9150503d8060008114620031bc576040519150601f19603f3d011682016040523d82523d6000602084013e620031c1565b606091505b50915091508162003208576040518060400160405280600781526020017f4e4f5f4e414d450000000000000000000000000000000000000000000000000081525062003213565b620032138162003c38565b949350505050565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f95d89b4100000000000000000000000000000000000000000000000000000000179052905160609160009182916001600160a01b0386169162003292919062004aca565b600060405180830381855afa9150503d8060008114620032cf576040519150601f19603f3d011682016040523d82523d6000602084013e620032d4565b606091505b50915091508162003208576040518060400160405280600981526020017f4e4f5f53594d424f4c000000000000000000000000000000000000000000000081525062003213565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f313ce567000000000000000000000000000000000000000000000000000000001790529051600091829182916001600160a01b0386169162003391919062004aca565b600060405180830381855afa9150503d8060008114620033ce576040519150601f19603f3d011682016040523d82523d6000602084013e620033d3565b606091505b5091509150818015620033e7575060208151145b1562003403578080602001905181019062003213919062004af8565b6040517fb5a2f1c60000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240162000b05565b60018055565b6001600160a01b0381166200346f576040516342bcdf7f60e11b815260040160405180910390fd5b60ca80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040513391907fe68b208814fdb633b222cd15e73d5a27fb4ef9eef4cae78c623bc27702141d2890600090a350565b600054610100900460ff16620035535760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b6001600160a01b0381166200357b576040516342bcdf7f60e11b815260040160405180910390fd5b60c980547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b7fd505accf00000000000000000000000000000000000000000000000000000000620035e660046000848662004b18565b620035f19162004b44565b7fffffffff000000000000000000000000000000000000000000000000000000001614620036b2576200362960046000838562004b18565b620036349162004b44565b6040517fcf9e29460000000000000000000000000000000000000000000000000000000081527fffffffff0000000000000000000000000000000000000000000000000000000090911660048201527fd505accf00000000000000000000000000000000000000000000000000000000602482015260440162000b05565b6000808080808080620036c9886004818c62004b18565b810190620036d8919062004b8d565b9650965096509650965096509650336001600160a01b0316876001600160a01b0316146200373e576040517f200688cc0000000000000000000000000000000000000000000000000000000081526001600160a01b038816600482015260240162000b05565b6001600160a01b03861630146200378d576040517f291159480000000000000000000000000000000000000000000000000000000081526001600160a01b038716600482015260240162000b05565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015287811660248301528691908c169063dd62ed3e90604401602060405180830381865afa158015620037f8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200381e91906200494d565b1015620038c5576040517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018690526064810185905260ff8416608482015260a4810183905260c481018290526001600160a01b038b169063d505accf9060e401600060405180830381600087803b158015620038ab57600080fd5b505af1158015620038c0573d6000803e3d6000fd5b505050505b50505050505050505050565b6040516001600160a01b038316602482015260448101829052620012f09084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401620030a3565b6000818152602085905260408120610107546040516001600160a01b039091169062003948906200419f565b6001600160a01b0390911681526040602082018190526000908201526060018190604051809103906000f590508015801562003988573d6000803e3d6000fd5b509050600080806200399d8688018862004c8c565b925092509250836001600160a01b0316631624f6c68484846040518463ffffffff1660e01b8152600401620039d5939291906200497d565b600060405180830381600087803b158015620039f057600080fd5b505af115801562003a05573d6000803e3d6000fd5b50506040516001600160a01b03808c169350871691507fd5d4920bb61e6141c8499d50a7bd617dae2b1818c9d6b995d3f2ba4975e32ea490600090a3505050949350505050565b600054610100900460ff16620034415760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b60008281526097602090815260408083206001600160a01b038516845290915290205460ff16620013815762003b018162003e0b565b62003b0e83602062003e1e565b60405160200162003b2192919062004d02565b60408051601f198184030181529082905262461bcd60e51b825262000b059160040162004480565b600062003ba0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200406c9092919063ffffffff16565b905080516000148062003bc457508080602001905181019062003bc4919062004d87565b620012f05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840162000b05565b6060604082511062003c5a578180602001905181019062000c9e919062004dab565b602082511462003c9d57505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e470000000000000000000000000000602082015290565b60005b60208110801562003ceb575082818151811062003cc15762003cc162004832565b01602001517fff000000000000000000000000000000000000000000000000000000000000001615155b1562003cfa5760010162003ca0565b8060000362003d3e57505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e4700000000000000000000000000006020820152919050565b60008167ffffffffffffffff81111562003d5c5762003d5c62004495565b6040519080825280601f01601f19166020018201604052801562003d87576020820181803683370190505b50905060005b8281101562003e035784818151811062003dab5762003dab62004832565b602001015160f81c60f81b82828151811062003dcb5762003dcb62004832565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060010162003d8d565b509392505050565b606062000c9e6001600160a01b03831660145b6060600062003e2f83600262004e22565b62003e3c90600262004e3c565b67ffffffffffffffff81111562003e575762003e5762004495565b6040519080825280601f01601f19166020018201604052801562003e82576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811062003ebc5762003ebc62004832565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811062003f225762003f2262004832565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600062003f6084600262004e22565b62003f6d90600162004e3c565b90505b600181111562004014577f303132333435363738396162636465660000000000000000000000000000000085600f166010811062003fb25762003fb262004832565b1a60f81b82828151811062003fcb5762003fcb62004832565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c936200400c8162004e52565b905062003f70565b508315620040655760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640162000b05565b9392505050565b606062003213848460008585600080866001600160a01b0316858760405162004096919062004aca565b60006040518083038185875af1925050503d8060008114620040d5576040519150601f19603f3d011682016040523d82523d6000602084013e620040da565b606091505b5091509150620040ed87838387620040f8565b979650505050505050565b606083156200416c57825160000362004164576001600160a01b0385163b620041645760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000b05565b508162003213565b620032138383815115620041835781518083602001fd5b8060405162461bcd60e51b815260040162000b05919062004480565b6106f38062004e8b83390190565b6001600160a01b038116811462002eba57600080fd5b60008083601f840112620041d657600080fd5b50813567ffffffffffffffff811115620041ef57600080fd5b6020830191508360208260061b85010111156200420b57600080fd5b9250929050565b60008060008060008060006080888a0312156200422e57600080fd5b87356200423b81620041ad565b9650602088013567ffffffffffffffff808211156200425957600080fd5b620042678b838c01620041c3565b909850965060408a01359150808211156200428157600080fd5b6200428f8b838c01620041c3565b909650945060608a0135915080821115620042a957600080fd5b50620042b88a828b01620041c3565b989b979a50959850939692959293505050565b600060208284031215620042de57600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146200406557600080fd5b600080604083850312156200432357600080fd5b8235915060208301356200433781620041ad565b809150509250929050565b6000602082840312156200435557600080fd5b8135600981106200406557600080fd5b600080604083850312156200437957600080fd5b82356200438681620041ad565b915060208301356200433781620041ad565b600060208284031215620043ab57600080fd5b5035919050565b60008060208385031215620043c657600080fd5b823567ffffffffffffffff80821115620043df57600080fd5b818501915085601f830112620043f457600080fd5b8135818111156200440457600080fd5b8660208260051b85010111156200441a57600080fd5b60209290920196919550909350505050565b60005b83811015620044495781810151838201526020016200442f565b50506000910152565b600081518084526200446c8160208601602086016200442c565b601f01601f19169290920160200192915050565b60208152600062004065602083018462004452565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715620044f057620044f062004495565b604052919050565b600060208083850312156200450c57600080fd5b823567ffffffffffffffff808211156200452557600080fd5b818501915085601f8301126200453a57600080fd5b8135818111156200454f576200454f62004495565b8060051b915062004562848301620044c4565b81815291830184019184810190888411156200457d57600080fd5b938501935b83851015620045ab57843592506200459a83620041ad565b828252938501939085019062004582565b98975050505050505050565b600080600060608486031215620045cd57600080fd5b8335620045da81620041ad565b9250602084013591506040840135620045f381620041ad565b809150509250925092565b6000602082840312156200461157600080fd5b81356200406581620041ad565b6000602082840312156200463157600080fd5b813567ffffffffffffffff8111156200464957600080fd5b820161012081850312156200406557600080fd5b60008083601f8401126200467057600080fd5b50813567ffffffffffffffff8111156200468957600080fd5b6020830191508360208285010111156200420b57600080fd5b600080600080600060808688031215620046bb57600080fd5b8535620046c881620041ad565b9450602086013593506040860135620046e181620041ad565b9250606086013567ffffffffffffffff811115620046fe57600080fd5b6200470c888289016200465d565b969995985093965092949392505050565b60008060008060008060a087890312156200473757600080fd5b86356200474481620041ad565b95506020870135945060408701356200475d81620041ad565b935060608701359250608087013567ffffffffffffffff8111156200478157600080fd5b6200478f89828a016200465d565b979a9699509497509295939492505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208101600983106200480c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b6000602082840312156200482557600080fd5b81516200406581620041ad565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203620048c457620048c462004861565b5060010190565b6020808252825182820181905260009190848201906040850190845b818110156200490e5783516001600160a01b031683529284019291840191600101620048e7565b50909695505050505050565b6001600160a01b038416815282602082015260606040820152600062004944606083018462004452565b95945050505050565b6000602082840312156200496057600080fd5b5051919050565b8181038181111562000c9e5762000c9e62004861565b60608152600062004992606083018662004452565b8281036020840152620049a6818662004452565b91505060ff83166040830152949350505050565b60006001600160a01b03808816835286602084015280861660408401525083606083015260a06080830152620040ed60a083018462004452565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811262004a2a57600080fd5b83018035915067ffffffffffffffff82111562004a4657600080fd5b6020019150600681901b36038213156200420b57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811262004a9557600080fd5b83018035915067ffffffffffffffff82111562004ab157600080fd5b6020019150600581901b36038213156200420b57600080fd5b6000825162004ade8184602087016200442c565b9190910192915050565b60ff8116811462002eba57600080fd5b60006020828403121562004b0b57600080fd5b8151620040658162004ae8565b6000808585111562004b2957600080fd5b8386111562004b3757600080fd5b5050820193919092039150565b7fffffffff00000000000000000000000000000000000000000000000000000000813581811691600485101562004b855780818660040360031b1b83161692505b505092915050565b600080600080600080600060e0888a03121562004ba957600080fd5b873562004bb681620041ad565b9650602088013562004bc881620041ad565b95506040880135945060608801359350608088013562004be88162004ae8565b9699959850939692959460a0840135945060c09093013592915050565b600067ffffffffffffffff82111562004c225762004c2262004495565b50601f01601f191660200190565b600082601f83011262004c4257600080fd5b813562004c5962004c538262004c05565b620044c4565b81815284602083860101111562004c6f57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121562004ca257600080fd5b833567ffffffffffffffff8082111562004cbb57600080fd5b62004cc98783880162004c30565b9450602086013591508082111562004ce057600080fd5b5062004cef8682870162004c30565b9250506040840135620045f38162004ae8565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835162004d3c8160178501602088016200442c565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000601791840191820152835162004d7b8160288401602088016200442c565b01602801949350505050565b60006020828403121562004d9a57600080fd5b815180151581146200406557600080fd5b60006020828403121562004dbe57600080fd5b815167ffffffffffffffff81111562004dd657600080fd5b8201601f8101841362004de857600080fd5b805162004df962004c538262004c05565b81815285602083850101111562004e0f57600080fd5b620049448260208301602086016200442c565b808202811582820484141762000c9e5762000c9e62004861565b8082018082111562000c9e5762000c9e62004861565b60008162004e645762004e6462004861565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fe60806040526040516106f33803806106f383398101604081905261002291610420565b61002e82826000610035565b505061054a565b61003e836100f6565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100f1576100ef836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e991906104e0565b8361027a565b505b505050565b6001600160a01b0381163b6101605760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101d4816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101c591906104e0565b6001600160a01b03163b151590565b6102395760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610157565b7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b0392909216919091179055565b606061029f83836040518060600160405280602781526020016106cc602791396102a6565b9392505050565b6060600080856001600160a01b0316856040516102c391906104fb565b600060405180830381855af49150503d80600081146102fe576040519150601f19603f3d011682016040523d82523d6000602084013e610303565b606091505b5090925090506103158683838761031f565b9695505050505050565b6060831561038e578251600003610387576001600160a01b0385163b6103875760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610157565b5081610398565b61039883836103a0565b949350505050565b8151156103b05781518083602001fd5b8060405162461bcd60e51b81526004016101579190610517565b80516001600160a01b03811681146103e157600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b838110156104175781810151838201526020016103ff565b50506000910152565b6000806040838503121561043357600080fd5b61043c836103ca565b60208401519092506001600160401b038082111561045957600080fd5b818501915085601f83011261046d57600080fd5b81518181111561047f5761047f6103e6565b604051601f8201601f19908116603f011681019083821181831017156104a7576104a76103e6565b816040528281528860208487010111156104c057600080fd5b6104d18360208301602088016103fc565b80955050505050509250929050565b6000602082840312156104f257600080fd5b61029f826103ca565b6000825161050d8184602087016103fc565b9190910192915050565b60208152600082518060208401526105368160408501602087016103fc565b601f01601f19169190910160400192915050565b610173806105596000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610029565b6100dc565b565b60006100697fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d505473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100d79190610100565b905090565b3660008037600080366000845af43d6000803e8080156100fb573d6000f35b3d6000fd5b60006020828403121561011257600080fd5b815173ffffffffffffffffffffffffffffffffffffffff8116811461013657600080fd5b939250505056fea2646970667358221220662c40b76fc0d477a291a78deacd27f4cddd7512dea18087244e38acb2fd99dd64736f6c63430008130033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122008b6c34a5d8997b54caed58d53678d49279942ee4709ef64c362fdb42f961e2064736f6c63430008130033", - "deployedBytecode": "0x6080604052600436106200030b5760003560e01c806391d148541162000197578063ca41a24711620000e7578063d547741f1162000095578063e4d27451116200006c578063e4d2745114620009f3578063edc42a221462000a18578063fe3c50a01462000a3d57600080fd5b8063d547741f1462000992578063dfa96efb14620009b7578063e196fb5d14620009ce57600080fd5b8063ccf5a77c11620000ca578063ccf5a77c1462000914578063cdd914c51462000937578063cf4a7208146200095c57600080fd5b8063ca41a24714620008a5578063cc5782f614620008e057600080fd5b8063b3232bdf1162000145578063be46096f1162000128578063be46096f1462000814578063c483d8381462000839578063c986752a146200086f57600080fd5b8063b3232bdf14620007ca578063bc61e73314620007ef57600080fd5b8063a217fddf116200017a578063a217fddf146200076c578063a676e8ab1462000783578063a6ef995f14620007a857600080fd5b806391d1485414620006ec5780639ac25d08146200073657600080fd5b80632f2ff15d116200025f578063522ea81a116200020d5780636a906b8011620001e45780636a906b80146200065e57806380efb43a14620006945780638dae45dd14620006ca57600080fd5b8063522ea81a14620005db5780635626fc2514620005f25780635a06a42a146200062857600080fd5b806336568abe116200024257806336568abe146200054557806338b90333146200056a5780634bf98dce14620005c457600080fd5b80632f2ff15d14620004ea5780633551237b146200050f57600080fd5b80631544298e11620002bd578063248a9ca311620002a0578063248a9ca3146200045b5780632a564f34146200048f5780632e4c3fff14620004b457600080fd5b80631544298e146200041d5780631754f301146200043657600080fd5b80630f6f86ec11620002f25780630f6f86ec14620003715780631065a39914620003d0578063146ffb2614620003f557600080fd5b806301941d39146200031057806301ffc9a71462000337575b600080fd5b3480156200031d57600080fd5b50620003356200032f36600462004212565b62000a73565b005b3480156200034457600080fd5b506200035c62000356366004620042cb565b62000c0a565b60405190151581526020015b60405180910390f35b3480156200037e57600080fd5b50620003b7620003903660046200430f565b6101086020908152600092835260408084209091529082529020546001600160a01b031681565b6040516001600160a01b03909116815260200162000368565b348015620003dd57600080fd5b5062000335620003ef36600462004342565b62000ca4565b3480156200040257600080fd5b506200040e61010b5481565b60405190815260200162000368565b3480156200042a57600080fd5b506200040e61010a5481565b3480156200044357600080fd5b50620003356200045536600462004365565b62000dad565b3480156200046857600080fd5b506200040e6200047a36600462004398565b60009081526097602052604090206001015490565b3480156200049c57600080fd5b5062000335620004ae366004620043b2565b620010a8565b348015620004c157600080fd5b506200040e7f8a7b208fd13ab36d18025be4f62b53d46aeb2cbe8958d2e13de74c040dddcddd81565b348015620004f757600080fd5b5062000335620005093660046200430f565b620012c7565b3480156200051c57600080fd5b506200040e7f19bf281d118073c159a713666aba52e0d403520cd01e03f42e0f62a0b3bd4a3581565b3480156200055257600080fd5b5062000335620005643660046200430f565b620012f5565b3480156200057757600080fd5b50620005b56040518060400160405280600381526020017f312e30000000000000000000000000000000000000000000000000000000000081525081565b60405162000368919062004480565b62000335620005d5366004620044f8565b62001385565b62000335620005ec366004620045b7565b620015f4565b348015620005ff57600080fd5b506200040e7f46e34517dc946faf87aabe65eb5b4fa06b974e5c8d72c5df73b9fb6ff7b6d80281565b3480156200063557600080fd5b506200040e7f50962b2d10066f5051f78d5ea04a3ab09b9c87dd1002962f0b1e30e66eeb80a581565b3480156200066b57600080fd5b506200040e7fd8b4c34c2ec1f3194471108c64ad2beda340c0337ee4ca35592f9ef270f4228b81565b348015620006a157600080fd5b506200040e7fbf094fe3c005c553ff0d33c7dff9d1273add12fb3f258b992f8d36224dd35b2481565b348015620006d757600080fd5b5060c954620003b7906001600160a01b031681565b348015620006f957600080fd5b506200035c6200070b3660046200430f565b60009182526097602090815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156200074357600080fd5b506200040e7f56bdc3c9ec86cb7db110a7699b2ade72f0b8819727d9f7d906b012641505fa7781565b3480156200077957600080fd5b506200040e600081565b3480156200079057600080fd5b5062000335620007a2366004620045fe565b62001ba2565b348015620007b557600080fd5b5060ca54620003b7906001600160a01b031681565b348015620007d757600080fd5b5062000335620007e93660046200461e565b62001c67565b348015620007fc57600080fd5b506200035c6200080e36600462004342565b620020c5565b3480156200082157600080fd5b506200033562000833366004620045fe565b620020ed565b3480156200084657600080fd5b506200040e7feaf25fcc6b7d45bda16c56628df3f435e20319ef53b065c11ee4510083f0ae2d81565b3480156200087c57600080fd5b506200040e7f550554a677c8e7b73b62db78b0ef06c5f237da4ef30b88196a899ccf591041fe81565b348015620008b257600080fd5b50620003b7620008c4366004620045fe565b610109602052600090815260409020546001600160a01b031681565b348015620008ed57600080fd5b506200035c620008ff36600462004398565b60d56020526000908152604090205460ff1681565b3480156200092157600080fd5b5061010754620003b7906001600160a01b031681565b3480156200094457600080fd5b506200033562000956366004620045fe565b620021b0565b3480156200096957600080fd5b506200040e7f3900d9d72d5177a154375317154fdc0e08377e3134a8a5d21cadccf831cc231c81565b3480156200099f57600080fd5b5062000335620009b13660046200430f565b6200231b565b62000335620009c8366004620046a2565b62002344565b348015620009db57600080fd5b5062000335620009ed36600462004342565b6200236c565b34801562000a0057600080fd5b506200033562000a123660046200471d565b6200245a565b34801562000a2557600080fd5b506200033562000a37366004620045fe565b6200279d565b34801562000a4a57600080fd5b506200040e7f77974cc9cb5bafc9bb265be792d93fa46355c05701895b82f6d3b4b448c8ce0081565b600054600290610100900460ff1615801562000a96575060005460ff8083169116105b62000b0e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001790556001600160a01b03881662000b67576040516342bcdf7f60e11b815260040160405180910390fd5b62000b74600089620028d9565b6000606555600060d55562000b886200299b565b62000b968585858562002a26565b62000ba2878762002d0c565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148062000c9e57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60d8600082600881111562000cbd5762000cbd620047a1565b600881111562000cd15762000cd1620047a1565b81526020019081526020016000205462000ceb8162002eae565b62000cf682620020c5565b62000d3157816040517f1865965400000000000000000000000000000000000000000000000000000000815260040162000b059190620047d0565b81600881111562000d465762000d46620047a1565b60d68054600190921b19909116905581600881111562000d6a5762000d6a620047a1565b7fd071d2b85dec4489435b541d2f0e2570db09b09db9efd8703948d44a433df65a335b6040516001600160a01b0390911681526020015b60405180910390a25050565b816001600160a01b03811662000dd6576040516342bcdf7f60e11b815260040160405180910390fd5b816001600160a01b03811662000dff576040516342bcdf7f60e11b815260040160405180910390fd5b7f550554a677c8e7b73b62db78b0ef06c5f237da4ef30b88196a899ccf591041fe62000e2b8162002eae565b6001600160a01b038086166000908152610109602052604090205486911615158062000e7f575061010a546000908152610108602090815260408083206001600160a01b0385811685529252909120541615155b1562000ec3576040517f12f3df090000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260240162000b05565b6001600160a01b0385811660009081526101096020526040902054161562000f23576040517ff8fb7c270000000000000000000000000000000000000000000000000000000081526001600160a01b038616600482015260240162000b05565b6001600160a01b038516610222148062000f4757506001600160a01b038516610333145b8062000f5d57506001600160a01b038516610111145b1562000fa1576040517fd8ce8acb0000000000000000000000000000000000000000000000000000000081526001600160a01b038616600482015260240162000b05565b61010b546000818152610108602090815260408083206001600160a01b038b8116855292529091205416156200100f576040517f022bc8410000000000000000000000000000000000000000000000000000000081526001600160a01b038816600482015260240162000b05565b6000818152610108602090815260408083206001600160a01b03808c168086529184528285208054918c167fffffffffffffffffffffffff00000000000000000000000000000000000000009283168117909155808652610109909452828520805490911682179055905133937f844cb5c635052898ad92bea4ece14519111765d835105e76aa1f77ad0d0aa81f91a450505050505050565b60c9546001600160a01b03163314620010ed576040517f8c56efb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ca5460c954604080517f67e404ce00000000000000000000000000000000000000000000000000000000815290516001600160a01b0393841693909216916367e404ce916004808201926020929091908290030181865afa15801562001158573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200117e919062004812565b6001600160a01b031614620011bf576040517f79d1e58f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61010a5460005b82811015620012c15760008281526101086020526040812061033391868685818110620011f757620011f762004832565b90506020020160208101906200120e9190620045fe565b6001600160a01b039081168252602082019290925260400160002080547fffffffffffffffffffffffff000000000000000000000000000000000000000016929091169190911790558383828181106200126c576200126c62004832565b9050602002016020810190620012839190620045fe565b6001600160a01b03167f91d24864a084ab70b268a1f865e757ca12006cf298d763b6be697302ef86498c60405160405180910390a2600101620011c6565b50505050565b600082815260976020526040902060010154620012e48162002eae565b620012f08383620028d9565b505050565b6001600160a01b0381163314620013755760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c660000000000000000000000000000000000606482015260840162000b05565b62001381828262002ebd565b5050565b80516000819003620013c3576040517f10cbd58300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015620014bf5760006101096000858481518110620013eb57620013eb62004832565b6020908102919091018101516001600160a01b0390811683529082019290925260400160002054169050806200147b5783828151811062001430576200143062004832565b60200260200101516040517fa5ea89da00000000000000000000000000000000000000000000000000000000815260040162000b0591906001600160a01b0391909116815260200190565b8084838151811062001491576200149162004832565b6001600160a01b03909216602092830291909101909101525080620014b68162004890565b915050620013c6565b5060c95460ca546040516001600160a01b0392831692639f3ce55a9234929116908290620014f2908890602401620048cb565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f2a564f3400000000000000000000000000000000000000000000000000000000179052517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815262001585939291906004016200491a565b6000604051808303818588803b1580156200159f57600080fd5b505af1158015620015b4573d6000803e3d6000fd5b5050505050336001600160a01b03167f59eab5b5f813ac9e0c10035dfb55b5e3419eff53c0f7a869fb3c22400ea036d68360405162000da19190620048cb565b826001600160a01b0381166200161d576040516342bcdf7f60e11b815260040160405180910390fd5b816001600160a01b03811662001646576040516342bcdf7f60e11b815260040160405180910390fd5b838060000362001686576040517f4618044a0000000000000000000000000000000000000000000000000000000081526004810182905260240162000b05565b6200169062002f5f565b6200169c600762002fba565b61010a546000818152610108602090815260408083206001600160a01b03808c168552925290912054167ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeef81016200172c576040517f6dad9c780000000000000000000000000000000000000000000000000000000081526001600160a01b038916600482015260240162000b05565b6001600160a01b03808916600090815261010960205260408120549091169060608215620017db576040517f9dc29fac000000000000000000000000000000000000000000000000000000008152336004820152602481018b90526001600160a01b038c1690639dc29fac90604401600060405180830381600087803b158015620017b657600080fd5b505af1158015620017cb573d6000803e3d6000fd5b5050505061010b54915062001a15565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000906001600160a01b038d16906370a0823190602401602060405180830381865afa1580156200183c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200186291906200494d565b90506200187b6001600160a01b038d1633308e62003055565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038e16906370a0823190602401602060405180830381865afa158015620018db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200190191906200494d565b6200190d919062004967565b9a508b93506001600160a01b038516620019b657610222610108600088815260200190815260200160002060008e6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508b6001600160a01b03167f0f53e2a811b6fd2d6cd965fd6c27b44fb924ca39f7a7f321115705c22366d62360405160405180910390a25b6001600160a01b0385166103331462001a1057620019d48c62003108565b620019df8d6200321b565b620019ea8e6200331b565b604051602001620019fe939291906200497d565b60405160208183030381529060405291505b859250505b60c960009054906101000a90046001600160a01b03166001600160a01b0316639f3ce55a3460ca60009054906101000a90046001600160a01b031634878f8f898960405160240162001a6c959493929190620049ba565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe4d2745100000000000000000000000000000000000000000000000000000000179052517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815262001aff939291906004016200491a565b6000604051808303818588803b15801562001b1957600080fd5b505af115801562001b2e573d6000803e3d6000fd5b50505050508a6001600160a01b0316896001600160a01b0316336001600160a01b03167f8780a94875b70464f8ac6c28851501d32e7fd4ee574e4b94beb28923a3c42d9c8d60405162001b8391815260200190565b60405180910390a4505050505062001b9a60018055565b505050505050565b7fbf094fe3c005c553ff0d33c7dff9d1273add12fb3f258b992f8d36224dd35b2462001bce8162002eae565b60ca546001600160a01b03161562001c225760ca546040517f94fbfd2e0000000000000000000000000000000000000000000000000000000081526001600160a01b03909116600482015260240162000b05565b62001c2d8262003447565b60405133906001600160a01b038416907fb044c1a1a05a729c402def784b4e4cb01612ff03eee6f0beb3eba0f0606260a190600090a35050565b62001c796040820160208301620045fe565b6001600160a01b03811662001ca1576040516342bcdf7f60e11b815260040160405180910390fd5b62001cb36060830160408401620045fe565b6001600160a01b03811662001cdb576040516342bcdf7f60e11b815260040160405180910390fd5b600054610100900460ff161580801562001cfc5750600054600160ff909116105b8062001d185750303b15801562001d18575060005460ff166001145b62001d8c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840162000b05565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801562001deb57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b62001e1462001dfe60e0860186620049f4565b62001e0e610100880188620049f4565b62002a26565b62001e3062001e2a6040860160208701620045fe565b620034d4565b62001e3a6200299b565b62001e55600062001e4f6020870187620045fe565b620028d9565b62001e6e62001e6860c0860186620049f4565b62002d0c565b62001e806060850160408601620045fe565b61010780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055606084013561010a55608084013561010b5560005b62001edd60a086018662004a5f565b90508110156200205b57600062001ef860a087018762004a5f565b8381811062001f0b5762001f0b62004832565b905060200201602081019062001f229190620045fe565b6001600160a01b03160362001f4a576040516342bcdf7f60e11b815260040160405180910390fd5b60608501356000908152610108602052604081206101119162001f7160a089018962004a5f565b8581811062001f845762001f8462004832565b905060200201602081019062001f9b9190620045fe565b6001600160a01b039081168252602082019290925260400160002080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169290911691909117905562001ff360a086018662004a5f565b8281811062002006576200200662004832565b90506020020160208101906200201d9190620045fe565b6001600160a01b03167f5e023c7a09fa0534ce3199f65fc3e635a5e851c5adc88ebda3b9d332ae07cbe960405160405180910390a260010162001ece565b508015620012c157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050565b6000816008811115620020dc57620020dc620047a1565b60d654600190911b16151592915050565b806001600160a01b03811662002116576040516342bcdf7f60e11b815260040160405180910390fd5b7f77974cc9cb5bafc9bb265be792d93fa46355c05701895b82f6d3b4b448c8ce00620021428162002eae565b60c980546001600160a01b038581167fffffffffffffffffffffffff00000000000000000000000000000000000000008316811790935560405191169133918391907fc96d462e42a71473da49a1d58c1754b9b2d319786692d621dc7f921331c517e990600090a450505050565b806001600160a01b038116620021d9576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b03808316600090815261010960205260409020548391161515806200222d575061010a546000908152610108602090815260408083206001600160a01b0385811685529252909120541615155b1562002271576040517f12f3df090000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260240162000b05565b7feaf25fcc6b7d45bda16c56628df3f435e20319ef53b065c11ee4510083f0ae2d6200229d8162002eae565b61010a546000908152610108602090815260408083206001600160a01b038816808552925280832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166101111790555190917f5e023c7a09fa0534ce3199f65fc3e635a5e851c5adc88ebda3b9d332ae07cbe991a250505050565b600082815260976020526040902060010154620023388162002eae565b620012f0838362002ebd565b8015620023585762002358858383620035b5565b62002365858585620015f4565b5050505050565b60d76000826008811115620023855762002385620047a1565b6008811115620023995762002399620047a1565b815260200190815260200160002054620023b38162002eae565b620023be82620020c5565b15620023fa57816040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040162000b059190620047d0565b8160088111156200240f576200240f620047a1565b60d68054600190921b9091179055816008811115620024325762002432620047a1565b7f534f879afd40abb4e39f8e1b77a316be4c8e3521d9cf5a3a3db8959d574d45593362000d8d565b6200246462002f5f565b60c9546001600160a01b03163314620024a9576040517f8c56efb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ca5460c954604080517f67e404ce00000000000000000000000000000000000000000000000000000000815290516001600160a01b0393841693909216916367e404ce916004808201926020929091908290030181865afa15801562002514573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200253a919062004812565b6001600160a01b0316146200257b576040517f79d1e58f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6008620025888162002fba565b6000848152610108602090815260408083206001600160a01b03808c16855292528220541690610222821480620025c957506001600160a01b038216610333145b15620025eb57620025e56001600160a01b038a16888a620038d1565b62002738565b50806001600160a01b038116620026ba576200260d89868661010a546200391c565b9050886101096000836001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555080610108600061010b54815260200190815260200160002060008b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b038881166004830152602482018a90528216906340c10f1990604401600060405180830381600087803b1580156200271e57600080fd5b505af115801562002733573d6000803e3d6000fd5b505050505b866001600160a01b0316816001600160a01b03168a6001600160a01b03167f6ed06519caca659cdefa71015c79a561928d3cf8cc4a3e9739fde9fb5fb38d648b6040516200278891815260200190565b60405180910390a450505062001b9a60018055565b806001600160a01b038116620027c6576040516342bcdf7f60e11b815260040160405180910390fd5b7f19bf281d118073c159a713666aba52e0d403520cd01e03f42e0f62a0b3bd4a35620027f28162002eae565b61010a546000818152610108602090815260408083206001600160a01b038881168552925290912054166101111462002863576040517f82f5d0a50000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240162000b05565b6000818152610108602090815260408083206001600160a01b038816808552925280832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555190917f0145163d8d460d1ab21463758d147fdfe79d4b57c81ca3d1439996104ae6895991a250505050565b60008281526097602090815260408083206001600160a01b038516845290915290205460ff16620013815760008281526097602090815260408083206001600160a01b0385168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055620029573390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600054610100900460ff1662002a1a5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b62002a2462003a4c565b565b600054610100900460ff1662002aa55760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b60005b8381101562002bd85784848281811062002ac65762002ac662004832565b9050604002016020013560d7600087878581811062002ae95762002ae962004832565b62002b01926020604090920201908101915062004342565b600881111562002b155762002b15620047a1565b600881111562002b295762002b29620047a1565b815260208101919091526040016000205584848281811062002b4f5762002b4f62004832565b9050604002016020013585858381811062002b6e5762002b6e62004832565b62002b86926020604090920201908101915062004342565b600881111562002b9a5762002b9a620047a1565b6040517f33aa8fd1ce49e1761bc8d27fd53414bfefc45d690feed0ce55019d7d3aec609190600090a38062002bcf8162004890565b91505062002aa8565b5060005b81811015620023655782828281811062002bfa5762002bfa62004832565b9050604002016020013560d8600085858581811062002c1d5762002c1d62004832565b62002c35926020604090920201908101915062004342565b600881111562002c495762002c49620047a1565b600881111562002c5d5762002c5d620047a1565b815260208101919091526040016000205582828281811062002c835762002c8362004832565b9050604002016020013583838381811062002ca25762002ca262004832565b62002cba926020604090920201908101915062004342565b600881111562002cce5762002cce620047a1565b6040517fe7bf4b8dc0c17a52dc9e52323a3ab61cb2079db35f969125b1f8a3d984c6f6c290600090a38062002d038162004890565b91505062002bdc565b600054610100900460ff1662002d8b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b60005b81811015620012f057600083838381811062002dae5762002dae62004832565b62002dc69260206040909202019081019150620045fe565b6001600160a01b03160362002dee576040516342bcdf7f60e11b815260040160405180910390fd5b82828281811062002e035762002e0362004832565b905060400201602001356000801b0362002e49576040517f0742d05300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62002e9983838381811062002e625762002e6262004832565b9050604002016020013584848481811062002e815762002e8162004832565b62001e4f9260206040909202019081019150620045fe565b8062002ea58162004890565b91505062002d8e565b62002eba813362003acb565b50565b60008281526097602090815260408083206001600160a01b038516845290915290205460ff1615620013815760008281526097602090815260408083206001600160a01b038516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60026001540362002fb35760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640162000b05565b6002600155565b60d65481600881111562002fd25762002fd2620047a1565b6001901b8116156200301457816040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040162000b059190620047d0565b6002811615620013815760016040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040162000b059190620047d0565b6040516001600160a01b0380851660248301528316604482015260648101829052620012c19085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915262003b49565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f06fdde0300000000000000000000000000000000000000000000000000000000179052905160609160009182916001600160a01b038616916200317f919062004aca565b600060405180830381855afa9150503d8060008114620031bc576040519150601f19603f3d011682016040523d82523d6000602084013e620031c1565b606091505b50915091508162003208576040518060400160405280600781526020017f4e4f5f4e414d450000000000000000000000000000000000000000000000000081525062003213565b620032138162003c38565b949350505050565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f95d89b4100000000000000000000000000000000000000000000000000000000179052905160609160009182916001600160a01b0386169162003292919062004aca565b600060405180830381855afa9150503d8060008114620032cf576040519150601f19603f3d011682016040523d82523d6000602084013e620032d4565b606091505b50915091508162003208576040518060400160405280600981526020017f4e4f5f53594d424f4c000000000000000000000000000000000000000000000081525062003213565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f313ce567000000000000000000000000000000000000000000000000000000001790529051600091829182916001600160a01b0386169162003391919062004aca565b600060405180830381855afa9150503d8060008114620033ce576040519150601f19603f3d011682016040523d82523d6000602084013e620033d3565b606091505b5091509150818015620033e7575060208151145b1562003403578080602001905181019062003213919062004af8565b6040517fb5a2f1c60000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240162000b05565b60018055565b6001600160a01b0381166200346f576040516342bcdf7f60e11b815260040160405180910390fd5b60ca80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040513391907fe68b208814fdb633b222cd15e73d5a27fb4ef9eef4cae78c623bc27702141d2890600090a350565b600054610100900460ff16620035535760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b6001600160a01b0381166200357b576040516342bcdf7f60e11b815260040160405180910390fd5b60c980547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b7fd505accf00000000000000000000000000000000000000000000000000000000620035e660046000848662004b18565b620035f19162004b44565b7fffffffff000000000000000000000000000000000000000000000000000000001614620036b2576200362960046000838562004b18565b620036349162004b44565b6040517fcf9e29460000000000000000000000000000000000000000000000000000000081527fffffffff0000000000000000000000000000000000000000000000000000000090911660048201527fd505accf00000000000000000000000000000000000000000000000000000000602482015260440162000b05565b6000808080808080620036c9886004818c62004b18565b810190620036d8919062004b8d565b9650965096509650965096509650336001600160a01b0316876001600160a01b0316146200373e576040517f200688cc0000000000000000000000000000000000000000000000000000000081526001600160a01b038816600482015260240162000b05565b6001600160a01b03861630146200378d576040517f291159480000000000000000000000000000000000000000000000000000000081526001600160a01b038716600482015260240162000b05565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015287811660248301528691908c169063dd62ed3e90604401602060405180830381865afa158015620037f8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200381e91906200494d565b1015620038c5576040517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018690526064810185905260ff8416608482015260a4810183905260c481018290526001600160a01b038b169063d505accf9060e401600060405180830381600087803b158015620038ab57600080fd5b505af1158015620038c0573d6000803e3d6000fd5b505050505b50505050505050505050565b6040516001600160a01b038316602482015260448101829052620012f09084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401620030a3565b6000818152602085905260408120610107546040516001600160a01b039091169062003948906200419f565b6001600160a01b0390911681526040602082018190526000908201526060018190604051809103906000f590508015801562003988573d6000803e3d6000fd5b509050600080806200399d8688018862004c8c565b925092509250836001600160a01b0316631624f6c68484846040518463ffffffff1660e01b8152600401620039d5939291906200497d565b600060405180830381600087803b158015620039f057600080fd5b505af115801562003a05573d6000803e3d6000fd5b50506040516001600160a01b03808c169350871691507fd5d4920bb61e6141c8499d50a7bd617dae2b1818c9d6b995d3f2ba4975e32ea490600090a3505050949350505050565b600054610100900460ff16620034415760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b60008281526097602090815260408083206001600160a01b038516845290915290205460ff16620013815762003b018162003e0b565b62003b0e83602062003e1e565b60405160200162003b2192919062004d02565b60408051601f198184030181529082905262461bcd60e51b825262000b059160040162004480565b600062003ba0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200406c9092919063ffffffff16565b905080516000148062003bc457508080602001905181019062003bc4919062004d87565b620012f05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840162000b05565b6060604082511062003c5a578180602001905181019062000c9e919062004dab565b602082511462003c9d57505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e470000000000000000000000000000602082015290565b60005b60208110801562003ceb575082818151811062003cc15762003cc162004832565b01602001517fff000000000000000000000000000000000000000000000000000000000000001615155b1562003cfa5760010162003ca0565b8060000362003d3e57505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e4700000000000000000000000000006020820152919050565b60008167ffffffffffffffff81111562003d5c5762003d5c62004495565b6040519080825280601f01601f19166020018201604052801562003d87576020820181803683370190505b50905060005b8281101562003e035784818151811062003dab5762003dab62004832565b602001015160f81c60f81b82828151811062003dcb5762003dcb62004832565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060010162003d8d565b509392505050565b606062000c9e6001600160a01b03831660145b6060600062003e2f83600262004e22565b62003e3c90600262004e3c565b67ffffffffffffffff81111562003e575762003e5762004495565b6040519080825280601f01601f19166020018201604052801562003e82576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811062003ebc5762003ebc62004832565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811062003f225762003f2262004832565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600062003f6084600262004e22565b62003f6d90600162004e3c565b90505b600181111562004014577f303132333435363738396162636465660000000000000000000000000000000085600f166010811062003fb25762003fb262004832565b1a60f81b82828151811062003fcb5762003fcb62004832565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c936200400c8162004e52565b905062003f70565b508315620040655760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640162000b05565b9392505050565b606062003213848460008585600080866001600160a01b0316858760405162004096919062004aca565b60006040518083038185875af1925050503d8060008114620040d5576040519150601f19603f3d011682016040523d82523d6000602084013e620040da565b606091505b5091509150620040ed87838387620040f8565b979650505050505050565b606083156200416c57825160000362004164576001600160a01b0385163b620041645760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000b05565b508162003213565b620032138383815115620041835781518083602001fd5b8060405162461bcd60e51b815260040162000b05919062004480565b6106f38062004e8b83390190565b6001600160a01b038116811462002eba57600080fd5b60008083601f840112620041d657600080fd5b50813567ffffffffffffffff811115620041ef57600080fd5b6020830191508360208260061b85010111156200420b57600080fd5b9250929050565b60008060008060008060006080888a0312156200422e57600080fd5b87356200423b81620041ad565b9650602088013567ffffffffffffffff808211156200425957600080fd5b620042678b838c01620041c3565b909850965060408a01359150808211156200428157600080fd5b6200428f8b838c01620041c3565b909650945060608a0135915080821115620042a957600080fd5b50620042b88a828b01620041c3565b989b979a50959850939692959293505050565b600060208284031215620042de57600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146200406557600080fd5b600080604083850312156200432357600080fd5b8235915060208301356200433781620041ad565b809150509250929050565b6000602082840312156200435557600080fd5b8135600981106200406557600080fd5b600080604083850312156200437957600080fd5b82356200438681620041ad565b915060208301356200433781620041ad565b600060208284031215620043ab57600080fd5b5035919050565b60008060208385031215620043c657600080fd5b823567ffffffffffffffff80821115620043df57600080fd5b818501915085601f830112620043f457600080fd5b8135818111156200440457600080fd5b8660208260051b85010111156200441a57600080fd5b60209290920196919550909350505050565b60005b83811015620044495781810151838201526020016200442f565b50506000910152565b600081518084526200446c8160208601602086016200442c565b601f01601f19169290920160200192915050565b60208152600062004065602083018462004452565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715620044f057620044f062004495565b604052919050565b600060208083850312156200450c57600080fd5b823567ffffffffffffffff808211156200452557600080fd5b818501915085601f8301126200453a57600080fd5b8135818111156200454f576200454f62004495565b8060051b915062004562848301620044c4565b81815291830184019184810190888411156200457d57600080fd5b938501935b83851015620045ab57843592506200459a83620041ad565b828252938501939085019062004582565b98975050505050505050565b600080600060608486031215620045cd57600080fd5b8335620045da81620041ad565b9250602084013591506040840135620045f381620041ad565b809150509250925092565b6000602082840312156200461157600080fd5b81356200406581620041ad565b6000602082840312156200463157600080fd5b813567ffffffffffffffff8111156200464957600080fd5b820161012081850312156200406557600080fd5b60008083601f8401126200467057600080fd5b50813567ffffffffffffffff8111156200468957600080fd5b6020830191508360208285010111156200420b57600080fd5b600080600080600060808688031215620046bb57600080fd5b8535620046c881620041ad565b9450602086013593506040860135620046e181620041ad565b9250606086013567ffffffffffffffff811115620046fe57600080fd5b6200470c888289016200465d565b969995985093965092949392505050565b60008060008060008060a087890312156200473757600080fd5b86356200474481620041ad565b95506020870135945060408701356200475d81620041ad565b935060608701359250608087013567ffffffffffffffff8111156200478157600080fd5b6200478f89828a016200465d565b979a9699509497509295939492505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208101600983106200480c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b6000602082840312156200482557600080fd5b81516200406581620041ad565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203620048c457620048c462004861565b5060010190565b6020808252825182820181905260009190848201906040850190845b818110156200490e5783516001600160a01b031683529284019291840191600101620048e7565b50909695505050505050565b6001600160a01b038416815282602082015260606040820152600062004944606083018462004452565b95945050505050565b6000602082840312156200496057600080fd5b5051919050565b8181038181111562000c9e5762000c9e62004861565b60608152600062004992606083018662004452565b8281036020840152620049a6818662004452565b91505060ff83166040830152949350505050565b60006001600160a01b03808816835286602084015280861660408401525083606083015260a06080830152620040ed60a083018462004452565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811262004a2a57600080fd5b83018035915067ffffffffffffffff82111562004a4657600080fd5b6020019150600681901b36038213156200420b57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811262004a9557600080fd5b83018035915067ffffffffffffffff82111562004ab157600080fd5b6020019150600581901b36038213156200420b57600080fd5b6000825162004ade8184602087016200442c565b9190910192915050565b60ff8116811462002eba57600080fd5b60006020828403121562004b0b57600080fd5b8151620040658162004ae8565b6000808585111562004b2957600080fd5b8386111562004b3757600080fd5b5050820193919092039150565b7fffffffff00000000000000000000000000000000000000000000000000000000813581811691600485101562004b855780818660040360031b1b83161692505b505092915050565b600080600080600080600060e0888a03121562004ba957600080fd5b873562004bb681620041ad565b9650602088013562004bc881620041ad565b95506040880135945060608801359350608088013562004be88162004ae8565b9699959850939692959460a0840135945060c09093013592915050565b600067ffffffffffffffff82111562004c225762004c2262004495565b50601f01601f191660200190565b600082601f83011262004c4257600080fd5b813562004c5962004c538262004c05565b620044c4565b81815284602083860101111562004c6f57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121562004ca257600080fd5b833567ffffffffffffffff8082111562004cbb57600080fd5b62004cc98783880162004c30565b9450602086013591508082111562004ce057600080fd5b5062004cef8682870162004c30565b9250506040840135620045f38162004ae8565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835162004d3c8160178501602088016200442c565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000601791840191820152835162004d7b8160288401602088016200442c565b01602801949350505050565b60006020828403121562004d9a57600080fd5b815180151581146200406557600080fd5b60006020828403121562004dbe57600080fd5b815167ffffffffffffffff81111562004dd657600080fd5b8201601f8101841362004de857600080fd5b805162004df962004c538262004c05565b81815285602083850101111562004e0f57600080fd5b620049448260208301602086016200442c565b808202811582820484141762000c9e5762000c9e62004861565b8082018082111562000c9e5762000c9e62004861565b60008162004e645762004e6462004861565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fe60806040526040516106f33803806106f383398101604081905261002291610420565b61002e82826000610035565b505061054a565b61003e836100f6565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100f1576100ef836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e991906104e0565b8361027a565b505b505050565b6001600160a01b0381163b6101605760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101d4816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101c591906104e0565b6001600160a01b03163b151590565b6102395760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610157565b7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b0392909216919091179055565b606061029f83836040518060600160405280602781526020016106cc602791396102a6565b9392505050565b6060600080856001600160a01b0316856040516102c391906104fb565b600060405180830381855af49150503d80600081146102fe576040519150601f19603f3d011682016040523d82523d6000602084013e610303565b606091505b5090925090506103158683838761031f565b9695505050505050565b6060831561038e578251600003610387576001600160a01b0385163b6103875760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610157565b5081610398565b61039883836103a0565b949350505050565b8151156103b05781518083602001fd5b8060405162461bcd60e51b81526004016101579190610517565b80516001600160a01b03811681146103e157600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b838110156104175781810151838201526020016103ff565b50506000910152565b6000806040838503121561043357600080fd5b61043c836103ca565b60208401519092506001600160401b038082111561045957600080fd5b818501915085601f83011261046d57600080fd5b81518181111561047f5761047f6103e6565b604051601f8201601f19908116603f011681019083821181831017156104a7576104a76103e6565b816040528281528860208487010111156104c057600080fd5b6104d18360208301602088016103fc565b80955050505050509250929050565b6000602082840312156104f257600080fd5b61029f826103ca565b6000825161050d8184602087016103fc565b9190910192915050565b60208152600082518060208401526105368160408501602087016103fc565b601f01601f19169190910160400192915050565b610173806105596000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610029565b6100dc565b565b60006100697fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d505473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100d79190610100565b905090565b3660008037600080366000845af43d6000803e8080156100fb573d6000f35b3d6000fd5b60006020828403121561011257600080fd5b815173ffffffffffffffffffffffffffffffffffffffff8116811461013657600080fd5b939250505056fea2646970667358221220662c40b76fc0d477a291a78deacd27f4cddd7512dea18087244e38acb2fd99dd64736f6c63430008130033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122008b6c34a5d8997b54caed58d53678d49279942ee4709ef64c362fdb42f961e2064736f6c63430008130033", + "bytecode": "0x60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e1576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61567780620000f36000396000f3fe6080604052600436106200030b5760003560e01c806391d148541162000197578063ca41a24711620000e7578063d547741f1162000095578063e4d27451116200006c578063e4d2745114620009f3578063edc42a221462000a18578063fe3c50a01462000a3d57600080fd5b8063d547741f1462000992578063dfa96efb14620009b7578063e196fb5d14620009ce57600080fd5b8063ccf5a77c11620000ca578063ccf5a77c1462000914578063cdd914c51462000937578063cf4a7208146200095c57600080fd5b8063ca41a24714620008a5578063cc5782f614620008e057600080fd5b8063b3232bdf1162000145578063be46096f1162000128578063be46096f1462000814578063c483d8381462000839578063c986752a146200086f57600080fd5b8063b3232bdf14620007ca578063bc61e73314620007ef57600080fd5b8063a217fddf116200017a578063a217fddf146200076c578063a676e8ab1462000783578063a6ef995f14620007a857600080fd5b806391d1485414620006ec5780639ac25d08146200073657600080fd5b80632f2ff15d116200025f578063522ea81a116200020d5780636a906b8011620001e45780636a906b80146200065e57806380efb43a14620006945780638dae45dd14620006ca57600080fd5b8063522ea81a14620005db5780635626fc2514620005f25780635a06a42a146200062857600080fd5b806336568abe116200024257806336568abe146200054557806338b90333146200056a5780634bf98dce14620005c457600080fd5b80632f2ff15d14620004ea5780633551237b146200050f57600080fd5b80631544298e11620002bd578063248a9ca311620002a0578063248a9ca3146200045b5780632a564f34146200048f5780632e4c3fff14620004b457600080fd5b80631544298e146200041d5780631754f301146200043657600080fd5b80630f6f86ec11620002f25780630f6f86ec14620003715780631065a39914620003d0578063146ffb2614620003f557600080fd5b806301941d39146200031057806301ffc9a71462000337575b600080fd5b3480156200031d57600080fd5b50620003356200032f366004620042d6565b62000a73565b005b3480156200034457600080fd5b506200035c620003563660046200438f565b62000c0a565b60405190151581526020015b60405180910390f35b3480156200037e57600080fd5b50620003b762000390366004620043d3565b6101086020908152600092835260408084209091529082529020546001600160a01b031681565b6040516001600160a01b03909116815260200162000368565b348015620003dd57600080fd5b5062000335620003ef36600462004406565b62000ca4565b3480156200040257600080fd5b506200040e61010b5481565b60405190815260200162000368565b3480156200042a57600080fd5b506200040e61010a5481565b3480156200044357600080fd5b50620003356200045536600462004429565b62000dad565b3480156200046857600080fd5b506200040e6200047a3660046200445c565b60009081526097602052604090206001015490565b3480156200049c57600080fd5b5062000335620004ae36600462004476565b620010a8565b348015620004c157600080fd5b506200040e7f8a7b208fd13ab36d18025be4f62b53d46aeb2cbe8958d2e13de74c040dddcddd81565b348015620004f757600080fd5b506200033562000509366004620043d3565b620012c7565b3480156200051c57600080fd5b506200040e7f19bf281d118073c159a713666aba52e0d403520cd01e03f42e0f62a0b3bd4a3581565b3480156200055257600080fd5b506200033562000564366004620043d3565b620012f5565b3480156200057757600080fd5b50620005b56040518060400160405280600381526020017f312e30000000000000000000000000000000000000000000000000000000000081525081565b60405162000368919062004544565b62000335620005d5366004620045bc565b62001385565b62000335620005ec3660046200467b565b620015f4565b348015620005ff57600080fd5b506200040e7f46e34517dc946faf87aabe65eb5b4fa06b974e5c8d72c5df73b9fb6ff7b6d80281565b3480156200063557600080fd5b506200040e7f50962b2d10066f5051f78d5ea04a3ab09b9c87dd1002962f0b1e30e66eeb80a581565b3480156200066b57600080fd5b506200040e7fd8b4c34c2ec1f3194471108c64ad2beda340c0337ee4ca35592f9ef270f4228b81565b348015620006a157600080fd5b506200040e7fbf094fe3c005c553ff0d33c7dff9d1273add12fb3f258b992f8d36224dd35b2481565b348015620006d757600080fd5b5060c954620003b7906001600160a01b031681565b348015620006f957600080fd5b506200035c6200070b366004620043d3565b60009182526097602090815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156200074357600080fd5b506200040e7f56bdc3c9ec86cb7db110a7699b2ade72f0b8819727d9f7d906b012641505fa7781565b3480156200077957600080fd5b506200040e600081565b3480156200079057600080fd5b5062000335620007a2366004620046c2565b62001ba2565b348015620007b557600080fd5b5060ca54620003b7906001600160a01b031681565b348015620007d757600080fd5b5062000335620007e9366004620046e2565b62001c67565b348015620007fc57600080fd5b506200035c6200080e36600462004406565b62002189565b3480156200082157600080fd5b506200033562000833366004620046c2565b620021b1565b3480156200084657600080fd5b506200040e7feaf25fcc6b7d45bda16c56628df3f435e20319ef53b065c11ee4510083f0ae2d81565b3480156200087c57600080fd5b506200040e7f550554a677c8e7b73b62db78b0ef06c5f237da4ef30b88196a899ccf591041fe81565b348015620008b257600080fd5b50620003b7620008c4366004620046c2565b610109602052600090815260409020546001600160a01b031681565b348015620008ed57600080fd5b506200035c620008ff3660046200445c565b60d56020526000908152604090205460ff1681565b3480156200092157600080fd5b5061010754620003b7906001600160a01b031681565b3480156200094457600080fd5b506200033562000956366004620046c2565b62002274565b3480156200096957600080fd5b506200040e7f3900d9d72d5177a154375317154fdc0e08377e3134a8a5d21cadccf831cc231c81565b3480156200099f57600080fd5b5062000335620009b1366004620043d3565b620023df565b62000335620009c836600462004766565b62002408565b348015620009db57600080fd5b5062000335620009ed36600462004406565b62002430565b34801562000a0057600080fd5b506200033562000a12366004620047e1565b6200251e565b34801562000a2557600080fd5b506200033562000a37366004620046c2565b62002861565b34801562000a4a57600080fd5b506200040e7f77974cc9cb5bafc9bb265be792d93fa46355c05701895b82f6d3b4b448c8ce0081565b600054600290610100900460ff1615801562000a96575060005460ff8083169116105b62000b0e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001790556001600160a01b03881662000b67576040516342bcdf7f60e11b815260040160405180910390fd5b62000b746000896200299d565b6000606555600060d55562000b8862002a5f565b62000b968585858562002aea565b62000ba2878762002dd0565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148062000c9e57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60d8600082600881111562000cbd5762000cbd62004865565b600881111562000cd15762000cd162004865565b81526020019081526020016000205462000ceb8162002f72565b62000cf68262002189565b62000d3157816040517f1865965400000000000000000000000000000000000000000000000000000000815260040162000b05919062004894565b81600881111562000d465762000d4662004865565b60d68054600190921b19909116905581600881111562000d6a5762000d6a62004865565b7fd071d2b85dec4489435b541d2f0e2570db09b09db9efd8703948d44a433df65a335b6040516001600160a01b0390911681526020015b60405180910390a25050565b816001600160a01b03811662000dd6576040516342bcdf7f60e11b815260040160405180910390fd5b816001600160a01b03811662000dff576040516342bcdf7f60e11b815260040160405180910390fd5b7f550554a677c8e7b73b62db78b0ef06c5f237da4ef30b88196a899ccf591041fe62000e2b8162002f72565b6001600160a01b038086166000908152610109602052604090205486911615158062000e7f575061010a546000908152610108602090815260408083206001600160a01b0385811685529252909120541615155b1562000ec3576040517f12f3df090000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260240162000b05565b6001600160a01b0385811660009081526101096020526040902054161562000f23576040517ff8fb7c270000000000000000000000000000000000000000000000000000000081526001600160a01b038616600482015260240162000b05565b6001600160a01b038516610222148062000f4757506001600160a01b038516610333145b8062000f5d57506001600160a01b038516610111145b1562000fa1576040517fd8ce8acb0000000000000000000000000000000000000000000000000000000081526001600160a01b038616600482015260240162000b05565b61010b546000818152610108602090815260408083206001600160a01b038b8116855292529091205416156200100f576040517f022bc8410000000000000000000000000000000000000000000000000000000081526001600160a01b038816600482015260240162000b05565b6000818152610108602090815260408083206001600160a01b03808c168086529184528285208054918c167fffffffffffffffffffffffff00000000000000000000000000000000000000009283168117909155808652610109909452828520805490911682179055905133937f844cb5c635052898ad92bea4ece14519111765d835105e76aa1f77ad0d0aa81f91a450505050505050565b60c9546001600160a01b03163314620010ed576040517f8c56efb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ca5460c954604080517f67e404ce00000000000000000000000000000000000000000000000000000000815290516001600160a01b0393841693909216916367e404ce916004808201926020929091908290030181865afa15801562001158573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200117e9190620048d6565b6001600160a01b031614620011bf576040517f79d1e58f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61010a5460005b82811015620012c15760008281526101086020526040812061033391868685818110620011f757620011f7620048f6565b90506020020160208101906200120e9190620046c2565b6001600160a01b039081168252602082019290925260400160002080547fffffffffffffffffffffffff000000000000000000000000000000000000000016929091169190911790558383828181106200126c576200126c620048f6565b9050602002016020810190620012839190620046c2565b6001600160a01b03167f91d24864a084ab70b268a1f865e757ca12006cf298d763b6be697302ef86498c60405160405180910390a2600101620011c6565b50505050565b600082815260976020526040902060010154620012e48162002f72565b620012f083836200299d565b505050565b6001600160a01b0381163314620013755760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c660000000000000000000000000000000000606482015260840162000b05565b62001381828262002f81565b5050565b80516000819003620013c3576040517f10cbd58300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015620014bf5760006101096000858481518110620013eb57620013eb620048f6565b6020908102919091018101516001600160a01b0390811683529082019290925260400160002054169050806200147b57838281518110620014305762001430620048f6565b60200260200101516040517fa5ea89da00000000000000000000000000000000000000000000000000000000815260040162000b0591906001600160a01b0391909116815260200190565b80848381518110620014915762001491620048f6565b6001600160a01b03909216602092830291909101909101525080620014b68162004954565b915050620013c6565b5060c95460ca546040516001600160a01b0392831692639f3ce55a9234929116908290620014f29088906024016200498f565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f2a564f3400000000000000000000000000000000000000000000000000000000179052517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b1681526200158593929190600401620049de565b6000604051808303818588803b1580156200159f57600080fd5b505af1158015620015b4573d6000803e3d6000fd5b5050505050336001600160a01b03167f59eab5b5f813ac9e0c10035dfb55b5e3419eff53c0f7a869fb3c22400ea036d68360405162000da191906200498f565b826001600160a01b0381166200161d576040516342bcdf7f60e11b815260040160405180910390fd5b816001600160a01b03811662001646576040516342bcdf7f60e11b815260040160405180910390fd5b838060000362001686576040517f4618044a0000000000000000000000000000000000000000000000000000000081526004810182905260240162000b05565b6200169062003023565b6200169c60076200307e565b61010a546000818152610108602090815260408083206001600160a01b03808c168552925290912054167ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeef81016200172c576040517f6dad9c780000000000000000000000000000000000000000000000000000000081526001600160a01b038916600482015260240162000b05565b6001600160a01b03808916600090815261010960205260408120549091169060608215620017db576040517f9dc29fac000000000000000000000000000000000000000000000000000000008152336004820152602481018b90526001600160a01b038c1690639dc29fac90604401600060405180830381600087803b158015620017b657600080fd5b505af1158015620017cb573d6000803e3d6000fd5b5050505061010b54915062001a15565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000906001600160a01b038d16906370a0823190602401602060405180830381865afa1580156200183c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001862919062004a11565b90506200187b6001600160a01b038d1633308e62003119565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038e16906370a0823190602401602060405180830381865afa158015620018db573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001901919062004a11565b6200190d919062004a2b565b9a508b93506001600160a01b038516620019b657610222610108600088815260200190815260200160002060008e6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508b6001600160a01b03167f0f53e2a811b6fd2d6cd965fd6c27b44fb924ca39f7a7f321115705c22366d62360405160405180910390a25b6001600160a01b0385166103331462001a1057620019d48c620031cc565b620019df8d620032df565b620019ea8e620033df565b604051602001620019fe9392919062004a41565b60405160208183030381529060405291505b859250505b60c960009054906101000a90046001600160a01b03166001600160a01b0316639f3ce55a3460ca60009054906101000a90046001600160a01b031634878f8f898960405160240162001a6c95949392919062004a7e565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe4d2745100000000000000000000000000000000000000000000000000000000179052517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815262001aff93929190600401620049de565b6000604051808303818588803b15801562001b1957600080fd5b505af115801562001b2e573d6000803e3d6000fd5b50505050508a6001600160a01b0316896001600160a01b0316336001600160a01b03167f8780a94875b70464f8ac6c28851501d32e7fd4ee574e4b94beb28923a3c42d9c8d60405162001b8391815260200190565b60405180910390a4505050505062001b9a60018055565b505050505050565b7fbf094fe3c005c553ff0d33c7dff9d1273add12fb3f258b992f8d36224dd35b2462001bce8162002f72565b60ca546001600160a01b03161562001c225760ca546040517f94fbfd2e0000000000000000000000000000000000000000000000000000000081526001600160a01b03909116600482015260240162000b05565b62001c2d826200350b565b60405133906001600160a01b038416907fb044c1a1a05a729c402def784b4e4cb01612ff03eee6f0beb3eba0f0606260a190600090a35050565b62001c796040820160208301620046c2565b6001600160a01b03811662001ca1576040516342bcdf7f60e11b815260040160405180910390fd5b62001cb36060830160408401620046c2565b6001600160a01b03811662001cdb576040516342bcdf7f60e11b815260040160405180910390fd5b82606001358060000362001d1b576040517f488d765100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83608001358060000362001d5b576040517f488d765100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff161580801562001d7c5750600054600160ff909116105b8062001d985750303b15801562001d98575060005460ff166001145b62001e0c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840162000b05565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801562001e6b57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b62001e9462001e7e60e088018862004ab8565b62001e8e6101008a018a62004ab8565b62002aea565b62001eb062001eaa6040880160208901620046c2565b62003598565b62001eba62002a5f565b62001ed5600062001ecf6020890189620046c2565b6200299d565b62001eee62001ee860c088018862004ab8565b62002dd0565b62001f006060870160408801620046c2565b61010780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055608086013560608701350362001f7b576040517fac867a5500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606086013561010a55608086013561010b5560005b62001f9f60a088018862004b23565b90508110156200211d57600062001fba60a089018962004b23565b8381811062001fcd5762001fcd620048f6565b905060200201602081019062001fe49190620046c2565b6001600160a01b0316036200200c576040516342bcdf7f60e11b815260040160405180910390fd5b6060870135600090815261010860205260408120610111916200203360a08b018b62004b23565b85818110620020465762002046620048f6565b90506020020160208101906200205d9190620046c2565b6001600160a01b039081168252602082019290925260400160002080547fffffffffffffffffffffffff00000000000000000000000000000000000000001692909116919091179055620020b560a088018862004b23565b82818110620020c857620020c8620048f6565b9050602002016020810190620020df9190620046c2565b6001600160a01b03167f5e023c7a09fa0534ce3199f65fc3e635a5e851c5adc88ebda3b9d332ae07cbe960405160405180910390a260010162001f90565b50801562001b9a57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b6000816008811115620021a057620021a062004865565b60d654600190911b16151592915050565b806001600160a01b038116620021da576040516342bcdf7f60e11b815260040160405180910390fd5b7f77974cc9cb5bafc9bb265be792d93fa46355c05701895b82f6d3b4b448c8ce00620022068162002f72565b60c980546001600160a01b038581167fffffffffffffffffffffffff00000000000000000000000000000000000000008316811790935560405191169133918391907fc96d462e42a71473da49a1d58c1754b9b2d319786692d621dc7f921331c517e990600090a450505050565b806001600160a01b0381166200229d576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0380831660009081526101096020526040902054839116151580620022f1575061010a546000908152610108602090815260408083206001600160a01b0385811685529252909120541615155b1562002335576040517f12f3df090000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260240162000b05565b7feaf25fcc6b7d45bda16c56628df3f435e20319ef53b065c11ee4510083f0ae2d620023618162002f72565b61010a546000908152610108602090815260408083206001600160a01b038816808552925280832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166101111790555190917f5e023c7a09fa0534ce3199f65fc3e635a5e851c5adc88ebda3b9d332ae07cbe991a250505050565b600082815260976020526040902060010154620023fc8162002f72565b620012f0838362002f81565b80156200241c576200241c85838362003679565b62002429858585620015f4565b5050505050565b60d7600082600881111562002449576200244962004865565b60088111156200245d576200245d62004865565b815260200190815260200160002054620024778162002f72565b620024828262002189565b15620024be57816040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040162000b05919062004894565b816008811115620024d357620024d362004865565b60d68054600190921b9091179055816008811115620024f657620024f662004865565b7f534f879afd40abb4e39f8e1b77a316be4c8e3521d9cf5a3a3db8959d574d45593362000d8d565b6200252862003023565b60c9546001600160a01b031633146200256d576040517f8c56efb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ca5460c954604080517f67e404ce00000000000000000000000000000000000000000000000000000000815290516001600160a01b0393841693909216916367e404ce916004808201926020929091908290030181865afa158015620025d8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620025fe9190620048d6565b6001600160a01b0316146200263f576040517f79d1e58f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60086200264c816200307e565b6000848152610108602090815260408083206001600160a01b03808c168552925282205416906102228214806200268d57506001600160a01b038216610333145b15620026af57620026a96001600160a01b038a16888a62003995565b620027fc565b50806001600160a01b0381166200277e57620026d189868661010a54620039e0565b9050886101096000836001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555080610108600061010b54815260200190815260200160002060008b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b038881166004830152602482018a90528216906340c10f1990604401600060405180830381600087803b158015620027e257600080fd5b505af1158015620027f7573d6000803e3d6000fd5b505050505b866001600160a01b0316816001600160a01b03168a6001600160a01b03167f6ed06519caca659cdefa71015c79a561928d3cf8cc4a3e9739fde9fb5fb38d648b6040516200284c91815260200190565b60405180910390a450505062001b9a60018055565b806001600160a01b0381166200288a576040516342bcdf7f60e11b815260040160405180910390fd5b7f19bf281d118073c159a713666aba52e0d403520cd01e03f42e0f62a0b3bd4a35620028b68162002f72565b61010a546000818152610108602090815260408083206001600160a01b038881168552925290912054166101111462002927576040517f82f5d0a50000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240162000b05565b6000818152610108602090815260408083206001600160a01b038816808552925280832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555190917f0145163d8d460d1ab21463758d147fdfe79d4b57c81ca3d1439996104ae6895991a250505050565b60008281526097602090815260408083206001600160a01b038516845290915290205460ff16620013815760008281526097602090815260408083206001600160a01b0385168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905562002a1b3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600054610100900460ff1662002ade5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b62002ae862003b10565b565b600054610100900460ff1662002b695760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b60005b8381101562002c9c5784848281811062002b8a5762002b8a620048f6565b9050604002016020013560d7600087878581811062002bad5762002bad620048f6565b62002bc5926020604090920201908101915062004406565b600881111562002bd95762002bd962004865565b600881111562002bed5762002bed62004865565b815260208101919091526040016000205584848281811062002c135762002c13620048f6565b9050604002016020013585858381811062002c325762002c32620048f6565b62002c4a926020604090920201908101915062004406565b600881111562002c5e5762002c5e62004865565b6040517f33aa8fd1ce49e1761bc8d27fd53414bfefc45d690feed0ce55019d7d3aec609190600090a38062002c938162004954565b91505062002b6c565b5060005b81811015620024295782828281811062002cbe5762002cbe620048f6565b9050604002016020013560d8600085858581811062002ce15762002ce1620048f6565b62002cf9926020604090920201908101915062004406565b600881111562002d0d5762002d0d62004865565b600881111562002d215762002d2162004865565b815260208101919091526040016000205582828281811062002d475762002d47620048f6565b9050604002016020013583838381811062002d665762002d66620048f6565b62002d7e926020604090920201908101915062004406565b600881111562002d925762002d9262004865565b6040517fe7bf4b8dc0c17a52dc9e52323a3ab61cb2079db35f969125b1f8a3d984c6f6c290600090a38062002dc78162004954565b91505062002ca0565b600054610100900460ff1662002e4f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b60005b81811015620012f057600083838381811062002e725762002e72620048f6565b62002e8a9260206040909202019081019150620046c2565b6001600160a01b03160362002eb2576040516342bcdf7f60e11b815260040160405180910390fd5b82828281811062002ec75762002ec7620048f6565b905060400201602001356000801b0362002f0d576040517f0742d05300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62002f5d83838381811062002f265762002f26620048f6565b9050604002016020013584848481811062002f455762002f45620048f6565b62001ecf9260206040909202019081019150620046c2565b8062002f698162004954565b91505062002e52565b62002f7e813362003b8f565b50565b60008281526097602090815260408083206001600160a01b038516845290915290205460ff1615620013815760008281526097602090815260408083206001600160a01b038516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600260015403620030775760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640162000b05565b6002600155565b60d65481600881111562003096576200309662004865565b6001901b811615620030d857816040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040162000b05919062004894565b6002811615620013815760016040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040162000b05919062004894565b6040516001600160a01b0380851660248301528316604482015260648101829052620012c19085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915262003c0d565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f06fdde0300000000000000000000000000000000000000000000000000000000179052905160609160009182916001600160a01b0386169162003243919062004b8e565b600060405180830381855afa9150503d806000811462003280576040519150601f19603f3d011682016040523d82523d6000602084013e62003285565b606091505b509150915081620032cc576040518060400160405280600781526020017f4e4f5f4e414d4500000000000000000000000000000000000000000000000000815250620032d7565b620032d78162003cfc565b949350505050565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f95d89b4100000000000000000000000000000000000000000000000000000000179052905160609160009182916001600160a01b0386169162003356919062004b8e565b600060405180830381855afa9150503d806000811462003393576040519150601f19603f3d011682016040523d82523d6000602084013e62003398565b606091505b509150915081620032cc576040518060400160405280600981526020017f4e4f5f53594d424f4c0000000000000000000000000000000000000000000000815250620032d7565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f313ce567000000000000000000000000000000000000000000000000000000001790529051600091829182916001600160a01b0386169162003455919062004b8e565b600060405180830381855afa9150503d806000811462003492576040519150601f19603f3d011682016040523d82523d6000602084013e62003497565b606091505b5091509150818015620034ab575060208151145b15620034c75780806020019051810190620032d7919062004bbc565b6040517fb5a2f1c60000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240162000b05565b60018055565b6001600160a01b03811662003533576040516342bcdf7f60e11b815260040160405180910390fd5b60ca80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040513391907fe68b208814fdb633b222cd15e73d5a27fb4ef9eef4cae78c623bc27702141d2890600090a350565b600054610100900460ff16620036175760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b6001600160a01b0381166200363f576040516342bcdf7f60e11b815260040160405180910390fd5b60c980547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b7fd505accf00000000000000000000000000000000000000000000000000000000620036aa60046000848662004bdc565b620036b59162004c08565b7fffffffff0000000000000000000000000000000000000000000000000000000016146200377657620036ed60046000838562004bdc565b620036f89162004c08565b6040517fcf9e29460000000000000000000000000000000000000000000000000000000081527fffffffff0000000000000000000000000000000000000000000000000000000090911660048201527fd505accf00000000000000000000000000000000000000000000000000000000602482015260440162000b05565b60008080808080806200378d886004818c62004bdc565b8101906200379c919062004c51565b9650965096509650965096509650336001600160a01b0316876001600160a01b03161462003802576040517f200688cc0000000000000000000000000000000000000000000000000000000081526001600160a01b038816600482015260240162000b05565b6001600160a01b038616301462003851576040517f291159480000000000000000000000000000000000000000000000000000000081526001600160a01b038716600482015260240162000b05565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015287811660248301528691908c169063dd62ed3e90604401602060405180830381865afa158015620038bc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620038e2919062004a11565b101562003989576040517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018690526064810185905260ff8416608482015260a4810183905260c481018290526001600160a01b038b169063d505accf9060e401600060405180830381600087803b1580156200396f57600080fd5b505af115801562003984573d6000803e3d6000fd5b505050505b50505050505050505050565b6040516001600160a01b038316602482015260448101829052620012f09084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640162003167565b6000818152602085905260408120610107546040516001600160a01b039091169062003a0c9062004263565b6001600160a01b0390911681526040602082018190526000908201526060018190604051809103906000f590508015801562003a4c573d6000803e3d6000fd5b5090506000808062003a618688018862004d50565b925092509250836001600160a01b0316631624f6c68484846040518463ffffffff1660e01b815260040162003a999392919062004a41565b600060405180830381600087803b15801562003ab457600080fd5b505af115801562003ac9573d6000803e3d6000fd5b50506040516001600160a01b03808c169350871691507fd5d4920bb61e6141c8499d50a7bd617dae2b1818c9d6b995d3f2ba4975e32ea490600090a3505050949350505050565b600054610100900460ff16620035055760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b60008281526097602090815260408083206001600160a01b038516845290915290205460ff16620013815762003bc58162003ecf565b62003bd283602062003ee2565b60405160200162003be592919062004dc6565b60408051601f198184030181529082905262461bcd60e51b825262000b059160040162004544565b600062003c64826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316620041309092919063ffffffff16565b905080516000148062003c8857508080602001905181019062003c88919062004e4b565b620012f05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840162000b05565b6060604082511062003d1e578180602001905181019062000c9e919062004e6f565b602082511462003d6157505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e470000000000000000000000000000602082015290565b60005b60208110801562003daf575082818151811062003d855762003d85620048f6565b01602001517fff000000000000000000000000000000000000000000000000000000000000001615155b1562003dbe5760010162003d64565b8060000362003e0257505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e4700000000000000000000000000006020820152919050565b60008167ffffffffffffffff81111562003e205762003e2062004559565b6040519080825280601f01601f19166020018201604052801562003e4b576020820181803683370190505b50905060005b8281101562003ec75784818151811062003e6f5762003e6f620048f6565b602001015160f81c60f81b82828151811062003e8f5762003e8f620048f6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060010162003e51565b509392505050565b606062000c9e6001600160a01b03831660145b6060600062003ef383600262004ee6565b62003f0090600262004f00565b67ffffffffffffffff81111562003f1b5762003f1b62004559565b6040519080825280601f01601f19166020018201604052801562003f46576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811062003f805762003f80620048f6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811062003fe65762003fe6620048f6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006200402484600262004ee6565b6200403190600162004f00565b90505b6001811115620040d8577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110620040765762004076620048f6565b1a60f81b8282815181106200408f576200408f620048f6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93620040d08162004f16565b905062004034565b508315620041295760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640162000b05565b9392505050565b6060620032d7848460008585600080866001600160a01b031685876040516200415a919062004b8e565b60006040518083038185875af1925050503d806000811462004199576040519150601f19603f3d011682016040523d82523d6000602084013e6200419e565b606091505b5091509150620041b187838387620041bc565b979650505050505050565b606083156200423057825160000362004228576001600160a01b0385163b620042285760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000b05565b5081620032d7565b620032d78383815115620042475781518083602001fd5b8060405162461bcd60e51b815260040162000b05919062004544565b6106f38062004f4f83390190565b6001600160a01b038116811462002f7e57600080fd5b60008083601f8401126200429a57600080fd5b50813567ffffffffffffffff811115620042b357600080fd5b6020830191508360208260061b8501011115620042cf57600080fd5b9250929050565b60008060008060008060006080888a031215620042f257600080fd5b8735620042ff8162004271565b9650602088013567ffffffffffffffff808211156200431d57600080fd5b6200432b8b838c0162004287565b909850965060408a01359150808211156200434557600080fd5b620043538b838c0162004287565b909650945060608a01359150808211156200436d57600080fd5b506200437c8a828b0162004287565b989b979a50959850939692959293505050565b600060208284031215620043a257600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146200412957600080fd5b60008060408385031215620043e757600080fd5b823591506020830135620043fb8162004271565b809150509250929050565b6000602082840312156200441957600080fd5b8135600981106200412957600080fd5b600080604083850312156200443d57600080fd5b82356200444a8162004271565b91506020830135620043fb8162004271565b6000602082840312156200446f57600080fd5b5035919050565b600080602083850312156200448a57600080fd5b823567ffffffffffffffff80821115620044a357600080fd5b818501915085601f830112620044b857600080fd5b813581811115620044c857600080fd5b8660208260051b8501011115620044de57600080fd5b60209290920196919550909350505050565b60005b838110156200450d578181015183820152602001620044f3565b50506000910152565b6000815180845262004530816020860160208601620044f0565b601f01601f19169290920160200192915050565b60208152600062004129602083018462004516565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715620045b457620045b462004559565b604052919050565b60006020808385031215620045d057600080fd5b823567ffffffffffffffff80821115620045e957600080fd5b818501915085601f830112620045fe57600080fd5b81358181111562004613576200461362004559565b8060051b91506200462684830162004588565b81815291830184019184810190888411156200464157600080fd5b938501935b838510156200466f57843592506200465e8362004271565b828252938501939085019062004646565b98975050505050505050565b6000806000606084860312156200469157600080fd5b83356200469e8162004271565b9250602084013591506040840135620046b78162004271565b809150509250925092565b600060208284031215620046d557600080fd5b8135620041298162004271565b600060208284031215620046f557600080fd5b813567ffffffffffffffff8111156200470d57600080fd5b820161012081850312156200412957600080fd5b60008083601f8401126200473457600080fd5b50813567ffffffffffffffff8111156200474d57600080fd5b602083019150836020828501011115620042cf57600080fd5b6000806000806000608086880312156200477f57600080fd5b85356200478c8162004271565b9450602086013593506040860135620047a58162004271565b9250606086013567ffffffffffffffff811115620047c257600080fd5b620047d08882890162004721565b969995985093965092949392505050565b60008060008060008060a08789031215620047fb57600080fd5b8635620048088162004271565b9550602087013594506040870135620048218162004271565b935060608701359250608087013567ffffffffffffffff8111156200484557600080fd5b6200485389828a0162004721565b979a9699509497509295939492505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160098310620048d0577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b600060208284031215620048e957600080fd5b8151620041298162004271565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820362004988576200498862004925565b5060010190565b6020808252825182820181905260009190848201906040850190845b81811015620049d25783516001600160a01b031683529284019291840191600101620049ab565b50909695505050505050565b6001600160a01b038416815282602082015260606040820152600062004a08606083018462004516565b95945050505050565b60006020828403121562004a2457600080fd5b5051919050565b8181038181111562000c9e5762000c9e62004925565b60608152600062004a56606083018662004516565b828103602084015262004a6a818662004516565b91505060ff83166040830152949350505050565b60006001600160a01b03808816835286602084015280861660408401525083606083015260a06080830152620041b160a083018462004516565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811262004aee57600080fd5b83018035915067ffffffffffffffff82111562004b0a57600080fd5b6020019150600681901b3603821315620042cf57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811262004b5957600080fd5b83018035915067ffffffffffffffff82111562004b7557600080fd5b6020019150600581901b3603821315620042cf57600080fd5b6000825162004ba2818460208701620044f0565b9190910192915050565b60ff8116811462002f7e57600080fd5b60006020828403121562004bcf57600080fd5b8151620041298162004bac565b6000808585111562004bed57600080fd5b8386111562004bfb57600080fd5b5050820193919092039150565b7fffffffff00000000000000000000000000000000000000000000000000000000813581811691600485101562004c495780818660040360031b1b83161692505b505092915050565b600080600080600080600060e0888a03121562004c6d57600080fd5b873562004c7a8162004271565b9650602088013562004c8c8162004271565b95506040880135945060608801359350608088013562004cac8162004bac565b9699959850939692959460a0840135945060c09093013592915050565b600067ffffffffffffffff82111562004ce65762004ce662004559565b50601f01601f191660200190565b600082601f83011262004d0657600080fd5b813562004d1d62004d178262004cc9565b62004588565b81815284602083860101111562004d3357600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121562004d6657600080fd5b833567ffffffffffffffff8082111562004d7f57600080fd5b62004d8d8783880162004cf4565b9450602086013591508082111562004da457600080fd5b5062004db38682870162004cf4565b9250506040840135620046b78162004bac565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835162004e00816017850160208801620044f0565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000601791840191820152835162004e3f816028840160208801620044f0565b01602801949350505050565b60006020828403121562004e5e57600080fd5b815180151581146200412957600080fd5b60006020828403121562004e8257600080fd5b815167ffffffffffffffff81111562004e9a57600080fd5b8201601f8101841362004eac57600080fd5b805162004ebd62004d178262004cc9565b81815285602083850101111562004ed357600080fd5b62004a08826020830160208601620044f0565b808202811582820484141762000c9e5762000c9e62004925565b8082018082111562000c9e5762000c9e62004925565b60008162004f285762004f2862004925565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fe60806040526040516106f33803806106f383398101604081905261002291610420565b61002e82826000610035565b505061054a565b61003e836100f6565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100f1576100ef836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e991906104e0565b8361027a565b505b505050565b6001600160a01b0381163b6101605760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101d4816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101c591906104e0565b6001600160a01b03163b151590565b6102395760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610157565b7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b0392909216919091179055565b606061029f83836040518060600160405280602781526020016106cc602791396102a6565b9392505050565b6060600080856001600160a01b0316856040516102c391906104fb565b600060405180830381855af49150503d80600081146102fe576040519150601f19603f3d011682016040523d82523d6000602084013e610303565b606091505b5090925090506103158683838761031f565b9695505050505050565b6060831561038e578251600003610387576001600160a01b0385163b6103875760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610157565b5081610398565b61039883836103a0565b949350505050565b8151156103b05781518083602001fd5b8060405162461bcd60e51b81526004016101579190610517565b80516001600160a01b03811681146103e157600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b838110156104175781810151838201526020016103ff565b50506000910152565b6000806040838503121561043357600080fd5b61043c836103ca565b60208401519092506001600160401b038082111561045957600080fd5b818501915085601f83011261046d57600080fd5b81518181111561047f5761047f6103e6565b604051601f8201601f19908116603f011681019083821181831017156104a7576104a76103e6565b816040528281528860208487010111156104c057600080fd5b6104d18360208301602088016103fc565b80955050505050509250929050565b6000602082840312156104f257600080fd5b61029f826103ca565b6000825161050d8184602087016103fc565b9190910192915050565b60208152600082518060208401526105368160408501602087016103fc565b601f01601f19169190910160400192915050565b610173806105596000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610029565b6100dc565b565b60006100697fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d505473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100d79190610100565b905090565b3660008037600080366000845af43d6000803e8080156100fb573d6000f35b3d6000fd5b60006020828403121561011257600080fd5b815173ffffffffffffffffffffffffffffffffffffffff8116811461013657600080fd5b939250505056fea2646970667358221220662c40b76fc0d477a291a78deacd27f4cddd7512dea18087244e38acb2fd99dd64736f6c63430008130033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212201f32ef901647bd30a862a1b3c8df5817d7cc11f4c5759955bd247c2eb12e6c9564736f6c63430008130033", + "deployedBytecode": "0x6080604052600436106200030b5760003560e01c806391d148541162000197578063ca41a24711620000e7578063d547741f1162000095578063e4d27451116200006c578063e4d2745114620009f3578063edc42a221462000a18578063fe3c50a01462000a3d57600080fd5b8063d547741f1462000992578063dfa96efb14620009b7578063e196fb5d14620009ce57600080fd5b8063ccf5a77c11620000ca578063ccf5a77c1462000914578063cdd914c51462000937578063cf4a7208146200095c57600080fd5b8063ca41a24714620008a5578063cc5782f614620008e057600080fd5b8063b3232bdf1162000145578063be46096f1162000128578063be46096f1462000814578063c483d8381462000839578063c986752a146200086f57600080fd5b8063b3232bdf14620007ca578063bc61e73314620007ef57600080fd5b8063a217fddf116200017a578063a217fddf146200076c578063a676e8ab1462000783578063a6ef995f14620007a857600080fd5b806391d1485414620006ec5780639ac25d08146200073657600080fd5b80632f2ff15d116200025f578063522ea81a116200020d5780636a906b8011620001e45780636a906b80146200065e57806380efb43a14620006945780638dae45dd14620006ca57600080fd5b8063522ea81a14620005db5780635626fc2514620005f25780635a06a42a146200062857600080fd5b806336568abe116200024257806336568abe146200054557806338b90333146200056a5780634bf98dce14620005c457600080fd5b80632f2ff15d14620004ea5780633551237b146200050f57600080fd5b80631544298e11620002bd578063248a9ca311620002a0578063248a9ca3146200045b5780632a564f34146200048f5780632e4c3fff14620004b457600080fd5b80631544298e146200041d5780631754f301146200043657600080fd5b80630f6f86ec11620002f25780630f6f86ec14620003715780631065a39914620003d0578063146ffb2614620003f557600080fd5b806301941d39146200031057806301ffc9a71462000337575b600080fd5b3480156200031d57600080fd5b50620003356200032f366004620042d6565b62000a73565b005b3480156200034457600080fd5b506200035c620003563660046200438f565b62000c0a565b60405190151581526020015b60405180910390f35b3480156200037e57600080fd5b50620003b762000390366004620043d3565b6101086020908152600092835260408084209091529082529020546001600160a01b031681565b6040516001600160a01b03909116815260200162000368565b348015620003dd57600080fd5b5062000335620003ef36600462004406565b62000ca4565b3480156200040257600080fd5b506200040e61010b5481565b60405190815260200162000368565b3480156200042a57600080fd5b506200040e61010a5481565b3480156200044357600080fd5b50620003356200045536600462004429565b62000dad565b3480156200046857600080fd5b506200040e6200047a3660046200445c565b60009081526097602052604090206001015490565b3480156200049c57600080fd5b5062000335620004ae36600462004476565b620010a8565b348015620004c157600080fd5b506200040e7f8a7b208fd13ab36d18025be4f62b53d46aeb2cbe8958d2e13de74c040dddcddd81565b348015620004f757600080fd5b506200033562000509366004620043d3565b620012c7565b3480156200051c57600080fd5b506200040e7f19bf281d118073c159a713666aba52e0d403520cd01e03f42e0f62a0b3bd4a3581565b3480156200055257600080fd5b506200033562000564366004620043d3565b620012f5565b3480156200057757600080fd5b50620005b56040518060400160405280600381526020017f312e30000000000000000000000000000000000000000000000000000000000081525081565b60405162000368919062004544565b62000335620005d5366004620045bc565b62001385565b62000335620005ec3660046200467b565b620015f4565b348015620005ff57600080fd5b506200040e7f46e34517dc946faf87aabe65eb5b4fa06b974e5c8d72c5df73b9fb6ff7b6d80281565b3480156200063557600080fd5b506200040e7f50962b2d10066f5051f78d5ea04a3ab09b9c87dd1002962f0b1e30e66eeb80a581565b3480156200066b57600080fd5b506200040e7fd8b4c34c2ec1f3194471108c64ad2beda340c0337ee4ca35592f9ef270f4228b81565b348015620006a157600080fd5b506200040e7fbf094fe3c005c553ff0d33c7dff9d1273add12fb3f258b992f8d36224dd35b2481565b348015620006d757600080fd5b5060c954620003b7906001600160a01b031681565b348015620006f957600080fd5b506200035c6200070b366004620043d3565b60009182526097602090815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156200074357600080fd5b506200040e7f56bdc3c9ec86cb7db110a7699b2ade72f0b8819727d9f7d906b012641505fa7781565b3480156200077957600080fd5b506200040e600081565b3480156200079057600080fd5b5062000335620007a2366004620046c2565b62001ba2565b348015620007b557600080fd5b5060ca54620003b7906001600160a01b031681565b348015620007d757600080fd5b5062000335620007e9366004620046e2565b62001c67565b348015620007fc57600080fd5b506200035c6200080e36600462004406565b62002189565b3480156200082157600080fd5b506200033562000833366004620046c2565b620021b1565b3480156200084657600080fd5b506200040e7feaf25fcc6b7d45bda16c56628df3f435e20319ef53b065c11ee4510083f0ae2d81565b3480156200087c57600080fd5b506200040e7f550554a677c8e7b73b62db78b0ef06c5f237da4ef30b88196a899ccf591041fe81565b348015620008b257600080fd5b50620003b7620008c4366004620046c2565b610109602052600090815260409020546001600160a01b031681565b348015620008ed57600080fd5b506200035c620008ff3660046200445c565b60d56020526000908152604090205460ff1681565b3480156200092157600080fd5b5061010754620003b7906001600160a01b031681565b3480156200094457600080fd5b506200033562000956366004620046c2565b62002274565b3480156200096957600080fd5b506200040e7f3900d9d72d5177a154375317154fdc0e08377e3134a8a5d21cadccf831cc231c81565b3480156200099f57600080fd5b5062000335620009b1366004620043d3565b620023df565b62000335620009c836600462004766565b62002408565b348015620009db57600080fd5b5062000335620009ed36600462004406565b62002430565b34801562000a0057600080fd5b506200033562000a12366004620047e1565b6200251e565b34801562000a2557600080fd5b506200033562000a37366004620046c2565b62002861565b34801562000a4a57600080fd5b506200040e7f77974cc9cb5bafc9bb265be792d93fa46355c05701895b82f6d3b4b448c8ce0081565b600054600290610100900460ff1615801562000a96575060005460ff8083169116105b62000b0e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001790556001600160a01b03881662000b67576040516342bcdf7f60e11b815260040160405180910390fd5b62000b746000896200299d565b6000606555600060d55562000b8862002a5f565b62000b968585858562002aea565b62000ba2878762002dd0565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148062000c9e57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60d8600082600881111562000cbd5762000cbd62004865565b600881111562000cd15762000cd162004865565b81526020019081526020016000205462000ceb8162002f72565b62000cf68262002189565b62000d3157816040517f1865965400000000000000000000000000000000000000000000000000000000815260040162000b05919062004894565b81600881111562000d465762000d4662004865565b60d68054600190921b19909116905581600881111562000d6a5762000d6a62004865565b7fd071d2b85dec4489435b541d2f0e2570db09b09db9efd8703948d44a433df65a335b6040516001600160a01b0390911681526020015b60405180910390a25050565b816001600160a01b03811662000dd6576040516342bcdf7f60e11b815260040160405180910390fd5b816001600160a01b03811662000dff576040516342bcdf7f60e11b815260040160405180910390fd5b7f550554a677c8e7b73b62db78b0ef06c5f237da4ef30b88196a899ccf591041fe62000e2b8162002f72565b6001600160a01b038086166000908152610109602052604090205486911615158062000e7f575061010a546000908152610108602090815260408083206001600160a01b0385811685529252909120541615155b1562000ec3576040517f12f3df090000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260240162000b05565b6001600160a01b0385811660009081526101096020526040902054161562000f23576040517ff8fb7c270000000000000000000000000000000000000000000000000000000081526001600160a01b038616600482015260240162000b05565b6001600160a01b038516610222148062000f4757506001600160a01b038516610333145b8062000f5d57506001600160a01b038516610111145b1562000fa1576040517fd8ce8acb0000000000000000000000000000000000000000000000000000000081526001600160a01b038616600482015260240162000b05565b61010b546000818152610108602090815260408083206001600160a01b038b8116855292529091205416156200100f576040517f022bc8410000000000000000000000000000000000000000000000000000000081526001600160a01b038816600482015260240162000b05565b6000818152610108602090815260408083206001600160a01b03808c168086529184528285208054918c167fffffffffffffffffffffffff00000000000000000000000000000000000000009283168117909155808652610109909452828520805490911682179055905133937f844cb5c635052898ad92bea4ece14519111765d835105e76aa1f77ad0d0aa81f91a450505050505050565b60c9546001600160a01b03163314620010ed576040517f8c56efb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ca5460c954604080517f67e404ce00000000000000000000000000000000000000000000000000000000815290516001600160a01b0393841693909216916367e404ce916004808201926020929091908290030181865afa15801562001158573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200117e9190620048d6565b6001600160a01b031614620011bf576040517f79d1e58f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61010a5460005b82811015620012c15760008281526101086020526040812061033391868685818110620011f757620011f7620048f6565b90506020020160208101906200120e9190620046c2565b6001600160a01b039081168252602082019290925260400160002080547fffffffffffffffffffffffff000000000000000000000000000000000000000016929091169190911790558383828181106200126c576200126c620048f6565b9050602002016020810190620012839190620046c2565b6001600160a01b03167f91d24864a084ab70b268a1f865e757ca12006cf298d763b6be697302ef86498c60405160405180910390a2600101620011c6565b50505050565b600082815260976020526040902060010154620012e48162002f72565b620012f083836200299d565b505050565b6001600160a01b0381163314620013755760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c660000000000000000000000000000000000606482015260840162000b05565b62001381828262002f81565b5050565b80516000819003620013c3576040517f10cbd58300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015620014bf5760006101096000858481518110620013eb57620013eb620048f6565b6020908102919091018101516001600160a01b0390811683529082019290925260400160002054169050806200147b57838281518110620014305762001430620048f6565b60200260200101516040517fa5ea89da00000000000000000000000000000000000000000000000000000000815260040162000b0591906001600160a01b0391909116815260200190565b80848381518110620014915762001491620048f6565b6001600160a01b03909216602092830291909101909101525080620014b68162004954565b915050620013c6565b5060c95460ca546040516001600160a01b0392831692639f3ce55a9234929116908290620014f29088906024016200498f565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f2a564f3400000000000000000000000000000000000000000000000000000000179052517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b1681526200158593929190600401620049de565b6000604051808303818588803b1580156200159f57600080fd5b505af1158015620015b4573d6000803e3d6000fd5b5050505050336001600160a01b03167f59eab5b5f813ac9e0c10035dfb55b5e3419eff53c0f7a869fb3c22400ea036d68360405162000da191906200498f565b826001600160a01b0381166200161d576040516342bcdf7f60e11b815260040160405180910390fd5b816001600160a01b03811662001646576040516342bcdf7f60e11b815260040160405180910390fd5b838060000362001686576040517f4618044a0000000000000000000000000000000000000000000000000000000081526004810182905260240162000b05565b6200169062003023565b6200169c60076200307e565b61010a546000818152610108602090815260408083206001600160a01b03808c168552925290912054167ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeef81016200172c576040517f6dad9c780000000000000000000000000000000000000000000000000000000081526001600160a01b038916600482015260240162000b05565b6001600160a01b03808916600090815261010960205260408120549091169060608215620017db576040517f9dc29fac000000000000000000000000000000000000000000000000000000008152336004820152602481018b90526001600160a01b038c1690639dc29fac90604401600060405180830381600087803b158015620017b657600080fd5b505af1158015620017cb573d6000803e3d6000fd5b5050505061010b54915062001a15565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000906001600160a01b038d16906370a0823190602401602060405180830381865afa1580156200183c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001862919062004a11565b90506200187b6001600160a01b038d1633308e62003119565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038e16906370a0823190602401602060405180830381865afa158015620018db573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001901919062004a11565b6200190d919062004a2b565b9a508b93506001600160a01b038516620019b657610222610108600088815260200190815260200160002060008e6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508b6001600160a01b03167f0f53e2a811b6fd2d6cd965fd6c27b44fb924ca39f7a7f321115705c22366d62360405160405180910390a25b6001600160a01b0385166103331462001a1057620019d48c620031cc565b620019df8d620032df565b620019ea8e620033df565b604051602001620019fe9392919062004a41565b60405160208183030381529060405291505b859250505b60c960009054906101000a90046001600160a01b03166001600160a01b0316639f3ce55a3460ca60009054906101000a90046001600160a01b031634878f8f898960405160240162001a6c95949392919062004a7e565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe4d2745100000000000000000000000000000000000000000000000000000000179052517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815262001aff93929190600401620049de565b6000604051808303818588803b15801562001b1957600080fd5b505af115801562001b2e573d6000803e3d6000fd5b50505050508a6001600160a01b0316896001600160a01b0316336001600160a01b03167f8780a94875b70464f8ac6c28851501d32e7fd4ee574e4b94beb28923a3c42d9c8d60405162001b8391815260200190565b60405180910390a4505050505062001b9a60018055565b505050505050565b7fbf094fe3c005c553ff0d33c7dff9d1273add12fb3f258b992f8d36224dd35b2462001bce8162002f72565b60ca546001600160a01b03161562001c225760ca546040517f94fbfd2e0000000000000000000000000000000000000000000000000000000081526001600160a01b03909116600482015260240162000b05565b62001c2d826200350b565b60405133906001600160a01b038416907fb044c1a1a05a729c402def784b4e4cb01612ff03eee6f0beb3eba0f0606260a190600090a35050565b62001c796040820160208301620046c2565b6001600160a01b03811662001ca1576040516342bcdf7f60e11b815260040160405180910390fd5b62001cb36060830160408401620046c2565b6001600160a01b03811662001cdb576040516342bcdf7f60e11b815260040160405180910390fd5b82606001358060000362001d1b576040517f488d765100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83608001358060000362001d5b576040517f488d765100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff161580801562001d7c5750600054600160ff909116105b8062001d985750303b15801562001d98575060005460ff166001145b62001e0c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840162000b05565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801562001e6b57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b62001e9462001e7e60e088018862004ab8565b62001e8e6101008a018a62004ab8565b62002aea565b62001eb062001eaa6040880160208901620046c2565b62003598565b62001eba62002a5f565b62001ed5600062001ecf6020890189620046c2565b6200299d565b62001eee62001ee860c088018862004ab8565b62002dd0565b62001f006060870160408801620046c2565b61010780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055608086013560608701350362001f7b576040517fac867a5500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606086013561010a55608086013561010b5560005b62001f9f60a088018862004b23565b90508110156200211d57600062001fba60a089018962004b23565b8381811062001fcd5762001fcd620048f6565b905060200201602081019062001fe49190620046c2565b6001600160a01b0316036200200c576040516342bcdf7f60e11b815260040160405180910390fd5b6060870135600090815261010860205260408120610111916200203360a08b018b62004b23565b85818110620020465762002046620048f6565b90506020020160208101906200205d9190620046c2565b6001600160a01b039081168252602082019290925260400160002080547fffffffffffffffffffffffff00000000000000000000000000000000000000001692909116919091179055620020b560a088018862004b23565b82818110620020c857620020c8620048f6565b9050602002016020810190620020df9190620046c2565b6001600160a01b03167f5e023c7a09fa0534ce3199f65fc3e635a5e851c5adc88ebda3b9d332ae07cbe960405160405180910390a260010162001f90565b50801562001b9a57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b6000816008811115620021a057620021a062004865565b60d654600190911b16151592915050565b806001600160a01b038116620021da576040516342bcdf7f60e11b815260040160405180910390fd5b7f77974cc9cb5bafc9bb265be792d93fa46355c05701895b82f6d3b4b448c8ce00620022068162002f72565b60c980546001600160a01b038581167fffffffffffffffffffffffff00000000000000000000000000000000000000008316811790935560405191169133918391907fc96d462e42a71473da49a1d58c1754b9b2d319786692d621dc7f921331c517e990600090a450505050565b806001600160a01b0381166200229d576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0380831660009081526101096020526040902054839116151580620022f1575061010a546000908152610108602090815260408083206001600160a01b0385811685529252909120541615155b1562002335576040517f12f3df090000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260240162000b05565b7feaf25fcc6b7d45bda16c56628df3f435e20319ef53b065c11ee4510083f0ae2d620023618162002f72565b61010a546000908152610108602090815260408083206001600160a01b038816808552925280832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166101111790555190917f5e023c7a09fa0534ce3199f65fc3e635a5e851c5adc88ebda3b9d332ae07cbe991a250505050565b600082815260976020526040902060010154620023fc8162002f72565b620012f0838362002f81565b80156200241c576200241c85838362003679565b62002429858585620015f4565b5050505050565b60d7600082600881111562002449576200244962004865565b60088111156200245d576200245d62004865565b815260200190815260200160002054620024778162002f72565b620024828262002189565b15620024be57816040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040162000b05919062004894565b816008811115620024d357620024d362004865565b60d68054600190921b9091179055816008811115620024f657620024f662004865565b7f534f879afd40abb4e39f8e1b77a316be4c8e3521d9cf5a3a3db8959d574d45593362000d8d565b6200252862003023565b60c9546001600160a01b031633146200256d576040517f8c56efb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ca5460c954604080517f67e404ce00000000000000000000000000000000000000000000000000000000815290516001600160a01b0393841693909216916367e404ce916004808201926020929091908290030181865afa158015620025d8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620025fe9190620048d6565b6001600160a01b0316146200263f576040517f79d1e58f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60086200264c816200307e565b6000848152610108602090815260408083206001600160a01b03808c168552925282205416906102228214806200268d57506001600160a01b038216610333145b15620026af57620026a96001600160a01b038a16888a62003995565b620027fc565b50806001600160a01b0381166200277e57620026d189868661010a54620039e0565b9050886101096000836001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555080610108600061010b54815260200190815260200160002060008b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b038881166004830152602482018a90528216906340c10f1990604401600060405180830381600087803b158015620027e257600080fd5b505af1158015620027f7573d6000803e3d6000fd5b505050505b866001600160a01b0316816001600160a01b03168a6001600160a01b03167f6ed06519caca659cdefa71015c79a561928d3cf8cc4a3e9739fde9fb5fb38d648b6040516200284c91815260200190565b60405180910390a450505062001b9a60018055565b806001600160a01b0381166200288a576040516342bcdf7f60e11b815260040160405180910390fd5b7f19bf281d118073c159a713666aba52e0d403520cd01e03f42e0f62a0b3bd4a35620028b68162002f72565b61010a546000818152610108602090815260408083206001600160a01b038881168552925290912054166101111462002927576040517f82f5d0a50000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240162000b05565b6000818152610108602090815260408083206001600160a01b038816808552925280832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555190917f0145163d8d460d1ab21463758d147fdfe79d4b57c81ca3d1439996104ae6895991a250505050565b60008281526097602090815260408083206001600160a01b038516845290915290205460ff16620013815760008281526097602090815260408083206001600160a01b0385168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905562002a1b3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600054610100900460ff1662002ade5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b62002ae862003b10565b565b600054610100900460ff1662002b695760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b60005b8381101562002c9c5784848281811062002b8a5762002b8a620048f6565b9050604002016020013560d7600087878581811062002bad5762002bad620048f6565b62002bc5926020604090920201908101915062004406565b600881111562002bd95762002bd962004865565b600881111562002bed5762002bed62004865565b815260208101919091526040016000205584848281811062002c135762002c13620048f6565b9050604002016020013585858381811062002c325762002c32620048f6565b62002c4a926020604090920201908101915062004406565b600881111562002c5e5762002c5e62004865565b6040517f33aa8fd1ce49e1761bc8d27fd53414bfefc45d690feed0ce55019d7d3aec609190600090a38062002c938162004954565b91505062002b6c565b5060005b81811015620024295782828281811062002cbe5762002cbe620048f6565b9050604002016020013560d8600085858581811062002ce15762002ce1620048f6565b62002cf9926020604090920201908101915062004406565b600881111562002d0d5762002d0d62004865565b600881111562002d215762002d2162004865565b815260208101919091526040016000205582828281811062002d475762002d47620048f6565b9050604002016020013583838381811062002d665762002d66620048f6565b62002d7e926020604090920201908101915062004406565b600881111562002d925762002d9262004865565b6040517fe7bf4b8dc0c17a52dc9e52323a3ab61cb2079db35f969125b1f8a3d984c6f6c290600090a38062002dc78162004954565b91505062002ca0565b600054610100900460ff1662002e4f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b60005b81811015620012f057600083838381811062002e725762002e72620048f6565b62002e8a9260206040909202019081019150620046c2565b6001600160a01b03160362002eb2576040516342bcdf7f60e11b815260040160405180910390fd5b82828281811062002ec75762002ec7620048f6565b905060400201602001356000801b0362002f0d576040517f0742d05300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62002f5d83838381811062002f265762002f26620048f6565b9050604002016020013584848481811062002f455762002f45620048f6565b62001ecf9260206040909202019081019150620046c2565b8062002f698162004954565b91505062002e52565b62002f7e813362003b8f565b50565b60008281526097602090815260408083206001600160a01b038516845290915290205460ff1615620013815760008281526097602090815260408083206001600160a01b038516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600260015403620030775760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640162000b05565b6002600155565b60d65481600881111562003096576200309662004865565b6001901b811615620030d857816040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040162000b05919062004894565b6002811615620013815760016040517fc0a71b5800000000000000000000000000000000000000000000000000000000815260040162000b05919062004894565b6040516001600160a01b0380851660248301528316604482015260648101829052620012c19085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915262003c0d565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f06fdde0300000000000000000000000000000000000000000000000000000000179052905160609160009182916001600160a01b0386169162003243919062004b8e565b600060405180830381855afa9150503d806000811462003280576040519150601f19603f3d011682016040523d82523d6000602084013e62003285565b606091505b509150915081620032cc576040518060400160405280600781526020017f4e4f5f4e414d4500000000000000000000000000000000000000000000000000815250620032d7565b620032d78162003cfc565b949350505050565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f95d89b4100000000000000000000000000000000000000000000000000000000179052905160609160009182916001600160a01b0386169162003356919062004b8e565b600060405180830381855afa9150503d806000811462003393576040519150601f19603f3d011682016040523d82523d6000602084013e62003398565b606091505b509150915081620032cc576040518060400160405280600981526020017f4e4f5f53594d424f4c0000000000000000000000000000000000000000000000815250620032d7565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f313ce567000000000000000000000000000000000000000000000000000000001790529051600091829182916001600160a01b0386169162003455919062004b8e565b600060405180830381855afa9150503d806000811462003492576040519150601f19603f3d011682016040523d82523d6000602084013e62003497565b606091505b5091509150818015620034ab575060208151145b15620034c75780806020019051810190620032d7919062004bbc565b6040517fb5a2f1c60000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240162000b05565b60018055565b6001600160a01b03811662003533576040516342bcdf7f60e11b815260040160405180910390fd5b60ca80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040513391907fe68b208814fdb633b222cd15e73d5a27fb4ef9eef4cae78c623bc27702141d2890600090a350565b600054610100900460ff16620036175760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b6001600160a01b0381166200363f576040516342bcdf7f60e11b815260040160405180910390fd5b60c980547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b7fd505accf00000000000000000000000000000000000000000000000000000000620036aa60046000848662004bdc565b620036b59162004c08565b7fffffffff0000000000000000000000000000000000000000000000000000000016146200377657620036ed60046000838562004bdc565b620036f89162004c08565b6040517fcf9e29460000000000000000000000000000000000000000000000000000000081527fffffffff0000000000000000000000000000000000000000000000000000000090911660048201527fd505accf00000000000000000000000000000000000000000000000000000000602482015260440162000b05565b60008080808080806200378d886004818c62004bdc565b8101906200379c919062004c51565b9650965096509650965096509650336001600160a01b0316876001600160a01b03161462003802576040517f200688cc0000000000000000000000000000000000000000000000000000000081526001600160a01b038816600482015260240162000b05565b6001600160a01b038616301462003851576040517f291159480000000000000000000000000000000000000000000000000000000081526001600160a01b038716600482015260240162000b05565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015287811660248301528691908c169063dd62ed3e90604401602060405180830381865afa158015620038bc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620038e2919062004a11565b101562003989576040517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018690526064810185905260ff8416608482015260a4810183905260c481018290526001600160a01b038b169063d505accf9060e401600060405180830381600087803b1580156200396f57600080fd5b505af115801562003984573d6000803e3d6000fd5b505050505b50505050505050505050565b6040516001600160a01b038316602482015260448101829052620012f09084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640162003167565b6000818152602085905260408120610107546040516001600160a01b039091169062003a0c9062004263565b6001600160a01b0390911681526040602082018190526000908201526060018190604051809103906000f590508015801562003a4c573d6000803e3d6000fd5b5090506000808062003a618688018862004d50565b925092509250836001600160a01b0316631624f6c68484846040518463ffffffff1660e01b815260040162003a999392919062004a41565b600060405180830381600087803b15801562003ab457600080fd5b505af115801562003ac9573d6000803e3d6000fd5b50506040516001600160a01b03808c169350871691507fd5d4920bb61e6141c8499d50a7bd617dae2b1818c9d6b995d3f2ba4975e32ea490600090a3505050949350505050565b600054610100900460ff16620035055760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840162000b05565b60008281526097602090815260408083206001600160a01b038516845290915290205460ff16620013815762003bc58162003ecf565b62003bd283602062003ee2565b60405160200162003be592919062004dc6565b60408051601f198184030181529082905262461bcd60e51b825262000b059160040162004544565b600062003c64826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316620041309092919063ffffffff16565b905080516000148062003c8857508080602001905181019062003c88919062004e4b565b620012f05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840162000b05565b6060604082511062003d1e578180602001905181019062000c9e919062004e6f565b602082511462003d6157505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e470000000000000000000000000000602082015290565b60005b60208110801562003daf575082818151811062003d855762003d85620048f6565b01602001517fff000000000000000000000000000000000000000000000000000000000000001615155b1562003dbe5760010162003d64565b8060000362003e0257505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e4700000000000000000000000000006020820152919050565b60008167ffffffffffffffff81111562003e205762003e2062004559565b6040519080825280601f01601f19166020018201604052801562003e4b576020820181803683370190505b50905060005b8281101562003ec75784818151811062003e6f5762003e6f620048f6565b602001015160f81c60f81b82828151811062003e8f5762003e8f620048f6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060010162003e51565b509392505050565b606062000c9e6001600160a01b03831660145b6060600062003ef383600262004ee6565b62003f0090600262004f00565b67ffffffffffffffff81111562003f1b5762003f1b62004559565b6040519080825280601f01601f19166020018201604052801562003f46576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811062003f805762003f80620048f6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811062003fe65762003fe6620048f6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006200402484600262004ee6565b6200403190600162004f00565b90505b6001811115620040d8577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110620040765762004076620048f6565b1a60f81b8282815181106200408f576200408f620048f6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93620040d08162004f16565b905062004034565b508315620041295760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640162000b05565b9392505050565b6060620032d7848460008585600080866001600160a01b031685876040516200415a919062004b8e565b60006040518083038185875af1925050503d806000811462004199576040519150601f19603f3d011682016040523d82523d6000602084013e6200419e565b606091505b5091509150620041b187838387620041bc565b979650505050505050565b606083156200423057825160000362004228576001600160a01b0385163b620042285760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000b05565b5081620032d7565b620032d78383815115620042475781518083602001fd5b8060405162461bcd60e51b815260040162000b05919062004544565b6106f38062004f4f83390190565b6001600160a01b038116811462002f7e57600080fd5b60008083601f8401126200429a57600080fd5b50813567ffffffffffffffff811115620042b357600080fd5b6020830191508360208260061b8501011115620042cf57600080fd5b9250929050565b60008060008060008060006080888a031215620042f257600080fd5b8735620042ff8162004271565b9650602088013567ffffffffffffffff808211156200431d57600080fd5b6200432b8b838c0162004287565b909850965060408a01359150808211156200434557600080fd5b620043538b838c0162004287565b909650945060608a01359150808211156200436d57600080fd5b506200437c8a828b0162004287565b989b979a50959850939692959293505050565b600060208284031215620043a257600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146200412957600080fd5b60008060408385031215620043e757600080fd5b823591506020830135620043fb8162004271565b809150509250929050565b6000602082840312156200441957600080fd5b8135600981106200412957600080fd5b600080604083850312156200443d57600080fd5b82356200444a8162004271565b91506020830135620043fb8162004271565b6000602082840312156200446f57600080fd5b5035919050565b600080602083850312156200448a57600080fd5b823567ffffffffffffffff80821115620044a357600080fd5b818501915085601f830112620044b857600080fd5b813581811115620044c857600080fd5b8660208260051b8501011115620044de57600080fd5b60209290920196919550909350505050565b60005b838110156200450d578181015183820152602001620044f3565b50506000910152565b6000815180845262004530816020860160208601620044f0565b601f01601f19169290920160200192915050565b60208152600062004129602083018462004516565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715620045b457620045b462004559565b604052919050565b60006020808385031215620045d057600080fd5b823567ffffffffffffffff80821115620045e957600080fd5b818501915085601f830112620045fe57600080fd5b81358181111562004613576200461362004559565b8060051b91506200462684830162004588565b81815291830184019184810190888411156200464157600080fd5b938501935b838510156200466f57843592506200465e8362004271565b828252938501939085019062004646565b98975050505050505050565b6000806000606084860312156200469157600080fd5b83356200469e8162004271565b9250602084013591506040840135620046b78162004271565b809150509250925092565b600060208284031215620046d557600080fd5b8135620041298162004271565b600060208284031215620046f557600080fd5b813567ffffffffffffffff8111156200470d57600080fd5b820161012081850312156200412957600080fd5b60008083601f8401126200473457600080fd5b50813567ffffffffffffffff8111156200474d57600080fd5b602083019150836020828501011115620042cf57600080fd5b6000806000806000608086880312156200477f57600080fd5b85356200478c8162004271565b9450602086013593506040860135620047a58162004271565b9250606086013567ffffffffffffffff811115620047c257600080fd5b620047d08882890162004721565b969995985093965092949392505050565b60008060008060008060a08789031215620047fb57600080fd5b8635620048088162004271565b9550602087013594506040870135620048218162004271565b935060608701359250608087013567ffffffffffffffff8111156200484557600080fd5b6200485389828a0162004721565b979a9699509497509295939492505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160098310620048d0577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b600060208284031215620048e957600080fd5b8151620041298162004271565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820362004988576200498862004925565b5060010190565b6020808252825182820181905260009190848201906040850190845b81811015620049d25783516001600160a01b031683529284019291840191600101620049ab565b50909695505050505050565b6001600160a01b038416815282602082015260606040820152600062004a08606083018462004516565b95945050505050565b60006020828403121562004a2457600080fd5b5051919050565b8181038181111562000c9e5762000c9e62004925565b60608152600062004a56606083018662004516565b828103602084015262004a6a818662004516565b91505060ff83166040830152949350505050565b60006001600160a01b03808816835286602084015280861660408401525083606083015260a06080830152620041b160a083018462004516565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811262004aee57600080fd5b83018035915067ffffffffffffffff82111562004b0a57600080fd5b6020019150600681901b3603821315620042cf57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811262004b5957600080fd5b83018035915067ffffffffffffffff82111562004b7557600080fd5b6020019150600581901b3603821315620042cf57600080fd5b6000825162004ba2818460208701620044f0565b9190910192915050565b60ff8116811462002f7e57600080fd5b60006020828403121562004bcf57600080fd5b8151620041298162004bac565b6000808585111562004bed57600080fd5b8386111562004bfb57600080fd5b5050820193919092039150565b7fffffffff00000000000000000000000000000000000000000000000000000000813581811691600485101562004c495780818660040360031b1b83161692505b505092915050565b600080600080600080600060e0888a03121562004c6d57600080fd5b873562004c7a8162004271565b9650602088013562004c8c8162004271565b95506040880135945060608801359350608088013562004cac8162004bac565b9699959850939692959460a0840135945060c09093013592915050565b600067ffffffffffffffff82111562004ce65762004ce662004559565b50601f01601f191660200190565b600082601f83011262004d0657600080fd5b813562004d1d62004d178262004cc9565b62004588565b81815284602083860101111562004d3357600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121562004d6657600080fd5b833567ffffffffffffffff8082111562004d7f57600080fd5b62004d8d8783880162004cf4565b9450602086013591508082111562004da457600080fd5b5062004db38682870162004cf4565b9250506040840135620046b78162004bac565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835162004e00816017850160208801620044f0565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000601791840191820152835162004e3f816028840160208801620044f0565b01602801949350505050565b60006020828403121562004e5e57600080fd5b815180151581146200412957600080fd5b60006020828403121562004e8257600080fd5b815167ffffffffffffffff81111562004e9a57600080fd5b8201601f8101841362004eac57600080fd5b805162004ebd62004d178262004cc9565b81815285602083850101111562004ed357600080fd5b62004a08826020830160208601620044f0565b808202811582820484141762000c9e5762000c9e62004925565b8082018082111562000c9e5762000c9e62004925565b60008162004f285762004f2862004925565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fe60806040526040516106f33803806106f383398101604081905261002291610420565b61002e82826000610035565b505061054a565b61003e836100f6565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100f1576100ef836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e991906104e0565b8361027a565b505b505050565b6001600160a01b0381163b6101605760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101d4816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101c591906104e0565b6001600160a01b03163b151590565b6102395760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610157565b7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b0392909216919091179055565b606061029f83836040518060600160405280602781526020016106cc602791396102a6565b9392505050565b6060600080856001600160a01b0316856040516102c391906104fb565b600060405180830381855af49150503d80600081146102fe576040519150601f19603f3d011682016040523d82523d6000602084013e610303565b606091505b5090925090506103158683838761031f565b9695505050505050565b6060831561038e578251600003610387576001600160a01b0385163b6103875760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610157565b5081610398565b61039883836103a0565b949350505050565b8151156103b05781518083602001fd5b8060405162461bcd60e51b81526004016101579190610517565b80516001600160a01b03811681146103e157600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b838110156104175781810151838201526020016103ff565b50506000910152565b6000806040838503121561043357600080fd5b61043c836103ca565b60208401519092506001600160401b038082111561045957600080fd5b818501915085601f83011261046d57600080fd5b81518181111561047f5761047f6103e6565b604051601f8201601f19908116603f011681019083821181831017156104a7576104a76103e6565b816040528281528860208487010111156104c057600080fd5b6104d18360208301602088016103fc565b80955050505050509250929050565b6000602082840312156104f257600080fd5b61029f826103ca565b6000825161050d8184602087016103fc565b9190910192915050565b60208152600082518060208401526105368160408501602087016103fc565b601f01601f19169190910160400192915050565b610173806105596000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610029565b6100dc565b565b60006100697fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d505473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100d79190610100565b905090565b3660008037600080366000845af43d6000803e8080156100fb573d6000f35b3d6000fd5b60006020828403121561011257600080fd5b815173ffffffffffffffffffffffffffffffffffffffff8116811461013657600080fd5b939250505056fea2646970667358221220662c40b76fc0d477a291a78deacd27f4cddd7512dea18087244e38acb2fd99dd64736f6c63430008130033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212201f32ef901647bd30a862a1b3c8df5817d7cc11f4c5759955bd247c2eb12e6c9564736f6c63430008130033", "linkReferences": {}, "deployedLinkReferences": {} } diff --git a/contracts/package.json b/contracts/package.json index 1669baf18..3169fe785 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -19,7 +19,8 @@ "lint:ts:fix": "npx eslint --fix '**/*.{js,ts}'", "lint": "pnpm run lint:sol && npm run lint:ts && npm run prettier", "lint:fix": "pnpm run lint:sol:fix && npm run lint:ts:fix && npm run prettier:fix", - "clean": "rimraf .openzeppelin build cache node_modules typechain-types coverage coverage.json" + "clean": "rimraf .openzeppelin build cache node_modules typechain-types coverage coverage.json", + "solidity:docgen": "npx hardhat docgen" }, "devDependencies": { "@ethereumjs/util": "9.0.3", diff --git a/contracts/test/LineaRollup.ts b/contracts/test/LineaRollup.ts index 9f0e1083d..327ddae60 100644 --- a/contracts/test/LineaRollup.ts +++ b/contracts/test/LineaRollup.ts @@ -8,11 +8,9 @@ import { CallForwardingProxy, TestLineaRollup, TestLineaRollupV5 } from "../type import calldataAggregatedProof1To155 from "./testData/compressedData/aggregatedProof-1-155.json"; import blobAggregatedProof1To155 from "./testData/compressedDataEip4844/aggregatedProof-1-155.json"; import blobMultipleAggregatedProof1To81 from "./testData/compressedDataEip4844/multipleProofs/aggregatedProof-1-81.json"; -import blobMultipleAggregatedProof82To153 from "./testData/compressedDataEip4844/multipleProofs/aggregatedProof-82-153.json"; import firstCompressedDataContent from "./testData/compressedData/blocks-1-46.json"; import secondCompressedDataContent from "./testData/compressedData/blocks-47-81.json"; import fourthCompressedDataContent from "./testData/compressedData/blocks-115-155.json"; -import fourthMultipleBlobDataContent from "./testData/compressedDataEip4844/multipleProofs/blocks-120-153.json"; import fourthMultipleCompressedDataContent from "./testData/compressedData/multipleProofs/blocks-120-153.json"; import { ADDRESS_ZERO, @@ -183,7 +181,7 @@ describe("Linea Rollup contract", () => { }); describe("Initialisation", () => { - it("Should revert if verifier address is zero address ", async () => { + it("Should revert if verifier address is zero address", async () => { const initializationData = { initialStateRootHash: parentStateRootHash, initialL2BlockNumber: INITIAL_MIGRATION_BLOCK, @@ -206,7 +204,53 @@ describe("Linea Rollup contract", () => { await expectRevertWithCustomError(lineaRollup, deployCall, "ZeroAddressNotAllowed"); }); - it("Should revert if an operator address is zero address ", async () => { + it("Should revert if the fallback operator address is zero address", async () => { + const initializationData = { + initialStateRootHash: parentStateRootHash, + initialL2BlockNumber: INITIAL_MIGRATION_BLOCK, + genesisTimestamp: GENESIS_L2_TIMESTAMP, + defaultVerifier: verifier, + rateLimitPeriodInSeconds: ONE_DAY_IN_SECONDS, + rateLimitAmountInWei: INITIAL_WITHDRAW_LIMIT, + roleAddresses: [...roleAddresses.slice(1)], + pauseTypeRoles: LINEA_ROLLUP_PAUSE_TYPES_ROLES, + unpauseTypeRoles: LINEA_ROLLUP_UNPAUSE_TYPES_ROLES, + fallbackOperator: ADDRESS_ZERO, + defaultAdmin: securityCouncil.address, + }; + + const deployCall = deployUpgradableFromFactory("TestLineaRollup", [initializationData], { + initializer: LINEA_ROLLUP_INITIALIZE_SIGNATURE, + unsafeAllow: ["constructor"], + }); + + await expectRevertWithCustomError(lineaRollup, deployCall, "ZeroAddressNotAllowed"); + }); + + it("Should revert if the default admin address is zero address", async () => { + const initializationData = { + initialStateRootHash: parentStateRootHash, + initialL2BlockNumber: INITIAL_MIGRATION_BLOCK, + genesisTimestamp: GENESIS_L2_TIMESTAMP, + defaultVerifier: verifier, + rateLimitPeriodInSeconds: ONE_DAY_IN_SECONDS, + rateLimitAmountInWei: INITIAL_WITHDRAW_LIMIT, + roleAddresses: [...roleAddresses.slice(1)], + pauseTypeRoles: LINEA_ROLLUP_PAUSE_TYPES_ROLES, + unpauseTypeRoles: LINEA_ROLLUP_UNPAUSE_TYPES_ROLES, + fallbackOperator: fallbackoperatorAddress, + defaultAdmin: ADDRESS_ZERO, + }; + + const deployCall = deployUpgradableFromFactory("TestLineaRollup", [initializationData], { + initializer: LINEA_ROLLUP_INITIALIZE_SIGNATURE, + unsafeAllow: ["constructor"], + }); + + await expectRevertWithCustomError(lineaRollup, deployCall, "ZeroAddressNotAllowed"); + }); + + it("Should revert if an operator address is zero address", async () => { const initializationData = { initialStateRootHash: parentStateRootHash, initialL2BlockNumber: INITIAL_MIGRATION_BLOCK, @@ -229,7 +273,7 @@ describe("Linea Rollup contract", () => { await expectRevertWithCustomError(lineaRollup, deployCall, "ZeroAddressNotAllowed"); }); - it("Should store verifier address in storage ", async () => { + it("Should store verifier address in storage", async () => { lineaRollup = await loadFixture(deployLineaRollupFixture); expect(await lineaRollup.verifiers(0)).to.be.equal(verifier); }); @@ -1180,15 +1224,45 @@ describe("Linea Rollup contract", () => { generateBlobParentShnarfData, true, ); - // Finalize last 2 blobs - await expectSuccessfulFinalize( - blobMultipleAggregatedProof82To153, - 4, - fourthMultipleBlobDataContent.finalStateRootHash, - generateBlobParentShnarfData, - true, - blobMultipleAggregatedProof1To81.l1RollingHash, - BigInt(blobMultipleAggregatedProof1To81.l1RollingHashMessageNumber), + }); + + it("Should fail to prove if last finalized is higher than proving range", async () => { + // Submit 2 blobs + await sendBlobTransaction(0, 2, true); + // Submit another 2 blobs + await sendBlobTransaction(2, 4, true); + + await lineaRollup.setLastFinalizedBlock(10_000_000); + + const finalizationData = await generateFinalizationData({ + l1RollingHash: blobAggregatedProof1To155.l1RollingHash, + l1RollingHashMessageNumber: BigInt(blobAggregatedProof1To155.l1RollingHashMessageNumber), + lastFinalizedTimestamp: BigInt(blobAggregatedProof1To155.parentAggregationLastBlockTimestamp), + endBlockNumber: BigInt(blobAggregatedProof1To155.finalBlockNumber), + parentStateRootHash: HASH_ZERO, // Manipulate for bypass + finalTimestamp: BigInt(blobAggregatedProof1To155.finalTimestamp), + l2MerkleRoots: blobAggregatedProof1To155.l2MerkleRoots, + l2MerkleTreesDepth: BigInt(blobAggregatedProof1To155.l2MerkleTreesDepth), + l2MessagingBlocksOffsets: blobAggregatedProof1To155.l2MessagingBlocksOffsets, + aggregatedProof: blobAggregatedProof1To155.aggregatedProof, + shnarfData: generateBlobParentShnarfData(4, false), + lastFinalizedL1RollingHash: HASH_ZERO, + lastFinalizedL1RollingHashMessageNumber: 0n, + }); + + await lineaRollup.setRollingHash( + blobAggregatedProof1To155.l1RollingHashMessageNumber, + blobAggregatedProof1To155.l1RollingHash, + ); + + await lineaRollup.setLastFinalizedBlock(10_000_000); + + expectRevertWithCustomError( + lineaRollup, + lineaRollup + .connect(operator) + .finalizeBlocks(blobAggregatedProof1To155.aggregatedProof, TEST_PUBLIC_VERIFIER_INDEX, finalizationData), + "InvalidProof", ); }); }); @@ -1202,29 +1276,6 @@ describe("Linea Rollup contract", () => { }); describe("With and without submission data", () => { - it("Should revert if _finalizationData.endBlockNumber is less than or equal to currentL2BlockNumber", async () => { - await lineaRollup.setLastFinalizedBlock(10_000_000); - - const finalizationData = await generateFinalizationData(); - - const lastFinalizedBlockNumber = await lineaRollup.currentL2BlockNumber(); - const parentStateRootHash = await lineaRollup.stateRootHashes(lastFinalizedBlockNumber); - finalizationData.parentStateRootHash = parentStateRootHash; - - const proof = calldataAggregatedProof1To155.aggregatedProof; - - const finalizeCall = lineaRollup - .connect(operator) - .finalizeBlocks(proof, TEST_PUBLIC_VERIFIER_INDEX, finalizationData); - - await expectRevertWithCustomError( - lineaRollup, - finalizeCall, - "FinalBlockNumberLessThanOrEqualToLastFinalizedBlock", - [finalizationData.endBlockNumber, 10_000_000], - ); - }); - it("Should revert if l1 message number == 0 and l1 rolling hash is not empty", async () => { const finalizationData = await generateFinalizationData({ l1RollingHashMessageNumber: 0n, diff --git a/contracts/test/common/constants/pauseTypes.ts b/contracts/test/common/constants/pauseTypes.ts index d08fcf90a..610f78220 100644 --- a/contracts/test/common/constants/pauseTypes.ts +++ b/contracts/test/common/constants/pauseTypes.ts @@ -15,6 +15,7 @@ import { UNPAUSE_COMPLETE_TOKEN_BRIDGING_ROLE, } from "./roles"; +export const UNUSED_PAUSE_TYPE = 0; export const GENERAL_PAUSE_TYPE = 1; export const L1_L2_PAUSE_TYPE = 2; export const L2_L1_PAUSE_TYPE = 3; diff --git a/contracts/test/lib/PauseManager.ts b/contracts/test/lib/PauseManager.ts index 8860b1ab6..d2cb3614e 100644 --- a/contracts/test/lib/PauseManager.ts +++ b/contracts/test/lib/PauseManager.ts @@ -24,9 +24,10 @@ import { FINALIZATION_PAUSE_TYPE, pauseTypeRoles, unpauseTypeRoles, + UNUSED_PAUSE_TYPE, } from "../common/constants"; import { deployUpgradableFromFactory } from "../common/deployment"; -import { buildAccessErrorMessage, expectEvent } from "../common/helpers"; +import { buildAccessErrorMessage, expectEvent, expectRevertWithCustomError, expectRevertWithReason } from "../common/helpers"; async function deployTestPauseManagerFixture(): Promise { return deployUpgradableFromFactory("TestPauseManager", [ @@ -80,6 +81,76 @@ describe("PauseManager", () => { }); }); + describe("Updating pause type and unpause type roles", () => { + it("should fail updatePauseTypeRole if unused pause type is used", async () => { + const updateCall = pauseManager.updatePauseTypeRole(UNUSED_PAUSE_TYPE, DEFAULT_ADMIN_ROLE); + await expectRevertWithCustomError(pauseManager, updateCall, "PauseTypeNotUsed"); + }); + + it("should fail updateUnpauseTypeRole if unused pause type is used", async () => { + const updateCall = pauseManager.updateUnpauseTypeRole(UNUSED_PAUSE_TYPE, DEFAULT_ADMIN_ROLE); + await expectRevertWithCustomError(pauseManager, updateCall, "PauseTypeNotUsed"); + }); + + it("should fail updatePauseTypeRole if correct role not used", async () => { + const updateCall = pauseManager.connect(nonManager).updatePauseTypeRole(GENERAL_PAUSE_TYPE, DEFAULT_ADMIN_ROLE); + await expectRevertWithReason(updateCall, buildAccessErrorMessage(nonManager, PAUSE_ALL_ROLE)); + }); + + it("should fail updateUnpauseTypeRole if correct role not used", async () => { + const updateCall = pauseManager.connect(nonManager).updateUnpauseTypeRole(GENERAL_PAUSE_TYPE, DEFAULT_ADMIN_ROLE); + await expectRevertWithReason(updateCall, buildAccessErrorMessage(nonManager, UNPAUSE_ALL_ROLE)); + }); + + it("should fail updateUnpauseTypeRole if roles are not different", async () => { + const updateCall = pauseManager.connect(pauseManagerAccount).updatePauseTypeRole(GENERAL_PAUSE_TYPE, PAUSE_ALL_ROLE); + await expectRevertWithCustomError(pauseManager, updateCall, "RolesNotDifferent"); + }); + + it("should fail updateUnpauseTypeRole if roles are not different", async () => { + const updateCall = pauseManager.connect(pauseManagerAccount).updateUnpauseTypeRole(GENERAL_PAUSE_TYPE, UNPAUSE_ALL_ROLE); + await expectRevertWithCustomError(pauseManager, updateCall, "RolesNotDifferent"); + }); + + it("should update pause type role with pausing working", async () => { + const updateCall = pauseManager.connect(pauseManagerAccount).updatePauseTypeRole(GENERAL_PAUSE_TYPE, DEFAULT_ADMIN_ROLE); + await expectEvent(pauseManager, updateCall, "PauseTypeRoleUpdated", [GENERAL_PAUSE_TYPE, DEFAULT_ADMIN_ROLE, PAUSE_ALL_ROLE]) + + await pauseManager.connect(defaultAdmin).pauseByType(GENERAL_PAUSE_TYPE); + expect(await pauseManager.isPaused(GENERAL_PAUSE_TYPE)).to.be.true; + }); + + it("should fail to pause with old role", async () => { + const updateCall = pauseManager.connect(pauseManagerAccount).updatePauseTypeRole(GENERAL_PAUSE_TYPE, DEFAULT_ADMIN_ROLE); + await expectEvent(pauseManager, updateCall, "PauseTypeRoleUpdated", [GENERAL_PAUSE_TYPE, DEFAULT_ADMIN_ROLE, PAUSE_ALL_ROLE]) + + await expectRevertWithReason(pauseManager.connect(pauseManagerAccount).pauseByType(GENERAL_PAUSE_TYPE), buildAccessErrorMessage(pauseManagerAccount, DEFAULT_ADMIN_ROLE)); + }); + + it("should update unpause type role with unpausing working", async () => { + const updateCall = pauseManager.connect(pauseManagerAccount).updateUnpauseTypeRole(GENERAL_PAUSE_TYPE, DEFAULT_ADMIN_ROLE); + await expectEvent(pauseManager, updateCall, "UnPauseTypeRoleUpdated", [GENERAL_PAUSE_TYPE, DEFAULT_ADMIN_ROLE, UNPAUSE_ALL_ROLE]) + + // pause with non-modified pausing account + await pauseManager.connect(pauseManagerAccount).pauseByType(GENERAL_PAUSE_TYPE); + expect(await pauseManager.isPaused(GENERAL_PAUSE_TYPE)).to.be.true; + + await pauseManager.connect(defaultAdmin).unPauseByType(GENERAL_PAUSE_TYPE); + expect(await pauseManager.isPaused(GENERAL_PAUSE_TYPE)).to.be.false; + }); + + it("should fail to unpause with old role", async () => { + const updateCall = pauseManager.connect(pauseManagerAccount).updateUnpauseTypeRole(GENERAL_PAUSE_TYPE, DEFAULT_ADMIN_ROLE); + await expectEvent(pauseManager, updateCall, "UnPauseTypeRoleUpdated", [GENERAL_PAUSE_TYPE, DEFAULT_ADMIN_ROLE, UNPAUSE_ALL_ROLE]) + + // pause with non-modified pausing account + await pauseManager.connect(pauseManagerAccount).pauseByType(GENERAL_PAUSE_TYPE); + expect(await pauseManager.isPaused(GENERAL_PAUSE_TYPE)).to.be.true; + + await expectRevertWithReason(pauseManager.connect(pauseManagerAccount).unPauseByType(GENERAL_PAUSE_TYPE), buildAccessErrorMessage(pauseManagerAccount, DEFAULT_ADMIN_ROLE)); + }); + }); + describe("General pausing", () => { // can pause as PAUSE_ALL_ROLE it("should pause the contract if PAUSE_ALL_ROLE", async () => { @@ -131,6 +202,16 @@ describe("PauseManager", () => { }); describe("Specific type pausing", () => { + describe("Unused pause type", () => { + it("should revert when pausing with the unused pause type", async () => { + await expectRevertWithCustomError(pauseManager, pauseManager.pauseByType(UNUSED_PAUSE_TYPE), "PauseTypeNotUsed"); + }); + + it("should revert when unpausing with the unused pause type", async () => { + await expectRevertWithCustomError(pauseManager, pauseManager.unPauseByType(UNUSED_PAUSE_TYPE), "PauseTypeNotUsed"); + }); + }); + describe("With permissions as PAUSE_ALL_ROLE", () => { it("should pause the L1_L2_PAUSE_TYPE", async () => { await pauseByType(L1_L2_PAUSE_TYPE); @@ -192,7 +273,6 @@ describe("PauseManager", () => { expect(await pauseManager.isPaused(FINALIZATION_PAUSE_TYPE)).to.be.false; }); }); - describe("Without permissions - non-PAUSE_ALL_ROLE", () => { it("cannot pause the L1_L2_PAUSE_TYPE as non-manager", async () => { await expect(pauseByType(L1_L2_PAUSE_TYPE, nonManager)).to.be.revertedWith( @@ -264,7 +344,6 @@ describe("PauseManager", () => { ); }); }); - describe("Incorrect states for pausing and unpausing", () => { it("Should pause and fail to pause when paused", async () => { await pauseByType(L1_L2_PAUSE_TYPE); diff --git a/contracts/test/tokenBridge/TokenBridge.ts b/contracts/test/tokenBridge/TokenBridge.ts index 23c5061ed..cf1eaf947 100644 --- a/contracts/test/tokenBridge/TokenBridge.ts +++ b/contracts/test/tokenBridge/TokenBridge.ts @@ -175,6 +175,94 @@ describe("TokenBridge", function () { "ZeroAddressNotAllowed", ); }); + + it("Should revert if one of the initializing parameters is chainId 0", async function () { + const { chainIds } = await loadFixture(deployContractsFixture); + const TokenBridge = await ethers.getContractFactory("TokenBridge"); + + await expectRevertWithCustomError( + TokenBridge, + upgrades.deployProxy(TokenBridge, [ + { + defaultAdmin: PLACEHOLDER_ADDRESS, + messageService: PLACEHOLDER_ADDRESS, + tokenBeacon: PLACEHOLDER_ADDRESS, + sourceChainId: 0, + targetChainId: chainIds[1], + reservedTokens: [], + roleAddresses: [], + pauseTypeRoles: [], + unpauseTypeRoles: [], + }, + ]), + "ZeroChainIdNotAllowed", + ); + + await expectRevertWithCustomError( + TokenBridge, + upgrades.deployProxy(TokenBridge, [ + { + defaultAdmin: PLACEHOLDER_ADDRESS, + messageService: PLACEHOLDER_ADDRESS, + tokenBeacon: PLACEHOLDER_ADDRESS, + sourceChainId: chainIds[0], + targetChainId: 0, + reservedTokens: [], + roleAddresses: [], + pauseTypeRoles: [], + unpauseTypeRoles: [], + }, + ]), + "ZeroChainIdNotAllowed", + ); + }); + + it("Should revert if the sourceChainId is the same as the targetChainId", async function () { + const { chainIds } = await loadFixture(deployContractsFixture); + const TokenBridge = await ethers.getContractFactory("TokenBridge"); + + await expectRevertWithCustomError( + TokenBridge, + upgrades.deployProxy(TokenBridge, [ + { + defaultAdmin: PLACEHOLDER_ADDRESS, + messageService: PLACEHOLDER_ADDRESS, + tokenBeacon: PLACEHOLDER_ADDRESS, + sourceChainId: chainIds[0], + targetChainId: chainIds[0], + reservedTokens: [], + roleAddresses: [], + pauseTypeRoles: [], + unpauseTypeRoles: [], + }, + ]), + "SourceChainSameAsTargetChain", + ); + }); + + it("Should revert if the default admin is empty", async function () { + const { chainIds } = await loadFixture(deployContractsFixture); + const TokenBridge = await ethers.getContractFactory("TokenBridge"); + + await expectRevertWithCustomError( + TokenBridge, + upgrades.deployProxy(TokenBridge, [ + { + defaultAdmin: ADDRESS_ZERO, + messageService: PLACEHOLDER_ADDRESS, + tokenBeacon: PLACEHOLDER_ADDRESS, + sourceChainId: chainIds[0], + targetChainId: chainIds[1], + reservedTokens: [], + roleAddresses: [], + pauseTypeRoles: [], + unpauseTypeRoles: [], + }, + ]), + "ZeroAddressNotAllowed", + ); + }); + it("Should return 'NOT_VALID_ENCODING' for invalid data in _returnDataToString", async function () { const TestTokenBridgeFactory = await ethers.getContractFactory("TestTokenBridge"); diff --git a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/blockcreation/BlockCreationMonitorTest.kt b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/blockcreation/BlockCreationMonitorTest.kt index 0007f2a5f..d1ff75515 100644 --- a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/blockcreation/BlockCreationMonitorTest.kt +++ b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/blockcreation/BlockCreationMonitorTest.kt @@ -260,7 +260,7 @@ class BlockCreationMonitorTest { await().atLeast(config.pollingInterval.times(2).toJavaDuration()) fakeL2RpcNode.resumeHttpServer() await() - .atMost(20.seconds.toJavaDuration()) + .atMost(40.seconds.toJavaDuration()) .untilAsserted { assertThat(blockCreationListener.blocksReceived).isNotEmpty assertThat(blockCreationListener.blocksReceived.last().number).isGreaterThan(lastBlockReceived) diff --git a/coordinator/ethereum/test-utils/src/main/kotlin/net/consensys/zkevm/ethereum/AccountManager.kt b/coordinator/ethereum/test-utils/src/main/kotlin/net/consensys/zkevm/ethereum/AccountManager.kt index 3b23e3761..36611739f 100644 --- a/coordinator/ethereum/test-utils/src/main/kotlin/net/consensys/zkevm/ethereum/AccountManager.kt +++ b/coordinator/ethereum/test-utils/src/main/kotlin/net/consensys/zkevm/ethereum/AccountManager.kt @@ -4,6 +4,7 @@ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue import kotlinx.datetime.Clock import net.consensys.linea.contract.AsyncFriendlyTransactionManager +import net.consensys.linea.jsonrpc.JsonRpcErrorResponseException import net.consensys.linea.testing.filesystem.getPathTo import net.consensys.toULong import org.apache.logging.log4j.LogManager @@ -136,35 +137,38 @@ private open class WhaleBasedAccountManager( (0..numberOfAccounts).map { val randomPrivKey = Bytes.random(32).toHexString().replace("0x", "") val newAccount = Account(randomPrivKey, Credentials.create(randomPrivKey).address) - val transferResult = whaleTxManager.sendTransaction( - /*gasPrice*/ 300_000_000.toBigInteger(), - /*gasLimit*/ 21000.toBigInteger(), - newAccount.address, - "", - initialBalanceWei - ) - if (transferResult.hasError()) { + val transactionHash = try { + retry { + whaleTxManager.sendTransaction( + /*gasPrice*/ 300_000_000.toBigInteger(), + /*gasLimit*/ 21000.toBigInteger(), + newAccount.address, + "", + initialBalanceWei + ) + } + } catch (e: Exception) { val accountBalance = web3jClient.ethGetBalance(whaleAccount.address, DefaultBlockParameterName.LATEST).send().result throw RuntimeException( "Failed to send funds from accAddress=${whaleAccount.address}, " + "accBalance=$accountBalance, " + "accPrivKey=0x...${whaleAccount.privateKey.takeLast(8)}, " + - "error: ${transferResult.error.asString()}" + "error: ${e.message}" ) } - newAccount to transferResult + newAccount to transactionHash } } - result.forEach { (account, transferTx) -> + result.forEach { (account, transactionHash) -> log.debug( "Waiting for account funding: newAccount={} txHash={} whaleAccount={}", account.address, - transferTx.transactionHash, + transactionHash, whaleAccount.address ) web3jClient.waitForTxReceipt( - transferTx.transactionHash, + transactionHash, expectedStatus = "0x1", timeout = 40.seconds, pollingInterval = 500.milliseconds @@ -180,10 +184,6 @@ private open class WhaleBasedAccountManager( return result.map { it.first } } - fun Response.Error.asString(): String { - return "Response.Error(code=$code, message=$message)" - } - override fun getTransactionManager(account: Account): AsyncFriendlyTransactionManager { return getTransactionManager( web3jClient, @@ -231,3 +231,32 @@ object L2AccountManager : AccountManager by WhaleBasedAccountManager( genesisFile = getPathTo(System.getProperty("L2_GENESIS", "docker/config/linea-local-dev-genesis.json")), log = LogManager.getLogger(L2AccountManager::class.java) ) + +fun > retry( + timeout: Duration = 30.seconds, + retryInterval: Duration = 1.seconds, + action: () -> T +): R { + val start = Clock.System.now() + var response: T? = null + var latestError: Exception? = null + do { + try { + response = action() + if (response.hasError()) { + Thread.sleep(retryInterval.inWholeMilliseconds) + } + } catch (e: Exception) { + latestError = e + Thread.sleep(retryInterval.inWholeMilliseconds) + } + } while (response?.hasError() == true && Clock.System.now() < start + timeout) + + return response?.let { + if (it.hasError()) { + throw JsonRpcErrorResponseException(it.error.code, it.error.message, it.error.data) + } else { + it.result + } + } ?: throw latestError!! +} diff --git a/docker/compose.yml b/docker/compose.yml index 19dc5a010..0bc9bd5e5 100644 --- a/docker/compose.yml +++ b/docker/compose.yml @@ -267,7 +267,7 @@ services: coordinator: hostname: coordinator container_name: coordinator - image: consensys/linea-coordinator:${COORDINATOR_TAG:-bb7cd3d} + image: consensys/linea-coordinator:${COORDINATOR_TAG:-a5119c4} platform: linux/amd64 profiles: [ "l2", "debug" ] depends_on: diff --git a/docker/linea-mainnet/docker-compose.yml b/docker/linea-mainnet/docker-compose.yml index 839fd7e55..167fc5f3a 100644 --- a/docker/linea-mainnet/docker-compose.yml +++ b/docker/linea-mainnet/docker-compose.yml @@ -1,19 +1,28 @@ version: "3.9" +# Define named volumes volumes: - linea-mainnet: - name: "linea-mainnet" + linea-mainnet-geth: + name: "linea-mainnet-geth" + linea-mainnet-besu: + name: "linea-mainnet-besu" + linea-mainnet-erigon: + name: "linea-mainnet-erigon" + linea-mainnet-nethermind: + name: "linea-mainnet-nethermind" services: + # Geth initialization geth-init: image: ethereum/client-go:v1.13.4 command: - - init - - /genesis.json + - init + - /genesis.json volumes: - ./genesis.json:/genesis.json:ro - - linea-mainnet:/root/.ethereum + - linea-mainnet-geth:/root/.ethereum + # Geth node geth-node: image: ethereum/client-go:v1.13.4 pull_policy: always @@ -23,16 +32,16 @@ services: geth-init: condition: service_completed_successfully command: - --networkid=59144 - --syncmode=snap - --http - --http.addr='0.0.0.0' - --http.port=8545 - --http.corsdomain='*' - --http.api='admin,web3,eth,txpool,net' - --http.vhosts='*' - --bootnodes=enode://ca2f06aa93728e2883ff02b0c2076329e475fe667a48035b4f77711ea41a73cf6cb2ff232804c49538ad77794185d83295b57ddd2be79eefc50a9dd5c48bbb2e@3.23.106.165:30303,enode://eef91d714494a1ceb6e06e5ce96fe5d7d25d3701b2d2e68c042b33d5fa0e4bf134116e06947b3f40b0f22db08f104504dd2e5c790d8bcbb6bfb1b7f4f85313ec@3.133.179.213:30303,enode://cfd472842582c422c7c98b0f2d04c6bf21d1afb2c767f72b032f7ea89c03a7abdaf4855b7cb2dc9ae7509836064ba8d817572cf7421ba106ac87857836fa1d1b@3.145.12.13:30303 - --verbosity=3 + - --networkid=59144 + - --syncmode=snap + - --http + - --http.addr=0.0.0.0 + - --http.port=8545 + - --http.corsdomain=* + - --http.api=admin,web3,eth,txpool,net + - --http.vhosts=* + - --bootnodes=enode://ca2f06aa93728e2883ff02b0c2076329e475fe667a48035b4f77711ea41a73cf6cb2ff232804c49538ad77794185d83295b57ddd2be79eefc50a9dd5c48bbb2e@3.23.106.165:30303,enode://eef91d714494a1ceb6e06e5ce96fe5d7d25d3701b2d2e68c042b33d5fa0e4bf134116e06947b3f40b0f22db08f104504dd2e5c790d8bcbb6bfb1b7f4f85313ec@3.133.179.213:30303,enode://cfd472842582c422c7c98b0f2d04c6bf21d1afb2c767f72b032f7ea89c03a7abdaf4855b7cb2dc9ae7509836064ba8d817572cf7421ba106ac87857836fa1d1b@3.145.12.13:30303 + - --verbosity=3 ports: - 30303:30303 - 30303:30303/udp @@ -40,10 +49,10 @@ services: - 8546:8546 volumes: - ./genesis.json:/genesis.json:ro - - linea-mainnet:/root/.ethereum + - linea-mainnet-geth:/root/.ethereum - #Besu node currently not peering with bootnodes - need to verify whether this is because they're at max peers or - #whether the docs have outdated enodes + # Besu node currently not peering with bootnodes - need to verify whether this is because they're at max peers or + # whether the docs have outdated enodes besu-node: hostname: besu-node container_name: besu-node @@ -64,12 +73,53 @@ services: - --Xrpc-ipc-enabled=true - --static-nodes-file=/var/lib/besu/static-nodes.json volumes: - - ./datadir/:/data + - ./datadir:/data - ./linea-besu.config.toml:/var/lib/besu/linea-besu.config.toml:ro - ./besu-genesis.json:/var/lib/besu/genesis.json:ro - ../config/linea-besu-sequencer/log4j.xml:/var/lib/besu/log4j.xml - ./static-nodes.json:/var/lib/besu/static-nodes.json + - linea-mainnet-besu:/data + # Erigon initialization + erigon-init: + image: erigontech/erigon:2.61.0 + command: + - init + - /genesis.json + - --datadir=/data + volumes: + - ./genesis.json:/genesis.json:ro + - linea-mainnet-erigon:/home/erigon/.local/share/erigon/ + + # Erigon node + erigon-node: + image: erigontech/erigon:2.61.0 + pull_policy: always + restart: unless-stopped + stop_grace_period: 30s + depends_on: + erigon-init: + condition: service_completed_successfully + command: + - --networkid=59144 + - --prune=hrtc + - --http + - --http.addr=0.0.0.0 + - --http.port=8545 + - --http.corsdomain=* + - --http.api=admin,web3,eth,txpool,net + - --http.vhosts=* + - --bootnodes=enode://069800db9e6e0ec9cadca670994ef1aea2cfd3d88133e63ecadbc1cdbd1a5847b09838ee08d8b5f02a9c32ee13abeb4d4104bb5514e5322c9d7ee19f41ff3e51@3.132.73.210:31002,enode://a8e03a71eab12ec4b47bb6e19169d8e4dc7a58373a2476969bbe463f2dded6003037fa4dd5f71e15027f7fc8d7340956fbbefed67ddd116ac19a7f74da034b61@3.132.73.210:31003,enode://97706526cf79df9d930003644f9156805f6c8bd964fc79e083444f7014ce10c9bdd2c5049e63b58040dca1d4c82ebef970822198cf0714de830cff4111534ff1@18.223.198.165:31004,enode://24e1c654a801975a96b7f54ebd7452ab15777fc635c1db25bdbd4425fdb04e7f4768e9e838a87ab724320a765e41631d5d37758c933ad0e8668693558125c8aa@18.223.198.165:31000 + - --verbosity=3 + ports: + - 30303:30303 + - 30303:30303/udp + - 8545:8545 + volumes: + - ./genesis.json:/genesis.json:ro + - linea-mainnet-erigon:/home/erigon/.local/share/erigon/ + + # Nethermind node nethermind-node: hostname: nethermind-node container_name: nethermind-node @@ -87,4 +137,4 @@ services: - 8545:8545 - 8008:8008 volumes: - - linea-mainnet:/nethermind/nethermind_db + - linea-mainnet-nethermind:/nethermind/nethermind_db diff --git a/docker/linea-sepolia/docker-compose.yml b/docker/linea-sepolia/docker-compose.yml index 3810377d9..159e1caf8 100644 --- a/docker/linea-sepolia/docker-compose.yml +++ b/docker/linea-sepolia/docker-compose.yml @@ -1,19 +1,28 @@ version: "3.9" +# Define named volumes volumes: - linea-sepolia: - name: "linea-sepolia" + linea-sepolia-geth: + name: "linea-sepolia-geth" + linea-sepolia-besu: + name: "linea-sepolia-besu" + linea-sepolia-erigon: + name: "linea-sepolia-erigon" + linea-sepolia-nethermind: + name: "linea-sepolia-nethermind" services: + # Geth initialization geth-init: image: ethereum/client-go:v1.11.6 command: - - init - - /genesis.json + - init + - /genesis.json volumes: - ./genesis.json:/genesis.json:ro - - linea-sepolia:/root/.ethereum + - linea-sepolia-geth:/root/.ethereum + # Geth node geth-node: image: ethereum/client-go:v1.11.6 pull_policy: always @@ -23,16 +32,16 @@ services: geth-init: condition: service_completed_successfully command: - --networkid=59141 - --syncmode=snap - --http - --http.addr='0.0.0.0' - --http.port=8545 - --http.corsdomain='*' - --http.api='admin,web3,eth,txpool,net' - --http.vhosts='*' - --bootnodes="enode://6f20afbe4397e51b717a7c1ad3095e79aee48c835eebd9237a3e8a16951ade1fe0e66e981e30ea269849fcb6ba03d838da37f524fabd2a557474194a2e2604fa@18.221.100.27:31002,enode://ce1e0d8e0500cb5c0ac56bdcdafb2d6320c3a2c5125b5ccf12f5dfc9b47ee74acbcafc32559017613136c9c36a0ce74ba4f83b7fb8244f099f3b15708d9d3129@3.23.75.47:31000,enode://1b026a5eb0ae74300f58987d235ef0e3a550df963345cb3574be3b0b54378bd11f14dfd515a8976f2c2d2826090e9507b8ccc24f896a9ffffffcabcfd996a733@3.129.120.128:31001" - --verbosity=3 + - --networkid=59141 + - --syncmode=snap + - --http + - --http.addr=0.0.0.0 + - --http.port=8545 + - --http.corsdomain=* + - --http.api=admin,web3,eth,txpool,net + - --http.vhosts=* + - --bootnodes="enode://6f20afbe4397e51b717a7c1ad3095e79aee48c835eebd9237a3e8a16951ade1fe0e66e981e30ea269849fcb6ba03d838da37f524fabd2a557474194a2e2604fa@18.221.100.27:31002,enode://ce1e0d8e0500cb5c0ac56bdcdafb2d6320c3a2c5125b5ccf12f5dfc9b47ee74acbcafc32559017613136c9c36a0ce74ba4f83b7fb8244f099f3b15708d9d3129@3.23.75.47:31000,enode://1b026a5eb0ae74300f58987d235ef0e3a550df963345cb3574be3b0b54378bd11f14dfd515a8976f2c2d2826090e9507b8ccc24f896a9ffffffcabcfd996a733@3.129.120.128:31001" + - --verbosity=3 ports: - 30303:30303 - 30303:30303/udp @@ -40,15 +49,16 @@ services: - 8546:8546 volumes: - ./genesis.json:/genesis.json:ro - - linea-sepolia:/root/.ethereum + - linea-sepolia-geth:/root/.ethereum + # Besu node besu-node: hostname: besu-node container_name: besu-node image: consensys/linea-besu:${SEQUENCER_TAG:-linea-delivery-17} platform: linux/amd64 healthcheck: - test: [ "CMD-SHELL", "bash -c \"[ -f /tmp/pid ]\"" ] + test: ["CMD-SHELL", "bash -c '[ -f /tmp/pid ]'"] interval: 1s timeout: 1s retries: 120 @@ -66,12 +76,53 @@ services: - --Xrpc-ipc-enabled=true - --static-nodes-file=/var/lib/besu/static-nodes.json volumes: - - ./datadir/:/data + - ./datadir:/data - ./linea-besu.config.toml:/var/lib/besu/linea-besu.config.toml:ro - ./besu-genesis.json:/var/lib/besu/genesis.json:ro - ../config/linea-besu-sequencer/log4j.xml:/var/lib/besu/log4j.xml - ./static-nodes.json:/var/lib/besu/static-nodes.json + - linea-sepolia-besu:/data + # Erigon initialization + erigon-init: + image: erigontech/erigon:2.61.0 + command: + - init + - /genesis.json + - --datadir=/data + volumes: + - ./genesis.json:/genesis.json:ro + - linea-sepolia-erigon:/home/erigon/.local/share/erigon/ + + # Erigon node + erigon-node: + image: erigontech/erigon:2.61.0 + pull_policy: always + restart: unless-stopped + stop_grace_period: 30s + depends_on: + erigon-init: + condition: service_completed_successfully + command: + - --networkid=59141 + - --prune=hrtc + - --http + - --http.addr=0.0.0.0 + - --http.port=8545 + - --http.corsdomain=* + - --http.api=admin,web3,eth,txpool,net + - --http.vhosts=* + - --bootnodes="enode://6f20afbe4397e51b717a7c1ad3095e79aee48c835eebd9237a3e8a16951ade1fe0e66e981e30ea269849fcb6ba03d838da37f524fabd2a557474194a2e2604fa@18.221.100.27:31002,enode://ce1e0d8e0500cb5c0ac56bdcdafb2d6320c3a2c5125b5ccf12f5dfc9b47ee74acbcafc32559017613136c9c36a0ce74ba4f83b7fb8244f099f3b15708d9d3129@3.23.75.47:31000,enode://1b026a5eb0ae74300f58987d235ef0e3a550df963345cb3574be3b0b54378bd11f14dfd515a8976f2c2d2826090e9507b8ccc24f896a9ffffffcabcfd996a733@3.129.120.128:31001" + - --verbosity=3 + ports: + - 30303:30303 + - 30303:30303/udp + - 8545:8545 + volumes: + - ./genesis.json:/genesis.json:ro + - linea-sepolia-erigon:/home/erigon/.local/share/erigon/ + + # Nethermind node nethermind-node: hostname: nethermind-node container_name: nethermind-node @@ -89,4 +140,4 @@ services: - 8545:8545 - 8008:8008 volumes: - - linea-sepolia:/nethermind/nethermind_db + - linea-sepolia-nethermind:/nethermind/nethermind_db diff --git a/e2e/jest.config.ts b/e2e/jest.config.ts index a70a68e58..1ee0d495d 100644 --- a/e2e/jest.config.ts +++ b/e2e/jest.config.ts @@ -8,6 +8,7 @@ const config: Config = { verbose: true, globalSetup: "./config/jest/global-setup.ts", globalTeardown: "./config/jest/global-teardown.ts", + setupFilesAfterEnv: ["./config/jest/setup.ts"], testTimeout: 3 * 60 * 1000, maxConcurrency: 7, maxWorkers: "75%", diff --git a/e2e/jest.testnet.config.ts b/e2e/jest.testnet.config.ts index 33efc4afd..fd88c6e12 100644 --- a/e2e/jest.testnet.config.ts +++ b/e2e/jest.testnet.config.ts @@ -6,8 +6,11 @@ const config: Config = { rootDir: "src", testRegex: ".spec.ts$", verbose: true, - maxWorkers: "50%", + setupFilesAfterEnv: ["./config/jest/setup.ts"], testTimeout: 3 * 60 * 1000, + maxConcurrency: 7, + maxWorkers: "75%", + workerThreads: true, }; export default config; diff --git a/e2e/package.json b/e2e/package.json index 14249d1da..cdb047832 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -28,6 +28,7 @@ "ethers": "6.13.3", "jest": "29.7.0", "ts-jest": "29.2.5", - "typechain": "8.3.2" + "typechain": "8.3.2", + "winston": "3.17.0" } } diff --git a/e2e/src/bridge-tokens.spec.ts b/e2e/src/bridge-tokens.spec.ts index 8b00894bf..dca0672fd 100644 --- a/e2e/src/bridge-tokens.spec.ts +++ b/e2e/src/bridge-tokens.spec.ts @@ -24,12 +24,12 @@ describe("Bridge ERC20 Tokens L1 -> L2 and L2 -> L1", () => { const l1Token = config.getL1TokenContract(); const l1Provider = config.getL1Provider(); - console.log("Minting ERC20 tokens to L1 Account"); + logger.debug("Minting ERC20 tokens to L1 Account"); let { maxPriorityFeePerGas: l1MaxPriorityFeePerGas, maxFeePerGas: l1MaxFeePerGas } = await l1Provider.getFeeData(); let nonce = await l1Provider.getTransactionCount(l1Account.address, "pending"); - console.log("Minting and approving tokens to L1 TokenBridge"); + logger.debug("Minting and approving tokens to L1 TokenBridge"); await Promise.all([ ( @@ -52,9 +52,9 @@ describe("Bridge ERC20 Tokens L1 -> L2 and L2 -> L1", () => { const l1TokenAddress = await l1Token.getAddress(); const allowanceL1Account = await l1Token.allowance(l1Account.address, l1TokenBridgeAddress); - console.log("Current allowance of L1 account to L1 TokenBridge is :", allowanceL1Account.toString()); + logger.debug(`Current allowance of L1 account to L1 TokenBridge is ${allowanceL1Account.toString()}`); - console.log("Calling the bridgeToken function on the L1 TokenBridge contract"); + logger.debug("Calling the bridgeToken function on the L1 TokenBridge contract"); ({ maxPriorityFeePerGas: l1MaxPriorityFeePerGas, maxFeePerGas: l1MaxFeePerGas } = await l1Provider.getFeeData()); nonce = await l1Provider.getTransactionCount(l1Account.address, "pending"); @@ -79,18 +79,18 @@ describe("Bridge ERC20 Tokens L1 -> L2 and L2 -> L1", () => { ); const l1TokenBalance = await l1Token.balanceOf(l1Account.address); - console.log("Token balance of L1 account :", l1TokenBalance.toString()); + logger.debug(`Token balance of L1 account is ${l1TokenBalance.toString()}`); expect(l1TokenBalance).toEqual(0n); - console.log("Waiting for MessageSent event on L1."); + logger.debug("Waiting for MessageSent event on L1."); const messageNumber = messageSentEvent[messageSentEventMessageNumberIndex]; const messageHash = messageSentEvent[messageSentEventMessageHashIndex]; - console.log(`Message sent on L1 : messageHash=${messageHash}`); + logger.debug(`Message sent on L1. messageHash=${messageHash}`); - console.log("Waiting for anchoring..."); + logger.debug("Waiting for anchoring..."); const [rollingHashUpdatedEvent] = await waitForEvents( l2MessageService, @@ -106,9 +106,9 @@ describe("Bridge ERC20 Tokens L1 -> L2 and L2 -> L1", () => { expect(anchoredStatus).toBeGreaterThan(0); - console.log(`Message anchored : ${JSON.stringify(rollingHashUpdatedEvent)}`); + logger.debug(`Message anchored. event=${JSON.stringify(rollingHashUpdatedEvent)}`); - console.log("Waiting for MessageClaimed event on L2..."); + logger.debug("Waiting for MessageClaimed event on L2..."); const [claimedEvent] = await waitForEvents(l2MessageService, l2MessageService.filters.MessageClaimed(messageHash)); expect(claimedEvent).not.toBeNull(); @@ -116,14 +116,14 @@ describe("Bridge ERC20 Tokens L1 -> L2 and L2 -> L1", () => { const [newTokenDeployed] = await waitForEvents(l2TokenBridge, l2TokenBridge.filters.NewTokenDeployed()); expect(newTokenDeployed).not.toBeNull(); - console.log(`Message claimed on L2 : ${JSON.stringify(claimedEvent)}.`); + logger.debug(`Message claimed on L2. event=${JSON.stringify(claimedEvent)}.`); const l2Token = config.getL2BridgedTokenContract(newTokenDeployed.args.bridgedToken); - console.log("Verify the token balance on L2"); + logger.debug("Verify the token balance on L2"); const l2TokenBalance = await l2Token.balanceOf(l2Account.address); - console.log("Token balance of L2 account :", l2TokenBalance.toString()); + logger.debug(`Token balance of L2 account is ${l2TokenBalance.toString()}`); expect(l2TokenBalance).toEqual(bridgeAmount); }); @@ -163,10 +163,10 @@ describe("Bridge ERC20 Tokens L1 -> L2 and L2 -> L1", () => { ]); const allowanceL2Account = await l2Token.allowance(l2Account.address, l2TokenBridge.getAddress()); - console.log("Current allowance of L2 account to L2 TokenBridge is :", allowanceL2Account.toString()); - console.log("Current balance of L2 account is :", await l2Token.balanceOf(l2Account)); + logger.debug(`Current allowance of L2 account to L2 TokenBridge is ${allowanceL2Account.toString()}`); + logger.debug(`Current balance of L2 account is ${await l2Token.balanceOf(l2Account)}`); - console.log("Calling the bridgeToken function on the L2 TokenBridge contract"); + logger.debug("Calling the bridgeToken function on the L2 TokenBridge contract"); nonce = await l2Provider.getTransactionCount(l2Account.address, "pending"); @@ -189,22 +189,22 @@ describe("Bridge ERC20 Tokens L1 -> L2 and L2 -> L1", () => { ); const messageHash = messageSentEvent[messageSentEventMessageHashIndex]; - console.log("Waiting for L1 MessageClaimed event."); + logger.debug("Waiting for L1 MessageClaimed event."); const [claimedEvent] = await waitForEvents(lineaRollup, lineaRollup.filters.MessageClaimed(messageHash)); expect(claimedEvent).not.toBeNull(); - console.log(`Message claimed on L1 : ${JSON.stringify(claimedEvent)}`); + logger.debug(`Message claimed on L1. event=${JSON.stringify(claimedEvent)}`); const [newTokenDeployed] = await waitForEvents(l1TokenBridge, l1TokenBridge.filters.NewTokenDeployed()); expect(newTokenDeployed).not.toBeNull(); const l1BridgedToken = config.getL1BridgedTokenContract(newTokenDeployed.args.bridgedToken); - console.log("Verify the token balance on L1"); + logger.debug("Verify the token balance on L1"); const l1BridgedTokenBalance = await l1BridgedToken.balanceOf(l1Account.address); - console.log("Token balance of L1 account :", l1BridgedTokenBalance.toString()); + logger.debug(`Token balance of L1 account is ${l1BridgedTokenBalance.toString()}`); expect(l1BridgedTokenBalance).toEqual(bridgeAmount); }); diff --git a/e2e/src/common/deployments.ts b/e2e/src/common/deployments.ts index 24870f3c6..c67e73b04 100644 --- a/e2e/src/common/deployments.ts +++ b/e2e/src/common/deployments.ts @@ -1,5 +1,8 @@ import { AbiCoder, AbstractSigner, BaseContract, ContractFactory, Wallet, ethers } from "ethers"; import { ProxyAdmin__factory, TransparentUpgradeableProxy__factory, ProxyAdmin } from "../typechain"; +import { createTestLogger } from "../config/logger"; + +const logger = createTestLogger(); export const encodeData = (types: string[], values: unknown[], packed?: boolean) => { if (packed) { @@ -56,7 +59,7 @@ export async function deployUpgradableContractWithProxyAdmin( export async function execDockerCommand(command: string, containerName: string): Promise { const dockerCommand = `docker ${command} ${containerName}`; - console.log(`Executing: ${dockerCommand}...`); + logger.info(`Executing ${dockerCommand}...`); return new Promise((resolve, reject) => { exec(dockerCommand, (error, stdout, stderr) => { if (error) { - console.error(`Error executing (${dockerCommand}): ${stderr}`); + logger.error(`Error executing (${dockerCommand}). error=${stderr}`); reject(error); } - console.log(`Execution success (${dockerCommand}): ${stdout}`); + logger.info(`Execution success (${dockerCommand}). output=${stdout}`); resolve(stdout); }); }); diff --git a/e2e/src/config/global.d.ts b/e2e/src/config/global.d.ts new file mode 100644 index 000000000..dd0b3bd5f --- /dev/null +++ b/e2e/src/config/global.d.ts @@ -0,0 +1,10 @@ +/* eslint-disable no-var */ + +import { Logger } from "winston"; + +declare global { + var stopL2TrafficGeneration: () => void; + var logger: Logger; +} + +export {}; diff --git a/e2e/src/config/jest/global-setup.ts b/e2e/src/config/jest/global-setup.ts index 1a7d693bf..8fe32c97e 100644 --- a/e2e/src/config/jest/global-setup.ts +++ b/e2e/src/config/jest/global-setup.ts @@ -5,21 +5,20 @@ import { deployContract } from "../../common/deployments"; import { DummyContract__factory, TestContract__factory, OpcodeTestContract__factory } from "../../typechain"; import { etherToWei, sendTransactionsToGenerateTrafficWithInterval } from "../../common/utils"; import { EMPTY_CONTRACT_CODE } from "../../common/constants"; +import { createTestLogger } from "../logger"; -declare global { - var stopL2TrafficGeneration: () => void; -} +const logger = createTestLogger(); export default async (): Promise => { const dummyContractCode = await config.getL1Provider().getCode(config.getL1DummyContractAddress()); // If this is empty, we have not deployed and prerequisites or configured token bridges. if (dummyContractCode === EMPTY_CONTRACT_CODE) { - console.log("Configuring once-off prerequisite contracts"); + logger.info("Configuring once-off prerequisite contracts"); await configureOnceOffPrerequisities(); } - console.log("Generating L2 traffic..."); + logger.info("Generating L2 traffic..."); const pollingAccount = await config.getL2AccountManager().generateAccount(etherToWei("200")); const stopPolling = await sendTransactionsToGenerateTrafficWithInterval(pollingAccount, 2_000); @@ -71,8 +70,8 @@ async function configureOnceOffPrerequisities() { ).wait(), ]); - console.log(`L1 Dummy contract deployed at address: ${await dummyContract.getAddress()}`); - console.log(`L2 Dummy contract deployed at address: ${await l2DummyContract.getAddress()}`); - console.log(`L2 Test contract deployed at address: ${await l2TestContract.getAddress()}`); - console.log(`L2 OpcodeTest contract deployed at address: ${await opcodeTestContract.getAddress()}`); + logger.info(`L1 Dummy contract deployed. address=${await dummyContract.getAddress()}`); + logger.info(`L2 Dummy contract deployed. address=${await l2DummyContract.getAddress()}`); + logger.info(`L2 Test contract deployed. address=${await l2TestContract.getAddress()}`); + logger.info(`L2 OpcodeTest contract deployed. address=${await opcodeTestContract.getAddress()}`); } diff --git a/e2e/src/config/jest/setup.ts b/e2e/src/config/jest/setup.ts new file mode 100644 index 000000000..9e15b56fb --- /dev/null +++ b/e2e/src/config/jest/setup.ts @@ -0,0 +1,3 @@ +import { createTestLogger } from "../logger"; + +global.logger = createTestLogger(); diff --git a/e2e/src/config/logger/base-logger.ts b/e2e/src/config/logger/base-logger.ts new file mode 100644 index 000000000..8cd813300 --- /dev/null +++ b/e2e/src/config/logger/base-logger.ts @@ -0,0 +1,17 @@ +import { createLogger, format, transports, Logger } from "winston"; + +const { splat, combine, colorize, timestamp, printf } = format; + +export const baseLogger: Logger = createLogger({ + level: process.env.LOG_LEVEL || "info", + format: combine( + timestamp(), + colorize({ level: true }), + splat(), + printf(({ level, message, timestamp, testName }) => { + const testContext = testName ? ` test=${testName}` : ""; + return `timestamp=${timestamp} level=${level}${testContext} | message=${message}`; + }), + ), + transports: [new transports.Console()], +}); diff --git a/e2e/src/config/logger/index.ts b/e2e/src/config/logger/index.ts new file mode 100644 index 000000000..b191813f5 --- /dev/null +++ b/e2e/src/config/logger/index.ts @@ -0,0 +1 @@ +export { createTestLogger } from "./logger"; diff --git a/e2e/src/config/logger/logger.ts b/e2e/src/config/logger/logger.ts new file mode 100644 index 000000000..180efc891 --- /dev/null +++ b/e2e/src/config/logger/logger.ts @@ -0,0 +1,62 @@ +import { Logger, LeveledLogMethod } from "winston"; +import { baseLogger } from "./base-logger"; + +type LogLevel = "error" | "warn" | "info" | "verbose" | "debug" | "silly"; + +function getActiveTestName(): string | undefined { + if (typeof expect !== "function" || typeof expect.getState !== "function") { + return undefined; + } + + const { currentTestName, currentConcurrentTestName } = expect.getState() || {}; + + if (!currentConcurrentTestName) { + return currentTestName; + } + + return currentConcurrentTestName(); +} + +function prefixWithTestName(level: LogLevel, args: unknown[]): Logger { + const testName = getActiveTestName(); + + if (!testName) { + return baseLogger[level as keyof Logger](...args); + } + + const [firstArg] = args; + + if (typeof firstArg === "string") { + return baseLogger[level](firstArg, { testName }); + } + + if (firstArg && typeof firstArg === "object" && !Array.isArray(firstArg)) { + return baseLogger[level]({ testName, ...firstArg }); + } + + return baseLogger[level as keyof Logger](...args); +} + +export function createTestLogger(): Logger { + return { + ...baseLogger, + error(...args: Parameters) { + return prefixWithTestName("error", args); + }, + warn(...args: Parameters) { + return prefixWithTestName("warn", args); + }, + info(...args: Parameters) { + return prefixWithTestName("info", args); + }, + verbose(...args: Parameters) { + return prefixWithTestName("verbose", args); + }, + debug(...args: Parameters) { + return prefixWithTestName("debug", args); + }, + silly(...args: Parameters) { + return prefixWithTestName("silly", args); + }, + } as Logger; +} diff --git a/e2e/src/config/tests-config/accounts/account-manager.ts b/e2e/src/config/tests-config/accounts/account-manager.ts index f0f4c3cf0..ab4f59925 100644 --- a/e2e/src/config/tests-config/accounts/account-manager.ts +++ b/e2e/src/config/tests-config/accounts/account-manager.ts @@ -1,7 +1,9 @@ import { ethers, NonceManager, Provider, TransactionResponse, Wallet } from "ethers"; import { Mutex } from "async-mutex"; +import type { Logger } from "winston"; import Account from "./account"; import { etherToWei } from "../../../common/utils"; +import { createTestLogger } from "../../../config/logger"; interface IAccountManager { whaleAccount(accIndex?: number): NonceManager; @@ -29,6 +31,7 @@ abstract class AccountManager implements IAccountManager { protected provider: Provider; protected accountWallets: NonceManager[]; private whaleAccountMutex: Mutex; + private logger: Logger; constructor(provider: Provider, whaleAccounts: Account[], chainId: number) { this.provider = provider; @@ -38,6 +41,8 @@ abstract class AccountManager implements IAccountManager { (account) => new NonceManager(getWallet(this.provider, account.privateKey)), ); this.whaleAccountMutex = new Mutex(); + + this.logger = createTestLogger(); } selectWhaleAccount(accIndex?: number): { account: Account; accountWallet: NonceManager } { @@ -65,8 +70,8 @@ abstract class AccountManager implements IAccountManager { async generateAccounts(numberOfAccounts: number, initialBalanceWei = etherToWei("10")): Promise { const { account: whaleAccount, accountWallet: whaleAccountWallet } = this.selectWhaleAccount(); - console.log( - `Generating accounts: chainId=${this.chainId} numberOfAccounts=${numberOfAccounts} whaleAccount=${whaleAccount.address}`, + this.logger.debug( + `Generating accounts... chainId=${this.chainId} numberOfAccounts=${numberOfAccounts} whaleAccount=${whaleAccount.address}`, ); const accounts: Account[] = []; @@ -88,13 +93,13 @@ abstract class AccountManager implements IAccountManager { const release = await this.whaleAccountMutex.acquire(); try { const transactionResponse = await whaleAccountWallet.sendTransaction(tx); - console.log( - `Transaction sent: newAccount=${newAccount.address} txHash=${transactionResponse.hash} whaleAccount=${whaleAccount.address}`, + this.logger.debug( + `Transaction sent. newAccount=${newAccount.address} txHash=${transactionResponse.hash} whaleAccount=${whaleAccount.address}`, ); transactionResponses.push(transactionResponse); // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { - console.error(`Failed to fund account ${newAccount.address}: ${error.message}`); + logger.error(`Failed to fund account. address=${newAccount.address} error=${error.message}`); whaleAccountWallet.reset(); } finally { release(); @@ -103,8 +108,8 @@ abstract class AccountManager implements IAccountManager { await Promise.all(transactionResponses.map((tx) => tx.wait())); - console.log( - `Accounts funded: newAccounts=${accounts.map((account) => account.address).join(",")} balance=${initialBalanceWei.toString()} wei`, + this.logger.debug( + `Accounts funded. newAccounts=${accounts.map((account) => account.address).join(",")} balance=${initialBalanceWei.toString()} wei`, ); return accounts.map((account) => this.getWallet(account)); diff --git a/e2e/src/gas-limit.spec.ts b/e2e/src/gas-limit.spec.ts index 2b967eb02..37db2db6a 100644 --- a/e2e/src/gas-limit.spec.ts +++ b/e2e/src/gas-limit.spec.ts @@ -8,23 +8,35 @@ const l2Provider = config.getL2Provider(); describe("Gas limit test suite", () => { const setGasLimit = async (account: Wallet): Promise => { + logger.debug(`setGasLimit called with account=${account.address}`); + const opcodeTestContract = config.getOpcodeTestContract(account); const nonce = await l2Provider.getTransactionCount(account.address, "pending"); + logger.debug(`Fetched nonce. nonce=${nonce} account=${account.address}`); + const { maxPriorityFeePerGas, maxFeePerGas } = await l2Provider.getFeeData(); + logger.debug(`Fetched fee data. maxPriorityFeePerGas=${maxPriorityFeePerGas} maxFeePerGas=${maxFeePerGas}`); const tx = await opcodeTestContract.connect(account).setGasLimit({ nonce: nonce, maxPriorityFeePerGas: maxPriorityFeePerGas, maxFeePerGas: maxFeePerGas, }); + logger.debug(`setGasLimit transaction sent. transactionHash=${tx.hash}`); const receipt = await tx.wait(); + logger.debug(`Transaction receipt received. transactionHash=${tx.hash} status=${receipt?.status}`); + return receipt; }; const getGasLimit = async (): Promise => { const opcodeTestContract = config.getOpcodeTestContract(); - return await opcodeTestContract.getGasLimit(); + const gasLimit = await opcodeTestContract.getGasLimit(); + + logger.debug(`Current gas limit retrieved. gasLimit=${gasLimit}`); + + return gasLimit; }; it.concurrent("Should successfully invoke OpcodeTestContract.setGasLimit()", async () => { @@ -42,13 +54,15 @@ describe("Gas limit test suite", () => { // Ok to type assertion here, because txReceipt won't be null if it passed above assertion. const txBlockNumber = txReceipt?.blockNumber; - console.log(`Waiting for ${txBlockNumber} to be finalized...`); + logger.debug(`Waiting for block to be finalized... blockNumber=${txBlockNumber}`); const isBlockFinalized = await pollForContractMethodReturnValueExceedTarget( lineaRollupV6.currentL2BlockNumber, BigInt(txBlockNumber), ); + logger.debug(`Block finalized. blockNumber=${txBlockNumber}`); + expect(isBlockFinalized).toEqual(true); }); @@ -60,13 +74,13 @@ describe("Gas limit test suite", () => { const account = await l2AccountManager.generateAccount(); const lineaRollupV6 = config.getLineaRollupContract(); - console.log(`Target block gas limit: ${targetBlockGasLimit}`); + logger.debug(`Target block gasLimit=${targetBlockGasLimit}`); while (!isTargetBlockGasLimitReached) { const txReceipt = await setGasLimit(account); expect(txReceipt?.status).toEqual(1); const blockGasLimit = await getGasLimit(); - console.log("blockGasLimit: ", blockGasLimit); + if (blockGasLimit === targetBlockGasLimit) { isTargetBlockGasLimitReached = true; // Ok to type assertion here, because txReceipt won't be null if it passed above assertion. @@ -75,13 +89,15 @@ describe("Gas limit test suite", () => { await wait(1000); } - console.log(`Waiting for ${blockNumberToCheckFinalization} to be finalized...`); + logger.debug(`Waiting for block to be finalized... blockNumber=${blockNumberToCheckFinalization}`); const isBlockFinalized = await pollForContractMethodReturnValueExceedTarget( lineaRollupV6.currentL2BlockNumber, BigInt(blockNumberToCheckFinalization), ); + logger.debug(`Block finalized. blockNumber=${blockNumberToCheckFinalization}`); + expect(isBlockFinalized).toEqual(true); // Timeout of 6 hrs }, 21_600_000); diff --git a/e2e/src/l2.spec.ts b/e2e/src/l2.spec.ts index 651424cf8..c3d1b8382 100644 --- a/e2e/src/l2.spec.ts +++ b/e2e/src/l2.spec.ts @@ -13,24 +13,32 @@ describe("Layer 2 test suite", () => { const account = await l2AccountManager.generateAccount(); const dummyContract = config.getL2DummyContract(account); - await expect( - dummyContract.connect(account).setPayload(ethers.randomBytes(TRANSACTION_CALLDATA_LIMIT)), - ).rejects.toThrow("missing revert data"); + const oversizedData = ethers.randomBytes(TRANSACTION_CALLDATA_LIMIT); + logger.debug(`Generated oversized transaction data. dataLength=${oversizedData.length}`); + + await expect(dummyContract.connect(account).setPayload(oversizedData)).rejects.toThrow("missing revert data"); + logger.debug("Transaction correctly reverted due to oversized data."); }); it.concurrent("Should succeed if transaction data size is below the limit", async () => { const account = await l2AccountManager.generateAccount(); const dummyContract = config.getL2DummyContract(account); const nonce = await l2Provider.getTransactionCount(account.address, "pending"); + logger.debug(`Fetched nonce. nonce=${nonce} account=${account.address}`); + const { maxPriorityFeePerGas, maxFeePerGas } = await l2Provider.getFeeData(); + logger.debug(`Fetched fee data. maxPriorityFeePerGas=${maxPriorityFeePerGas} maxFeePerGas=${maxFeePerGas}`); const tx = await dummyContract.connect(account).setPayload(ethers.randomBytes(1000), { nonce: nonce, maxPriorityFeePerGas: maxPriorityFeePerGas, maxFeePerGas: maxFeePerGas, }); + logger.debug(`setPayload transaction sent. transactionHash=${tx.hash}`); const receipt = await tx.wait(); + logger.debug(`Transaction receipt received. transactionHash=${tx.hash} status=${receipt?.status}`); + expect(receipt?.status).toEqual(1); }); @@ -38,17 +46,21 @@ describe("Layer 2 test suite", () => { const account = await l2AccountManager.generateAccount(); const { gasPrice } = await config.getL2Provider().getFeeData(); + logger.debug(`Fetched gasPrice=${gasPrice}`); + + const tx = await account.sendTransaction({ + type: 0, + to: "0x8D97689C9818892B700e27F316cc3E41e17fBeb9", + gasPrice, + value: etherToWei("0.01"), + gasLimit: "0x466124", + chainId: config.getL2ChainId(), + }); - const receipt = await ( - await account.sendTransaction({ - type: 0, - to: "0x8D97689C9818892B700e27F316cc3E41e17fBeb9", - gasPrice, - value: etherToWei("0.01"), - gasLimit: "0x466124", - chainId: config.getL2ChainId(), - }) - ).wait(); + logger.debug(`Legacy transaction sent. transactionHash=${tx.hash}`); + + const receipt = await tx.wait(); + logger.debug(`Legacy transaction receipt received. transactionHash=${tx.hash} status=${receipt?.status}`); expect(receipt).not.toBeNull(); }); @@ -57,18 +69,22 @@ describe("Layer 2 test suite", () => { const account = await l2AccountManager.generateAccount(); const { maxPriorityFeePerGas, maxFeePerGas } = await config.getL2Provider().getFeeData(); + logger.debug(`Fetched fee data. maxPriorityFeePerGas=${maxPriorityFeePerGas} maxFeePerGas=${maxFeePerGas}`); + + const tx = await account.sendTransaction({ + type: 2, + to: "0x8D97689C9818892B700e27F316cc3E41e17fBeb9", + maxPriorityFeePerGas, + maxFeePerGas, + value: etherToWei("0.01"), + gasLimit: "21000", + chainId: config.getL2ChainId(), + }); + + logger.debug(`EIP1559 transaction sent. transactionHash=${tx.hash}`); - const receipt = await ( - await account.sendTransaction({ - type: 2, - to: "0x8D97689C9818892B700e27F316cc3E41e17fBeb9", - maxPriorityFeePerGas, - maxFeePerGas, - value: etherToWei("0.01"), - gasLimit: "21000", - chainId: config.getL2ChainId(), - }) - ).wait(); + const receipt = await tx.wait(); + logger.debug(`EIP1559 transaction receipt received. transactionHash=${tx.hash} status=${receipt?.status}`); expect(receipt).not.toBeNull(); }); @@ -77,17 +93,23 @@ describe("Layer 2 test suite", () => { const account = await l2AccountManager.generateAccount(); const { gasPrice } = await config.getL2Provider().getFeeData(); + logger.debug(`Fetched gasPrice=${gasPrice}`); + + const tx = await account.sendTransaction({ + type: 1, + to: "0x8D97689C9818892B700e27F316cc3E41e17fBeb9", + gasPrice, + value: etherToWei("0.01"), + gasLimit: "21000", + chainId: config.getL2ChainId(), + }); - const receipt = await ( - await account.sendTransaction({ - type: 1, - to: "0x8D97689C9818892B700e27F316cc3E41e17fBeb9", - gasPrice, - value: etherToWei("0.01"), - gasLimit: "21000", - chainId: config.getL2ChainId(), - }) - ).wait(); + logger.debug(`Empty access list transaction sent. transactionHash=${tx.hash}`); + + const receipt = await tx.wait(); + logger.debug( + `Empty access list transaction receipt received. transactionHash=${tx.hash} status=${receipt?.status}`, + ); expect(receipt).not.toBeNull(); }); @@ -96,6 +118,8 @@ describe("Layer 2 test suite", () => { const account = await l2AccountManager.generateAccount(); const { gasPrice } = await config.getL2Provider().getFeeData(); + logger.debug(`Fetched gasPrice=${gasPrice}`); + const accessList = { "0x8D97689C9818892B700e27F316cc3E41e17fBeb9": [ "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -103,17 +127,19 @@ describe("Layer 2 test suite", () => { ], }; - const receipt = await ( - await account.sendTransaction({ - type: 1, - to: "0x8D97689C9818892B700e27F316cc3E41e17fBeb9", - gasPrice, - value: etherToWei("0.01"), - gasLimit: "200000", - chainId: config.getL2ChainId(), - accessList: ethers.accessListify(accessList), - }) - ).wait(); + const tx = await account.sendTransaction({ + type: 1, + to: "0x8D97689C9818892B700e27F316cc3E41e17fBeb9", + gasPrice, + value: etherToWei("0.01"), + gasLimit: "200000", + chainId: config.getL2ChainId(), + accessList: ethers.accessListify(accessList), + }); + logger.debug(`Access list transaction sent. transactionHash=${tx.hash}`); + + const receipt = await tx.wait(); + logger.debug(`Access list transaction receipt received. transactionHash=${tx.hash} status=${receipt?.status}`); expect(receipt).not.toBeNull(); }); @@ -134,6 +160,9 @@ describe("Layer 2 test suite", () => { for (let i = 0; i < 5; i++) { const { maxPriorityFeePerGas, maxFeePerGas } = await config.getL2Provider().getFeeData(); + logger.debug( + `Fetched fee data. transactionNumber=${i + 1} maxPriorityFeePerGas=${maxPriorityFeePerGas} maxFeePerGas=${maxFeePerGas}`, + ); await ( await account.sendTransaction({ @@ -151,9 +180,12 @@ describe("Layer 2 test suite", () => { shomeiClient.rollupGetZkEVMBlockNumber(), shomeiFrontendClient.rollupGetZkEVMBlockNumber(), ]); - console.log(`shomeiBlock = ${shomeiBlock}, shomeiFrontendBlock = ${shomeiFrontendBlock}`); + logger.debug(`shomeiBlock=${shomeiBlock}, shomeiFrontendBlock=${shomeiFrontendBlock}`); expect(shomeiBlock).toBeGreaterThan(shomeiFrontendBlock); + logger.debug( + `shomeiBlock is greater than shomeiFrontendBlock. shomeiBlock=${shomeiBlock} shomeiFrontendBlock=${shomeiFrontendBlock}`, + ); } }, 150_000); }); diff --git a/e2e/src/messaging.spec.ts b/e2e/src/messaging.spec.ts index 722531d48..35e414b67 100644 --- a/e2e/src/messaging.spec.ts +++ b/e2e/src/messaging.spec.ts @@ -1,18 +1,22 @@ import { ethers, Wallet } from "ethers"; import { describe, expect, it } from "@jest/globals"; +import type { Logger } from "winston"; import { config } from "./config/tests-config"; import { encodeFunctionCall, etherToWei, waitForEvents } from "./common/utils"; import { MESSAGE_SENT_EVENT_SIGNATURE } from "./common/constants"; -async function sendL1ToL2Message({ - l1Account, - l2Account, - withCalldata = false, -}: { - l1Account: Wallet; - l2Account: Wallet; - withCalldata: boolean; -}) { +async function sendL1ToL2Message( + logger: Logger, + { + l1Account, + l2Account, + withCalldata = false, + }: { + l1Account: Wallet; + l2Account: Wallet; + withCalldata: boolean; + }, +) { const dummyContract = config.getL2DummyContract(l2Account); const lineaRollup = config.getLineaRollupContract(l1Account); @@ -26,7 +30,12 @@ async function sendL1ToL2Message({ const l1Provider = config.getL1Provider(); const { maxPriorityFeePerGas, maxFeePerGas } = await l1Provider.getFeeData(); + + logger.debug(`Fetched fee data. maxPriorityFeePerGas=${maxPriorityFeePerGas} maxFeePerGas=${maxFeePerGas}`); + const nonce = await l1Provider.getTransactionCount(l1Account.address, "pending"); + logger.debug(`Fetched nonce. nonce=${nonce} account=${l1Account.address}`); + const tx = await lineaRollup.sendMessage(destinationAddress, valueAndFee, calldata, { value: valueAndFee, nonce, @@ -34,24 +43,31 @@ async function sendL1ToL2Message({ maxFeePerGas, }); + logger.debug(`sendMessage transaction sent. transactionHash=${tx.hash}`); + let receipt = await tx.wait(); while (!receipt) { - console.log("Waiting for transaction to be mined..."); + logger.debug(`Waiting for transaction to be mined... transactionHash=${tx.hash}`); receipt = await tx.wait(); } + logger.debug(`Transaction mined. transactionHash=${tx.hash} status=${receipt.status}`); + return { tx, receipt }; } -async function sendL2ToL1Message({ - l1Account, - l2Account, - withCalldata = false, -}: { - l1Account: Wallet; - l2Account: Wallet; - withCalldata: boolean; -}) { +async function sendL2ToL1Message( + logger: Logger, + { + l1Account, + l2Account, + withCalldata = false, + }: { + l1Account: Wallet; + l2Account: Wallet; + withCalldata: boolean; + }, +) { const l2Provider = config.getL2Provider(); const dummyContract = config.getL1DummyContract(l1Account); const l2MessageService = config.getL2MessageServiceContract(l2Account); @@ -63,7 +79,10 @@ async function sendL2ToL1Message({ const destinationAddress = withCalldata ? await dummyContract.getAddress() : l1Account.address; const nonce = await l2Provider.getTransactionCount(l2Account.address, "pending"); + logger.debug(`Fetched nonce. nonce=${nonce} account=${l2Account.address}`); + const { maxPriorityFeePerGas, maxFeePerGas } = await l2Provider.getFeeData(); + logger.debug(`Fetched fee data. maxPriorityFeePerGas=${maxPriorityFeePerGas} maxFeePerGas=${maxFeePerGas}`); const tx = await l2MessageService.sendMessage(destinationAddress, valueAndFee, calldata, { value: valueAndFee, @@ -72,13 +91,17 @@ async function sendL2ToL1Message({ maxFeePerGas, }); + logger.debug(`sendMessage transaction sent. transactionHash=${tx.hash}`); + let receipt = await tx.wait(); while (!receipt) { - console.log("Waiting for transaction to be mined..."); + logger.debug(`Waiting for transaction to be mined... transactionHash=${tx.hash}`); receipt = await tx.wait(); } + logger.debug(`Transaction mined. transactionHash=${tx.hash} status=${receipt.status}`); + return { tx, receipt }; } @@ -94,21 +117,23 @@ describe("Messaging test suite", () => { l2AccountManager.generateAccount(), ]); - const { tx, receipt } = await sendL1ToL2Message({ l1Account, l2Account, withCalldata: true }); + const { tx, receipt } = await sendL1ToL2Message(logger, { l1Account, l2Account, withCalldata: true }); const [messageSentEvent] = receipt.logs.filter((log) => log.topics[0] === MESSAGE_SENT_EVENT_SIGNATURE); const messageHash = messageSentEvent.topics[3]; - console.log(`L1 message sent: messageHash=${messageHash} transaction=${JSON.stringify(tx)}`); + logger.debug(`L1 message sent. messageHash=${messageHash} transaction=${JSON.stringify(tx)}`); - console.log("Waiting for MessageClaimed event on L2."); + logger.debug(`Waiting for MessageClaimed event on L2. messageHash=${messageHash}`); const l2MessageService = config.getL2MessageServiceContract(); const [messageClaimedEvent] = await waitForEvents( l2MessageService, l2MessageService.filters.MessageClaimed(messageHash), ); - console.log(`Message claimed on L2: ${JSON.stringify(messageClaimedEvent)}`); expect(messageClaimedEvent).toBeDefined(); + logger.debug( + `Message claimed on L2. messageHash=${messageClaimedEvent.args._messageHash} transactionHash=${messageClaimedEvent.transactionHash}`, + ); }, 100_000, ); @@ -121,20 +146,22 @@ describe("Messaging test suite", () => { l2AccountManager.generateAccount(), ]); - const { tx, receipt } = await sendL1ToL2Message({ l1Account, l2Account, withCalldata: false }); + const { tx, receipt } = await sendL1ToL2Message(logger, { l1Account, l2Account, withCalldata: false }); const [messageSentEvent] = receipt.logs.filter((log) => log.topics[0] === MESSAGE_SENT_EVENT_SIGNATURE); const messageHash = messageSentEvent.topics[3]; - console.log(`L1 message sent: messageHash=${messageHash} transaction=${JSON.stringify(tx)}`); + logger.debug(`L1 message sent. messageHash=${messageHash} transactionHash=${tx.hash}`); - console.log("Waiting for MessageClaimed event on L2."); + logger.debug(`Waiting for MessageClaimed event on L2. messageHash=${messageHash}`); const l2MessageService = config.getL2MessageServiceContract(); const [messageClaimedEvent] = await waitForEvents( l2MessageService, l2MessageService.filters.MessageClaimed(messageHash), ); - console.log(`Message claimed on L2: ${JSON.stringify(messageClaimedEvent)}`); expect(messageClaimedEvent).toBeDefined(); + logger.debug( + `Message claimed on L2. messageHash=${messageClaimedEvent.args._messageHash} transactionHash=${messageClaimedEvent.transactionHash}`, + ); }, 100_000, ); @@ -148,28 +175,30 @@ describe("Messaging test suite", () => { ]); const lineaRollup = config.getLineaRollupContract(); - const { tx, receipt } = await sendL2ToL1Message({ l1Account, l2Account, withCalldata: true }); + const { tx, receipt } = await sendL2ToL1Message(logger, { l1Account, l2Account, withCalldata: true }); const [messageSentEvent] = receipt.logs.filter((log) => log.topics[0] === MESSAGE_SENT_EVENT_SIGNATURE); const messageHash = messageSentEvent.topics[3]; - console.log(`L2 message sent: messageHash=${messageHash} transaction=${JSON.stringify(tx)}`); + logger.debug(`L2 message sent. messageHash=${messageHash} transaction=${JSON.stringify(tx)}`); - console.log(`Waiting for L2MessagingBlockAnchored... with blockNumber=${messageSentEvent.blockNumber}`); + logger.debug(`Waiting for L2MessagingBlockAnchored event... blockNumber=${messageSentEvent.blockNumber}`); await waitForEvents( lineaRollup, lineaRollup.filters.L2MessagingBlockAnchored(messageSentEvent.blockNumber), 1_000, ); - console.log("Waiting for MessageClaimed event on L1."); + logger.debug(`Waiting for MessageClaimed event on L1... messageHash=${messageHash}`); const [messageClaimedEvent] = await waitForEvents( lineaRollup, lineaRollup.filters.MessageClaimed(messageHash), 1_000, ); - console.log(`Message claimed on L1: ${JSON.stringify(messageClaimedEvent)}`); expect(messageClaimedEvent).toBeDefined(); + logger.debug( + `Message claimed on L1. messageHash=${messageClaimedEvent.args._messageHash} transactionHash=${messageClaimedEvent.transactionHash}`, + ); }, 150_000, ); @@ -183,28 +212,31 @@ describe("Messaging test suite", () => { ]); const lineaRollup = config.getLineaRollupContract(); - const { tx, receipt } = await sendL2ToL1Message({ l1Account, l2Account, withCalldata: false }); + const { tx, receipt } = await sendL2ToL1Message(logger, { l1Account, l2Account, withCalldata: false }); const [messageSentEvent] = receipt.logs.filter((log) => log.topics[0] === MESSAGE_SENT_EVENT_SIGNATURE); const messageHash = messageSentEvent.topics[3]; - console.log(`L2 message sent: messageHash=${messageHash} transaction=${JSON.stringify(tx)}`); + logger.debug(`L2 message sent. messageHash=${messageHash} transaction=${JSON.stringify(tx)}`); - console.log(`Waiting for L2MessagingBlockAnchored... with blockNumber=${messageSentEvent.blockNumber}`); + logger.debug(`Waiting for L2MessagingBlockAnchored event... blockNumber=${messageSentEvent.blockNumber}`); await waitForEvents( lineaRollup, lineaRollup.filters.L2MessagingBlockAnchored(messageSentEvent.blockNumber), 1_000, ); - console.log("Waiting for MessageClaimed event on L1."); + logger.debug(`Waiting for MessageClaimed event on L1. messageHash=${messageHash}`); const [messageClaimedEvent] = await waitForEvents( lineaRollup, lineaRollup.filters.MessageClaimed(messageHash), 1_000, ); - console.log(`Message claimed on L1: ${JSON.stringify(messageClaimedEvent)}`); expect(messageClaimedEvent).toBeDefined(); + + logger.debug( + `Message claimed on L1. messageHash=${messageClaimedEvent.args._messageHash} transactionHash=${messageClaimedEvent.transactionHash}`, + ); }, 150_000, ); diff --git a/e2e/src/restart.spec.ts b/e2e/src/restart.spec.ts index 8b347a723..db8f5d286 100644 --- a/e2e/src/restart.spec.ts +++ b/e2e/src/restart.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from "@jest/globals"; +import type { Logger } from "winston"; import { execDockerCommand, waitForEvents, @@ -13,19 +14,19 @@ let testsWaitingForRestart = 0; const TOTAL_TESTS_WAITING = 2; let coordinatorHasRestarted = false; -async function waitForCoordinatorRestart() { +async function waitForCoordinatorRestart(logger: Logger) { testsWaitingForRestart += 1; while (testsWaitingForRestart < TOTAL_TESTS_WAITING) { - console.log("Both tests have reached the restart point. Restarting coordinator..."); + logger.debug("Both tests have reached the restart point. Restarting coordinator..."); await wait(1_000); if (!coordinatorHasRestarted) { coordinatorHasRestarted = true; try { await execDockerCommand("restart", "coordinator"); - console.log("Coordinator restarted."); + logger.debug("Coordinator restarted."); return; } catch (error) { - console.error("Failed to restart coordinator:", error); + logger.error(`Failed to restart coordinator: ${error}`); throw error; } } @@ -39,7 +40,7 @@ describe("Coordinator restart test suite", () => { "When the coordinator restarts it should resume blob submission and finalization", async () => { if (process.env.TEST_ENV !== "local") { - console.log("Skipping test because it's not running on a local environment."); + logger.warn("Skipping test because it's not running on a local environment."); return; } const lineaRollup = config.getLineaRollupContract(); @@ -53,16 +54,23 @@ describe("Coordinator restart test suite", () => { const lastDataSubmittedEventBeforeRestart = dataSubmittedEventsBeforeRestart.slice(-1)[0]; const lastDataFinalizedEventsBeforeRestart = dataFinalizedEventsBeforeRestart.slice(-1)[0]; + logger.debug( + `DataSubmittedV3 event before coordinator restart found. event=${JSON.stringify(lastDataSubmittedEventBeforeRestart)}`, + ); + logger.debug( + `DataFinalizedV3 event before coordinator restart found. event=${JSON.stringify(lastDataFinalizedEventsBeforeRestart)}`, + ); + // Just some sanity checks // Check that the coordinator has submitted and finalized data before the restart expect(lastDataSubmittedEventBeforeRestart.blockNumber).toBeGreaterThan(0n); expect(lastDataFinalizedEventsBeforeRestart.args.endBlockNumber).toBeGreaterThan(0n); - await waitForCoordinatorRestart(); + await waitForCoordinatorRestart(logger); const currentBlockNumberAfterRestart = await l1Provider.getBlockNumber(); - console.log("Waiting for DataSubmittedV3 event after coordinator restart..."); + logger.debug("Waiting for DataSubmittedV3 event after coordinator restart..."); const [dataSubmittedV3EventAfterRestart] = await waitForEvents( lineaRollup, lineaRollup.filters.DataSubmittedV3(), @@ -71,9 +79,11 @@ describe("Coordinator restart test suite", () => { "latest", async (events) => events.filter((event) => event.blockNumber > lastDataSubmittedEventBeforeRestart.blockNumber), ); - console.log(`New DataSubmittedV3 event found: event=${JSON.stringify(dataSubmittedV3EventAfterRestart)}`); + logger.debug( + `DataSubmittedV3 event after coordinator restart found. event=${JSON.stringify(dataSubmittedV3EventAfterRestart)}`, + ); - console.log("Waiting for DataFinalized event after coordinator restart..."); + logger.debug("Waiting for DataFinalizedV3 event after coordinator restart..."); const [dataFinalizedEventAfterRestart] = await waitForEvents( lineaRollup, lineaRollup.filters.DataFinalizedV3(), @@ -85,7 +95,9 @@ describe("Coordinator restart test suite", () => { (event) => event.args.endBlockNumber > lastDataFinalizedEventsBeforeRestart.args.endBlockNumber, ), ); - console.log(`New DataFinalized event found: event=${JSON.stringify(dataFinalizedEventAfterRestart)}`); + logger.debug( + `DataFinalizedV3 event after coordinator restart found. event=${JSON.stringify(dataFinalizedEventAfterRestart)}`, + ); expect(dataFinalizedEventAfterRestart.args.endBlockNumber).toBeGreaterThan( lastDataFinalizedEventsBeforeRestart.args.endBlockNumber, @@ -98,7 +110,7 @@ describe("Coordinator restart test suite", () => { "When the coordinator restarts it should resume anchoring", async () => { if (process.env.TEST_ENV !== "local") { - console.log("Skipping test because it's not running on a local environment."); + logger.warn("Skipping test because it's not running on a local environment."); return; } @@ -116,7 +128,9 @@ describe("Coordinator restart test suite", () => { const l1MessagesPromises = []; let l1MessageSenderNonce = await l1Provider.getTransactionCount(l1MessageSender.address); const { maxPriorityFeePerGas, maxFeePerGas } = await l1Provider.getFeeData(); + logger.debug(`Fetched fee data. maxPriorityFeePerGas=${maxPriorityFeePerGas} maxFeePerGas=${maxFeePerGas}`); + logger.debug("Sending messages L1 -> L2 before coordinator restart..."); for (let i = 0; i < 5; i++) { l1MessagesPromises.push( sendMessage( @@ -144,7 +158,7 @@ describe("Coordinator restart test suite", () => { // Wait for L2 Anchoring const lastNewL1MessageNumber = l1Messages.slice(-1)[0].messageNumber; - console.log(`Waiting L1->L2 anchoring messageNumber=${lastNewL1MessageNumber}`); + logger.debug(`Waiting for L1->L2 anchoring before coordinator restart. messageNumber=${lastNewL1MessageNumber}`); await waitForEvents( l2MessageService, l2MessageService.filters.RollingHashUpdated(), @@ -157,9 +171,10 @@ describe("Coordinator restart test suite", () => { ); // Restart Coordinator - await waitForCoordinatorRestart(); + await waitForCoordinatorRestart(logger); const l1Fees = await l1Provider.getFeeData(); + logger.debug("Sending messages L1 -> L2 after coordinator restart..."); // Send more messages L1 -> L2 for (let i = 0; i < 5; i++) { l1MessagesPromises.push( @@ -188,8 +203,8 @@ describe("Coordinator restart test suite", () => { // Wait for messages to be anchored on L2 const lastNewL1MessageNumberAfterRestart = l1MessagesAfterRestart.slice(-1)[0].messageNumber; - console.log( - `Waiting L1->L2 anchoring after coordinator restart messageNumber=${lastNewL1MessageNumberAfterRestart}`, + logger.debug( + `Waiting for L1->L2 anchoring after coordinator restart. messageNumber=${lastNewL1MessageNumberAfterRestart}`, ); const [rollingHashUpdatedEventAfterRestart] = await waitForEvents( l2MessageService, diff --git a/e2e/src/submission-finalization.spec.ts b/e2e/src/submission-finalization.spec.ts index 1ece48d9d..f040c9050 100644 --- a/e2e/src/submission-finalization.spec.ts +++ b/e2e/src/submission-finalization.spec.ts @@ -21,7 +21,7 @@ describe("Submission and finalization test suite", () => { const l1MessageSender = new NonceManager(await l1AccountManager.generateAccount()); const lineaRollup = config.getLineaRollupContract(); - console.log("Sending messages on L1"); + logger.debug("Sending messages on L1..."); // Send L1 messages const l1MessagesPromises = []; @@ -45,7 +45,7 @@ describe("Submission and finalization test suite", () => { const l1Receipts = await Promise.all(l1MessagesPromises); - console.log("Messages sent on L1."); + logger.debug("Messages sent on L1."); // Extract message events const l1Messages = getMessageSentEventFromLogs(lineaRollup, l1Receipts); @@ -65,7 +65,7 @@ describe("Submission and finalization test suite", () => { // Wait for the last L1->L2 message to be anchored on L2 const lastNewL1MessageNumber = l1Messages.slice(-1)[0].messageNumber; - console.log("Waiting for the anchoring using rolling hash..."); + logger.debug(`Waiting for the anchoring using rolling hash... messageNumber=${lastNewL1MessageNumber}`); const [rollingHashUpdatedEvent] = await waitForEvents( l2MessageService, l2MessageService.filters.RollingHashUpdated(), @@ -82,7 +82,7 @@ describe("Submission and finalization test suite", () => { expect(lastNewMessageRollingHash).toEqual(rollingHashUpdatedEvent.args.rollingHash); expect(lastAnchoredL1MessageNumber).toEqual(rollingHashUpdatedEvent.args.messageNumber); - console.log("New anchoring using rolling hash done."); + logger.debug(`New anchoring using rolling hash done. rollingHash=${lastNewMessageRollingHash}`); }, 150_000, ); @@ -94,10 +94,10 @@ describe("Submission and finalization test suite", () => { const currentL2BlockNumber = await lineaRollupV6.currentL2BlockNumber(); - console.log("Waiting for DataSubmittedV3 used to finalize with proof..."); + logger.debug("Waiting for DataSubmittedV3 used to finalize with proof..."); await waitForEvents(lineaRollupV6, lineaRollupV6.filters.DataSubmittedV3(), 1_000); - console.log("Waiting for the first DataFinalizedV3 event with proof..."); + logger.debug("Waiting for DataFinalizedV3 event with proof..."); const [dataFinalizedEvent] = await waitForEvents( lineaRollupV6, lineaRollupV6.filters.DataFinalizedV3(currentL2BlockNumber + 1n), @@ -112,7 +112,7 @@ describe("Submission and finalization test suite", () => { expect(lastBlockFinalized).toBeGreaterThanOrEqual(dataFinalizedEvent.args.endBlockNumber); expect(newStateRootHash).toEqual(dataFinalizedEvent.args.finalStateRootHash); - console.log("Finalization with proof done."); + logger.debug(`Finalization with proof done. lastFinalizedBlockNumber=${lastBlockFinalized}`); }, 150_000, ); @@ -122,12 +122,12 @@ describe("Submission and finalization test suite", () => { async () => { const sequencerEndpoint = config.getSequencerEndpoint(); if (!sequencerEndpoint) { - console.log('Skipped the "Check L2 safe/finalized tag update on sequencer" test'); + logger.warn('Skipped the "Check L2 safe/finalized tag update on sequencer" test'); return; } const lastFinalizedL2BlockNumberOnL1 = 0; - console.log(`lastFinalizedL2BlockNumberOnL1=${lastFinalizedL2BlockNumberOnL1}`); + logger.debug(`lastFinalizedL2BlockNumberOnL1=${lastFinalizedL2BlockNumberOnL1}`); let safeL2BlockNumber = -1, finalizedL2BlockNumber = -1; @@ -142,12 +142,12 @@ describe("Submission and finalization test suite", () => { await wait(1_000); } - console.log(`safeL2BlockNumber=${safeL2BlockNumber} finalizedL2BlockNumber=${finalizedL2BlockNumber}`); + logger.debug(`safeL2BlockNumber=${safeL2BlockNumber} finalizedL2BlockNumber=${finalizedL2BlockNumber}`); expect(safeL2BlockNumber).toBeGreaterThanOrEqual(lastFinalizedL2BlockNumberOnL1); expect(finalizedL2BlockNumber).toBeGreaterThanOrEqual(lastFinalizedL2BlockNumberOnL1); - console.log("L2 safe/finalized tag update on sequencer done."); + logger.debug("L2 safe/finalized tag update on sequencer done."); }, 150_000, ); diff --git a/e2e/src/transaction-exclusion.spec.ts b/e2e/src/transaction-exclusion.spec.ts index d3f75ef3f..723702ee4 100644 --- a/e2e/src/transaction-exclusion.spec.ts +++ b/e2e/src/transaction-exclusion.spec.ts @@ -30,11 +30,11 @@ describe("Transaction exclusion test suite", () => { await l2AccountLocal.sendTransaction(txRequest); } catch (err) { // This shall return error with traces limit overflow - console.debug(`sendTransaction expected err: ${JSON.stringify(err)}`); + logger.debug(`sendTransaction expected. error=${JSON.stringify(err)}`); } expect(rejectedTxHash).toBeDefined(); - console.log(`rejectedTxHash (RPC): ${rejectedTxHash}`); + logger.debug(`Transaction rejected as expected (RPC). transactionHash=${rejectedTxHash}`); let getResponse; do { @@ -42,6 +42,8 @@ describe("Transaction exclusion test suite", () => { getResponse = await transactionExclusionClient.getTransactionExclusionStatusV1(rejectedTxHash!); } while (!getResponse?.result); + logger.debug(`Transaction exclusion status received. response=${JSON.stringify(getResponse.result)}`); + expect(getResponse.result.txHash).toStrictEqual(rejectedTxHash); expect(getResponse.result.txRejectionStage).toStrictEqual("RPC"); expect(getResponse.result.from.toLowerCase()).toStrictEqual(l2AccountLocal.address.toLowerCase()); @@ -60,7 +62,7 @@ describe("Transaction exclusion test suite", () => { // This shall be rejected by sequencer due to traces module limit overflow const tx = await testContract!.connect(l2AccountLocal).testAddmod(13000, 31); const rejectedTxHash = tx.hash; - console.log(`rejectedTxHash (SEQUENCER): ${rejectedTxHash}`); + logger.debug(`Transaction rejected as expected (SEQUENCER). transactionHash=${rejectedTxHash}`); let getResponse; do { @@ -68,6 +70,8 @@ describe("Transaction exclusion test suite", () => { getResponse = await transactionExclusionClient.getTransactionExclusionStatusV1(rejectedTxHash); } while (!getResponse?.result); + logger.debug(`Transaction exclusion status received. response=${JSON.stringify(getResponse.result)}`); + expect(getResponse.result.txHash).toStrictEqual(rejectedTxHash); expect(getResponse.result.txRejectionStage).toStrictEqual("SEQUENCER"); expect(getResponse.result.from.toLowerCase()).toStrictEqual(l2AccountLocal.address.toLowerCase()); diff --git a/e2e/tsconfig.json b/e2e/tsconfig.json index be4ae3d27..f45a3edf5 100644 --- a/e2e/tsconfig.json +++ b/e2e/tsconfig.json @@ -18,5 +18,6 @@ "path": "../sdk" } ], + "include": ["**/*.ts"], "exclude": ["node_modules", "dist"], } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ede6c9b3d..670b1201d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ jreleaser = {id = "org.jreleaser", version = "1.15.0"} jreleaser = { group = "org.jreleaser", name = "jreleaser-gradle-plugin", version = "1.15.0" } [versions] -besu = "24.10.0" +besu = "24.12.2" caffeine = "3.1.6" hoplite = "2.7.5" jackson = "2.18.0" diff --git a/jvm-libs/linea/besu-libs/build.gradle b/jvm-libs/linea/besu-libs/build.gradle index 4e009a0d2..e9b797c88 100644 --- a/jvm-libs/linea/besu-libs/build.gradle +++ b/jvm-libs/linea/besu-libs/build.gradle @@ -3,25 +3,27 @@ plugins { id 'java-library' } +def besuArtifactGroup="org.hyperledger.besu" + dependencies { - api("org.hyperledger.besu:besu-datatypes:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}:besu-datatypes:${libs.versions.besu.get()}") { transitive = false } - api("org.hyperledger.besu:evm:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}:evm:${libs.versions.besu.get()}") { transitive = false } - api("org.hyperledger.besu.internal:core:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}.internal:core:${libs.versions.besu.get()}") { transitive = false } - api("org.hyperledger.besu.internal:algorithms:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}.internal:algorithms:${libs.versions.besu.get()}") { transitive = false } - api("org.hyperledger.besu:plugin-api:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}:plugin-api:${libs.versions.besu.get()}") { transitive = false } - api("org.hyperledger.besu.internal:rlp:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}.internal:rlp:${libs.versions.besu.get()}") { transitive = false } diff --git a/jvm-libs/linea/blob-decompressor/build.gradle b/jvm-libs/linea/blob-decompressor/build.gradle index 2fbaee83b..42c637950 100644 --- a/jvm-libs/linea/blob-decompressor/build.gradle +++ b/jvm-libs/linea/blob-decompressor/build.gradle @@ -14,11 +14,7 @@ dependencies { testImplementation(testFixtures(project(":jvm-libs:linea:blob-compressor"))) testImplementation(project(":jvm-libs:linea:testing:file-system")) testImplementation("io.tmio:tuweni-bytes:${libs.versions.tuweni.get()}") - testImplementation("org.hyperledger.besu:besu-datatypes:${libs.versions.besu.get()}") - testImplementation "org.hyperledger.besu:evm:${libs.versions.besu.get()}" - testImplementation("org.hyperledger.besu.internal:core:${libs.versions.besu.get()}") - testImplementation("org.hyperledger.besu:plugin-api:${libs.versions.besu.get()}") - testImplementation("org.hyperledger.besu.internal:rlp:${libs.versions.besu.get()}") + testImplementation(project(":jvm-libs:linea:besu-libs")) } jar { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 852d395ca..42db29159 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,7 +46,7 @@ importers: dependencies: '@consensys/linea-sdk': specifier: 0.3.0 - version: 0.3.0(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))(utf-8-validate@5.0.10) + version: 0.3.0(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))(utf-8-validate@5.0.10) '@headlessui/react': specifier: 2.1.9 version: 2.1.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -134,7 +134,7 @@ importers: version: 8.1.0(typescript@5.4.5) '@synthetixio/synpress': specifier: 4.0.0-alpha.7 - version: 4.0.0-alpha.7(@playwright/test@1.45.3)(bufferutil@4.0.8)(playwright-core@1.45.3)(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))(typescript@5.4.5)(utf-8-validate@5.0.10)(zod@3.22.4) + version: 4.0.0-alpha.7(@playwright/test@1.45.3)(bufferutil@4.0.8)(playwright-core@1.45.3)(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))(typescript@5.4.5)(utf-8-validate@5.0.10)(zod@3.22.4) '@types/fs-extra': specifier: 11.0.4 version: 11.0.4 @@ -158,16 +158,16 @@ importers: version: 14.2.15(eslint@8.57.0)(typescript@5.4.5) eslint-plugin-tailwindcss: specifier: 3.17.4 - version: 3.17.4(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))) + version: 3.17.4(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))) postcss: specifier: 8.4.47 version: 8.4.47 tailwind-scrollbar: specifier: 3.1.0 - version: 3.1.0(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))) + version: 3.1.0(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))) tailwindcss: specifier: 3.4.13 - version: 3.4.13(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5)) + version: 3.4.13(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5)) contracts: dependencies: @@ -263,8 +263,6 @@ importers: specifier: 17.7.2 version: 17.7.2 - contracts/lib/forge-std: {} - e2e: devDependencies: '@jest/globals': @@ -300,6 +298,9 @@ importers: typechain: specifier: 8.3.2 version: 8.3.2(typescript@5.4.5) + winston: + specifier: 3.17.0 + version: 3.17.0 operations: dependencies: @@ -6647,10 +6648,6 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} - logform@2.6.1: - resolution: {integrity: sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA==} - engines: {node: '>= 12.0.0'} - logform@2.7.0: resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==} engines: {node: '>= 12.0.0'} @@ -9475,18 +9472,10 @@ packages: resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} engines: {node: '>=8'} - winston-transport@4.8.0: - resolution: {integrity: sha512-qxSTKswC6llEMZKgCQdaWgDuMJQnhuvF5f2Nk3SNXc4byfQ+voo2mX1Px9dkNOuR8p0KAjfPG29PuYUSIb+vSA==} - engines: {node: '>= 12.0.0'} - winston-transport@4.9.0: resolution: {integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==} engines: {node: '>= 12.0.0'} - winston@3.13.0: - resolution: {integrity: sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==} - engines: {node: '>= 12.0.0'} - winston@3.17.0: resolution: {integrity: sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==} engines: {node: '>= 12.0.0'} @@ -10728,7 +10717,7 @@ snapshots: '@colors/colors@1.6.0': {} - '@consensys/linea-sdk@0.3.0(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))(utf-8-validate@5.0.10)': + '@consensys/linea-sdk@0.3.0(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))(utf-8-validate@5.0.10)': dependencies: better-sqlite3: 9.6.0 class-validator: 0.14.1 @@ -10736,9 +10725,9 @@ snapshots: ethers: 6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10) lru-cache: 10.2.2 pg: 8.11.3 - typeorm: 0.3.20(better-sqlite3@9.6.0)(pg@8.11.3)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5)) - typeorm-naming-strategies: 4.1.0(typeorm@0.3.20(better-sqlite3@9.6.0)(pg@8.11.3)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))) - winston: 3.13.0 + typeorm: 0.3.20(better-sqlite3@9.6.0)(pg@8.11.3)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5)) + typeorm-naming-strategies: 4.1.0(typeorm@0.3.20(better-sqlite3@9.6.0)(pg@8.11.3)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))) + winston: 3.17.0 transitivePeerDependencies: - '@google-cloud/spanner' - '@sap/hana-client' @@ -13040,7 +13029,7 @@ snapshots: - utf-8-validate - zod - '@synthetixio/synpress-cache@0.0.1-alpha.7(playwright-core@1.45.3)(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))(typescript@5.4.5)': + '@synthetixio/synpress-cache@0.0.1-alpha.7(playwright-core@1.45.3)(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))(typescript@5.4.5)': dependencies: axios: 1.6.7 chalk: 5.3.0 @@ -13051,7 +13040,7 @@ snapshots: gradient-string: 2.0.2 playwright-core: 1.45.3 progress: 2.0.3 - tsup: 8.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))(typescript@5.4.5) + tsup: 8.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))(typescript@5.4.5) unzipper: 0.10.14 zod: 3.22.4 transitivePeerDependencies: @@ -13067,10 +13056,10 @@ snapshots: dependencies: '@playwright/test': 1.45.3 - '@synthetixio/synpress-metamask@0.0.1-alpha.7(@playwright/test@1.45.3)(bufferutil@4.0.8)(playwright-core@1.45.3)(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))(typescript@5.4.5)(utf-8-validate@5.0.10)': + '@synthetixio/synpress-metamask@0.0.1-alpha.7(@playwright/test@1.45.3)(bufferutil@4.0.8)(playwright-core@1.45.3)(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))(typescript@5.4.5)(utf-8-validate@5.0.10)': dependencies: '@playwright/test': 1.45.3 - '@synthetixio/synpress-cache': 0.0.1-alpha.7(playwright-core@1.45.3)(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))(typescript@5.4.5) + '@synthetixio/synpress-cache': 0.0.1-alpha.7(playwright-core@1.45.3)(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))(typescript@5.4.5) '@synthetixio/synpress-core': 0.0.1-alpha.7(@playwright/test@1.45.3) '@viem/anvil': 0.0.7(bufferutil@4.0.8)(utf-8-validate@5.0.10) fs-extra: 11.2.0 @@ -13087,13 +13076,13 @@ snapshots: - typescript - utf-8-validate - '@synthetixio/synpress@4.0.0-alpha.7(@playwright/test@1.45.3)(bufferutil@4.0.8)(playwright-core@1.45.3)(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))(typescript@5.4.5)(utf-8-validate@5.0.10)(zod@3.22.4)': + '@synthetixio/synpress@4.0.0-alpha.7(@playwright/test@1.45.3)(bufferutil@4.0.8)(playwright-core@1.45.3)(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))(typescript@5.4.5)(utf-8-validate@5.0.10)(zod@3.22.4)': dependencies: '@playwright/test': 1.45.3 '@synthetixio/ethereum-wallet-mock': 0.0.1-alpha.7(@playwright/test@1.45.3)(bufferutil@4.0.8)(typescript@5.4.5)(utf-8-validate@5.0.10)(zod@3.22.4) - '@synthetixio/synpress-cache': 0.0.1-alpha.7(playwright-core@1.45.3)(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))(typescript@5.4.5) + '@synthetixio/synpress-cache': 0.0.1-alpha.7(playwright-core@1.45.3)(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))(typescript@5.4.5) '@synthetixio/synpress-core': 0.0.1-alpha.7(@playwright/test@1.45.3) - '@synthetixio/synpress-metamask': 0.0.1-alpha.7(@playwright/test@1.45.3)(bufferutil@4.0.8)(playwright-core@1.45.3)(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))(typescript@5.4.5)(utf-8-validate@5.0.10) + '@synthetixio/synpress-metamask': 0.0.1-alpha.7(@playwright/test@1.45.3)(bufferutil@4.0.8)(playwright-core@1.45.3)(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))(typescript@5.4.5)(utf-8-validate@5.0.10) transitivePeerDependencies: - '@microsoft/api-extractor' - '@swc/core' @@ -15973,7 +15962,7 @@ snapshots: debug: 4.3.7(supports-color@8.1.1) enhanced-resolve: 5.17.1 eslint: 8.57.0 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 @@ -15986,7 +15975,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -16008,7 +15997,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -16081,11 +16070,11 @@ snapshots: string.prototype.matchall: 4.0.11 string.prototype.repeat: 1.0.0 - eslint-plugin-tailwindcss@3.17.4(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))): + eslint-plugin-tailwindcss@3.17.4(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))): dependencies: fast-glob: 3.3.2 postcss: 8.4.47 - tailwindcss: 3.4.13(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5)) + tailwindcss: 3.4.13(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5)) eslint-scope@7.2.2: dependencies: @@ -18336,15 +18325,6 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 - logform@2.6.1: - dependencies: - '@colors/colors': 1.6.0 - '@types/triple-beam': 1.3.5 - fecha: 4.2.3 - ms: 2.1.3 - safe-stable-stringify: 2.5.0 - triple-beam: 1.4.1 - logform@2.7.0: dependencies: '@colors/colors': 1.6.0 @@ -19407,13 +19387,13 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.4.47 - postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5)): + postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5)): dependencies: lilconfig: 3.1.2 yaml: 2.5.1 optionalDependencies: postcss: 8.4.47 - ts-node: 10.9.2(@types/node@20.12.7)(typescript@5.4.5) + ts-node: 10.9.2(@types/node@22.7.5)(typescript@5.4.5) postcss-nested@6.2.0(postcss@8.4.47): dependencies: @@ -20662,11 +20642,11 @@ snapshots: tailwind-merge@2.5.3: {} - tailwind-scrollbar@3.1.0(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))): + tailwind-scrollbar@3.1.0(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))): dependencies: - tailwindcss: 3.4.13(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5)) + tailwindcss: 3.4.13(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5)) - tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5)): + tailwindcss@3.4.13(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -20685,7 +20665,7 @@ snapshots: postcss: 8.4.47 postcss-import: 15.1.0(postcss@8.4.47) postcss-js: 4.0.1(postcss@8.4.47) - postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5)) + postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5)) postcss-nested: 6.2.0(postcss@8.4.47) postcss-selector-parser: 6.1.2 resolve: 1.22.8 @@ -20937,7 +20917,7 @@ snapshots: tsort@0.0.1: {} - tsup@8.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))(typescript@5.4.5): + tsup@8.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))(typescript@5.4.5): dependencies: bundle-require: 4.2.1(esbuild@0.19.12) cac: 6.7.14 @@ -20947,7 +20927,7 @@ snapshots: execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5)) + postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5)) resolve-from: 5.0.0 rollup: 4.24.0 source-map: 0.8.0-beta.0 @@ -21055,9 +21035,9 @@ snapshots: dependencies: typeorm: 0.3.20(better-sqlite3@11.6.0)(pg@8.13.1)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5)) - typeorm-naming-strategies@4.1.0(typeorm@0.3.20(better-sqlite3@9.6.0)(pg@8.11.3)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5))): + typeorm-naming-strategies@4.1.0(typeorm@0.3.20(better-sqlite3@9.6.0)(pg@8.11.3)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5))): dependencies: - typeorm: 0.3.20(better-sqlite3@9.6.0)(pg@8.11.3)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5)) + typeorm: 0.3.20(better-sqlite3@9.6.0)(pg@8.11.3)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5)) typeorm@0.3.20(better-sqlite3@11.6.0)(pg@8.13.1)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5)): dependencies: @@ -21083,7 +21063,7 @@ snapshots: transitivePeerDependencies: - supports-color - typeorm@0.3.20(better-sqlite3@9.6.0)(pg@8.11.3)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5)): + typeorm@0.3.20(better-sqlite3@9.6.0)(pg@8.11.3)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5)): dependencies: '@sqltools/formatter': 1.2.5 app-root-path: 3.1.0 @@ -21103,7 +21083,7 @@ snapshots: optionalDependencies: better-sqlite3: 9.6.0 pg: 8.11.3 - ts-node: 10.9.2(@types/node@20.12.7)(typescript@5.4.5) + ts-node: 10.9.2(@types/node@22.7.5)(typescript@5.4.5) transitivePeerDependencies: - supports-color @@ -21675,32 +21655,12 @@ snapshots: dependencies: string-width: 4.2.3 - winston-transport@4.8.0: - dependencies: - logform: 2.6.1 - readable-stream: 4.5.2 - triple-beam: 1.4.1 - winston-transport@4.9.0: dependencies: logform: 2.7.0 readable-stream: 3.6.2 triple-beam: 1.4.1 - winston@3.13.0: - dependencies: - '@colors/colors': 1.6.0 - '@dabh/diagnostics': 2.0.3 - async: 3.2.6 - is-stream: 2.0.1 - logform: 2.6.1 - one-time: 1.0.0 - readable-stream: 3.6.2 - safe-stable-stringify: 2.5.0 - stack-trace: 0.0.10 - triple-beam: 1.4.1 - winston-transport: 4.8.0 - winston@3.17.0: dependencies: '@colors/colors': 1.6.0 diff --git a/prover/circuits/blobdecompression/large-tests/compile-batch-hasher/main.go b/prover/circuits/blobdecompression/large-tests/compile-batch-hasher/main.go index 9e20624a4..5dd6076bb 100644 --- a/prover/circuits/blobdecompression/large-tests/compile-batch-hasher/main.go +++ b/prover/circuits/blobdecompression/large-tests/compile-batch-hasher/main.go @@ -28,5 +28,5 @@ type circuit struct { func (c *circuit) Define(api frontend.API) error { hsh := gkrmimc.NewHasherFactory(api).NewHasher() - return v1.CheckBatchesSums(api, &hsh, c.NbBatches, c.BlobPayload[:], c.BatchEnds[:], c.ExpectedSums[:]) + return v1.CheckBatchesSums(api, hsh, c.NbBatches, c.BlobPayload[:], c.BatchEnds[:], c.ExpectedSums[:]) } diff --git a/prover/circuits/blobdecompression/v1/circuit.go b/prover/circuits/blobdecompression/v1/circuit.go index db864aea6..a04669002 100644 --- a/prover/circuits/blobdecompression/v1/circuit.go +++ b/prover/circuits/blobdecompression/v1/circuit.go @@ -4,11 +4,12 @@ import ( "bytes" "errors" "fmt" - "github.com/consensys/linea-monorepo/prover/lib/compressor/blob/dictionary" - "github.com/consensys/linea-monorepo/prover/lib/compressor/blob/encode" "hash" "math/big" + "github.com/consensys/linea-monorepo/prover/lib/compressor/blob/dictionary" + "github.com/consensys/linea-monorepo/prover/lib/compressor/blob/encode" + "github.com/consensys/gnark-crypto/ecc" fr377 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" fr381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" @@ -192,8 +193,7 @@ func (i *FunctionalPublicInputSnark) Sum(api frontend.API, hsh snarkHash.FieldHa func (c Circuit) Define(api frontend.API) error { var hsh snarkHash.FieldHasher if c.UseGkrMiMC { - h := gkrmimc.NewHasherFactory(api).NewHasher() - hsh = &h + hsh = gkrmimc.NewHasherFactory(api).NewHasher() } else { if h, err := mimc.NewMiMC(api); err != nil { return err diff --git a/prover/circuits/execution/circuit.go b/prover/circuits/execution/circuit.go index 36f772c3d..3403911c6 100644 --- a/prover/circuits/execution/circuit.go +++ b/prover/circuits/execution/circuit.go @@ -12,7 +12,6 @@ import ( "github.com/consensys/linea-monorepo/prover/circuits" "github.com/consensys/linea-monorepo/prover/protocol/wizard" "github.com/consensys/linea-monorepo/prover/zkevm" - "github.com/consensys/linea-monorepo/prover/zkevm/prover/publicInput" "github.com/sirupsen/logrus" "github.com/consensys/gnark/std/hash/mimc" @@ -23,11 +22,6 @@ import ( type CircuitExecution struct { // The wizard verifier circuit WizardVerifier wizard.WizardVerifierCircuit `gnark:",secret"` - // The extractor is not part of the circuit per se, but hold informations - // that is used to extract the public inputs from the the WizardVerifier. - // The extractor only needs to be provided during the definition of the - // circuit and is omitted during the assignment of the circuit. - extractor publicInput.FunctionalInputExtractor `gnark:"-"` // The functional public inputs are the "actual" statement made by the // circuit. They are not part of the public input of the circuit for // a number of reasons involving efficiency and simplicity in the aggregation @@ -45,7 +39,6 @@ func Allocate(zkevm *zkevm.ZkEvm) CircuitExecution { } return CircuitExecution{ WizardVerifier: *wverifier, - extractor: zkevm.PublicInput.Extractor, FuncInputs: FunctionalPublicInputSnark{ FunctionalPublicInputQSnark: FunctionalPublicInputQSnark{ L2MessageHashes: L2MessageHashes{ @@ -90,7 +83,6 @@ func (c *CircuitExecution) Define(api frontend.API) error { api, &c.WizardVerifier, c.FuncInputs, - c.extractor, ) // Add missing public input check diff --git a/prover/circuits/execution/pi_wizard_extraction.go b/prover/circuits/execution/pi_wizard_extraction.go index 2f14948ca..e564320c4 100644 --- a/prover/circuits/execution/pi_wizard_extraction.go +++ b/prover/circuits/execution/pi_wizard_extraction.go @@ -16,13 +16,12 @@ func checkPublicInputs( api frontend.API, wvc *wizard.WizardVerifierCircuit, gnarkFuncInp FunctionalPublicInputSnark, - wizardFuncInp publicInput.FunctionalInputExtractor, ) { var ( lastRollingHash = internal.CombineBytesIntoElements(api, gnarkFuncInp.FinalRollingHashUpdate) firstRollingHash = internal.CombineBytesIntoElements(api, gnarkFuncInp.InitialRollingHashUpdate) - execDataHash = execDataHash(api, wvc, wizardFuncInp) + execDataHash = execDataHash(api, wvc) ) // As we have this issue, the execDataHash will not match what we have in the @@ -32,7 +31,7 @@ func checkPublicInputs( shouldBeEqual(api, execDataHash, gnarkFuncInp.DataChecksum) api.AssertIsEqual( - wvc.GetLocalPointEvalParams(wizardFuncInp.L2MessageHash.ID).Y, + wvc.GetPublicInput(api, publicInput.L2MessageHash), // TODO: this operation is done a second time when computing the final // public input which is wasteful although not dramatic (~8000 unused // constraints) @@ -40,62 +39,62 @@ func checkPublicInputs( ) api.AssertIsEqual( - wvc.GetLocalPointEvalParams(wizardFuncInp.InitialStateRootHash.ID).Y, + wvc.GetPublicInput(api, publicInput.InitialStateRootHash), gnarkFuncInp.InitialStateRootHash, ) api.AssertIsEqual( - wvc.GetLocalPointEvalParams(wizardFuncInp.InitialBlockNumber.ID).Y, + wvc.GetPublicInput(api, publicInput.InitialBlockNumber), gnarkFuncInp.InitialBlockNumber, ) api.AssertIsEqual( - wvc.GetLocalPointEvalParams(wizardFuncInp.InitialBlockTimestamp.ID).Y, + wvc.GetPublicInput(api, publicInput.InitialBlockTimestamp), gnarkFuncInp.InitialBlockTimestamp, ) api.AssertIsEqual( - wvc.GetLocalPointEvalParams(wizardFuncInp.FirstRollingHashUpdate[0].ID).Y, + wvc.GetPublicInput(api, publicInput.FirstRollingHashUpdate_0), firstRollingHash[0], ) api.AssertIsEqual( - wvc.GetLocalPointEvalParams(wizardFuncInp.FirstRollingHashUpdate[1].ID).Y, + wvc.GetPublicInput(api, publicInput.FirstRollingHashUpdate_1), firstRollingHash[1], ) api.AssertIsEqual( - wvc.GetLocalPointEvalParams(wizardFuncInp.FirstRollingHashUpdateNumber.ID).Y, + wvc.GetPublicInput(api, publicInput.FirstRollingHashUpdateNumber), gnarkFuncInp.FirstRollingHashUpdateNumber, ) api.AssertIsEqual( - wvc.GetLocalPointEvalParams(wizardFuncInp.FinalStateRootHash.ID).Y, + wvc.GetPublicInput(api, publicInput.FinalStateRootHash), gnarkFuncInp.FinalStateRootHash, ) api.AssertIsEqual( - wvc.GetLocalPointEvalParams(wizardFuncInp.FinalBlockNumber.ID).Y, + wvc.GetPublicInput(api, publicInput.FinalBlockNumber), gnarkFuncInp.FinalBlockNumber, ) api.AssertIsEqual( - wvc.GetLocalPointEvalParams(wizardFuncInp.FinalBlockTimestamp.ID).Y, + wvc.GetPublicInput(api, publicInput.FinalBlockTimestamp), gnarkFuncInp.FinalBlockTimestamp, ) api.AssertIsEqual( - wvc.GetLocalPointEvalParams(wizardFuncInp.LastRollingHashUpdate[0].ID).Y, + wvc.GetPublicInput(api, publicInput.LastRollingHashUpdate_0), lastRollingHash[0], ) api.AssertIsEqual( - wvc.GetLocalPointEvalParams(wizardFuncInp.LastRollingHashUpdate[1].ID).Y, + wvc.GetPublicInput(api, publicInput.LastRollingHashUpdate_1), lastRollingHash[1], ) api.AssertIsEqual( - wvc.GetLocalPointEvalParams(wizardFuncInp.LastRollingHashUpdateNumber.ID).Y, + wvc.GetPublicInput(api, publicInput.LastRollingHashNumberUpdate), gnarkFuncInp.LastRollingHashUpdateNumber, ) @@ -107,9 +106,9 @@ func checkPublicInputs( bridgeAddress = api.Add( api.Mul( twoPow128, - wizardFuncInp.L2MessageServiceAddrHi.GetFrontendVariable(api, wvc), + wvc.GetPublicInput(api, publicInput.L2MessageServiceAddrHi), ), - wizardFuncInp.L2MessageServiceAddrLo.GetFrontendVariable(api, wvc), + wvc.GetPublicInput(api, publicInput.L2MessageServiceAddrLo), ) ) @@ -119,10 +118,10 @@ func checkPublicInputs( // chainID) then the traces will return a chainID of zero. api.AssertIsEqual( api.Mul( - wvc.GetLocalPointEvalParams(wizardFuncInp.ChainID.ID).Y, + wvc.GetPublicInput(api, publicInput.ChainID), api.Sub( api.Div( - wvc.GetLocalPointEvalParams(wizardFuncInp.ChainID.ID).Y, + wvc.GetPublicInput(api, publicInput.ChainID), twoPow112, ), gnarkFuncInp.ChainID, @@ -141,7 +140,6 @@ func checkPublicInputs( func execDataHash( api frontend.API, wvc *wizard.WizardVerifierCircuit, - wFuncInp publicInput.FunctionalInputExtractor, ) frontend.Variable { hsh, err := mimc.NewMiMC(api) @@ -150,8 +148,8 @@ func execDataHash( } hsh.Write( - wvc.GetLocalPointEvalParams(wFuncInp.DataNbBytes.ID).Y, - wvc.GetLocalPointEvalParams(wFuncInp.DataChecksum.ID).Y, + wvc.GetPublicInput(api, publicInput.DataNbBytes), + wvc.GetPublicInput(api, publicInput.DataChecksum), ) return hsh.Sum() diff --git a/prover/circuits/pi-interconnection/circuit.go b/prover/circuits/pi-interconnection/circuit.go index eb6e2953d..a19573995 100644 --- a/prover/circuits/pi-interconnection/circuit.go +++ b/prover/circuits/pi-interconnection/circuit.go @@ -98,8 +98,7 @@ func (c *Circuit) Define(api frontend.API) error { hshM hash.FieldHasher ) if c.UseGkrMimc { - hsh := gkrmimc.NewHasherFactory(api).NewHasher() - hshM = &hsh + hshM = gkrmimc.NewHasherFactory(api).NewHasher() } else { if hsh, err := mimc.NewMiMC(api); err != nil { return err diff --git a/prover/circuits/pi-interconnection/e2e_test.go b/prover/circuits/pi-interconnection/e2e_test.go index 5f559ecda..ca53f69ae 100644 --- a/prover/circuits/pi-interconnection/e2e_test.go +++ b/prover/circuits/pi-interconnection/e2e_test.go @@ -112,6 +112,7 @@ func TestTinyTwoBatchBlob(t *testing.T) { req := pi_interconnection.Request{ Decompressions: []blobsubmission.Response{*blobResp}, Executions: execReq, + DictPath: "../../lib/compressor/compressor_dict.bin", Aggregation: public_input.Aggregation{ FinalShnarf: blobResp.ExpectedShnarf, ParentAggregationFinalShnarf: blobReq.PrevShnarf, @@ -208,6 +209,7 @@ func TestTwoTwoBatchBlobs(t *testing.T) { req := pi_interconnection.Request{ Decompressions: []blobsubmission.Response{*blobResp0, *blobResp1}, Executions: execReq, + DictPath: "../../lib/compressor/compressor_dict.bin", Aggregation: public_input.Aggregation{ FinalShnarf: blobResp1.ExpectedShnarf, ParentAggregationFinalShnarf: blobReq0.PrevShnarf, diff --git a/prover/circuits/pi-interconnection/test_utils/test_utils.go b/prover/circuits/pi-interconnection/test_utils/test_utils.go index c678f1673..36f1162ed 100644 --- a/prover/circuits/pi-interconnection/test_utils/test_utils.go +++ b/prover/circuits/pi-interconnection/test_utils/test_utils.go @@ -48,6 +48,7 @@ func AssignSingleBlockBlob(t require.TestingT) pi_interconnection.Request { merkleRoots := aggregation.PackInMiniTrees(test_utils.BlocksToHex(execReq.L2MessageHashes)) return pi_interconnection.Request{ + DictPath: "../../lib/compressor/compressor_dict.bin", Decompressions: []blobsubmission.Response{*blobResp}, Executions: []public_input.Execution{execReq}, Aggregation: public_input.Aggregation{ diff --git a/prover/crypto/fiatshamir/fiatshamir.go b/prover/crypto/fiatshamir/fiatshamir.go index c9752d7ca..3a52bdca9 100644 --- a/prover/crypto/fiatshamir/fiatshamir.go +++ b/prover/crypto/fiatshamir/fiatshamir.go @@ -1,9 +1,9 @@ package fiatshamir import ( - "hash" "math" + "github.com/consensys/gnark-crypto/hash" "github.com/consensys/linea-monorepo/prover/crypto/mimc" "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" "github.com/consensys/linea-monorepo/prover/maths/field" @@ -31,7 +31,7 @@ import ( // // https://blog.trailofbits.com/2022/04/18/the-frozen-heart-vulnerability-in-plonk/ type State struct { - hasher hash.Hash + hasher hash.StateStorer TranscriptSize int NumCoinGenerated int } @@ -39,10 +39,26 @@ type State struct { // NewMiMCFiatShamir constructs a fresh and empty Fiat-Shamir state. func NewMiMCFiatShamir() *State { return &State{ - hasher: mimc.NewMiMC(), + hasher: mimc.NewMiMC().(hash.StateStorer), } } +// State returns the internal state of the Fiat-Shamir hasher. Only works for +// MiMC. +func (s *State) State() []field.Element { + _ = s.hasher.Sum(nil) + b := s.hasher.State() + f := new(field.Element).SetBytes(b) + return []field.Element{*f} +} + +// SetState sets the fiat-shamir state to the requested value +func (s *State) SetState(f []field.Element) { + _ = s.hasher.Sum(nil) + b := f[0].Bytes() + s.hasher.SetState(b[:]) +} + // Update the Fiat-Shamir state with a one or more of field elements. The // function as no-op if the caller supplies no field elements. func (fs *State) Update(vec ...field.Element) { diff --git a/prover/crypto/fiatshamir/snark.go b/prover/crypto/fiatshamir/snark.go index 198549ed5..7d26df39c 100644 --- a/prover/crypto/fiatshamir/snark.go +++ b/prover/crypto/fiatshamir/snark.go @@ -19,7 +19,7 @@ import ( // of the verifier of a protocol calling [State] as it allows having a very // similar code for both tasks. type GnarkFiatShamir struct { - hasher hash.FieldHasher + hasher hash.StateStorer // pointer to the gnark-API (also passed to the hasher but behind an // interface). This is needed to perform bit-decomposition. api frontend.API @@ -30,10 +30,10 @@ type GnarkFiatShamir struct { // used in the scope of a [frontend.Define] function. func NewGnarkFiatShamir(api frontend.API, factory *gkrmimc.HasherFactory) *GnarkFiatShamir { - var hasher hash.FieldHasher + var hasher hash.StateStorer if factory != nil { h := factory.NewHasher() - hasher = &h + hasher = h } else { h, err := mimc.NewMiMC(api) if err != nil { @@ -52,6 +52,34 @@ func NewGnarkFiatShamir(api frontend.API, factory *gkrmimc.HasherFactory) *Gnark } } +// SetState mutates the fiat-shamir state of +func (fs *GnarkFiatShamir) SetState(state []frontend.Variable) { + + switch hsh := fs.hasher.(type) { + case interface { + SetState([]frontend.Variable) error + }: + if err := hsh.SetState(state); err != nil { + panic(err) + } + default: + panic("unexpected hasher type") + } +} + +// State mutates the fiat-shamir state of +func (fs *GnarkFiatShamir) State() []frontend.Variable { + + switch hsh := fs.hasher.(type) { + case interface { + State() []frontend.Variable + }: + return hsh.State() + default: + panic("unexpected hasher type") + } +} + // Update updates the Fiat-Shamir state with a vector of frontend.Variable // representing field element each. func (fs *GnarkFiatShamir) Update(vec ...frontend.Variable) { diff --git a/prover/crypto/mimc/gkrmimc/helper.go b/prover/crypto/mimc/gkrmimc/helper.go index ef7977097..dd748d9c2 100644 --- a/prover/crypto/mimc/gkrmimc/helper.go +++ b/prover/crypto/mimc/gkrmimc/helper.go @@ -1,6 +1,7 @@ package gkrmimc import ( + "errors" "math/big" "github.com/consensys/gnark/frontend" @@ -70,8 +71,8 @@ type Hasher struct { // and will provide the same results for the same usage. // // However, the hasher should not be used in deferred gnark circuit execution. -func (f *HasherFactory) NewHasher() Hasher { - return Hasher{factory: f, state: frontend.Variable(0)} +func (f *HasherFactory) NewHasher() *Hasher { + return &Hasher{factory: f, state: frontend.Variable(0)} } // Writes fields elements into the hasher; implements [hash.FieldHasher] @@ -107,6 +108,30 @@ func (h *Hasher) Sum() frontend.Variable { return curr } +// SetState manually sets the state of the hasher to the provided value. In the +// case of MiMC only a single frontend variable is expected to represent the +// state. +func (h *Hasher) SetState(newState []frontend.Variable) error { + + if len(h.data) > 0 { + return errors.New("the hasher is not in an initial state") + } + + if len(newState) != 1 { + return errors.New("the MiMC hasher expects a single field element to represent the state") + } + + h.state = newState[0] + return nil +} + +// State returns the inner-state of the hasher. In the context of MiMC only a +// single field element is returned. +func (h *Hasher) State() []frontend.Variable { + _ = h.Sum() // to flush the hasher + return []frontend.Variable{h.state} +} + // compress calls returns a frontend.Variable holding the result of applying // the compression function of MiMC over state and block. The alleged returned // result is pushed on the stack of all the claims to verify. diff --git a/prover/go.mod b/prover/go.mod index 65b10c575..d955410d0 100644 --- a/prover/go.mod +++ b/prover/go.mod @@ -5,10 +5,10 @@ go 1.22.7 toolchain go1.23.0 require ( - github.com/consensys/bavard v0.1.22 + github.com/consensys/bavard v0.1.24 github.com/consensys/compress v0.2.5 - github.com/consensys/gnark v0.11.1-0.20240910135928-e8cb61d0be1d - github.com/consensys/gnark-crypto v0.14.1-0.20241007145620-e26bbdf97a4a + github.com/consensys/gnark v0.11.1-0.20241217141116-f3d91999250b + github.com/consensys/gnark-crypto v0.14.1-0.20241217134352-810063550bd4 github.com/consensys/go-corset v0.0.0-20241125005324-5cb0c289c021 github.com/crate-crypto/go-kzg-4844 v1.1.0 github.com/dlclark/regexp2 v1.11.2 @@ -24,9 +24,9 @@ require ( github.com/spf13/cobra v1.8.1 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 - golang.org/x/crypto v0.26.0 + golang.org/x/crypto v0.31.0 golang.org/x/net v0.27.0 - golang.org/x/sync v0.8.0 + golang.org/x/sync v0.10.0 golang.org/x/time v0.5.0 ) @@ -63,8 +63,7 @@ require ( github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/uint256 v1.3.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/ingonyama-zk/icicle v1.1.0 // indirect - github.com/ingonyama-zk/iciclegnark v0.1.0 // indirect + github.com/ingonyama-zk/icicle/v3 v3.1.1-0.20241118092657-fccdb2f0921b // indirect github.com/klauspost/compress v1.17.7 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect @@ -98,7 +97,7 @@ require ( github.com/x448/float16 v0.8.4 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/text v0.21.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/ini.v1 v1.67.0 // indirect rsc.io/tmplfunc v0.0.3 // indirect @@ -111,6 +110,6 @@ require ( github.com/pkg/profile v1.7.0 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 - golang.org/x/sys v0.25.0 // indirect + golang.org/x/sys v0.28.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/prover/go.sum b/prover/go.sum index d7d3ca9b4..29ee7f512 100644 --- a/prover/go.sum +++ b/prover/go.sum @@ -92,14 +92,14 @@ github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwP github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= -github.com/consensys/bavard v0.1.22 h1:Uw2CGvbXSZWhqK59X0VG/zOjpTFuOMcPLStrp1ihI0A= -github.com/consensys/bavard v0.1.22/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs= +github.com/consensys/bavard v0.1.24 h1:Lfe+bjYbpaoT7K5JTFoMi5wo9V4REGLvQQbHmatoN2I= +github.com/consensys/bavard v0.1.24/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs= github.com/consensys/compress v0.2.5 h1:gJr1hKzbOD36JFsF1AN8lfXz1yevnJi1YolffY19Ntk= github.com/consensys/compress v0.2.5/go.mod h1:pyM+ZXiNUh7/0+AUjUf9RKUM6vSH7T/fsn5LLS0j1Tk= -github.com/consensys/gnark v0.11.1-0.20240910135928-e8cb61d0be1d h1:TmNupI1+K5/LOg1K0kqEhRf5sZwRtxXah5iTHQ6fJvw= -github.com/consensys/gnark v0.11.1-0.20240910135928-e8cb61d0be1d/go.mod h1:f9CH911SPCrbSZp5z9LYzJ3rZvI7mOUzzf48lCZO/5o= -github.com/consensys/gnark-crypto v0.14.1-0.20241007145620-e26bbdf97a4a h1:yUHuYq+v1C3maTwnntLYhTDmboq3scSo1PQIl375/sE= -github.com/consensys/gnark-crypto v0.14.1-0.20241007145620-e26bbdf97a4a/go.mod h1:F/hJyWBcTr1sWeifAKfEN3aVb3G4U5zheEC8IbWQun4= +github.com/consensys/gnark v0.11.1-0.20241217141116-f3d91999250b h1:isTN/YOs57bOt0JlJHJ8gF8C3CdETU2Z9ao4y8R6qms= +github.com/consensys/gnark v0.11.1-0.20241217141116-f3d91999250b/go.mod h1:8YNyW/+XsYiLRzROLaj/PSktYO4VAdv6YW1b1P3UsZk= +github.com/consensys/gnark-crypto v0.14.1-0.20241217134352-810063550bd4 h1:Kp6egjRqKZf4469dfAWqFe6gi3MRs4VvNHmTfEjUlS8= +github.com/consensys/gnark-crypto v0.14.1-0.20241217134352-810063550bd4/go.mod h1:GMPeN3dUSslNBYJsK3WTjIGd3l0ccfMbcEh/d5knFrc= github.com/consensys/go-corset v0.0.0-20241125005324-5cb0c289c021 h1:zAPMHjY72pXmjuyb/niQ816pd+B9RAmZoL/W/f5uJSU= github.com/consensys/go-corset v0.0.0-20241125005324-5cb0c289c021/go.mod h1:J64guTfpmfXl4Yk2D7lsWdYg0ilP+N8JWPudP7+sZpA= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -290,10 +290,8 @@ github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBD github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/ingonyama-zk/icicle v1.1.0 h1:a2MUIaF+1i4JY2Lnb961ZMvaC8GFs9GqZgSnd9e95C8= -github.com/ingonyama-zk/icicle v1.1.0/go.mod h1:kAK8/EoN7fUEmakzgZIYdWy1a2rBnpCaZLqSHwZWxEk= -github.com/ingonyama-zk/iciclegnark v0.1.0 h1:88MkEghzjQBMjrYRJFxZ9oR9CTIpB8NG2zLeCJSvXKQ= -github.com/ingonyama-zk/iciclegnark v0.1.0/go.mod h1:wz6+IpyHKs6UhMMoQpNqz1VY+ddfKqC/gRwR/64W6WU= +github.com/ingonyama-zk/icicle/v3 v3.1.1-0.20241118092657-fccdb2f0921b h1:AvQTK7l0PTHODD06PVQX1Tn2o29sRIaKIDOvTJmKurY= +github.com/ingonyama-zk/icicle/v3 v3.1.1-0.20241118092657-fccdb2f0921b/go.mod h1:e0JHb27/P6WorCJS3YolbY5XffS4PGBuoW38OthLkDs= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -504,8 +502,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -615,8 +613,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -678,8 +676,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -694,8 +692,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/prover/protocol/column/store.go b/prover/protocol/column/store.go index cef1772e0..7e669f86f 100644 --- a/prover/protocol/column/store.go +++ b/prover/protocol/column/store.go @@ -44,6 +44,11 @@ type storedColumnInfo struct { ID ifaces.ColID // Status of the commitment Status Status + // IncludeInProverFS states the prover should include the column in his FS + // transcript. This is used for columns that are recursed using + // FullRecursion. This field is only meaningfull for [Ignored] columns as + // they are excluded by default. + IncludeInProverFS bool } // AddToRound constructs a [Natural], registers it in the [Store] and returns @@ -444,3 +449,39 @@ func assertCorrectStatusTransition(old, new Status) { utils.Panic("attempted the transition %v -> %v, which is forbidden", old.String(), new.String()) } } + +// IgnoreButKeepInProverTranscript marks a column as ignored but also asks that +// the column stays included in the FS transcript. This is used as part of +// full-recursion where the commitments to an inner-proofs should not be sent to +// the verifier but should still play a part in the FS transcript. +func (s *Store) IgnoreButKeepInProverTranscript(colName ifaces.ColID) { + in := s.info(colName) + in.Status = Ignored + in.IncludeInProverFS = true +} + +// IsIgnoredAndNotKeptInTranscript indicates whether the column can be ignored +// from the transcript and is used during the Fiat-Shamir randomness generation. +func (s *Store) IsIgnoredAndNotKeptInTranscript(colName ifaces.ColID) bool { + in := s.info(colName) + return in.Status == Ignored && !in.IncludeInProverFS +} + +// AllKeysProofsOrIgnoredButKeptInProverTranscript returns the list of the +// columns to be used as part of the FS transcript. +func (s *Store) AllKeysProofsOrIgnoredButKeptInProverTranscript(round int) []ifaces.ColID { + res := []ifaces.ColID{} + rnd := s.byRounds.MustGet(round) // precomputed are always at round zero + + for i, info := range rnd { + + ok := (info.Status == Proof) || (info.Status == Ignored && info.IncludeInProverFS) + if !ok { + continue + } + + res = append(res, rnd[i].ID) + } + + return res +} diff --git a/prover/protocol/compiler/dummy/dummy_prover_level.go b/prover/protocol/compiler/dummy/dummy_prover_level.go index 9054b203d..14ff60ba3 100644 --- a/prover/protocol/compiler/dummy/dummy_prover_level.go +++ b/prover/protocol/compiler/dummy/dummy_prover_level.go @@ -22,8 +22,6 @@ import ( // suitable for established unit-tests where we want to analyze the errors. func CompileAtProverLvl(comp *wizard.CompiledIOP) { - comp.DummyCompiled = true - /* Registers all declared commitments and query parameters as messages in the same round. This steps is only relevant diff --git a/prover/protocol/compiler/fullrecursion/actions.go b/prover/protocol/compiler/fullrecursion/actions.go new file mode 100644 index 000000000..44927aa99 --- /dev/null +++ b/prover/protocol/compiler/fullrecursion/actions.go @@ -0,0 +1,207 @@ +package fullrecursion + +import ( + "fmt" + + "github.com/consensys/gnark/frontend" + "github.com/consensys/linea-monorepo/prover/maths/field" + "github.com/consensys/linea-monorepo/prover/protocol/wizard" +) + +// CircuitAssignment is an implementation of [wizard.ProverAction]. As such, it +// embodies the action of assigning the full-recursion Plonk circuit columns. +type CircuitAssignment fullRecursionCtx + +// ConsistencyCheck is an implementation of [wizard.VerifierAction]. As such it +// is responsible for checking that the public inputs of the full-recursion +// Plonk circuit are assigned to values that are consistent with (1) the public +// inputs of the wrapping wizard protocol and with the inputs of the +// self-recursion wizard. +type ConsistencyCheck struct { + fullRecursionCtx + isSkipped bool +} + +// ReplacementAssignment is a [wizard.ProverAction] implementation. It assigns +// the queries and columns that are "replaced" in the wizard. In essence, this +// concerns the main grail polynomial evaluation (the grail query) and the +// Merkle roots assignment. These have to be replaced so that they can be +// refered to by the self-recursion. Otherwise, they would be swallowed by the +// recursion Plonk circuit. +type ReplacementAssignment fullRecursionCtx + +// LocalOpeningAssignment assigns the local openings made over the Plonk PI. +// These are needed in order to (1) perform the consistency check (2) replace +// the "old" and recursed public inputs of the original wizard by new ones. +type LocalOpeningAssignment fullRecursionCtx + +// ResetFsActions is a [wizard.FsHook] responsible for tweaking the FS state as +// required by the self-recursion process. +type ResetFsActions struct { + fullRecursionCtx + isSkipped bool +} + +func (c CircuitAssignment) Run(run *wizard.ProverRuntime) { + c.PlonkInWizard.ProverAction.Run(run, WitnessAssigner(c)) +} + +func (c ReplacementAssignment) Run(run *wizard.ProverRuntime) { + params := run.GetUnivariateParams(c.PolyQuery.QueryID) + run.AssignUnivariate(c.PolyQueryReplacement.QueryID, params.X, params.Ys...) + + oldRoots := c.PcsCtx.Items.MerkleRoots + for i := range c.MerkleRootsReplacement { + + if c.PcsCtx.Items.MerkleRoots[i] == nil { + continue + } + + run.AssignColumn( + c.MerkleRootsReplacement[i].GetColID(), + oldRoots[i].GetColAssignment(run), + ) + } +} + +func (c LocalOpeningAssignment) Run(run *wizard.ProverRuntime) { + for i := range c.LocalOpenings { + run.AssignLocalPoint( + c.LocalOpenings[i].ID, + c.PlonkInWizard.PI.GetColAssignmentAt(run, i), + ) + } +} + +func (c *ConsistencyCheck) Run(run *wizard.VerifierRuntime) error { + + var ( + initialFsCirc = run.GetLocalPointEvalParams(c.LocalOpenings[0].ID).Y + initialFsRt = run.FiatShamirHistory[c.FirstRound+1][0][0] + piCursor = 2 + ) + + if initialFsCirc != initialFsRt { + return fmt.Errorf("full recursion: the initial FS do not match") + } + + for i := range c.NonEmptyMerkleRootPositions { + + var ( + pos = c.NonEmptyMerkleRootPositions[i] + fromRt = c.MerkleRootsReplacement[pos].GetColAssignmentAt(run, 0) + fromCirc = run.GetLocalPointEvalParams(c.LocalOpenings[piCursor+i].ID).Y + ) + + if fromRt != fromCirc { + return fmt.Errorf("full recursion: the commitment does not match (pos: %v)", i) + } + } + + piCursor += len(c.NonEmptyMerkleRootPositions) + + var ( + paramsRt = run.GetUnivariateParams(c.PolyQueryReplacement.QueryID) + xRt = paramsRt.X + xCirc = run.GetLocalPointEvalParams(c.LocalOpenings[piCursor].ID).Y + ) + + if xRt != xCirc { + return fmt.Errorf("full recursion: the Ys does not match") + } + + piCursor++ + + for i := range paramsRt.Ys { + + var ( + fromRt = paramsRt.Ys[i] + fromCirc = run.GetLocalPointEvalParams(c.LocalOpenings[piCursor+i].ID).Y + ) + + if fromRt != fromCirc { + return fmt.Errorf("full recursion: the Ys does not match (pos: %v)", i) + } + } + + // The public inputs do not need to be checked because they are redefined in + // term of the local openings directly. So checking it would amount to checking + // that the local openings are equal to themselves. + + return nil +} + +func (c *ConsistencyCheck) RunGnark(api frontend.API, run *wizard.WizardVerifierCircuit) { + + var ( + initialFsCirc = run.GetLocalPointEvalParams(c.LocalOpenings[0].ID).Y + initialFsRt = run.FiatShamirHistory[c.FirstRound+1][0][0] + piCursor = 2 + ) + + api.AssertIsEqual(initialFsCirc, initialFsRt) + + for i := range c.NonEmptyMerkleRootPositions { + + var ( + pos = c.NonEmptyMerkleRootPositions[i] + fromRt = c.MerkleRootsReplacement[pos].GetColAssignmentGnarkAt(run, 0) + fromCirc = run.GetLocalPointEvalParams(c.LocalOpenings[piCursor+i].ID).Y + ) + + api.AssertIsEqual(fromRt, fromCirc) + } + + piCursor += len(c.NonEmptyMerkleRootPositions) + + var ( + paramsRt = run.GetUnivariateParams(c.PolyQueryReplacement.QueryID) + xRt = paramsRt.X + xCirc = run.GetLocalPointEvalParams(c.LocalOpenings[piCursor].ID).Y + ) + + api.AssertIsEqual(xRt, xCirc) + + piCursor++ + + for i := range paramsRt.Ys { + + var ( + fromRt = paramsRt.Ys[i] + fromCirc = run.GetLocalPointEvalParams(c.LocalOpenings[piCursor+i].ID).Y + ) + + api.AssertIsEqual(fromRt, fromCirc) + } + + // The public inputs do not need to be checked because they are redefined in + // term of the local openings directly. So checking it would amount to checking + // that the local openings are equal to themselves. +} + +func (c *ConsistencyCheck) Skip() { + c.isSkipped = true +} + +func (c *ConsistencyCheck) IsSkipped() bool { + return c.isSkipped +} + +func (r *ResetFsActions) Run(run *wizard.VerifierRuntime) error { + finalFsCirc := run.GetLocalPointEvalParams(r.LocalOpenings[1].ID).Y + run.FS.SetState([]field.Element{finalFsCirc}) + return nil +} + +func (r *ResetFsActions) RunGnark(api frontend.API, run *wizard.WizardVerifierCircuit) { + finalFsCirc := run.GetLocalPointEvalParams(r.LocalOpenings[1].ID).Y + run.FS.SetState([]frontend.Variable{finalFsCirc}) +} + +func (r *ResetFsActions) Skip() { + r.isSkipped = true +} + +func (r *ResetFsActions) IsSkipped() bool { + return r.isSkipped +} diff --git a/prover/protocol/compiler/fullrecursion/circuit.go b/prover/protocol/compiler/fullrecursion/circuit.go new file mode 100644 index 000000000..2151dfa7f --- /dev/null +++ b/prover/protocol/compiler/fullrecursion/circuit.go @@ -0,0 +1,255 @@ +package fullrecursion + +import ( + "fmt" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/frontend" + "github.com/consensys/linea-monorepo/prover/crypto/fiatshamir" + "github.com/consensys/linea-monorepo/prover/crypto/mimc/gkrmimc" + "github.com/consensys/linea-monorepo/prover/protocol/coin" + "github.com/consensys/linea-monorepo/prover/protocol/query" + "github.com/consensys/linea-monorepo/prover/protocol/wizard" +) + +type gnarkCircuit struct { + InitialFsState frontend.Variable `gnark:",public"` + FinalFsState frontend.Variable `gnark:",public"` + Commitments []frontend.Variable `gnark:",public"` + X frontend.Variable `gnark:",public"` + Ys []frontend.Variable `gnark:",public"` + Pubs []frontend.Variable `gnark:",public"` + WizardVerifier *wizard.WizardVerifierCircuit + comp *wizard.CompiledIOP `gnark:"-"` + ctx *fullRecursionCtx `gnark:"-"` + withoutGkr bool `gnark:"-"` +} + +func allocateGnarkCircuit(comp *wizard.CompiledIOP, ctx *fullRecursionCtx) *gnarkCircuit { + + var ( + wizardVerifier = wizard.NewWizardVerifierCircuit() + ) + + for round := range ctx.Columns { + for _, col := range ctx.Columns[round] { + wizardVerifier.AllocColumn(col.GetColID(), col.Size()) + } + } + + for round := range ctx.QueryParams { + for _, qInfoIface := range ctx.QueryParams[round] { + switch qInfo := qInfoIface.(type) { + case query.UnivariateEval: + wizardVerifier.AllocUnivariateEval(qInfo.QueryID, qInfo) + case query.InnerProduct: + wizardVerifier.AllocInnerProduct(qInfo.ID, qInfo) + case query.LocalOpening: + wizardVerifier.AllocLocalOpening(qInfo.ID, qInfo) + } + } + } + + wizardVerifier.Spec = comp + + return &gnarkCircuit{ + ctx: ctx, + comp: comp, + WizardVerifier: wizardVerifier, + Commitments: make([]frontend.Variable, len(ctx.NonEmptyMerkleRootPositions)), + Ys: make([]frontend.Variable, len(ctx.PolyQuery.Pols)), + Pubs: make([]frontend.Variable, len(comp.PublicInputs)), + } + +} + +func (c *gnarkCircuit) Define(api frontend.API) error { + + w := c.WizardVerifier + + if c.withoutGkr { + w.FS = fiatshamir.NewGnarkFiatShamir(api, nil) + } else { + w.HasherFactory = gkrmimc.NewHasherFactory(api) + w.FS = fiatshamir.NewGnarkFiatShamir(api, w.HasherFactory) + } + + w.FiatShamirHistory = make([][2][]frontend.Variable, c.comp.NumRounds()) + + c.generateAllRandomCoins(api) + + for round := 0; round <= c.ctx.LastRound; round++ { + roundSteps := c.ctx.VerifierActions[round] + for _, step := range roundSteps { + step.RunGnark(api, w) + } + } + + for i := range c.Pubs { + api.AssertIsEqual(c.Pubs[i], c.ctx.PublicInputs[i].Acc.GetFrontendVariable(api, w)) + } + + polyParams := w.GetUnivariateParams(c.ctx.PolyQuery.Name()) + + api.AssertIsEqual(c.X, polyParams.X) + + for i := range polyParams.Ys { + api.AssertIsEqual(c.Ys[i], polyParams.Ys[i]) + } + + for i := range c.Commitments { + pos := c.ctx.NonEmptyMerkleRootPositions[i] + api.AssertIsEqual( + c.Commitments[i], + w.GetColumn(c.ctx.PcsCtx.Items.MerkleRoots[pos].GetColID())[0], + ) + } + + return nil +} + +// generateAllRandomCoins is as [VerifierRuntime.generateAllRandomCoins]. Note +// that the function does create constraints via the hasher factory that is +// inside of `c.FS`. +func (c *gnarkCircuit) generateAllRandomCoins(api frontend.API) { + + var ( + ctx = c.ctx + w = c.WizardVerifier + ) + + w.FS.SetState([]frontend.Variable{c.InitialFsState}) + + for currRound := 0; currRound <= c.ctx.LastRound; currRound++ { + + initialState := w.FS.State() + + if currRound > 0 { + + toUpdateFS := ctx.Columns[currRound-1] + for _, msg := range toUpdateFS { + val := w.GetColumn(msg.GetColID()) + w.FS.UpdateVec(val) + } + + queries := ctx.QueryParams[currRound-1] + for _, q := range queries { + params := w.GetParams(q.Name()) + params.UpdateFS(w.FS) + } + } + + for _, info := range ctx.Coins[currRound] { + switch info.Type { + case coin.Field: + value := w.FS.RandomField() + w.Coins.InsertNew(info.Name, value) + case coin.IntegerVec: + value := w.FS.RandomManyIntegers(info.Size, info.UpperBound) + w.Coins.InsertNew(info.Name, value) + } + } + + for _, fsHook := range ctx.FsHooks[currRound] { + fsHook.RunGnark(api, w) + } + + w.FiatShamirHistory[currRound] = [2][]frontend.Variable{ + initialState, + w.FS.State(), + } + } + + api.AssertIsEqual(w.FS.State()[0], c.FinalFsState) +} + +// AssignGnarkCircuit returns an assignment for the gnark circuit +func AssignGnarkCircuit(ctx *fullRecursionCtx, comp *wizard.CompiledIOP, run *wizard.ProverRuntime) *gnarkCircuit { + + var ( + wizardVerifier = wizard.NewWizardVerifierCircuit() + ) + + for round := range ctx.Columns { + for _, col := range ctx.Columns[round] { + wizardVerifier.AssignColumn(col.GetColID(), col.GetColAssignment(run)) + } + } + + for round := range ctx.QueryParams { + for _, qInfoIface := range ctx.QueryParams[round] { + switch qInfo := qInfoIface.(type) { + case query.UnivariateEval: + params := run.GetUnivariateParams(qInfo.QueryID) + wizardVerifier.AssignUnivariateEval(qInfo.QueryID, params) + case query.InnerProduct: + params := run.GetInnerProductParams(qInfo.ID) + wizardVerifier.AssignInnerProduct(qInfo.ID, params) + case query.LocalOpening: + params := run.GetLocalPointEvalParams(qInfo.ID) + wizardVerifier.AssignLocalOpening(qInfo.ID, params) + } + } + } + + c := &gnarkCircuit{ + ctx: ctx, + comp: comp, + WizardVerifier: wizardVerifier, + Pubs: make([]frontend.Variable, len(comp.PublicInputs)), + Commitments: make([]frontend.Variable, len(ctx.NonEmptyMerkleRootPositions)), + // It is important we start from the begining because of the case where + // we stack several FullRecursion. In that case, the FsHooks are going + // to automatically set the FsState to the correct value at first round. + InitialFsState: run.FiatShamirHistory[1][0][0], + FinalFsState: run.FiatShamirHistory[ctx.LastRound][1][0], + } + + polyParams := run.GetUnivariateParams(ctx.PolyQuery.QueryID).GnarkAssign() + c.X = polyParams.X + c.Ys = polyParams.Ys + + for i := range c.Pubs { + c.Pubs[i] = comp.PublicInputs[i].Acc.GetVal(run) + } + + for i := range c.Commitments { + pos := ctx.NonEmptyMerkleRootPositions[i] + c.Commitments[i] = ctx.PcsCtx.Items.MerkleRoots[pos].GetColAssignmentAt(run, 0) + } + + return c +} + +// WitnessAssign is an implementation of the [plonk.WitnessAssigner] and is used to +// generate the assignment of the fullRecursion circuit. +type WitnessAssigner fullRecursionCtx + +func (w WitnessAssigner) NumEffWitnesses(_ *wizard.ProverRuntime) int { + return 1 +} + +func (w WitnessAssigner) Assign(run *wizard.ProverRuntime, i int) (private, public witness.Witness, err error) { + + if i > 0 { + panic("only a single witness for the full-recursion") + } + + var ( + ctx = fullRecursionCtx(w) + assignment = AssignGnarkCircuit(&ctx, w.Comp, run) + ) + + witness, err := frontend.NewWitness(assignment, ecc.BLS12_377.ScalarField()) + if err != nil { + return nil, nil, fmt.Errorf("new witness: %W", err) + } + + pubWitness, err := witness.Public() + if err != nil { + return nil, nil, fmt.Errorf("public witness: %w", err) + } + + return witness, pubWitness, nil +} diff --git a/prover/protocol/compiler/fullrecursion/full_recursion.go b/prover/protocol/compiler/fullrecursion/full_recursion.go new file mode 100644 index 000000000..9c8017ae8 --- /dev/null +++ b/prover/protocol/compiler/fullrecursion/full_recursion.go @@ -0,0 +1,230 @@ +package fullrecursion + +import ( + "strconv" + + "github.com/consensys/linea-monorepo/prover/protocol/accessors" + "github.com/consensys/linea-monorepo/prover/protocol/coin" + "github.com/consensys/linea-monorepo/prover/protocol/column" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/selfrecursion" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/vortex" + "github.com/consensys/linea-monorepo/prover/protocol/dedicated/plonk" + "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" + "github.com/consensys/linea-monorepo/prover/protocol/wizard" + "github.com/consensys/linea-monorepo/prover/utils" +) + +// FullRecursion "recurses" the wizard protocol by wrapping all the verifier +// steps in a Plonk-in-Wizard context as well as all the Proof columns. The +// Vortex PCS verification is done via self-recursion. +func FullRecursion(withoutGkr bool) func(comp *wizard.CompiledIOP) { + + return func(comp *wizard.CompiledIOP) { + var ( + ctx = captureCtx(comp) + c = allocateGnarkCircuit(comp, ctx) + numPI = len(c.ctx.NonEmptyMerkleRootPositions) + + len(c.Pubs) + + len(c.Ys) + + 3 // (1.) for X (2.) for the initial FS state (3.) for the final state + funcPiOffset = 3 + len(ctx.NonEmptyMerkleRootPositions) + len(ctx.PolyQuery.Pols) + ) + + selfrecursion.SelfRecurse(comp) + + piw := plonk.PlonkCheck(comp, "full-recursion-"+strconv.Itoa(comp.SelfRecursionCount), ctx.LastRound, c, 1) + + ctx.PlonkInWizard.PI = piw.ConcatenatedTinyPIs(utils.NextPowerOfTwo(numPI)) + ctx.PlonkInWizard.ProverAction = piw.GetPlonkProverAction() + + for i := 0; i < numPI; i++ { + + var ( + pi = ctx.PlonkInWizard.PI + lo = comp.InsertLocalOpening( + ctx.PlonkInWizard.PI.Round(), + ifaces.QueryIDf("%v_LO_%v", pi.String(), i), + column.Shift(pi, i), + ) + ) + + ctx.LocalOpenings = append(ctx.LocalOpenings, lo) + } + + for i := range comp.PublicInputs { + comp.PublicInputs[i].Acc = accessors.NewLocalOpeningAccessor( + ctx.LocalOpenings[funcPiOffset+i], + ctx.PlonkInWizard.PI.Round(), + ) + } + + comp.FiatShamirHooks.AppendToInner(ctx.LastRound, &ResetFsActions{fullRecursionCtx: *ctx}) + comp.RegisterProverAction(ctx.LastRound, CircuitAssignment(*ctx)) + comp.RegisterProverAction(ctx.LastRound, ReplacementAssignment(*ctx)) + comp.RegisterProverAction(ctx.PlonkInWizard.PI.Round(), LocalOpeningAssignment(*ctx)) + comp.RegisterVerifierAction(ctx.PlonkInWizard.PI.Round(), &ConsistencyCheck{fullRecursionCtx: *ctx}) + } +} + +// fullRecursionCtx holds compilation context informations about the wizard +// protocol being compiled by a FullRecursion routine. +type fullRecursionCtx struct { + // A pointer to the compiled-IOP over which the compilation step has run + Comp *wizard.CompiledIOP + // The Vortex compilation context + PcsCtx *vortex.Ctx + PublicInputs []wizard.PublicInput + PolyQuery query.UnivariateEval + PolyQueryReplacement query.UnivariateEval + MerkleRootsReplacement []ifaces.Column + NonEmptyMerkleRootPositions []int + FirstRound, LastRound int + QueryParams [][]ifaces.Query + Columns [][]ifaces.Column + VerifierActions [][]wizard.VerifierAction + Coins [][]coin.Info + FsHooks [][]wizard.VerifierAction + PlonkInWizard struct { + ProverAction plonk.PlonkInWizardProverAction + PI ifaces.Column + } + LocalOpenings []query.LocalOpening +} + +// captureCtx scans the content of comp to store the compilation infos of the +// CompiledIOP at the beginning of the compilation. +func captureCtx(comp *wizard.CompiledIOP) *fullRecursionCtx { + + var ( + polyQuery = comp.PcsCtxs.(*vortex.Ctx).Query + lastRound = comp.QueriesParams.Round(polyQuery.QueryID) + ctx = &fullRecursionCtx{ + Comp: comp, + PcsCtx: comp.PcsCtxs.(*vortex.Ctx), + PolyQuery: polyQuery, + LastRound: lastRound, + FirstRound: lastRound, + PublicInputs: append([]wizard.PublicInput{}, comp.PublicInputs...), + } + ) + + for round := 0; round <= lastRound; round++ { + + ctx.QueryParams = append(ctx.QueryParams, []ifaces.Query{}) + ctx.Columns = append(ctx.Columns, []ifaces.Column{}) + ctx.VerifierActions = append(ctx.VerifierActions, []wizard.VerifierAction{}) + ctx.Coins = append(ctx.Coins, []coin.Info{}) + ctx.FsHooks = append(ctx.FsHooks, []wizard.VerifierAction{}) + + for _, colName := range comp.Columns.AllKeysAt(round) { + + // filter the columns by status + var ( + status = comp.Columns.Status(colName) + col = comp.Columns.GetHandle(colName) + ) + + if !status.IsPublic() { + // the column is not public so it is not part of the proof + continue + } + + if status == column.VerifyingKey { + // these are constant columns + continue + } + + ctx.FirstRound = min(ctx.FirstRound, round) + ctx.Columns[round] = append(ctx.Columns[round], col) + comp.Columns.IgnoreButKeepInProverTranscript(colName) + } + + for _, qName := range comp.QueriesParams.AllKeysAt(round) { + + if comp.QueriesParams.IsSkippedFromVerifierTranscript(qName) { + continue + } + + // Not that we do not filter the already compiled queries + qInfo := comp.QueriesParams.Data(qName) + ctx.QueryParams[round] = append(ctx.QueryParams[round], qInfo) + comp.QueriesParams.MarkAsSkippedFromVerifierTranscript(qName) + } + + for _, cname := range comp.Coins.AllKeysAt(round) { + + if comp.Coins.IsSkippedFromVerifierTranscript(cname) { + continue + } + + coin := comp.Coins.Data(cname) + ctx.Coins[round] = append(ctx.Coins[round], coin) + comp.Coins.MarkAsSkippedFromVerifierTranscript(cname) + } + + verifierActions := comp.SubVerifiers.Inner() + + for i := range verifierActions[round] { + + va := verifierActions[round][i] + if va.IsSkipped() { + continue + } + + ctx.VerifierActions[round] = append(ctx.VerifierActions[round], va) + va.Skip() + } + + if comp.FiatShamirHooks.Len() > round { + resetFs := comp.FiatShamirHooks.Inner()[round] + for i := range resetFs { + + fsHook := resetFs[i] + if fsHook.IsSkipped() { + continue + } + + ctx.FsHooks[round] = append(ctx.VerifierActions[round], fsHook) + fsHook.Skip() + } + } + } + + comp.QueriesParams.MarkAsSkippedFromProverTranscript(polyQuery.QueryID) + + ctx.PcsCtx.IsSelfrecursed = true + + pcsCtxReplacement := *ctx.PcsCtx + pcsCtxReplacement.Items.MerkleRoots = make([]ifaces.Column, len(pcsCtxReplacement.Items.MerkleRoots)) + + for i := range pcsCtxReplacement.Items.MerkleRoots { + + if ctx.PcsCtx.Items.MerkleRoots[i] == nil { + continue + } + + ctx.NonEmptyMerkleRootPositions = append(ctx.NonEmptyMerkleRootPositions, i) + pcsCtxReplacement.Items.MerkleRoots[i] = comp.InsertProof( + ctx.LastRound, + ctx.PcsCtx.Items.MerkleRoots[i].GetColID()+"_REPLACEMENT", + 1, + ) + } + + ctx.MerkleRootsReplacement = pcsCtxReplacement.Items.MerkleRoots + + comp.PcsCtxs = &pcsCtxReplacement + newPolyQuery := comp.InsertUnivariate( + lastRound, + polyQuery.QueryID+"_REPLACEMENT", + polyQuery.Pols, + ) + + comp.QueriesParams.MarkAsIgnored(newPolyQuery.QueryID) + + ctx.PolyQueryReplacement = newPolyQuery + pcsCtxReplacement.Query = ctx.PolyQueryReplacement + + return ctx +} diff --git a/prover/protocol/compiler/fullrecursion/full_recursion_test.go b/prover/protocol/compiler/fullrecursion/full_recursion_test.go new file mode 100644 index 000000000..5fd62cd43 --- /dev/null +++ b/prover/protocol/compiler/fullrecursion/full_recursion_test.go @@ -0,0 +1,105 @@ +//go:build !fuzzlight + +package fullrecursion_test + +import ( + "fmt" + "testing" + + "github.com/consensys/linea-monorepo/prover/crypto/ringsis" + "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/dummy" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/fullrecursion" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/globalcs" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/innerproduct" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/localcs" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/lookup" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/mimc" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/permutation" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/specialqueries" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/splitter" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/splitter/sticker" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/univariates" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/vortex" + "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/wizard" + "github.com/sirupsen/logrus" +) + +func TestLookup(t *testing.T) { + + logrus.SetLevel(logrus.FatalLevel) + + define := func(bui *wizard.Builder) { + + var ( + a = bui.RegisterCommit("A", 8) + b = bui.RegisterCommit("B", 8) + ) + + bui.Inclusion("Q", []ifaces.Column{a}, []ifaces.Column{b}) + } + + prove := func(run *wizard.ProverRuntime) { + run.AssignColumn("A", smartvectors.ForTest(1, 2, 3, 4, 5, 6, 7, 8)) + run.AssignColumn("B", smartvectors.ForTest(1, 2, 3, 4, 5, 6, 7, 8)) + } + + suites := [][]func(*wizard.CompiledIOP){ + { + lookup.CompileLogDerivative, + localcs.Compile, + globalcs.Compile, + univariates.CompileLocalOpening, + univariates.Naturalize, + univariates.MultiPointToSinglePoint(8), + vortex.Compile(2, vortex.ForceNumOpenedColumns(4), vortex.WithSISParams(&ringsis.StdParams)), + fullrecursion.FullRecursion(true), + dummy.CompileAtProverLvl, + }, + { + lookup.CompileLogDerivative, + localcs.Compile, + globalcs.Compile, + univariates.CompileLocalOpening, + univariates.Naturalize, + univariates.MultiPointToSinglePoint(8), + vortex.Compile(2, vortex.ForceNumOpenedColumns(4), vortex.WithSISParams(&ringsis.StdParams)), + fullrecursion.FullRecursion(true), + mimc.CompileMiMC, + specialqueries.RangeProof, + lookup.CompileLogDerivative, + specialqueries.CompileFixedPermutations, + permutation.CompileGrandProduct, + innerproduct.Compile, + sticker.Sticker(1<<8, 1<<16), + splitter.SplitColumns(1 << 16), + localcs.Compile, + globalcs.Compile, + univariates.CompileLocalOpening, + univariates.Naturalize, + univariates.MultiPointToSinglePoint(1 << 16), + vortex.Compile(2, vortex.ForceNumOpenedColumns(4), vortex.WithSISParams(&ringsis.StdParams)), + fullrecursion.FullRecursion(true), + dummy.CompileAtProverLvl, + }, + } + + for i, s := range suites { + + t.Run(fmt.Sprintf("case-%v", i), func(t *testing.T) { + + comp := wizard.Compile( + define, + s..., + ) + + proof := wizard.Prove(comp, prove) + + if err := wizard.Verify(comp, proof); err != nil { + t.Fatalf("verifier failed: %v", err) + } + }) + + } +} diff --git a/prover/protocol/compiler/globalcs/compile.go b/prover/protocol/compiler/globalcs/compile.go index 11dc45494..bf7f6b436 100644 --- a/prover/protocol/compiler/globalcs/compile.go +++ b/prover/protocol/compiler/globalcs/compile.go @@ -41,7 +41,7 @@ func Compile(comp *wizard.CompiledIOP) { comp.RegisterProverAction(quotientRound, "ientCtx) comp.RegisterProverAction(evaluationRound, evaluationProver(evaluationCtx)) - comp.RegisterVerifierAction(evaluationRound, evaluationVerifier(evaluationCtx)) + comp.RegisterVerifierAction(evaluationRound, &evaluationVerifier{evaluationCtx: evaluationCtx}) } diff --git a/prover/protocol/compiler/globalcs/evaluation.go b/prover/protocol/compiler/globalcs/evaluation.go index 4a9a03eeb..b612b78ec 100644 --- a/prover/protocol/compiler/globalcs/evaluation.go +++ b/prover/protocol/compiler/globalcs/evaluation.go @@ -37,7 +37,10 @@ type evaluationProver evaluationCtx // evaluationVerifier wraps [evaluationCtx] to implement the [wizard.VerifierAction] // interface. -type evaluationVerifier evaluationCtx +type evaluationVerifier struct { + evaluationCtx + skipped bool +} // declareUnivariateQueries declares the univariate queries over all the quotient // shares, making sure that the shares needing to be evaluated over the same @@ -162,7 +165,7 @@ func (pa evaluationProver) Run(run *wizard.ProverRuntime) { } // Run evaluate the constraint and checks that -func (ctx evaluationVerifier) Run(run *wizard.VerifierRuntime) error { +func (ctx *evaluationVerifier) Run(run *wizard.VerifierRuntime) error { var ( // Will be assigned to "X", the random point at which we check the constraint. @@ -236,7 +239,7 @@ func (ctx evaluationVerifier) Run(run *wizard.VerifierRuntime) error { } // Verifier step, evaluate the constraint and checks that -func (ctx evaluationVerifier) RunGnark(api frontend.API, c *wizard.WizardVerifierCircuit) { +func (ctx *evaluationVerifier) RunGnark(api frontend.API, c *wizard.WizardVerifierCircuit) { // Will be assigned to "X", the random point at which we check the constraint. r := c.GetRandomCoinField(ctx.EvalCoin.Name) @@ -463,3 +466,11 @@ func (ctx evaluationVerifier) recombineQuotientSharesEvaluationGnark(api fronten return recombinedYs } + +func (ctx *evaluationVerifier) Skip() { + ctx.skipped = true +} + +func (ctx *evaluationVerifier) IsSkipped() bool { + return ctx.skipped +} diff --git a/prover/protocol/compiler/innerproduct/verifier.go b/prover/protocol/compiler/innerproduct/verifier.go index ec01a9016..accc5acd0 100644 --- a/prover/protocol/compiler/innerproduct/verifier.go +++ b/prover/protocol/compiler/innerproduct/verifier.go @@ -20,6 +20,7 @@ type verifierForSize struct { SummationOpening query.LocalOpening // BatchOpening is the challenge used for the linear combination BatchOpening coin.Info + skipped bool } // Run implements [wizard.VerifierAction] @@ -87,3 +88,11 @@ func (v *verifierForSize) RunGnark(api frontend.API, run *wizard.WizardVerifierC api.AssertIsEqual(expected, actual) } + +func (v *verifierForSize) Skip() { + v.skipped = true +} + +func (v *verifierForSize) IsSkipped() bool { + return v.skipped +} diff --git a/prover/protocol/compiler/lookup/compiler.go b/prover/protocol/compiler/lookup/compiler.go index 6b4f8fea6..8bef9261e 100644 --- a/prover/protocol/compiler/lookup/compiler.go +++ b/prover/protocol/compiler/lookup/compiler.go @@ -36,7 +36,7 @@ func CompileLogDerivative(comp *wizard.CompiledIOP) { zCatalog = map[[2]int]*zCtx{} zEntries = [][2]int{} // verifier actions - va = finalEvaluationCheck{} + va = &finalEvaluationCheck{} ) // Skip the compilation phase if no lookup constraint is being used. Otherwise @@ -116,7 +116,7 @@ func CompileLogDerivative(comp *wizard.CompiledIOP) { } } - comp.RegisterVerifierAction(lastRound, &va) + comp.RegisterVerifierAction(lastRound, va) } // captureLookupTables inspects comp and look for Inclusion queries that are not diff --git a/prover/protocol/compiler/lookup/verifier.go b/prover/protocol/compiler/lookup/verifier.go index b5179574b..be3219d08 100644 --- a/prover/protocol/compiler/lookup/verifier.go +++ b/prover/protocol/compiler/lookup/verifier.go @@ -21,6 +21,7 @@ type finalEvaluationCheck struct { Name string // ZOpenings lists all the openings of all the zCtx ZOpenings []query.LocalOpening + skipped bool } // Run implements the [wizard.VerifierAction] @@ -54,3 +55,11 @@ func (f *finalEvaluationCheck) RunGnark(api frontend.API, run *wizard.WizardVeri api.AssertIsEqual(zSum, 0) } + +func (f *finalEvaluationCheck) Skip() { + f.skipped = true +} + +func (f *finalEvaluationCheck) IsSkipped() bool { + return f.skipped +} diff --git a/prover/protocol/compiler/permutation/compiler.go b/prover/protocol/compiler/permutation/compiler.go index 1c8320dba..7460ce9ea 100644 --- a/prover/protocol/compiler/permutation/compiler.go +++ b/prover/protocol/compiler/permutation/compiler.go @@ -49,7 +49,7 @@ func CompileGrandProduct(comp *wizard.CompiledIOP) { for round := range allProverActions { if len(allProverActions[round]) > 0 { comp.RegisterProverAction(round, allProverActions[round]) - comp.RegisterVerifierAction(round, VerifierCtx(allProverActions[round])) + comp.RegisterVerifierAction(round, &VerifierCtx{Ctxs: allProverActions[round]}) } } diff --git a/prover/protocol/compiler/permutation/verifier.go b/prover/protocol/compiler/permutation/verifier.go index 1fde7e51c..99924d329 100644 --- a/prover/protocol/compiler/permutation/verifier.go +++ b/prover/protocol/compiler/permutation/verifier.go @@ -11,15 +11,18 @@ import ( // The verifier gets all the query openings and multiple them together and // expect them to be one. It is represented by an array of ZCtx holding for // the same round. (we have the guarantee that they come from the same query). -type VerifierCtx []*ZCtx +type VerifierCtx struct { + Ctxs []*ZCtx + skipped bool +} // Run implements the [wizard.VerifierAction] interface and checks that the // product of the products given by the ZCtx is equal to one. -func (v VerifierCtx) Run(run *wizard.VerifierRuntime) error { +func (v *VerifierCtx) Run(run *wizard.VerifierRuntime) error { mustBeOne := field.One() - for _, zCtx := range v { + for _, zCtx := range v.Ctxs { for _, opening := range zCtx.ZOpenings { y := run.GetLocalPointEvalParams(opening.ID).Y mustBeOne.Mul(&mustBeOne, &y) @@ -35,11 +38,11 @@ func (v VerifierCtx) Run(run *wizard.VerifierRuntime) error { // Run implements the [wizard.VerifierAction] interface and is as // [VerifierCtx.Run] but in the context of a gnark circuit. -func (v VerifierCtx) RunGnark(api frontend.API, run *wizard.WizardVerifierCircuit) { +func (v *VerifierCtx) RunGnark(api frontend.API, run *wizard.WizardVerifierCircuit) { mustBeOne := frontend.Variable(1) - for _, zCtx := range v { + for _, zCtx := range v.Ctxs { for _, opening := range zCtx.ZOpenings { y := run.GetLocalPointEvalParams(opening.ID).Y mustBeOne = api.Mul(mustBeOne, y) @@ -48,3 +51,11 @@ func (v VerifierCtx) RunGnark(api frontend.API, run *wizard.WizardVerifierCircui api.AssertIsEqual(mustBeOne, frontend.Variable(1)) } + +func (v *VerifierCtx) Skip() { + v.skipped = true +} + +func (v *VerifierCtx) IsSkipped() bool { + return v.skipped +} diff --git a/prover/protocol/compiler/selfrecursion/context.go b/prover/protocol/compiler/selfrecursion/context.go index 13156815b..5226926f9 100644 --- a/prover/protocol/compiler/selfrecursion/context.go +++ b/prover/protocol/compiler/selfrecursion/context.go @@ -284,10 +284,10 @@ func NewSelfRecursionCxt(comp *wizard.CompiledIOP) SelfRecursionCtx { func assertVortexCompiled(comp *wizard.CompiledIOP) *vortex.Ctx { // When we compiled using Vortex, we annotated the compiledIOP // that the current protocol was a result of the - ctx := comp.CryptographicCompilerCtx + ctx := comp.PcsCtxs // Take ownership of the vortex context - comp.CryptographicCompilerCtx = nil + comp.PcsCtxs = nil // Check for non-nilness if ctx == nil { diff --git a/prover/protocol/compiler/splitter/sticker/sticker.go b/prover/protocol/compiler/splitter/sticker/sticker.go index 5bb8b21df..6e8b6a924 100644 --- a/prover/protocol/compiler/splitter/sticker/sticker.go +++ b/prover/protocol/compiler/splitter/sticker/sticker.go @@ -405,7 +405,7 @@ func (ctx *stickContext) compileFixedEvaluation() { // Filters out only the q, ok := ctx.comp.QueriesParams.Data(qName).(query.LocalOpening) if !ok { - utils.Panic("got an uncompilable query %v", qName) + utils.Panic("got an uncompilable query name=%v type=%T", qName, q) } // Assumption, the query is not over an interleaved column diff --git a/prover/protocol/compiler/vortex/compiler.go b/prover/protocol/compiler/vortex/compiler.go index 26c3c7868..7aa626bd3 100644 --- a/prover/protocol/compiler/vortex/compiler.go +++ b/prover/protocol/compiler/vortex/compiler.go @@ -61,7 +61,7 @@ func Compile(blowUpFactor int, options ...VortexOp) func(*wizard.CompiledIOP) { lastRound := comp.NumRounds() - 1 // Stores a pointer to the cryptographic compiler of Vortex - comp.CryptographicCompilerCtx = &ctx + comp.PcsCtxs = &ctx // Converts the precomputed as verifying key (e.g. send // them to the verifier) in the offline phase if the @@ -86,6 +86,10 @@ func Compile(blowUpFactor int, options ...VortexOp) func(*wizard.CompiledIOP) { // Registers the prover and verifier steps comp.SubProvers.AppendToInner(lastRound+1, ctx.ComputeLinearComb) comp.SubProvers.AppendToInner(lastRound+2, ctx.OpenSelectedColumns) + // This is separated from GnarkVerify because, when doing full-recursion + // , we want to recurse this verifier step but not [ctx.Verify] which is + // already handled by the self-recursion mechanism. + comp.InsertVerifier(lastRound, ctx.explicitPublicEvaluation, ctx.gnarkExplicitPublicEvaluation) comp.InsertVerifier(lastRound+2, ctx.Verify, ctx.GnarkVerify) } } diff --git a/prover/protocol/compiler/vortex/gnark_verifier.go b/prover/protocol/compiler/vortex/gnark_verifier.go index cf217bcec..430a15604 100644 --- a/prover/protocol/compiler/vortex/gnark_verifier.go +++ b/prover/protocol/compiler/vortex/gnark_verifier.go @@ -15,8 +15,6 @@ import ( ) func (ctx *Ctx) GnarkVerify(api frontend.API, vr *wizard.WizardVerifierCircuit) { - // Evaluate explicitly the public columns - ctx.gnarkExplicitPublicEvaluation(api, vr) // The skip verification flag may be on, if the current vortex // context get self-recursed. In this case, the verifier does @@ -64,7 +62,7 @@ func (ctx *Ctx) GnarkVerify(api frontend.API, vr *wizard.WizardVerifierCircuit) // function that will defer the hashing to gkr factoryHasherFunc := func(_ frontend.API) (hash.FieldHasher, error) { h := vr.HasherFactory.NewHasher() - return &h, nil + return h, nil } packedMProofs := vr.GetColumn(ctx.MerkleProofName()) @@ -93,7 +91,7 @@ func (ctx *Ctx) GnarkVerify(api frontend.API, vr *wizard.WizardVerifierCircuit) } // returns the Ys as a vector -func (ctx *Ctx) gnarkGetYs(api frontend.API, vr *wizard.WizardVerifierCircuit) (ys [][]frontend.Variable) { +func (ctx *Ctx) gnarkGetYs(_ frontend.API, vr *wizard.WizardVerifierCircuit) (ys [][]frontend.Variable) { query := ctx.Query params := vr.GetUnivariateParams(ctx.Query.QueryID) diff --git a/prover/protocol/compiler/vortex/verifier.go b/prover/protocol/compiler/vortex/verifier.go index 50ffc5205..1b27c1779 100644 --- a/prover/protocol/compiler/vortex/verifier.go +++ b/prover/protocol/compiler/vortex/verifier.go @@ -15,11 +15,6 @@ import ( func (ctx *Ctx) Verify(vr *wizard.VerifierRuntime) error { - // Evaluate explicitly the public columns - if err := ctx.explicitPublicEvaluation(vr); err != nil { - return err - } - // The skip verification flag may be on, if the current vortex // context get self-recursed. In this case, the verifier does // not need to do anything diff --git a/prover/protocol/dedicated/plonk/alignment.go b/prover/protocol/dedicated/plonk/alignment.go index 975667373..59ef0deae 100644 --- a/prover/protocol/dedicated/plonk/alignment.go +++ b/prover/protocol/dedicated/plonk/alignment.go @@ -171,6 +171,8 @@ func (ci *CircuitAlignmentInput) Assign(run *wizard.ProverRuntime, i int) (priva return ci.witnesses[i], ci.witnesses[i], nil } +// NumEffWitnesses returns the effective number of Plonk witnesses that are +// collected from the assignment of the AlignmentModule. func (ci *CircuitAlignmentInput) NumEffWitnesses(run *wizard.ProverRuntime) int { ci.prepareWitnesses(run) return ci.numEffWitnesses @@ -258,6 +260,9 @@ func DefineAlignment(comp *wizard.CompiledIOP, toAlign *CircuitAlignmentInput) * return res } +// csIsActive adds the cosntraints ensuring that the [Alignment.IsActive] column +// is well-formed. Namely, that this is a sequence of 1s followed by a sequence +// of 0s. func (a *Alignment) csIsActive(comp *wizard.CompiledIOP) { // IsActive is binary column comp.InsertGlobal(a.Round, ifaces.QueryIDf("%v_IS_ACTIVE_BINARY", a.Name), symbolic.Mul(a.IsActive, symbolic.Sub(a.IsActive, 1))) @@ -265,10 +270,16 @@ func (a *Alignment) csIsActive(comp *wizard.CompiledIOP) { comp.InsertGlobal(a.Round, ifaces.QueryIDf("%v_IS_ACTIVE_SWITCH", a.Name), symbolic.Sub(a.IsActive, symbolic.Mul(a.IsActive, column.Shift(a.IsActive, -1)))) } +// csProjection ensures the data in the [Alignment.Data] column is the same as +// the data provided by the [Alignment.CircuitInput]. func (a *Alignment) csProjection(comp *wizard.CompiledIOP) { projection.InsertProjection(comp, ifaces.QueryIDf("%v_PROJECTION", a.Name), []ifaces.Column{a.DataToCircuit}, []ifaces.Column{a.CircuitInput}, a.DataToCircuitMask, a.ActualCircuitInputMask) } +// csProjectionSelector constraints that the projection selection +// [Alignment.ActualCircuitInputMask] is well-formed. This ensures that the +// imported data are correctly imported "in-front" of the public inputs of the +// Plonk. func (a *Alignment) csProjectionSelector(comp *wizard.CompiledIOP) { // ACTUAL_PI_MASK = IS_ACTIVE * STATIC_PI_MASK comp.InsertGlobal(a.Round, ifaces.QueryIDf("%v_ACTUAL_SUBSET", a.Name), symbolic.Sub(a.ActualCircuitInputMask, symbolic.Mul(a.IsActive, a.FullCircuitInputMask))) @@ -281,6 +292,8 @@ func (a *Alignment) Assign(run *wizard.ProverRuntime) { a.assignCircMaskOpenings(run) } +// assignMasks assigns the [Alignment.IsActive] and the [Alignment.ActualCircuitInputMask] +// into `run`. func (a *Alignment) assignMasks(run *wizard.ProverRuntime) { // we want to assign IS_ACTIVE and ACTUAL_MASK columns. We can construct // them at the same time from the precomputed mask and selector. @@ -320,7 +333,7 @@ func (a *Alignment) assignMasks(run *wizard.ProverRuntime) { run.AssignColumn(a.ActualCircuitInputMask.GetColID(), smartvectors.NewRegular(actualCircMaskAssignment)) } -// assignCircMaskOpenings assigns the openings queries over [actualCircMaskAssignment] +// assignCircMaskOpenings assigns the openings queries over the actualCircMaskAssignment func (a *Alignment) assignCircMaskOpenings(run *wizard.ProverRuntime) { for i := range a.circMaskOpenings { v := a.circMaskOpenings[i].Pol.GetColAssignmentAt(run, 0) @@ -328,7 +341,8 @@ func (a *Alignment) assignCircMaskOpenings(run *wizard.ProverRuntime) { } } -// getCircuitMaskValue returns the +// getCircuitMaskValue returns the static assignment of the precomputed columns +// to be assigned to [Alignment.FullCircuitInputMask]. func getCircuitMaskValue(nbPublicInputPerCircuit, nbCircuitInstance int) smartvectors.SmartVector { var ( @@ -345,7 +359,8 @@ func getCircuitMaskValue(nbPublicInputPerCircuit, nbCircuitInstance int) smartve return smartvectors.NewRegular(maskValue) } -// check the activators are well-set w.r.t to the circuit mask column +// checkActivators adds the constraints checking the activators are well-set w.r.t +// to the circuit mask column. See [compilationCtx.Columns.Activators]. func (ci *Alignment) checkActivators(comp *wizard.CompiledIOP) { var ( @@ -366,12 +381,17 @@ func (ci *Alignment) checkActivators(comp *wizard.CompiledIOP) { ci.circMaskOpenings = openings - comp.RegisterVerifierAction(ci.Round, checkActivatorAndMask(*ci)) + comp.RegisterVerifierAction(ci.Round, &checkActivatorAndMask{Alignment: *ci}) } -type checkActivatorAndMask Alignment +// checkActivatorAndMask is an implementation of [wizard.VerifierAction] and is +// used to embody the verifier checks added by [checkActivators]. +type checkActivatorAndMask struct { + Alignment + skipped bool +} -func (c checkActivatorAndMask) Run(run *wizard.VerifierRuntime) error { +func (c *checkActivatorAndMask) Run(run *wizard.VerifierRuntime) error { for i := range c.circMaskOpenings { var ( localOpening = run.GetLocalPointEvalParams(c.circMaskOpenings[i].ID) @@ -390,7 +410,7 @@ func (c checkActivatorAndMask) Run(run *wizard.VerifierRuntime) error { return nil } -func (c checkActivatorAndMask) RunGnark(api frontend.API, run *wizard.WizardVerifierCircuit) { +func (c *checkActivatorAndMask) RunGnark(api frontend.API, run *wizard.WizardVerifierCircuit) { for i := range c.circMaskOpenings { var ( valOpened = run.GetLocalPointEvalParams(c.circMaskOpenings[i].ID).Y @@ -400,3 +420,11 @@ func (c checkActivatorAndMask) RunGnark(api frontend.API, run *wizard.WizardVeri api.AssertIsEqual(valOpened, valActiv) } } + +func (c *checkActivatorAndMask) Skip() { + c.skipped = true +} + +func (c *checkActivatorAndMask) IsSkipped() bool { + return c.skipped +} diff --git a/prover/protocol/dedicated/plonk/compile.go b/prover/protocol/dedicated/plonk/compile.go index ae0fcccc2..3e9182fbe 100644 --- a/prover/protocol/dedicated/plonk/compile.go +++ b/prover/protocol/dedicated/plonk/compile.go @@ -68,7 +68,7 @@ func PlonkCheck( comp.RegisterProverAction(round+1, lroCommitProverAction{compilationCtx: ctx, proverStateLock: &sync.Mutex{}}) } - comp.RegisterVerifierAction(round, checkingActivators(ctx.Columns.Activators)) + comp.RegisterVerifierAction(round, &checkingActivators{Cols: ctx.Columns.Activators}) return ctx } @@ -299,20 +299,23 @@ func (ctx *compilationCtx) addCopyConstraint() { // checkingActivators implements the [wizard.VerifierAction] interface and // checks that the [Activators] columns are correctly assigned -type checkingActivators []ifaces.Column +type checkingActivators struct { + Cols []ifaces.Column + skipped bool +} -var _ wizard.VerifierAction = checkingActivators{} +var _ wizard.VerifierAction = &checkingActivators{} -func (ca checkingActivators) Run(run *wizard.VerifierRuntime) error { - for i := range ca { +func (ca *checkingActivators) Run(run *wizard.VerifierRuntime) error { + for i := range ca.Cols { - curr := ca[i].GetColAssignmentAt(run, 0) + curr := ca.Cols[i].GetColAssignmentAt(run, 0) if !curr.IsOne() && !curr.IsZero() { return fmt.Errorf("error the activators must be 0 or 1") } - if i+1 < len(ca) { - next := ca[i+1].GetColAssignmentAt(run, 0) + if i+1 < len(ca.Cols) { + next := ca.Cols[i+1].GetColAssignmentAt(run, 0) if curr.IsZero() && !next.IsZero() { return fmt.Errorf("the activators must never go from 0 to 1") } @@ -322,15 +325,23 @@ func (ca checkingActivators) Run(run *wizard.VerifierRuntime) error { return nil } -func (ca checkingActivators) RunGnark(api frontend.API, run *wizard.WizardVerifierCircuit) { - for i := range ca { +func (ca *checkingActivators) RunGnark(api frontend.API, run *wizard.WizardVerifierCircuit) { + for i := range ca.Cols { - curr := ca[i].GetColAssignmentGnarkAt(run, 0) + curr := ca.Cols[i].GetColAssignmentGnarkAt(run, 0) api.AssertIsBoolean(curr) - if i+1 < len(ca) { - next := ca[i+1].GetColAssignmentGnarkAt(run, 0) + if i+1 < len(ca.Cols) { + next := ca.Cols[i+1].GetColAssignmentGnarkAt(run, 0) api.AssertIsEqual(next, api.Mul(curr, next)) } } } + +func (ca *checkingActivators) Skip() { + ca.skipped = true +} + +func (ca *checkingActivators) IsSkipped() bool { + return ca.skipped +} diff --git a/prover/protocol/dedicated/projection/projection.go b/prover/protocol/dedicated/projection/projection.go index efa137fb4..149b358e7 100644 --- a/prover/protocol/dedicated/projection/projection.go +++ b/prover/protocol/dedicated/projection/projection.go @@ -64,6 +64,7 @@ type projectionProverAction struct { type projectionVerifierAction struct { Name ifaces.QueryID HornerA0, HornerB0 query.LocalOpening + skipped bool } // InsertProjection applies a projection query between sets (columnsA, filterA) @@ -212,7 +213,7 @@ func InsertProjection( pa.HornerB0 = comp.InsertLocalOpening(round, ifaces.QueryIDf("%v_HORNER_B0", queryName), pa.HornerB) comp.RegisterProverAction(round, pa) - comp.RegisterVerifierAction(round, projectionVerifierAction{HornerA0: pa.HornerA0, HornerB0: pa.HornerB0, Name: queryName}) + comp.RegisterVerifierAction(round, &projectionVerifierAction{HornerA0: pa.HornerA0, HornerB0: pa.HornerB0, Name: queryName}) } // Run implements the [wizard.ProverAction] interface. @@ -314,7 +315,7 @@ func (pa projectionProverAction) Run(run *wizard.ProverRuntime) { } // Run implements the [wizard.VerifierAction] interface. -func (va projectionVerifierAction) Run(run *wizard.VerifierRuntime) error { +func (va *projectionVerifierAction) Run(run *wizard.VerifierRuntime) error { var ( a = run.GetLocalPointEvalParams(va.HornerA0.ID).Y @@ -329,7 +330,7 @@ func (va projectionVerifierAction) Run(run *wizard.VerifierRuntime) error { } // RunGnark implements the [wizard.VerifierAction] interface. -func (va projectionVerifierAction) RunGnark(api frontend.API, run *wizard.WizardVerifierCircuit) { +func (va *projectionVerifierAction) RunGnark(api frontend.API, run *wizard.WizardVerifierCircuit) { var ( a = run.GetLocalPointEvalParams(va.HornerA0.ID).Y @@ -339,6 +340,14 @@ func (va projectionVerifierAction) RunGnark(api frontend.API, run *wizard.Wizard api.AssertIsEqual(a, b) } +func (va *projectionVerifierAction) Skip() { + va.skipped = true +} + +func (va *projectionVerifierAction) IsSkipped() bool { + return va.skipped +} + // cmptHorner computes a random Horner accumulation of the filtered elements // starting from the last entry down to the first entry. The final value is // stored in the last entry of the returned slice. diff --git a/prover/protocol/query/global.go b/prover/protocol/query/global.go index 63dbbc4c4..a72947330 100644 --- a/prover/protocol/query/global.go +++ b/prover/protocol/query/global.go @@ -70,7 +70,7 @@ func NewGlobalConstraint(id ifaces.QueryID, expr *symbolic.Expression, noBoundCa } if len(noBoundCancel) > 0 { - utils.Require(len(noBoundCancel) == 1, "there should be only 2 bound cancel got %v", len(noBoundCancel)) + utils.Require(len(noBoundCancel) == 1, "there should be only 1 bound cancel got %v", len(noBoundCancel)) res.NoBoundCancel = noBoundCancel[0] } diff --git a/prover/protocol/query/global_test.go b/prover/protocol/query/global_test.go index 3a69cf216..dd3aa8a62 100644 --- a/prover/protocol/query/global_test.go +++ b/prover/protocol/query/global_test.go @@ -50,6 +50,7 @@ func fibonacci() (wizard.DefineFunc, wizard.ProverStep) { n := 1 << 3 P := build.RegisterCommit(P, n) // overshadows P + // X[i-1] + X[i-2] - X[i] = 0 expr := ifaces.ColumnAsVariable(column.Shift(P, -1)). Add(ifaces.ColumnAsVariable(column.Shift(P, -2))). Sub(ifaces.ColumnAsVariable(P)) @@ -79,7 +80,7 @@ func pythagoreTriplet() (wizard.DefineFunc, wizard.ProverStep) { X := build.RegisterCommit(X, n) // overshadows P Y := build.RegisterCommit(Y, n) // overshadows P - + // X[i]^2 + Y[i]^2 - 25 = 0 expr := ifaces.ColumnAsVariable(X).Square(). Add(ifaces.ColumnAsVariable(Y).Square()). Sub(symbolic.NewConstant(25)) @@ -106,15 +107,25 @@ func testDummyShifted() (wizard.DefineFunc, wizard.ProverStep) { define := func(build *wizard.Builder) { A := build.RegisterCommit(X, 4) B := build.RegisterCommit(Y, 4) - - expr := symbolic.Sub(column.Shift(A, 1), - symbolic.Mul(2, column.Shift(B, 1))) + // X[i+2] - 2 * Y[i+2] = 0 + expr := symbolic.Sub(column.Shift(A, 2), + symbolic.Mul(2, column.Shift(B, 2))) build.InsertGlobal(0, "Q", expr) } Prover := func(run *wizard.ProverRuntime) { - x := smartvectors.ForTest(2, 8, 4, 0) - y := smartvectors.ForTest(1, 4, 2, 0) + // Note that the first two indices of x and y columns below does not satisfy the + // constraints. The test still passes because the boundary condition cancellation is by default + // set to true for the InsertGlobal() function. The test will fail if we modify the above line + // by build.InsertGlobal(0, "Q", expr, true) and set noBoundCancellation to true. In this case, + // the columns will behave as circular vectors. + + // Also to observe that the boundary indices here are 0 and 1 because for i = 0 onwards, the constraint starts + // looking at index 2, 3, and so on i.e. X[2] = 2*Y[2], X[3] = 2*Y[3]. + // The boundary indices will be 2 and 3 if we had constraint: X[i-2] - 2 * Y[i-2] = 0, i.e. we could have put + // whatever values in those indices and the constraint would be satisfied. + x := smartvectors.ForTest(2, 8, 4, 2) + y := smartvectors.ForTest(2, 3, 2, 1) run.AssignColumn(X, x) run.AssignColumn(Y, y) } diff --git a/prover/protocol/query/local_opening.go b/prover/protocol/query/local_opening.go index 463948c04..bb77b5376 100644 --- a/prover/protocol/query/local_opening.go +++ b/prover/protocol/query/local_opening.go @@ -6,7 +6,6 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/linea-monorepo/prover/crypto/fiatshamir" "github.com/consensys/linea-monorepo/prover/maths/field" - "github.com/consensys/linea-monorepo/prover/protocol/column" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" "github.com/consensys/linea-monorepo/prover/utils" ) @@ -30,20 +29,6 @@ func (lop LocalOpeningParams) UpdateFS(fs *fiatshamir.State) { // Constructs a new local opening query func NewLocalOpening(id ifaces.QueryID, pol ifaces.Column) LocalOpening { - // For simplicity, we enforce the `pol` to be either Natural or Shifted(Natural) - // Allegedly, this does not block any-case - switch h := pol.(type) { - case column.Natural: - // allowed - case column.Shifted: - if _, ok := h.Parent.(column.Natural); !ok { - utils.Panic("Unsupported handle should only be a shifted or a natural %v", pol) - } - // allowed - default: - utils.Panic("Unsupported handle should only be a shifted %v", pol) - } - if len(pol.GetColID()) == 0 { utils.Panic("Assigned a polynomial name with an empty length") } diff --git a/prover/protocol/wizard/actions.go b/prover/protocol/wizard/actions.go index 630e51415..398017fba 100644 --- a/prover/protocol/wizard/actions.go +++ b/prover/protocol/wizard/actions.go @@ -14,6 +14,10 @@ type ProverAction interface { // protocol. Usually, this is used to represent verifier checks. They can be // registered via [CompiledIOP.RegisterVerifierAction]. type VerifierAction interface { + // Skip indicates that the verifier action can be skipped + Skip() + // IsSkipped returns whether the current VerifierAction is skipped + IsSkipped() bool // Run executes the VerifierAction over a [VerifierRuntime] it returns an // error. Run(*VerifierRuntime) error @@ -21,3 +25,26 @@ type VerifierAction interface { // error the function enforces the passing of the verifier's checks. RunGnark(frontend.API, *WizardVerifierCircuit) } + +// genVerifierAction represents a verifier action represented by closures +type genVerifierAction struct { + skipped bool + run func(*VerifierRuntime) error + runGnark func(frontend.API, *WizardVerifierCircuit) +} + +func (gva *genVerifierAction) Run(run *VerifierRuntime) error { + return gva.run(run) +} + +func (gva *genVerifierAction) RunGnark(api frontend.API, run *WizardVerifierCircuit) { + gva.runGnark(api, run) +} + +func (gva *genVerifierAction) Skip() { + gva.skipped = true +} + +func (gva *genVerifierAction) IsSkipped() bool { + return gva.skipped +} diff --git a/prover/protocol/wizard/builder.go b/prover/protocol/wizard/builder.go index 9bab4cfb6..baf08b2ee 100644 --- a/prover/protocol/wizard/builder.go +++ b/prover/protocol/wizard/builder.go @@ -294,16 +294,8 @@ func (b *Builder) equalizeRounds(numRounds int) { /* Check and reserve for the verifiers */ - if comp.subVerifiers.Len() > numRounds { - utils.Panic("Bug : numRounds is %v but %v rounds are registered for the verifier. %v", numRounds, comp.subVerifiers.Len(), helpMsg) + if comp.SubVerifiers.Len() > numRounds { + utils.Panic("Bug : numRounds is %v but %v rounds are registered for the verifier. %v", numRounds, comp.SubVerifiers.Len(), helpMsg) } - comp.subVerifiers.Reserve(numRounds) - - /* - Check and reserve for the gnark verifiers - */ - if comp.gnarkSubVerifiers.Len() > numRounds { - utils.Panic("Bug : numRounds is %v but %v rounds are registered for the gnark verifier. %v", numRounds, comp.gnarkSubVerifiers.Len(), helpMsg) - } - comp.gnarkSubVerifiers.Reserve(numRounds) + comp.SubVerifiers.Reserve(numRounds) } diff --git a/prover/protocol/wizard/compiled.go b/prover/protocol/wizard/compiled.go index 6cf5c37a3..eab3ecc2b 100644 --- a/prover/protocol/wizard/compiled.go +++ b/prover/protocol/wizard/compiled.go @@ -71,28 +71,26 @@ type CompiledIOP struct { // manual checks that the verifier has to perform. This is useful when a check // cannot be represented in term of query but, when possible, queries should // always be preferred to express a relation that the witness must satisfy. - subVerifiers collection.VecVec[VerifierStep] + SubVerifiers collection.VecVec[VerifierAction] - // gnarkSubVerifiers does the same as [gnarkSubVerifiers] but in a gnark - // circuit. Whenever, the user add a subVerifier function into the compiled - // IOP, he should also provide an equivalent gnark function that does - // exactly the same thing, but in a gnark circuit. This used when - // instantiating a gnark verifier for the sub-protocol. - gnarkSubVerifiers collection.VecVec[GnarkVerifierStep] + // FiatShamirHooks is an action that is run during the FS sampling. Compared + // to a normal verifier action it has the possibility to interact with the + // Fiat-Shamir state. + FiatShamirHooks collection.VecVec[VerifierAction] // Precomputed stores the assignments of all the Precomputed and VerifierKey // polynomials. It is assigned directly when registering a precomputed // column. Precomputed collection.Mapping[ifaces.ColID, ifaces.ColAssignment] - // CryptographicCompilerCtx stores the compilation context of the last used + // PcsCtxs stores the compilation context of the last used // cryptographic compiler. Specifically, it is aimed to store the last // Vortex compilation context (see [github.com/consensys/linea-monorepo/prover/protocol/compiler]) that was used. And // its purpose is to provide the Vortex context to the self-recursion // compilation context; see [github.com/consensys/linea-monorepo/prover/protocol/compiler/selfrecursion]. This allows // the self-recursion context to learn about the columns to use and the // Vortex parameters. - CryptographicCompilerCtx any + PcsCtxs any // DummyCompiled that can be set internally by the compilation, when we are // using the [github.com/consensys/linea-monorepo/prover/protocol/compiler/dummy.Compile] compilation step. This steps @@ -120,6 +118,10 @@ type CompiledIOP struct { // // For efficiency reasons, the fiatShamirSetup is derived using SHA2. fiatShamirSetup field.Element + + // FunctionalPublic inputs lists the queries representing a public inputs + // and their identifiers + PublicInputs []PublicInput } // NumRounds returns the total number of prover interactions with the verifier @@ -478,8 +480,10 @@ func (c *CompiledIOP) InsertPublicInput(round int, name ifaces.ColID, size int) // passing `nil` is fine. func (c *CompiledIOP) InsertVerifier(round int, ver VerifierStep, gnarkVer GnarkVerifierStep) { c.assertConsistentRound(round) - c.gnarkSubVerifiers.AppendToInner(round, gnarkVer) - c.subVerifiers.AppendToInner(round, ver) + c.SubVerifiers.AppendToInner(round, &genVerifierAction{ + run: ver, + runGnark: gnarkVer, + }) } // InsertRange registers [query.Range] in the CompiledIOP. Namely, it ensures diff --git a/prover/protocol/wizard/gnark_verifier.go b/prover/protocol/wizard/gnark_verifier.go index 82f37c718..40e48fcff 100644 --- a/prover/protocol/wizard/gnark_verifier.go +++ b/prover/protocol/wizard/gnark_verifier.go @@ -5,6 +5,7 @@ import ( "github.com/consensys/linea-monorepo/prover/crypto/fiatshamir" "github.com/consensys/linea-monorepo/prover/crypto/mimc/gkrmimc" "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" + "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/protocol/coin" "github.com/consensys/linea-monorepo/prover/protocol/column" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" @@ -80,6 +81,11 @@ type WizardVerifierCircuit struct { // hashes but also the MiMC Vortex column hashes that we use for the // last round of the self-recursion. HasherFactory *gkrmimc.HasherFactory `gnark:"-"` + + // FiatShamirHistory tracks the fiat-shamir state at the beginning of every + // round. The first entry is the initial state, the final entry is the final + // state. + FiatShamirHistory [][2][]frontend.Variable `gnark:"-"` } // AllocateWizardCircuit allocates the inner-slices of the verifier struct from a precompiled IOP. It @@ -89,7 +95,7 @@ type WizardVerifierCircuit struct { // the circuit. func AllocateWizardCircuit(comp *CompiledIOP) (*WizardVerifierCircuit, error) { - res := newWizardVerifierCircuit() + res := NewWizardVerifierCircuit() for i, colName := range comp.Columns.AllKeys() { // filter the columns by status @@ -109,9 +115,7 @@ func AllocateWizardCircuit(comp *CompiledIOP) (*WizardVerifierCircuit, error) { size := comp.Columns.GetSize(colName) // Allocates the column in the circuit and indexes it - colID := len(res.Columns) - res.Columns = append(res.Columns, gnarkutil.AllocateSlice(size)) - res.columnsIDs.InsertNew(colName, colID) + res.AllocColumn(colName, size) } /* @@ -129,17 +133,11 @@ func AllocateWizardCircuit(comp *CompiledIOP) (*WizardVerifierCircuit, error) { switch qInfo := qInfoIface.(type) { case query.UnivariateEval: - // Note that nil is the default value for frontend.Variable - res.univariateParamsIDs.InsertNew(qName, len(res.UnivariateParams)) - res.UnivariateParams = append(res.UnivariateParams, qInfo.GnarkAllocate()) + res.AllocUnivariateEval(qName, qInfo) case query.InnerProduct: - // Note that nil is the default value for frontend.Variable - res.innerProductIDs.InsertNew(qName, len(res.InnerProductParams)) - res.InnerProductParams = append(res.InnerProductParams, qInfo.GnarkAllocate()) + res.AllocInnerProduct(qName, qInfo) case query.LocalOpening: - // Note that nil is the default value for frontend.Variable - res.localOpeningIDs.InsertNew(qName, len(res.LocalOpeningParams)) - res.LocalOpeningParams = append(res.LocalOpeningParams, query.GnarkLocalOpeningParams{}) + res.AllocLocalOpening(qName, qInfo) } } @@ -154,67 +152,55 @@ func (c *WizardVerifierCircuit) Verify(api frontend.API) { c.HasherFactory = gkrmimc.NewHasherFactory(api) c.FS = fiatshamir.NewGnarkFiatShamir(api, c.HasherFactory) c.FS.Update(c.Spec.fiatShamirSetup) + c.FiatShamirHistory = make([][2][]frontend.Variable, c.Spec.NumRounds()) c.generateAllRandomCoins(api) - logrus.Tracef("Generated the coins") - - for _, roundSteps := range c.Spec.gnarkSubVerifiers.Inner() { + for _, roundSteps := range c.Spec.SubVerifiers.Inner() { for _, step := range roundSteps { - step(api, c) + if !step.IsSkipped() { + step.RunGnark(api, c) + } } } } // generateAllRandomCoins is as [VerifierRuntime.generateAllRandomCoins]. Note that the function // does create constraints via the hasher factory that is inside of `c.FS`. -func (c *WizardVerifierCircuit) generateAllRandomCoins(_ frontend.API) { +func (c *WizardVerifierCircuit) generateAllRandomCoins(api frontend.API) { for currRound := 0; currRound < c.Spec.NumRounds(); currRound++ { - if currRound > 0 { - /* - Sanity-check : Make sure all issued random coin have been - "consumed" by all the verifiers steps, in the round we are - "closing" - */ - toBeConsumed := c.Spec.Coins.AllKeysAt(currRound - 1) - c.Coins.Exists(toBeConsumed...) - if !c.Spec.DummyCompiled { + initialState := c.FS.State() - // Make sure that all messages have been written and use them - // to update the FS state. Note that we do not need to update - // FS using the last round of the prover because he is always - // the last one to "talk" in the protocol. - toUpdateFS := c.Spec.Columns.AllKeysProofAt(currRound - 1) - for _, msg := range toUpdateFS { - - msgID := c.columnsIDs.MustGet(msg) - msgContent := c.Columns[msgID] - - logrus.Tracef("VERIFIER CIRCUIT : Updating the FS oracle with a message - %v", msg) - c.FS.UpdateVec(msgContent) - } + if currRound > 0 { - toUpdateFS = c.Spec.Columns.AllKeysPublicInputAt(currRound - 1) - for _, msg := range toUpdateFS { + // Make sure that all messages have been written and use them + // to update the FS state. Note that we do not need to update + // FS using the last round of the prover because he is always + // the last one to "talk" in the protocol. + toUpdateFS := c.Spec.Columns.AllKeysProofAt(currRound - 1) + for _, msg := range toUpdateFS { + msgContent := c.GetColumn(msg) + c.FS.UpdateVec(msgContent) + } - msgID := c.columnsIDs.MustGet(msg) - msgContent := c.Columns[msgID] + toUpdateFS = c.Spec.Columns.AllKeysPublicInputAt(currRound - 1) + for _, msg := range toUpdateFS { + msgContent := c.GetColumn(msg) + c.FS.UpdateVec(msgContent) + } - logrus.Tracef("VERIFIER CIRCUIT : Updating the FS oracle with public input - %v", msg) - c.FS.UpdateVec(msgContent) + /* + Also include the prover's allegations for all evaluations + */ + queries := c.Spec.QueriesParams.AllKeysAt(currRound - 1) + for _, qName := range queries { + if c.Spec.QueriesParams.IsSkippedFromVerifierTranscript(qName) { + continue } - /* - Also include the prover's allegations for all evaluations - */ - queries := c.Spec.QueriesParams.AllKeysAt(currRound - 1) - for _, qName := range queries { - // Implicitly, this will panic whenever we start supporting - // a new type of query params - params := c.GetParams(qName) - params.UpdateFS(c.FS) - } + params := c.GetParams(qName) + params.UpdateFS(c.FS) } } @@ -223,8 +209,11 @@ func (c *WizardVerifierCircuit) generateAllRandomCoins(_ frontend.API) { */ toCompute := c.Spec.Coins.AllKeysAt(currRound) for _, coinName := range toCompute { + if c.Spec.Coins.IsSkippedFromVerifierTranscript(coinName) { + continue + } + info := c.Spec.Coins.Data(coinName) - logrus.Tracef("VERIFIER CIRCUIT : Generate a random coin - %v", coinName) switch info.Type { case coin.Field: value := c.FS.RandomField() @@ -234,6 +223,22 @@ func (c *WizardVerifierCircuit) generateAllRandomCoins(_ frontend.API) { c.Coins.InsertNew(coinName, value) } } + + if c.Spec.FiatShamirHooks.Len() > currRound { + fsHooks := c.Spec.FiatShamirHooks.MustGet(currRound) + for i := range fsHooks { + if fsHooks[i].IsSkipped() { + continue + } + + fsHooks[i].RunGnark(api, c) + } + } + + c.FiatShamirHistory[currRound] = [2][]frontend.Variable{ + initialState, + c.FS.State(), + } } } @@ -346,9 +351,9 @@ func (c *WizardVerifierCircuit) GetColumnAt(name ifaces.ColID, pos int) frontend return c.GetColumn(name)[pos] } -// newWizardVerifierCircuit creates an empty wizard verifier circuit. +// NewWizardVerifierCircuit creates an empty wizard verifier circuit. // Initializes the underlying structs and collections. -func newWizardVerifierCircuit() *WizardVerifierCircuit { +func NewWizardVerifierCircuit() *WizardVerifierCircuit { res := &WizardVerifierCircuit{} res.columnsIDs = collection.NewMapping[ifaces.ColID, int]() res.univariateParamsIDs = collection.NewMapping[ifaces.QueryID, int]() @@ -367,7 +372,7 @@ func newWizardVerifierCircuit() *WizardVerifierCircuit { // gnark assignment circuit involving the verification of Wizard proof. func GetWizardVerifierCircuitAssignment(comp *CompiledIOP, proof Proof) *WizardVerifierCircuit { - res := newWizardVerifierCircuit() + res := NewWizardVerifierCircuit() /* Assigns the messages. Note that the iteration order is made @@ -411,17 +416,11 @@ func GetWizardVerifierCircuitAssignment(comp *CompiledIOP, proof Proof) *WizardV switch params := paramsIface.(type) { case query.UnivariateEvalParams: - res.univariateParamsIDs.InsertNew(qName, len(res.UnivariateParams)) - res.UnivariateParams = append(res.UnivariateParams, params.GnarkAssign()) - + res.AssignUnivariateEval(qName, params) case query.InnerProductParams: - res.innerProductIDs.InsertNew(qName, len(res.InnerProductParams)) - res.InnerProductParams = append(res.InnerProductParams, params.GnarkAssign()) - + res.AssignInnerProduct(qName, params) case query.LocalOpeningParams: - res.localOpeningIDs.InsertNew(qName, len(res.LocalOpeningParams)) - res.LocalOpeningParams = append(res.LocalOpeningParams, params.GnarkAssign()) - + res.AssignLocalOpening(qName, params) default: utils.Panic("unknow type %T", params) } @@ -445,3 +444,79 @@ func (c *WizardVerifierCircuit) GetParams(id ifaces.QueryID) ifaces.GnarkQueryPa } panic("unreachable") } + +// AllocColumn inserts a column in the Wizard verifier circuit and is meant +// to be called at allocation time. +func (c *WizardVerifierCircuit) AllocColumn(id ifaces.ColID, size int) []frontend.Variable { + column := make([]frontend.Variable, size) + c.columnsIDs.InsertNew(id, len(c.Columns)) + c.Columns = append(c.Columns, column) + return column +} + +// AssignColumn assigns a column in the Wizard verifier circuit +func (c *WizardVerifierCircuit) AssignColumn(id ifaces.ColID, sv smartvectors.SmartVector) { + column := smartvectors.IntoGnarkAssignment(sv) + c.columnsIDs.InsertNew(id, len(c.Columns)) + c.Columns = append(c.Columns, column) +} + +// AllocUnivariableEval inserts a slot for a univariate query opening in the +// witness of the verifier circuit. +func (c *WizardVerifierCircuit) AllocUnivariateEval(qName ifaces.QueryID, qInfo query.UnivariateEval) { + // Note that nil is the default value for frontend.Variable + c.univariateParamsIDs.InsertNew(qName, len(c.UnivariateParams)) + c.UnivariateParams = append(c.UnivariateParams, qInfo.GnarkAllocate()) +} + +// AllocInnerProduct inserts a slot for an inner-product query opening in the +// witness of the verifier circuit. +func (c *WizardVerifierCircuit) AllocInnerProduct(qName ifaces.QueryID, qInfo query.InnerProduct) { + // Note that nil is the default value for frontend.Variable + c.innerProductIDs.InsertNew(qName, len(c.InnerProductParams)) + c.InnerProductParams = append(c.InnerProductParams, qInfo.GnarkAllocate()) +} + +// AllocLocalOpening inserts a slot for a local position opening in the witness +// of the verifier circuit. +func (c *WizardVerifierCircuit) AllocLocalOpening(qName ifaces.QueryID, qInfo query.LocalOpening) { + // Note that nil is the default value for frontend.Variable + c.localOpeningIDs.InsertNew(qName, len(c.LocalOpeningParams)) + c.LocalOpeningParams = append(c.LocalOpeningParams, query.GnarkLocalOpeningParams{}) +} + +// AssignUnivariableEval inserts a slot for a univariate query opening in the +// witness of the verifier circuit. +func (c *WizardVerifierCircuit) AssignUnivariateEval(qName ifaces.QueryID, params query.UnivariateEvalParams) { + // Note that nil is the default value for frontend.Variable + c.univariateParamsIDs.InsertNew(qName, len(c.UnivariateParams)) + c.UnivariateParams = append(c.UnivariateParams, params.GnarkAssign()) +} + +// AssignInnerProduct inserts a slot for an inner-product query opening in the +// witness of the verifier circuit. +func (c *WizardVerifierCircuit) AssignInnerProduct(qName ifaces.QueryID, params query.InnerProductParams) { + // Note that nil is the default value for frontend.Variable + c.innerProductIDs.InsertNew(qName, len(c.InnerProductParams)) + c.InnerProductParams = append(c.InnerProductParams, params.GnarkAssign()) +} + +// AssignLocalOpening inserts a slot for a local position opening in the witness +// of the verifier circuit. +func (c *WizardVerifierCircuit) AssignLocalOpening(qName ifaces.QueryID, params query.LocalOpeningParams) { + // Note that nil is the default value for frontend.Variable + c.localOpeningIDs.InsertNew(qName, len(c.LocalOpeningParams)) + c.LocalOpeningParams = append(c.LocalOpeningParams, params.GnarkAssign()) +} + +// GetPublicInput returns a public input value from its name +func (c *WizardVerifierCircuit) GetPublicInput(api frontend.API, name string) frontend.Variable { + allPubs := c.Spec.PublicInputs + for i := range allPubs { + if allPubs[i].Name == name { + return allPubs[i].Acc.GetFrontendVariable(api, c) + } + } + utils.Panic("could not find public input nb %v", name) + return field.Element{} +} diff --git a/prover/protocol/wizard/prover.go b/prover/protocol/wizard/prover.go index caa4df4aa..df61fd31b 100644 --- a/prover/protocol/wizard/prover.go +++ b/prover/protocol/wizard/prover.go @@ -12,7 +12,6 @@ import ( "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/utils" "github.com/consensys/linea-monorepo/prover/utils/collection" - "github.com/sirupsen/logrus" ) // ProverStep represents an operation to be performed by the prover of a @@ -120,6 +119,11 @@ type ProverRuntime struct { // lock is global lock so that the assignment maps are thread safes lock *sync.Mutex + + // FiatShamirHistory tracks the fiat-shamir state at the beginning of every + // round. The first entry is the initial state, the final entry is the final + // state. + FiatShamirHistory [][2][]field.Element } // Prove is the top-level function that runs the Prover on the user's side. It @@ -204,14 +208,20 @@ func (c *CompiledIOP) createProver() ProverRuntime { // Instantiates an empty Assignment (but link it to the CompiledIOP) runtime := ProverRuntime{ - Spec: c, - Columns: collection.NewMapping[ifaces.ColID, ifaces.ColAssignment](), - QueriesParams: collection.NewMapping[ifaces.QueryID, ifaces.QueryParams](), - Coins: collection.NewMapping[coin.Name, interface{}](), - State: collection.NewMapping[string, interface{}](), - FS: fs, - currRound: 0, - lock: &sync.Mutex{}, + Spec: c, + Columns: collection.NewMapping[ifaces.ColID, ifaces.ColAssignment](), + QueriesParams: collection.NewMapping[ifaces.QueryID, ifaces.QueryParams](), + Coins: collection.NewMapping[coin.Name, interface{}](), + State: collection.NewMapping[string, interface{}](), + FS: fs, + currRound: 0, + lock: &sync.Mutex{}, + FiatShamirHistory: make([][2][]field.Element, c.NumRounds()), + } + + runtime.FiatShamirHistory[0] = [2][]field.Element{ + fs.State(), + fs.State(), } // Pass the precomputed polynomials @@ -452,6 +462,8 @@ func (run *ProverRuntime) getRandomCoinGeneric(name coin.Name, requestedType coi // parameters. This makes all the new coins available in the prover runtime. func (run *ProverRuntime) goNextRound() { + initialState := run.FS.State() + /* Make sure all issued random coin have been "consumed" by all the prover steps, in the round we are closing. An error occuring here is more likely @@ -473,11 +485,6 @@ func (run *ProverRuntime) goNextRound() { toBeParametrized := run.Spec.QueriesParams.AllKeysAt(run.currRound) run.QueriesParams.MustExists(toBeParametrized...) - // Counts the transcript size of the round and the number of field - // element generated. - initialTranscriptSize := run.FS.TranscriptSize - initialNumCoinsGenerated := run.FS.NumCoinGenerated - if !run.Spec.DummyCompiled { /* @@ -486,13 +493,11 @@ func (run *ProverRuntime) goNextRound() { FS using the last round of the prover because he is always the last one to "talk" in the protocol. */ - start := run.FS.TranscriptSize - msgsToFS := run.Spec.Columns.AllKeysProofAt(run.currRound) + msgsToFS := run.Spec.Columns.AllKeysProofsOrIgnoredButKeptInProverTranscript(run.currRound) for _, msgName := range msgsToFS { instance := run.GetMessage(msgName) run.FS.UpdateSV(instance) } - logrus.Debugf("Fiat-shamir round %v - %v proof elements in the transcript", run.currRound, run.FS.TranscriptSize-start) /* Make sure that all messages have been written and use them @@ -500,26 +505,26 @@ func (run *ProverRuntime) goNextRound() { FS using the last round of the prover because he is always the last one to "talk" in the protocol. */ - start = run.FS.TranscriptSize msgsToFS = run.Spec.Columns.AllKeysPublicInputAt(run.currRound) for _, msgName := range msgsToFS { instance := run.GetMessage(msgName) run.FS.UpdateSV(instance) } - logrus.Debugf("Fiat-shamir round %v - %v public inputs in the transcript", run.currRound, run.FS.TranscriptSize-start) /* Also include the prover's allegations for all evaluations */ - start = run.FS.TranscriptSize paramsToFS := run.Spec.QueriesParams.AllKeysAt(run.currRound) for _, qName := range paramsToFS { + if run.Spec.QueriesParams.IsSkippedFromProverTranscript(qName) { + continue + } + // Implicitly, this will panic whenever we start supporting // a new type of query params params := run.QueriesParams.MustGet(qName) params.UpdateFS(run.FS) } - logrus.Debugf("Fiat-shamir round %v - %v query params in the transcript", run.currRound, run.FS.TranscriptSize-start) } // Increment the number of rounds @@ -537,9 +542,12 @@ func (run *ProverRuntime) goNextRound() { run.Coins.InsertNew(coin, value) } - logrus.Debugf("Ran Fiat-Shamir for round %v, transcript size %v (field element), generated %v field elements, total-transcript %v, total-generated %v", - run.currRound, run.FS.TranscriptSize-initialTranscriptSize, run.FS.NumCoinGenerated-initialNumCoinsGenerated, run.FS.TranscriptSize, run.FS.NumCoinGenerated, - ) + finalState := run.FS.State() + + run.FiatShamirHistory[run.currRound] = [2][]field.Element{ + initialState, + finalState, + } } // runProverSteps runs all the [ProverStep] specified in the underlying diff --git a/prover/protocol/wizard/public_input.go b/prover/protocol/wizard/public_input.go new file mode 100644 index 000000000..30b8c9328 --- /dev/null +++ b/prover/protocol/wizard/public_input.go @@ -0,0 +1,14 @@ +package wizard + +import "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + +// PublicInput represents a public input in a wizard protocol. Public inputs +// are materialized with a functional identifier and a local opening query. +// The identifier is what ultimately identifies the public input as the query +// may be mutated by compilation (if we use the FullRecursion compiler), therefore +// it would unsafe to use the ID of the query to identify the public input in +// the circuit. +type PublicInput struct { + Name string + Acc ifaces.Accessor +} diff --git a/prover/protocol/wizard/register.go b/prover/protocol/wizard/register.go index 45d84273c..6efdcbdb9 100644 --- a/prover/protocol/wizard/register.go +++ b/prover/protocol/wizard/register.go @@ -5,11 +5,10 @@ import ( "github.com/consensys/linea-monorepo/prover/utils/collection" ) -/* -In a nutshell, an item is an abstract type that -accounts for the fact that CompiledProtocol -registers various things for different rounds -*/ +// ByRoundRegister is a an abstract data-structure used to register the +// [column.Natural], [coin.Info] and [ifaces.Query] etc... Each item is added +// at a particular round. The structure additionally records compilation +// informations about the objects stored in the register. type ByRoundRegister[ID comparable, DATA any] struct { // All the data for each key mapping collection.Mapping[ID, DATA] @@ -19,6 +18,17 @@ type ByRoundRegister[ID comparable, DATA any] struct { byRoundsIndex collection.Mapping[ID, int] // Marks an entry as ignorable (but does not delete it) ignored collection.Set[ID] + // skippedFromVerifierTranscript marks an entry as "skipped from verifier + // transcript from the FS transcript for the verifier. This means that the + // verifier will not use this value. However, the value can still be used + // by the prover. The reason for this field is to work around subtle issues + // while dealing with recursion. + skippedFromVerifierTranscript collection.Set[ID] + // skippedFromProverTranscript marks an entry as "skipped from prover + // transcript" this means that neither the prover nor the verifier will use + // this value to update the transcript. The reason for this field is to work + // around subtle issues while dealing with recursion. + skippedFromProverTranscript collection.Set[ID] } /* @@ -26,10 +36,12 @@ Construct a new round register */ func NewRegister[ID comparable, DATA any]() ByRoundRegister[ID, DATA] { return ByRoundRegister[ID, DATA]{ - mapping: collection.NewMapping[ID, DATA](), - byRounds: collection.NewVecVec[ID](), - byRoundsIndex: collection.NewMapping[ID, int](), - ignored: collection.NewSet[ID](), + mapping: collection.NewMapping[ID, DATA](), + byRounds: collection.NewVecVec[ID](), + byRoundsIndex: collection.NewMapping[ID, int](), + ignored: collection.NewSet[ID](), + skippedFromVerifierTranscript: collection.NewSet[ID](), + skippedFromProverTranscript: collection.NewSet[ID](), } } @@ -166,3 +178,34 @@ func (r *ByRoundRegister[ID, DATA]) IsIgnored(id ID) bool { r.mapping.MustExists(id) return r.ignored.Exists(id) } + +// MarkAsSkippedFromVerifierTranscript marks an entry as skipped from the transcript +// of the verifier. Panic if the key is missing from the register. Returns true if +// the item was already ignored. +func (r *ByRoundRegister[ID, DATA]) MarkAsSkippedFromVerifierTranscript(id ID) bool { + r.mapping.MustExists(id) + return r.skippedFromVerifierTranscript.Insert(id) +} + +// IsSkippedFromVerifierTranscript returns if the entry is skipped from the +// transcript. Panics if the entry is missing from the map. +func (r *ByRoundRegister[ID, DATA]) IsSkippedFromVerifierTranscript(id ID) bool { + r.mapping.MustExists(id) + return r.skippedFromVerifierTranscript.Exists(id) +} + +// MarkAsSkippedFromProverTranscript marks an entry as skipped from the transcript +// of the verifier. Panic if the key is missing from the register. Returns true +// if the item was already ignored. +func (r *ByRoundRegister[ID, DATA]) MarkAsSkippedFromProverTranscript(id ID) bool { + r.mapping.MustExists(id) + r.skippedFromVerifierTranscript.Insert(id) + return r.skippedFromProverTranscript.Insert(id) +} + +// IsSkippedFromProverTranscript returns if the entry is skipped from the +// transcript. Panics if the entry is missing from the map. +func (r *ByRoundRegister[ID, DATA]) IsSkippedFromProverTranscript(id ID) bool { + r.mapping.MustExists(id) + return r.skippedFromProverTranscript.Exists(id) +} diff --git a/prover/protocol/wizard/verifier.go b/prover/protocol/wizard/verifier.go index 1a355796e..65b8d83bf 100644 --- a/prover/protocol/wizard/verifier.go +++ b/prover/protocol/wizard/verifier.go @@ -9,7 +9,6 @@ import ( "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/utils" "github.com/consensys/linea-monorepo/prover/utils/collection" - "github.com/sirupsen/logrus" ) // Proof generically represents a proof obtained from the wizard. This object does not @@ -69,6 +68,11 @@ type VerifierRuntime struct { // the verifer end up having different state or the same message being // included a second time. Use it externally at your own risks. FS *fiatshamir.State + + // FiatShamirHistory tracks the fiat-shamir state at the beginning of every + // round. The first entry is the initial state, the final entry is the final + // state. + FiatShamirHistory [][2][]field.Element } // Verify verifies a wizard proof. The caller specifies a [CompiledIOP] that @@ -91,10 +95,12 @@ func Verify(c *CompiledIOP, proof Proof) error { any */ errs := []error{} - for _, roundSteps := range runtime.Spec.subVerifiers.Inner() { + for _, roundSteps := range runtime.Spec.SubVerifiers.Inner() { for _, step := range roundSteps { - if err := step(&runtime); err != nil { - errs = append(errs, err) + if !step.IsSkipped() { + if err := step.Run(&runtime); err != nil { + errs = append(errs, err) + } } } } @@ -117,11 +123,12 @@ func (c *CompiledIOP) createVerifier(proof Proof) VerifierRuntime { Instantiate an empty assigment for the verifier */ runtime := VerifierRuntime{ - Spec: c, - Coins: collection.NewMapping[coin.Name, interface{}](), - Columns: proof.Messages, - QueriesParams: proof.QueriesParams, - FS: fiatshamir.NewMiMCFiatShamir(), + Spec: c, + Coins: collection.NewMapping[coin.Name, interface{}](), + Columns: proof.Messages, + QueriesParams: proof.QueriesParams, + FS: fiatshamir.NewMiMCFiatShamir(), + FiatShamirHistory: make([][2][]field.Element, c.NumRounds()), } runtime.FS.Update(c.fiatShamirSetup) @@ -146,14 +153,10 @@ func (c *CompiledIOP) createVerifier(proof Proof) VerifierRuntime { func (run *VerifierRuntime) generateAllRandomCoins() { for currRound := 0; currRound < run.Spec.NumRounds(); currRound++ { + + initialState := run.FS.State() + if currRound > 0 { - /* - Sanity-check : Make sure all issued random coin have been - "consumed" by all the verifiers steps, in the round we are - "closing" - */ - toBeConsumed := run.Spec.Coins.AllKeysAt(currRound - 1) - run.Coins.MustExists(toBeConsumed...) if !run.Spec.DummyCompiled { @@ -166,14 +169,12 @@ func (run *VerifierRuntime) generateAllRandomCoins() { msgsToFS := run.Spec.Columns.AllKeysProofAt(currRound - 1) for _, msgName := range msgsToFS { instance := run.GetColumn(msgName) - logrus.Tracef("VERIFIER : Update fiat-shamir with proof message %v", msgName) run.FS.UpdateSV(instance) } msgsToFS = run.Spec.Columns.AllKeysPublicInputAt(currRound - 1) for _, msgName := range msgsToFS { instance := run.GetColumn(msgName) - logrus.Tracef("VERIFIER : Update fiat-shamir with public input %v", msgName) run.FS.UpdateSV(instance) } @@ -182,9 +183,10 @@ func (run *VerifierRuntime) generateAllRandomCoins() { */ queries := run.Spec.QueriesParams.AllKeysAt(currRound - 1) for _, qName := range queries { - // Implicitly, this will panic whenever we start supporting - // a new type of query params - logrus.Tracef("VERIFIER : Update fiat-shamir with query parameters %v", qName) + if run.Spec.QueriesParams.IsSkippedFromVerifierTranscript(qName) { + continue + } + params := run.QueriesParams.MustGet(qName) params.UpdateFS(run.FS) } @@ -197,11 +199,30 @@ func (run *VerifierRuntime) generateAllRandomCoins() { */ toCompute := run.Spec.Coins.AllKeysAt(currRound) for _, coin := range toCompute { - logrus.Tracef("VERIFIER : Generate coin %v", coin) + if run.Spec.Coins.IsSkippedFromVerifierTranscript(coin) { + continue + } + info := run.Spec.Coins.Data(coin) value := info.Sample(run.FS) run.Coins.InsertNew(coin, value) } + + if run.Spec.FiatShamirHooks.Len() > currRound { + fsHooks := run.Spec.FiatShamirHooks.MustGet(currRound) + for i := range fsHooks { + if fsHooks[i].IsSkipped() { + continue + } + + fsHooks[i].Run(run) + } + } + + run.FiatShamirHistory[currRound] = [2][]field.Element{ + initialState, + run.FS.State(), + } } } @@ -358,3 +379,15 @@ func (run VerifierRuntime) GetColumnAt(name ifaces.ColID, pos int) field.Element func (run *VerifierRuntime) GetParams(name ifaces.QueryID) ifaces.QueryParams { return run.QueriesParams.MustGet(name) } + +// GetPublicInput returns a public input from its name +func (run *VerifierRuntime) GetPublicInput(name string) field.Element { + allPubs := run.Spec.PublicInputs + for i := range allPubs { + if allPubs[i].Name == name { + return allPubs[i].Acc.GetVal(run) + } + } + utils.Panic("could not find public input nb %v", name) + return field.Element{} +} diff --git a/prover/zkevm/prover/ecpair/circuits.go b/prover/zkevm/prover/ecpair/circuits.go index ca35d00b6..0eb122669 100644 --- a/prover/zkevm/prover/ecpair/circuits.go +++ b/prover/zkevm/prover/ecpair/circuits.go @@ -2,6 +2,7 @@ package ecpair import ( "fmt" + "math/big" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" @@ -9,10 +10,16 @@ import ( "github.com/consensys/gnark/std/evmprecompiles" "github.com/consensys/gnark/std/math/bitslice" "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/std/math/emulated/emparams" ) var fpParams sw_bn254.BaseField +type ( + fpField = emulated.Field[emparams.BN254Fp] + fpElement = emulated.Element[emparams.BN254Fp] +) + // G1ElementWizard represents G1 element as Wizard limbs (2 limbs of 128 bits) type G1ElementWizard struct { P [nbG1Limbs]frontend.Variable @@ -126,50 +133,22 @@ func (c *GtElementWizard) ToGtElement(api frontend.API, fp *emulated.Field[sw_bn C1B2YLimbs[2], C1B2YLimbs[3] = bitslice.Partition(api, c.T[22], 64, bitslice.WithNbDigits(128)) C1B2YLimbs[0], C1B2YLimbs[1] = bitslice.Partition(api, c.T[23], 64, bitslice.WithNbDigits(128)) - C0B0X := fp.NewElement(C0B0XLimbs) - C0B0Y := fp.NewElement(C0B0YLimbs) - C0B1X := fp.NewElement(C0B1XLimbs) - C0B1Y := fp.NewElement(C0B1YLimbs) - C0B2X := fp.NewElement(C0B2XLimbs) - C0B2Y := fp.NewElement(C0B2YLimbs) - C1B0X := fp.NewElement(C1B0XLimbs) - C1B0Y := fp.NewElement(C1B0YLimbs) - C1B1X := fp.NewElement(C1B1XLimbs) - C1B1Y := fp.NewElement(C1B1YLimbs) - C1B2X := fp.NewElement(C1B2XLimbs) - C1B2Y := fp.NewElement(C1B2YLimbs) - - T := sw_bn254.GTEl{ - C0: fields_bn254.E6{ - B0: fields_bn254.E2{ - A0: *C0B0X, - A1: *C0B0Y, - }, - B1: fields_bn254.E2{ - A0: *C0B1X, - A1: *C0B1Y, - }, - B2: fields_bn254.E2{ - A0: *C0B2X, - A1: *C0B2Y, - }, - }, - C1: fields_bn254.E6{ - B0: fields_bn254.E2{ - A0: *C1B0X, - A1: *C1B0Y, - }, - B1: fields_bn254.E2{ - A0: *C1B1X, - A1: *C1B1Y, - }, - B2: fields_bn254.E2{ - A0: *C1B2X, - A1: *C1B2Y, - }, - }, + e12Tower := [12]*fpElement{ + fp.NewElement(C0B0XLimbs), + fp.NewElement(C0B0YLimbs), + fp.NewElement(C0B1XLimbs), + fp.NewElement(C0B1YLimbs), + fp.NewElement(C0B2XLimbs), + fp.NewElement(C0B2YLimbs), + fp.NewElement(C1B0XLimbs), + fp.NewElement(C1B0YLimbs), + fp.NewElement(C1B1XLimbs), + fp.NewElement(C1B1YLimbs), + fp.NewElement(C1B2XLimbs), + fp.NewElement(C1B2YLimbs), } - return T + + return intoGtNoTower(fp, e12Tower) } // MultiG2GroupcheckCircuit is a circuit that checks multiple G2 group @@ -309,3 +288,53 @@ func (c *MillerLoopFinalExpInstance) Check(api frontend.API, fp *emulated.Field[ return evmprecompiles.ECPairMillerLoopAndFinalExpCheck(api, &prev, &P, &Q, c.Expected[1]) } + +// intoGtNoTower converts an E12 element as in the outputs of the pairing +// precompile on Ethereum into a non-tower representation of the same E12 +// element. +func intoGtNoTower(api *fpField, coordinates [12]*fpElement) sw_bn254.GTEl { + + var ( + C0B0X = coordinates[0] + C0B0Y = coordinates[1] + C0B1X = coordinates[2] + C0B1Y = coordinates[3] + C0B2X = coordinates[4] + C0B2Y = coordinates[5] + C1B0X = coordinates[6] + C1B0Y = coordinates[7] + C1B1X = coordinates[8] + C1B1Y = coordinates[9] + C1B2X = coordinates[10] + C1B2Y = coordinates[11] + ) + + var t *fpElement + t = api.MulConst(C0B0Y, big.NewInt(9)) + c0 := api.Sub(C0B0X, t) + t = api.MulConst(C1B0Y, big.NewInt(9)) + c1 := api.Sub(C1B0X, t) + t = api.MulConst(C0B1Y, big.NewInt(9)) + c2 := api.Sub(C0B1X, t) + t = api.MulConst(C1B1Y, big.NewInt(9)) + c3 := api.Sub(C1B1X, t) + t = api.MulConst(C0B2Y, big.NewInt(9)) + c4 := api.Sub(C0B2X, t) + t = api.MulConst(C1B2Y, big.NewInt(9)) + c5 := api.Sub(C1B2X, t) + + return sw_bn254.GTEl{ + A0: *c0, + A1: *c1, + A2: *c2, + A3: *c3, + A4: *c4, + A5: *c5, + A6: *C0B0Y, + A7: *C1B0Y, + A8: *C0B1Y, + A9: *C1B1Y, + A10: *C0B2Y, + A11: *C1B2Y, + } +} diff --git a/prover/zkevm/prover/publicInput/public_input.go b/prover/zkevm/prover/publicInput/public_input.go index 7ab94cd5d..555e8577a 100644 --- a/prover/zkevm/prover/publicInput/public_input.go +++ b/prover/zkevm/prover/publicInput/public_input.go @@ -17,6 +17,28 @@ import ( "github.com/ethereum/go-ethereum/common" ) +var ( + DataNbBytes = "DataNbBytes" + DataChecksum = "DataChecksum" + L2MessageHash = "L2MessageHash" + InitialStateRootHash = "InitialStateRootHash" + FinalStateRootHash = "FinalStateRootHash" + InitialBlockNumber = "InitialBlockNumber" + FinalBlockNumber = "FinalBlockNumber" + InitialBlockTimestamp = "InitialBlockTimestamp" + FinalBlockTimestamp = "FinalBlockTimestamp" + FirstRollingHashUpdate_0 = "FirstRollingHashUpdate_0" + FirstRollingHashUpdate_1 = "FirstRollingHashUpdate_1" + LastRollingHashUpdate_0 = "LastRollingHashUpdate_0" + LastRollingHashUpdate_1 = "LastRollingHashUpdate_1" + FirstRollingHashUpdateNumber = "FirstRollingHashUpdateNumber" + LastRollingHashNumberUpdate = "LastRollingHashNumberUpdate" + ChainID = "ChainID" + NBytesChainID = "NBytesChainID" + L2MessageServiceAddrHi = "L2MessageServiceAddrHi" + L2MessageServiceAddrLo = "L2MessageServiceAddrLo" +) + // PublicInput collects a number of submodules responsible for collecting the // wizard witness data holding the public inputs of the execution circuit. type PublicInput struct { @@ -302,4 +324,26 @@ func (pi *PublicInput) generateExtractor(comp *wizard.CompiledIOP) { L2MessageServiceAddrHi: accessors.NewFromPublicColumn(pi.Aux.logSelectors.L2BridgeAddressColHI, 0), L2MessageServiceAddrLo: accessors.NewFromPublicColumn(pi.Aux.logSelectors.L2BridgeAddressColLo, 0), } + + comp.PublicInputs = append(comp.PublicInputs, + wizard.PublicInput{Name: "DataNbBytes", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.DataNbBytes, 0)}, + wizard.PublicInput{Name: "DataChecksum", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.DataChecksum, 0)}, + wizard.PublicInput{Name: "L2MessageHash", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.L2MessageHash, 0)}, + wizard.PublicInput{Name: "InitialStateRootHash", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.InitialStateRootHash, 0)}, + wizard.PublicInput{Name: "FinalStateRootHash", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.FinalStateRootHash, 0)}, + wizard.PublicInput{Name: "InitialBlockNumber", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.InitialBlockNumber, 0)}, + wizard.PublicInput{Name: "FinalBlockNumber", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.FinalBlockNumber, 0)}, + wizard.PublicInput{Name: "InitialBlockTimestamp", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.InitialBlockTimestamp, 0)}, + wizard.PublicInput{Name: "FinalBlockTimestamp", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.FinalBlockTimestamp, 0)}, + wizard.PublicInput{Name: "FirstRollingHashUpdate[0]", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.FirstRollingHashUpdate[0], 0)}, + wizard.PublicInput{Name: "FirstRollingHashUpdate[1]", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.FirstRollingHashUpdate[1], 0)}, + wizard.PublicInput{Name: "LastRollingHashUpdate[0]", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.LastRollingHashUpdate[0], 0)}, + wizard.PublicInput{Name: "LastRollingHashUpdate[1]", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.LastRollingHashUpdate[1], 0)}, + wizard.PublicInput{Name: "FirstRollingHashUpdateNumber", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.FirstRollingHashUpdateNumber, 0)}, + wizard.PublicInput{Name: "LastRollingHashNumberUpdate", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.LastRollingHashUpdateNumber, 0)}, + wizard.PublicInput{Name: "ChainID", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.ChainID, 0)}, + wizard.PublicInput{Name: "NBytesChainID", Acc: accessors.NewLocalOpeningAccessor(pi.Extractor.NBytesChainID, 0)}, + wizard.PublicInput{Name: "L2MessageServiceAddrHi", Acc: pi.Extractor.L2MessageServiceAddrHi}, + wizard.PublicInput{Name: "L2MessageServiceAddrLo", Acc: pi.Extractor.L2MessageServiceAddrLo}, + ) } diff --git a/settings.gradle b/settings.gradle index 6a3fb0685..8ac12e88e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -71,5 +71,4 @@ include 'state-recover:appcore:domain-models' include 'state-recover:appcore:clients-interfaces' include 'state-recover:clients:blobscan-client' include 'state-recover:clients:execution-layer-json-rpc-client' -include 'state-recover:clients:smartcontract' include 'state-recover:clients:eth-api' diff --git a/state-recover/clients/smartcontract/build.gradle b/state-recover/clients/smartcontract/build.gradle deleted file mode 100644 index 05e0f07a1..000000000 --- a/state-recover/clients/smartcontract/build.gradle +++ /dev/null @@ -1,55 +0,0 @@ -import org.gradle.api.tasks.testing.logging.TestExceptionFormat -import org.gradle.api.tasks.testing.logging.TestLogEvent - -plugins { - id 'net.consensys.zkevm.kotlin-library-conventions' -} - -dependencies { - implementation(project(':jvm-libs:generic:extensions:kotlin')) - implementation(project(':jvm-libs:linea:web3j-extensions')) - implementation(project(':state-recover:appcore:clients-interfaces')) - implementation(project(':coordinator:clients:smart-contract-client')) - implementation('build.linea:l1-rollup-contract-client:6.0.0-rc2') - - testImplementation(project(':coordinator:core')) - testImplementation(project(":coordinator:ethereum:test-utils")) - testImplementation(project(":jvm-libs:linea:testing:l1-blob-and-proof-submission")) - testImplementation("io.vertx:vertx-junit5") -} - -sourceSets { - integrationTest { - kotlin { - compileClasspath += sourceSets.main.output - runtimeClasspath += sourceSets.main.output - } - compileClasspath += sourceSets.main.output + sourceSets.main.compileClasspath + sourceSets.test.compileClasspath - runtimeClasspath += sourceSets.main.output + sourceSets.main.runtimeClasspath + sourceSets.test.runtimeClasspath - } -} - -task integrationTest(type: Test) { test -> - description = "Runs integration tests." - group = "verification" - useJUnitPlatform() - - classpath = sourceSets.integrationTest.runtimeClasspath - testClassesDirs = sourceSets.integrationTest.output.classesDirs - - dependsOn(":localStackComposeUp") - - testLogging { - events TestLogEvent.FAILED, - TestLogEvent.SKIPPED, - TestLogEvent.STANDARD_ERROR, - TestLogEvent.STARTED, - TestLogEvent.PASSED - exceptionFormat TestExceptionFormat.FULL - showCauses true - showExceptions true - showStackTraces true - // set showStandardStreams if you need to see test logs - showStandardStreams false - } -}