diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fcecad6..1c72d20 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: - name: Build contracts to get sizes run: | forge --version - forge build --sizes + forge build --sizes --zksync test: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index febbf2a..fd594a5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Compiler files cache/ out/ +zkout/ # Ignores development broadcast logs !/broadcast @@ -17,3 +18,12 @@ lcov.info .vscode .idea node_modules + +# Artifacts +artifacts-zk/ + +# Cache +cache_hardhat-zk/ + +# Typechain +typechain-types/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index dd4cc20..928ace6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,7 @@ [submodule "lib/staker"] path = lib/staker url = https://github.com/withtally/staker +[submodule "lib/era-contracts"] + path = lib/era-contracts + url = https://github.com/matter-labs/era-contracts + branch = consensus-registry diff --git a/README.md b/README.md index 6050093..ee83640 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,15 @@ ZkStaker is built of of Tally's [Staker](https://github.com/withtally/staker) library, and incentivizes delegation within ZK Nation. The current system allows a ZK holder to stake their tokens and earn rewards in ZK tokens. Rewards are currently distributed via minting on a capped minter. In the future other reward sources can be added through a governance vote. -- [Overview](#overview) -- [Setup](#setup) -- [Development](#development) -- [Deployment](#deployment) -- [License](#license) +- [ZkStaker](#zkstaker) + - [Overview](#overview) + - [Setup](#setup) + - [Development](#development) + - [Deployment](#deployment) + - [Environment Variables](#environment-variables) + - [Script Constants](#script-constants) + - [Deployment Execution](#deployment-execution) + - [License](#license) ## Overview @@ -157,10 +161,11 @@ For a local deployment, use `zkSyncLocal` as the network-name: npx hardhat run script/DeployZkStaker.ts --network zkSyncLocal ``` -For a testnet deployment, use `zkSyncEraTestnet` as the network-name: +For a testnet deployment, use `zkSyncTestnet` as the network-name: ```bash -npx hardhat run script/DeployZkStaker.ts --network zkSyncEraTestnet +npx hardhat run script/DeployZkStaker.sepolia.ts --network zkSyncTestnet +npx hardhat run script/DeployConsensusRegistry.sepolia.ts --network zkSyncTestnet ``` For a mainnet deployment, use `zkSyncEra` as the network-name diff --git a/deployments-zk/zkSyncTestnet/era-contracts/l2-contracts/contracts/ConsensusRegistry.sol/ConsensusRegistry.json b/deployments-zk/zkSyncTestnet/era-contracts/l2-contracts/contracts/ConsensusRegistry.sol/ConsensusRegistry.json new file mode 100644 index 0000000..8996b0e --- /dev/null +++ b/deployments-zk/zkSyncTestnet/era-contracts/l2-contracts/contracts/ConsensusRegistry.sol/ConsensusRegistry.json @@ -0,0 +1,1254 @@ +{ + "sourceName": "era-contracts/l2-contracts/contracts/ConsensusRegistry.sol", + "contractName": "ConsensusRegistry", + "abi": [ + { + "inputs": [], + "name": "InvalidInputBLS12_381PublicKey", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInputBLS12_381Signature", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInputValidatorOwnerAddress", + "type": "error" + }, + { + "inputs": [], + "name": "NoActiveLeader", + "type": "error" + }, + { + "inputs": [], + "name": "NoPendingCommittee", + "type": "error" + }, + { + "inputs": [], + "name": "PreviousCommitStillPending", + "type": "error" + }, + { + "inputs": [], + "name": "UnauthorizedOnlyOwnerOrValidatorOwner", + "type": "error" + }, + { + "inputs": [], + "name": "ValidatorOwnerDoesNotExist", + "type": "error" + }, + { + "inputs": [], + "name": "ValidatorOwnerExists", + "type": "error" + }, + { + "inputs": [], + "name": "ValidatorOwnerNotFound", + "type": "error" + }, + { + "inputs": [], + "name": "ValidatorPubKeyExists", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroValidatorWeight", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newDelay", + "type": "uint256" + } + ], + "name": "CommitteeActivationDelayChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "uint64", + "name": "frequency", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "weighted", + "type": "bool" + } + ], + "indexed": false, + "internalType": "struct IConsensusRegistry.LeaderSelectionAttr", + "name": "newLeaderSelection", + "type": "tuple" + } + ], + "name": "LeaderSelectionChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validatorOwner", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isActive", + "type": "bool" + } + ], + "name": "ValidatorActiveStatusChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validatorOwner", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "validatorIsActive", + "type": "bool" + }, + { + "indexed": false, + "internalType": "bool", + "name": "validatorIsLeader", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "validatorWeight", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "b", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "c", + "type": "bytes32" + } + ], + "indexed": false, + "internalType": "struct IConsensusRegistry.BLS12_381PublicKey", + "name": "validatorPubKey", + "type": "tuple" + } + ], + "name": "ValidatorAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validatorOwner", + "type": "address" + } + ], + "name": "ValidatorDeleted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validatorOwner", + "type": "address" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "b", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "c", + "type": "bytes32" + } + ], + "indexed": false, + "internalType": "struct IConsensusRegistry.BLS12_381PublicKey", + "name": "newPubKey", + "type": "tuple" + } + ], + "name": "ValidatorKeyChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validatorOwner", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isLeader", + "type": "bool" + } + ], + "name": "ValidatorLeaderStatusChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validatorOwner", + "type": "address" + } + ], + "name": "ValidatorRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validatorOwner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newWeight", + "type": "uint256" + } + ], + "name": "ValidatorWeightChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "validatorsCommit", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "validatorsCommitBlock", + "type": "uint256" + } + ], + "name": "ValidatorsCommitted", + "type": "event" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "activeLeaderValidatorsCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_validatorOwner", + "type": "address" + }, + { + "internalType": "bool", + "name": "_validatorIsLeader", + "type": "bool" + }, + { + "internalType": "bool", + "name": "_validatorIsActive", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "_validatorWeight", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "b", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "c", + "type": "bytes32" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381PublicKey", + "name": "_validatorPubKey", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes16", + "name": "b", + "type": "bytes16" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381Signature", + "name": "_validatorPoP", + "type": "tuple" + } + ], + "name": "add", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_validatorOwner", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isActive", + "type": "bool" + } + ], + "name": "changeValidatorActive", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_validatorOwner", + "type": "address" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "b", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "c", + "type": "bytes32" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381PublicKey", + "name": "_pubKey", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes16", + "name": "b", + "type": "bytes16" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381Signature", + "name": "_pop", + "type": "tuple" + } + ], + "name": "changeValidatorKey", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_validatorOwner", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isLeader", + "type": "bool" + } + ], + "name": "changeValidatorLeader", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_validatorOwner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_weight", + "type": "uint256" + } + ], + "name": "changeValidatorWeight", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxDeletions", + "type": "uint256" + } + ], + "name": "cleanupRemovedValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "commitValidatorCommittee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "committeeActivationDelay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getNextValidatorCommittee", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "leader", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "b", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "c", + "type": "bytes32" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381PublicKey", + "name": "pubKey", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes16", + "name": "b", + "type": "bytes16" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381Signature", + "name": "proofOfPossession", + "type": "tuple" + } + ], + "internalType": "struct IConsensusRegistry.CommitteeValidator[]", + "name": "", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "frequency", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "weighted", + "type": "bool" + } + ], + "internalType": "struct IConsensusRegistry.LeaderSelectionAttr", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getValidatorCommittee", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "leader", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "b", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "c", + "type": "bytes32" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381PublicKey", + "name": "pubKey", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes16", + "name": "b", + "type": "bytes16" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381Signature", + "name": "proofOfPossession", + "type": "tuple" + } + ], + "internalType": "struct IConsensusRegistry.CommitteeValidator[]", + "name": "", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "frequency", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "weighted", + "type": "bool" + } + ], + "internalType": "struct IConsensusRegistry.LeaderSelectionAttr", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_initialOwner", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "leaderSelection", + "outputs": [ + { + "components": [ + { + "internalType": "uint64", + "name": "frequency", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "weighted", + "type": "bool" + } + ], + "internalType": "struct IConsensusRegistry.LeaderSelectionAttr", + "name": "latest", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "frequency", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "weighted", + "type": "bool" + } + ], + "internalType": "struct IConsensusRegistry.LeaderSelectionAttr", + "name": "snapshot", + "type": "tuple" + }, + { + "internalType": "uint64", + "name": "snapshotCommit", + "type": "uint64" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "frequency", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "weighted", + "type": "bool" + } + ], + "internalType": "struct IConsensusRegistry.LeaderSelectionAttr", + "name": "previousSnapshot", + "type": "tuple" + }, + { + "internalType": "uint64", + "name": "previousSnapshotCommit", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numRemovedValidators", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numValidators", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_validatorOwner", + "type": "address" + } + ], + "name": "remove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "removedValidators", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_delay", + "type": "uint256" + } + ], + "name": "setCommitteeActivationDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_frequency", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "_weighted", + "type": "bool" + } + ], + "name": "updateLeaderSelection", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "validatorOwners", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "validatorPubKeyHashes", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "validators", + "outputs": [ + { + "internalType": "uint32", + "name": "ownerIdx", + "type": "uint32" + }, + { + "components": [ + { + "internalType": "bool", + "name": "active", + "type": "bool" + }, + { + "internalType": "bool", + "name": "removed", + "type": "bool" + }, + { + "internalType": "bool", + "name": "leader", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "b", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "c", + "type": "bytes32" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381PublicKey", + "name": "pubKey", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes16", + "name": "b", + "type": "bytes16" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381Signature", + "name": "proofOfPossession", + "type": "tuple" + } + ], + "internalType": "struct IConsensusRegistry.ValidatorAttr", + "name": "latest", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bool", + "name": "active", + "type": "bool" + }, + { + "internalType": "bool", + "name": "removed", + "type": "bool" + }, + { + "internalType": "bool", + "name": "leader", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "b", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "c", + "type": "bytes32" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381PublicKey", + "name": "pubKey", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes16", + "name": "b", + "type": "bytes16" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381Signature", + "name": "proofOfPossession", + "type": "tuple" + } + ], + "internalType": "struct IConsensusRegistry.ValidatorAttr", + "name": "snapshot", + "type": "tuple" + }, + { + "internalType": "uint64", + "name": "snapshotCommit", + "type": "uint64" + }, + { + "components": [ + { + "internalType": "bool", + "name": "active", + "type": "bool" + }, + { + "internalType": "bool", + "name": "removed", + "type": "bool" + }, + { + "internalType": "bool", + "name": "leader", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "b", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "c", + "type": "bytes32" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381PublicKey", + "name": "pubKey", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes16", + "name": "b", + "type": "bytes16" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381Signature", + "name": "proofOfPossession", + "type": "tuple" + } + ], + "internalType": "struct IConsensusRegistry.ValidatorAttr", + "name": "previousSnapshot", + "type": "tuple" + }, + { + "internalType": "uint64", + "name": "previousSnapshotCommit", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "validatorsCommit", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "validatorsCommitBlock", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": "0x0002000000000002001200000000000200010000000103550000006003100270000006160030019d0000008004000039000000400040043f00000001002001900000001f0000c13d0000061602300197000000040020008c000016f90000413d000000000301043b000000e003300270000006180030009c000000270000a13d000006190030009c000000710000a13d0000061a0030009c000000ba0000213d000006200030009c000006500000213d000006230030009c000009eb0000613d000006240030009c000016f90000c13d0000000001000416000000000001004b000016f90000c13d0000009c010000390000099e0000013d0000000001000416000000000001004b000016f90000c13d0000002001000039000001000010044300000120000004430000061701000041000018540001042e0000062e0030009c000000360000213d000006380030009c000002c40000a13d000006390030009c000003f40000213d0000063c0030009c000007160000613d0000063d0030009c000016f90000c13d0000000001000416000000000001004b000016f90000c13d0000009a010000390000099e0000013d0000062f0030009c000003ba0000a13d000006300030009c000005d30000213d000006330030009c000008170000613d000006340030009c000016f90000c13d000000440020008c000016f90000413d0000000002000416000000000002004b000016f90000c13d0000000402100370000000000202043b000b00000002001d000006410020009c000016f90000213d0000002401100370000000000301043b0000003301000039000000000101041a00000641011001970000000002000411000000000021004b00000a380000c13d000a00000003001d0000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b0000000302100039000000000202041a000000000002004b0000006b0000c13d0000000402100039000000000202041a000000000002004b0000006b0000c13d0000000501100039000000000101041a000000000001004b00000a900000613d0000000a0000006b00000cdd0000c13d0000067f01000041000000000010043f00000659010000410000185500010430000006250030009c000003c50000a13d000006260030009c000005f50000213d000006290030009c0000092f0000613d0000062a0030009c000016f90000c13d0000000001000416000000000001004b000016f90000c13d000000c001000039000000400010043f000000800000043f000000a00000043f0000009701000039000000000101041a000800000001001d000006430010009c000011a10000213d000000080100002900000005021002100000003f012000390000066f031001970000065a0030009c000011a10000213d000000c001300039000000400010043f0000000804000029000000c00040043f000000000004004b00000aa00000c13d000000c00000043f0000065d0010009c000011a10000213d0000004002100039000000400020043f0000002002100039000000000002043500000000000104350000009e01000039000000000101041a000b00000001001d0000064a0100004100000000001004430000000001000414000006160010009c0000061601008041000000c0011002100000064b011001c70000800b020000391853184e0000040f0000000100200190000011980000613d0000009d02000039000000000202041a0000064302200197000000000101043b0000000b0010006c000000b00000813d000000010220008a000006430020009c00000b7a0000213d000000400300043d000000a201000039000000000101041a0000064301100197000000000012004b000011990000a13d0000065d0030009c000011a10000213d000000a001000039000011a70000013d0000061b0030009c000006590000213d0000061e0030009c00000a050000613d0000061f0030009c000016f90000c13d000001240020008c000016f90000413d0000000002000416000000000002004b000016f90000c13d0000000402100370000000000202043b000400000002001d000006410020009c000016f90000213d001000040000002d0000002402100370000000000302043b000000000003004b0000000002000039000000010200c039000300000003001d000000000023004b000016f90000c13d000f00030000002d0000004402100370000000000302043b000000000003004b0000000002000039000000010200c039000200000003001d000000000023004b000016f90000c13d000e00020000002d0000006401100370000000000101043b000100000001001d000d00000001001d000c00840000003d0000003301000039000000000101041a00000641011001970000000002000411000000000021004b00000a380000c13d0000009a01000039000000000101041a000000000001004b00000eae0000c13d0000000401000029000006410110019800000a720000613d000b00000001001d000000010000006b0000006d0000613d00000001010003670000008402100370000000000202043b000000000002004b000000ff0000c13d000000a402100370000000000202043b000000000002004b000000ff0000c13d000000c402100370000000000202043b000000000002004b00000ad40000613d000000e402100370000000000202043b000000000002004b000001090000c13d0000010401100370000000000101043b0000065300100198000016f90000c13d000006540010009c00000ae20000413d0000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b0000000302100039000000000202041a000000000002004b000014b30000c13d0000000402100039000000000202041a000000000002004b000014b30000c13d0000000501100039000000000101041a000000000001004b000014b30000c13d00000001010003670000008402100370000000000302043b000000a402100370000000000202043b000000c401100370000000000401043b000000400100043d00000060051000390000000000450435000000400410003900000000002404350000002002100039000000000032043500000060030000390000000000310435000006500010009c000011a10000213d0000008003100039000000400030043f000006160020009c000006160200804100000040022002100000000001010433000006160010009c00000616010080410000006001100210000000000121019f0000000002000414000006160020009c0000061602008041000000c002200210000000000112019f00000646011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000a00000001001d000000000010043f0000009901000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000101041a000000ff00100190000016a00000c13d0000000a01000029000000000010043f0000009901000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000201041a000006900220019700000001022001bf000000000021041b0000009702000039000000000102041a000006430010009c000011a10000213d0000000103100039000000000032041b000000000020043f0000064d0210009a000000000302041a00000645033001970000000b033001af000000000032041b000000400200043d0000065a0020009c000011a10000213d000000c003200039000000400030043f0000006003200039000000010400002900000000004304350000004003200039000000030400002900000000004304350000000203000029000000000332043600000000000304350000000003000031000000840430008a0000065b0040009c000016f90000213d000000600040008c000016f90000413d000000400500043d0000065c0050009c000011a10000213d0000006004500039000000400040043f00000001040003670000008406400370000000000606043b0000000006650436000000a407400370000000000707043b0000000000760435000000c406400370000000000606043b0000004007500039000000000067043500000080062000390000000000560435000000e40330008a000000400030008c000016f90000413d000000400300043d0000065d0030009c000011a10000213d0000004005300039000000400050043f000000e405400370000000000505043b00000000055304360000010404400370000000000404043b0000065300400198000016f90000c13d0000000000450435000000a0042000390000000000340435000000400400043d0000065c0040009c000011a10000213d0000006003400039000000400030043f00000040034000390000000000030435000000200340003900000000000304350000000000040435000000400500043d0000065d0050009c000011a10000213d0000004003500039000000400030043f000000200350003900000000000304350000000000050435000000400300043d0000065a0030009c000011a10000213d000000c006300039000000400060043f000000a0063000390000000000560435000000800530003900000000004504350000006004300039000000000004043500000040043000390000000000040435000000200430003900000000000404350000000000030435000000400500043d0000065c0050009c000011a10000213d0000009d04000039000000000404041a0000006006500039000000400060043f00000040065000390000000000060435000000200650003900000000000604350000000000050435000000400700043d0000065d0070009c000011a10000213d0000004006700039000000400060043f000000200670003900000000000604350000000000070435000000400600043d0000065a0060009c000011a10000213d000000c008600039000000400080043f000000a0086000390000000000780435000000800760003900000000005704350000006005600039000000000005043500000040056000390000000000050435000000200560003900000000000504350000000000060435000000400500043d000a00000005001d0000065a0050009c000011a10000213d000006160110019700000643044001970000000a07000029000000c005700039000000400050043f0000008005700039000800000005001d00000000006504350000006005700039000700000005001d00000000004504350000004004700039000600000004001d00000000003404350000002003700039000500000003001d00000000002304350000000000170435000000a001700039000900000001001d00000000000104350000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000000a0200002900000000020204330000061602200197000000000101043b000000000301041a0000064f03300197000000000223019f000000000021041b0000000103100039000000000203041a0000065704200197000000050200002900000000020204330000000065020434000000000005004b000000010440c1bf0000000005060433000000000005004b000001000440c1bf00000040052000390000000005050433000000000005004b00000655050000410000000005006019000000000454019f000000000043041b000000600320003900000000030304330000000204100039000000000034041b0000008003200039000000000303043300000003041000390000000065030434000000000054041b00000000040604330000000405100039000000000045041b000000400330003900000000030304330000000504100039000000000034041b000000a002200039000000000202043300000006031000390000000042020434000000000023041b000000000204043300000080022002700000000703100039000000000403041a0000064204400197000000000224019f000000000023041b0000000803100039000000000203041a0000065704200197000000060200002900000000020204330000000065020434000000000005004b000000010440c1bf0000000005060433000000000005004b000001000440c1bf00000040052000390000000005050433000000000005004b00000655050000410000000005006019000000000454019f000000000043041b000000600320003900000000030304330000000904100039000000000034041b000000800320003900000000030304330000000a041000390000000065030434000000000054041b00000000040604330000000b05100039000000000045041b000000400330003900000000030304330000000c04100039000000000034041b000000a00220003900000000020204330000000d031000390000000042020434000000000023041b000000000204043300000080022002700000000e03100039000000000403041a0000064204400197000000000224019f000000000023041b0000000702000029000000000202043300000643022001970000000f03100039000000000403041a0000065e04400197000000000224019f000000000023041b0000001003100039000000000203041a0000065704200197000000080200002900000000020204330000000065020434000000000005004b000000010440c1bf0000000005060433000000000005004b000001000440c1bf00000040052000390000000005050433000000000005004b00000655050000410000000005006019000000000454019f000000000043041b000000600320003900000000030304330000001104100039000000000034041b0000008003200039000000000303043300000012041000390000000065030434000000000054041b00000000040604330000001305100039000000000045041b000000400330003900000000030304330000001404100039000000000034041b000000a002200039000000000202043300000015031000390000000042020434000000000023041b000000000204043300000080022002700000001603100039000000000403041a0000064204400197000000000224019f000000000023041b0000001701100039000000090200002900000000020204330000064302200197000000000301041a0000065e03300197000000000223019f000000000021041b0002000e0000002d0003000f0000002d000000030000006b000015670000c13d0000156e0000013d0000063e0030009c000009bb0000613d0000063f0030009c000009860000613d000006400030009c000016f90000c13d000000440020008c000016f90000413d0000000002000416000000000002004b000016f90000c13d0000000402100370000000000202043b000b00000002001d000006410020009c000016f90000213d0000002401100370000000000201043b000000000002004b0000000001000039000000010100c039000a00000002001d000000000012004b000016f90000c13d0000003301000039000000000101041a00000641021001970000000001000411000000000012004b000002e40000613d0000000b0010006b000009db0000c13d0000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b0000000302100039000000000202041a000000000002004b000002fe0000c13d0000000402100039000000000202041a000000000002004b000002fe0000c13d0000000501100039000000000101041a000000000001004b00000a900000613d0000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000009e02000039000000000202041a000800000002001d000000000101043b000900000001001d0000064a0100004100000000001004430000000001000414000006160010009c0000061601008041000000c0011002100000064b011001c70000800b020000391853184e0000040f0000000100200190000011980000613d0000009d02000039000000000302041a0000064309300197000000000101043b000000080010006c0000000003090019000003250000813d000000010390008a0000066b0030009c00000b7a0000813d00000009070000290000001704700039000000000504041a0000064301500197000000000013004b0000000101700039000003300000213d0000001006700039000000000606041a0000ff00006001900000033c0000613d0000000f06700039000000000606041a0000064306600197000000000063004b000003390000213d0000000803700039000000000303041a0000ff00003001900000033c0000613d000000000301041a0000ff00003001900000132b0000c13d000000000301041a0000ff000030019000000a360000c13d0000000a0000006b0000000006000039000000010600c039000800ff0030019400000000070000390000000107006039000000000676013f000000010060019000000a360000c13d000706700030019b00000009060000290000000f06600039000600000006001d000000000606041a000500000006001d000006430b60019700000000009b004b000003ad0000813d000000090a0000290000001006a00039000000000706041a00000657077001970000000808a00039000400000008001d000000000c08041a000000ff00c00190000000010770c1bf0000ff0000c00190000001000770c1bf0000067000c0019800000655080000410000000008006019000000000787019f000000000076041b0000001106a000390000000907a00039000300000007001d000000000707041a000000000076041b0000001206a000390000000a07a00039000200000007001d000000000707041a000000000076041b0000001306a000390000000b07a00039000100000007001d000000000707041a000000000076041b0000001407a000390000000c09a00039000000000809041a000000000087041b0000001508a000390000000d07a00039000000000d07041a0000000000d8041b000000160ea0003900000000080e041a00000642068001970000000e08a00039000000000d08041a000006530fd001970000000006f6019f00000000006e041b0000065e0550019700000000055b019f000000000054041b000000080000006b0000000004000039000000010400c039000000070000006b00000655050000410000000005006019000000000445019f0000065705c00197000000000454019f0000000405000029000000000045041b0000000204a00039000000000404041a0000000305000029000000000045041b0000000304a00039000000000404041a0000000205000029000000000045041b0000000404a00039000000000404041a0000000105000029000000000045041b0000000504a00039000000000404041a000000000049041b0000000604a00039000000000404041a000000000047041b0000000704a000390000064205d00197000000000404041a0000065304400197000000000454019f000000000048041b00000005040000290000065e04400197000000000202041a0000064302200197000000000242019f0000000604000029000000000024041b00000690023001970000000a022001af000000000021041b000000070000006b0000159e0000613d0000009c01000039000000000201041a0000000a0000006b000015990000613d000006910020009c00000b7a0000613d00000001030000390000159c0000013d000006350030009c000009c90000613d000006360030009c0000099a0000613d000006370030009c000016f90000c13d0000000001000416000000000001004b000016f90000c13d0000009e010000390000099e0000013d0000062b0030009c000009df0000613d0000062c0030009c000009a20000613d0000062d0030009c000016f90000c13d0000000001000416000000000001004b000016f90000c13d185316fb0000040f000700000001001d185317100000040f000000a202000039000000000202041a000900000002001d000600000001001d185317250000040f000000a402000039000000000202041a000a00000002001d000800000001001d000000400200043d000b00000002001d00000007010000291853173a0000040f0000000b01000029000000400210003900000006010000291853173a0000040f000000090100002900000643011001970000000b0300002900000080023000390000000000120435000000a00230003900000008010000291853173a0000040f0000000a0100002900000643011001970000000b03000029000000e0023000390000000000120435000006160030009c0000061603008041000000400130021000000675011001c7000018540001042e0000063a0030009c000008250000613d0000063b0030009c000016f90000c13d000000240020008c000016f90000413d0000000002000416000000000002004b000016f90000c13d0000000401100370000000000101043b000500000001001d0000003301000039000000000101041a00000641011001970000000002000411000000000021004b00000a380000c13d0000009a01000039000000000101041a000000000001004b00000a360000613d000b00000000001d000700000000001d000004130000013d00000001033000390000009a01000039000000000101041a000b00000003001d000000000013004b00000a360000813d0000000702000029000000050020006c00000a360000813d0000000b01000029000006480110009a000600000001001d000000000101041a0000064101100197000a00000001001d000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b0000000302100039000000000202041a000000000002004b000004350000c13d0000000402100039000000000202041a000000000002004b000004350000c13d0000000501100039000000000101041a000000000001004b000005850000613d0000000a01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000009e02000039000000000202041a000800000002001d000000000101043b000900000001001d0000064a0100004100000000001004430000000001000414000006160010009c0000061601008041000000c0011002100000064b011001c70000800b020000391853184e0000040f0000000100200190000011980000613d0000009d02000039000000000202041a0000064302200197000000000101043b000000080010006c0000045e0000813d000000010220008a000006430020009c0000000b030000290000000904000029000004600000a13d00000b7a0000013d0000000b0300002900000009040000290000001701400039000000000101041a0000064301100197000000000012004b000004690000213d0000001001400039000000000101041a0000ff00001001900000040d0000613d0000000f01400039000000000101041a0000064301100197000000000012004b000004720000213d0000000801400039000000000101041a0000ff00001001900000040d0000613d0000000101400039000000000101041a0000ff00001001900000040d0000613d0000009701000039000000000101041a000000000001004b00000b7a0000613d000000000204041a0000061602200197000000000021004b000016d70000a13d0000064c0110009a000000000101041a000806410010019b0000064d0120009a000000000201041a000006450220019700000008022001af000000000021041b0000009701000039000000000101041a000400000001001d000000000001004b000014ad0000613d0000009701000039000000000010043f0000000001000414000006160010009c0000061601008041000000c0011002100000064e011001c700008010020000391853184e0000040f00000001002001900000000904000029000016f90000613d0000000402000029000000010220008a000000000101043b0000000001210019000000000301041a0000064503300197000000000031041b0000009701000039000000000021041b000000000104041a000400000001001d0000000801000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f00000009040000290000000100200190000016f90000613d00000004020000290000061602200197000000000101043b000000000301041a0000064f03300197000000000223019f000000000021041b0000000301400039000000000301041a0000000401400039000000000201041a0000000501400039000000000401041a000000400100043d0000006005100039000000000045043500000040041000390000000000240435000000600200003900000000022104360000000000320435000006500010009c000011a10000213d0000008003100039000000400030043f000006160020009c000006160200804100000040022002100000000001010433000006160010009c00000616010080410000006001100210000000000121019f0000000002000414000006160020009c0000061602008041000000c002200210000000000112019f00000646011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000010043f0000009901000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000201041a0000069002200197000000000021041b0000000a01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000001041b0000000102100039000000000002041b0000000202100039000000000002041b0000000302100039000000000002041b0000000402100039000000000002041b0000000502100039000000000002041b0000000602100039000000000002041b0000000702100039000000000002041b0000000802100039000000000002041b0000000902100039000000000002041b0000000a02100039000000000002041b0000000b02100039000000000002041b0000000c02100039000000000002041b0000000d02100039000000000002041b0000000e02100039000000000002041b0000000f02100039000000000002041b0000001002100039000000000002041b0000001102100039000000000002041b0000001202100039000000000002041b0000001302100039000000000002041b0000001402100039000000000002041b0000001502100039000000000002041b0000001602100039000000000002041b0000001701100039000000000001041b0000000001000414000006160010009c0000061601008041000000c00110021000000646011001c70000800d02000039000000020300003900000651040000410000000a05000029185318490000040f0000000100200190000016f90000613d0000009a01000039000000000501041a0000000b02000029000000000025004b000016d70000a13d0000000603000029000000000403041a000000010150008a000000000021004b000a00000004001d000005420000c13d000900000005001d0000055d0000013d0000064501400197000006520250009a000000000202041a0000064102200197000000000112019f000000000013041b000000000020043f0000009b01000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b0000000b020000290000000102200039000000000021041b0000009a01000039000000000101041a000900000001001d000000000001004b000014ad0000613d0000009a01000039000000000010043f0000000001000414000006160010009c0000061601008041000000c0011002100000064e011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000000a0200002900000641022001970000000903000029000000010330008a000000000101043b0000000001310019000000000401041a0000064504400197000000000041041b0000009a01000039000000000031041b000000000020043f0000009b01000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000001041b0000000701000029000700010010003d0000000b030000290000040e0000013d0000009a01000039000000000501041a0000000b02000029000000000025004b000016d70000a13d0000000603000029000000000403041a000000010150008a000000000021004b000a00000004001d000005920000c13d000900000005001d000005ad0000013d0000064501400197000006520250009a000000000202041a0000064102200197000000000112019f000000000013041b000000000020043f0000009b01000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b0000000b020000290000000102200039000000000021041b0000009a01000039000000000101041a000900000001001d000000000001004b000014ad0000613d0000009a01000039000000000010043f0000000001000414000006160010009c0000061601008041000000c0011002100000064e011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000000a0200002900000641022001970000000903000029000000010330008a000000000101043b0000000001310019000000000401041a0000064504400197000000000041041b0000009a01000039000000000031041b000000000020043f0000009b01000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000001041b0000000b030000290000040e0000013d000006310030009c000009160000613d000006320030009c000016f90000c13d0000000001000416000000000001004b000016f90000c13d0000003301000039000000000101041a00000641011001970000000002000411000000000021004b00000a380000c13d0000009e01000039000000000101041a000b00000001001d0000064a0100004100000000001004430000000001000414000006160010009c0000061601008041000000c0011002100000064b011001c70000800b020000391853184e0000040f0000000100200190000011980000613d000000000101043b0000000b0010006c00000a980000813d0000067d01000041000000000010043f00000659010000410000185500010430000006270030009c000009340000613d000006280030009c000016f90000c13d0000000001000416000000000001004b000016f90000c13d000000c001000039000000400010043f000000800000043f000000a00000043f0000009e01000039000000000101041a000b00000001001d0000064a0100004100000000001004430000000001000414000006160010009c0000061601008041000000c0011002100000064b011001c70000800b020000391853184e0000040f0000000100200190000011980000613d000000000101043b0000000b0010006c00000a940000813d0000009701000039000000000101041a000a00000001001d000006430010009c000011a10000213d0000000a0100002900000005011002100000003f021000390000066f02200197000000400300043d0000000002230019000600000003001d000000000032004b00000000030000390000000103004039000006430020009c000011a10000213d0000000100300190000011a10000c13d000000400020043f00000006020000290000000a030000290000000008320436000000000003004b000700000000001d00000d930000c13d000000060100002900000007020000290000000000210435000000400100043d0000065d0010009c000011a10000213d0000004002100039000000400020043f000000200210003900000000000204350000000000010435000000400300043d0000065d0030009c000011a10000213d0000009d01000039000000000101041a000000a202000039000000000202041a0000004004300039000000400040043f00000643022001970000064301100197000000000021004b000000a101000039000000a001002039000000000101041a00000671001001980000000002000039000000010200c0390000002004300039000000000024043500000643011001970000000000130435000000400100043d000b00000001001d0000000602000029000011b40000013d000006210030009c00000a0e0000613d000006220030009c000016f90000c13d0000000001000416000000000001004b000016f90000c13d0000009f010000390000099e0000013d0000061c0030009c00000a170000613d0000061d0030009c000016f90000c13d000000240020008c000016f90000413d0000000002000416000000000002004b000016f90000c13d0000000401100370000000000101043b000006410010009c000016f90000213d000000000010043f0000009801000039000000200010043f00000040020000390000000001000019185318340000040f0000000002010019000b00000001001d000000000101041a000800000001001d0000000101200039185317790000040f000700000001001d0000000b010000290000000801100039185317790000040f0000000b030000290000000f02300039000000000202041a000a00000002001d000900000001001d0000001001300039185317790000040f000000080200002900000616042001970000000b020000290000001702200039000000000302041a000000400200043d000000000442043600000007080000290000000065080434000000000005004b0000000005000039000000010500c03900000000005404350000000004060433000000000004004b0000000004000039000000010400c0390000004005200039000000000045043500000040048000390000000004040433000000000004004b0000000004000039000000010400c03900000060052000390000000000450435000000600480003900000000040404330000008005200039000000000045043500000080048000390000000004040433000000a005200039000000007604043400000000006504350000000005070433000000c006200039000000000056043500000040044000390000000004040433000000e0052000390000000000450435000000a0048000390000000004040433000001000520003900000000640404340000000000450435000000000406043300000642044001970000012005200039000000000045043500000009070000290000000054070434000000000004004b0000000004000039000000010400c039000001400620003900000000004604350000000004050433000000000004004b0000000004000039000000010400c0390000016005200039000000000045043500000040047000390000000004040433000000000004004b0000000004000039000000010400c0390000018005200039000000000045043500000060047000390000000004040433000001a0052000390000000000450435000000800470003900000000080700190000000004040433000001c005200039000000007604043400000000006504350000000005070433000001e00620003900000000005604350000004004400039000000000404043300000200052000390000000000450435000000a00480003900000000040404330000022005200039000000006404043400000000004504350000000a0400002900000643044001970000000005060433000002600620003900000000004604350000064204500197000002400520003900000000004504350000000054010434000000000004004b0000000004000039000000010400c039000002800620003900000000004604350000000004050433000000000004004b0000000004000039000000010400c039000002a005200039000000000045043500000040041000390000000004040433000000000004004b0000000004000039000000010400c039000002c005200039000000000045043500000060041000390000000004040433000002e0052000390000000000450435000000800410003900000000040404330000030005200039000000007604043400000000006504350000000005070433000003200620003900000000005604350000004004400039000000000404043300000340052000390000000000450435000000a001100039000000000101043300000360042000390000000051010434000000000014043500000643013001970000000003050433000003a0042000390000000000140435000006420130019700000380032000390000000000130435000006160020009c0000061602008041000000400120021000000644011001c7000018540001042e000000240020008c000016f90000413d0000000002000416000000000002004b000016f90000c13d0000000401100370000000000101043b000b00000001001d000006410010009c000016f90000213d0000003301000039000000000101041a00000641011001970000000002000411000000000021004b00000a380000c13d0000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b0000000302100039000000000202041a000000000002004b000007400000c13d0000000402100039000000000202041a000000000002004b000007400000c13d0000000501100039000000000101041a000000000001004b00000a900000613d0000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000009e02000039000000000202041a000900000002001d000000000101043b000a00000001001d0000064a0100004100000000001004430000000001000414000006160010009c0000061601008041000000c0011002100000064b011001c70000800b020000391853184e0000040f0000000100200190000011980000613d0000009d02000039000000000302041a0000064307300197000000000101043b000000090010006c0000000003070019000007670000813d000000010370008a000006430030009c00000b7a0000213d0000000a020000290000001704200039000000000504041a0000064301500197000000000013004b0000000f012000390000000108200039000007740000213d0000000a020000290000001006200039000000000606041a0000ff0000600190000007800000613d000000000601041a0000064306600197000000000063004b0000077d0000213d0000000a020000290000000803200039000000000303041a0000ff0000300190000007800000613d000000000308041a0000ff0000300190000011bf0000c13d000900000008001d000000000308041a0000ff000030019000000a360000c13d000000000201041a000800000002001d000706430020019b000000070070006b000007e10000813d0000000a080000290000001006800039000000000706041a00000657077001970000000802800039000600000002001d000000000902041a000000ff00900190000000010770c1bf0000ff0000900190000001000770c1bf0000067000900198000006550b000041000000000b0060190000000007b7019f000000000076041b00000011068000390000000902800039000500000002001d000000000b02041a0000000000b6041b00000012068000390000000a0b800039000000000c0b041a0000000000c6041b00000013068000390000000b0c800039000000000d0c041a0000000000d6041b00000014068000390000000c0d800039000000000e0d041a0000000000e6041b00000015068000390000000d0e800039000000000f0e041a0000000000f6041b000000160a80003900000000060a041a00000642026001970000000e0f80003900000000060f041a0000065307600197000000000272019f00000000002a041b0000065e0250019700000007022001af000000000024041b000000ff003001900000000002000039000000010200c039000006700030019800000655040000410000000004006019000000000224019f0000065704900197000000000242019f0000000604000029000000000024041b0000000202800039000000000202041a0000000504000029000000000024041b0000000302800039000000000202041a00000000002b041b0000000402800039000000000202041a00000000002c041b0000000502800039000000000202041a00000000002d041b0000000602800039000000000202041a00000000002e041b00000007028000390000064204600197000000000202041a0000065302200197000000000242019f00000000002f041b00000008020000290000065e022001970000009d04000039000000000404041a0000064304400197000000000224019f000000000021041b000006920130019700000100011001bf0000000902000029000000000012041b0000009a01000039000000000201041a000006430020009c000011a10000213d0000000103200039000000000031041b000006480220009a000000000302041a00000645033001970000000b04000029000000000343019f000000000032041b000000000101041a000a00000001001d000000000040043f0000009b01000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b0000000a02000029000000000021041b0000000901000029000000000101041a00000670001001980000080e0000613d000000ff001001900000080e0000613d0000009c01000039000000000201041a000000000002004b00000b7a0000613d000000010220008a000000000021041b0000000001000414000006160010009c0000061601008041000000c00110021000000646011001c70000800d0200003900000002030000390000068904000041000015c20000013d000000240020008c000016f90000413d0000000002000416000000000002004b000016f90000c13d0000000401100370000000000101043b0000009702000039000000000302041a000000000031004b000016f90000813d000000000020043f0000064d0110009a00000a120000013d000000440020008c000016f90000413d0000000002000416000000000002004b000016f90000c13d0000000402100370000000000202043b000b00000002001d000006410020009c000016f90000213d0000002401100370000000000201043b000000000002004b0000000001000039000000010100c039000a00000002001d000000000012004b000016f90000c13d0000003301000039000000000101041a00000641011001970000000002000411000000000021004b00000a380000c13d0000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b0000000302100039000000000202041a000000000002004b000008570000c13d0000000402100039000000000202041a000000000002004b000008570000c13d0000000501100039000000000101041a000000000001004b00000a900000613d0000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000009e02000039000000000202041a000800000002001d000000000101043b000900000001001d0000064a0100004100000000001004430000000001000414000006160010009c0000061601008041000000c0011002100000064b011001c70000800b020000391853184e0000040f0000000100200190000011980000613d0000009d02000039000000000302041a0000064309300197000000000101043b000000080010006c00000000030900190000087e0000813d000000010390008a000006430030009c00000b7a0000213d00000009070000290000001704700039000000000504041a0000064301500197000000000013004b0000000101700039000008890000213d0000001006700039000000000606041a0000ff0000600190000008950000613d0000000f06700039000000000606041a0000064306600197000000000063004b000008920000213d0000000803700039000000000303041a0000ff0000300190000008950000613d000000000301041a0000ff0000300190000013e10000c13d000000000301041a0000ff000030019000000a360000c13d0000000a0000006b0000000006000039000000010600c039000806700030019c00000000070000390000000107006039000000000676013f000000010060019000000a360000c13d000700ff0030019300000009060000290000000f06600039000600000006001d000000000606041a000500000006001d000006430b60019700000000009b004b000009060000813d000000090a0000290000001006a00039000000000706041a00000657077001970000000808a00039000400000008001d000000000c08041a000000ff00c00190000000010770c1bf0000ff0000c00190000001000770c1bf0000067000c0019800000655080000410000000008006019000000000787019f000000000076041b0000001106a000390000000907a00039000300000007001d000000000707041a000000000076041b0000001206a000390000000a07a00039000200000007001d000000000707041a000000000076041b0000001306a000390000000b07a00039000100000007001d000000000707041a000000000076041b0000001407a000390000000c09a00039000000000809041a000000000087041b0000001508a000390000000d07a00039000000000d07041a0000000000d8041b000000160ea0003900000000080e041a00000642068001970000000e08a00039000000000d08041a000006530fd001970000000006f6019f00000000006e041b0000065e0550019700000000055b019f000000000054041b000000070000006b0000000004000039000000010400c039000000080000006b00000655050000410000000005006019000000000445019f0000065705c00197000000000454019f0000000405000029000000000045041b0000000204a00039000000000404041a0000000305000029000000000045041b0000000304a00039000000000404041a0000000205000029000000000045041b0000000404a00039000000000404041a0000000105000029000000000045041b0000000504a00039000000000404041a000000000049041b0000000604a00039000000000404041a000000000047041b0000000704a000390000064205d00197000000000404041a0000065304400197000000000454019f000000000048041b00000005040000290000065e04400197000000000202041a0000064302200197000000000242019f0000000604000029000000000024041b0000000a0000006b000006550200004100000000020060190000068503300197000000000223019f000000000021041b000000070000006b000015b30000613d0000009c01000039000000000201041a0000000a0000006b000015ae0000613d000006910020009c00000b7a0000613d0000000103000039000015b10000013d0000000001000416000000000001004b000016f90000c13d0000003301000039000000000201041a00000641052001970000000003000411000000000035004b00000a380000c13d0000006503000039000000000403041a0000064504400197000000000043041b0000064502200197000000000021041b0000000001000414000006160010009c0000061601008041000000c00110021000000646011001c70000800d0200003900000003030000390000066804000041000000000600001900000a330000013d0000000001000416000000000001004b000016f90000c13d000000330100003900000a120000013d000000440020008c000016f90000413d0000000002000416000000000002004b000016f90000c13d0000000402100370000000000202043b000006430020009c000016f90000213d0000002401100370000000000101043b000000000001004b0000000003000039000000010300c039000000000031004b000016f90000c13d0000003303000039000000000303041a00000641033001970000000004000411000000000043004b00000a380000c13d000000a003000039000000000403041a0000009d05000039000000000505041a0000064305500197000000a206000039000000000706041a0000064308700197000000000058004b000009700000813d000000a309000039000000000a09041a0000066a0aa00197000000a10b000039000000000c0b041a000006430dc00197000000000ada019f0000067100c001980000066b0d000041000000000d006019000000000ada019f0000000000a9041b000000a409000039000000000a09041a0000065e0aa0019700000000088a019f000000000089041b000006430840019700000671004001980000066b090000410000000009006019000000000889019f0000066a09c00197000000000898019f00000000008b041b0000065e07700197000000000575019f000000000056041b000000c005000039000000400050043f0000066a04400197000000000001004b00000000050000190000066b0500c041000000000445019f000000800020043f000000a00010043f000000000424019f000000000043041b000000c00020043f000000e00010043f0000000001000414000006160010009c0000061601008041000000c00110021000000672011001c70000800d0200003900000001030000390000067304000041000009ba0000013d000000240020008c000016f90000413d0000000002000416000000000002004b000016f90000c13d0000000401100370000000000101043b000000000010043f0000009901000039000000200010043f00000040020000390000000001000019185318340000040f000000000101041a000000ff001001900000000001000039000000010100c039000000800010043f0000066101000041000018540001042e0000000001000416000000000001004b000016f90000c13d0000009701000039000000000101041a000000800010043f0000066101000041000018540001042e000000240020008c000016f90000413d0000000002000416000000000002004b000016f90000c13d0000003302000039000000000202041a00000641022001970000000003000411000000000032004b00000a380000c13d0000000401100370000000000101043b0000009f02000039000000000012041b000000800010043f0000000001000414000006160010009c0000061601008041000000c00110021000000676011001c70000800d020000390000000103000039000006770400004100000a330000013d000000240020008c000016f90000413d0000000002000416000000000002004b000016f90000c13d0000000401100370000000000101043b0000009a02000039000000000302041a000000000031004b000016f90000813d000000000020043f000006480110009a00000a120000013d000000c40020008c000016f90000413d0000000002000416000000000002004b000016f90000c13d0000000401100370000000000101043b000b00000001001d000006410010009c000016f90000213d0000003301000039000000000101041a00000641021001970000000001000411000000000012004b00000a760000613d0000000b0010006b00000a760000613d0000068a01000041000000000010043f000006590100004100001855000104300000000001000416000000000001004b000016f90000c13d0000006501000039000000000101041a00000641021001970000000001000411000000000012004b00000a410000c13d1853181a0000040f0000000001000019000018540001042e000000240020008c000016f90000413d0000000002000416000000000002004b000016f90000c13d0000000401100370000000000101043b000b00000001001d000006410010009c000016f90000213d0000000001000415000000120110008a0000000501100210000000000200041a0009ff000020019400000a4d0000c13d0000000001000415000000110110008a0000000501100210000000ff0020019000000a4d0000c13d000006900120019700000001011001bf000006920110019700000100011001bf00000a6e0000013d0000000001000416000000000001004b000016f90000c13d0000009d01000039000000000101041a0000064301100197000000800010043f0000066101000041000018540001042e0000000001000416000000000001004b000016f90000c13d0000006501000039000000000101041a0000064101100197000000800010043f0000066101000041000018540001042e000000240020008c000016f90000413d0000000002000416000000000002004b000016f90000c13d0000000401100370000000000601043b000006410060009c000016f90000213d0000003301000039000000000101041a00000641051001970000000001000411000000000015004b00000a380000c13d0000006501000039000000000201041a0000064502200197000000000262019f000000000021041b0000000001000414000006160010009c0000061601008041000000c00110021000000646011001c70000800d0200003900000003030000390000064704000041185318490000040f0000000100200190000016f90000613d0000000001000019000018540001042e0000066601000041000000800010043f0000002001000039000000840010043f000000a40010043f0000068701000041000000c40010043f000006880100004100001855000104300000066601000041000000800010043f0000002001000039000000840010043f0000002901000039000000a40010043f0000067801000041000000c40010043f0000067901000041000000e40010043f0000067a010000410000185500010430000800000002001d000a00000001001d00000662010000410000000000100443000000000100041000000004001004430000000001000414000006160010009c0000061601008041000000c00110021000000663011001c700008002020000391853184e0000040f0000000100200190000011980000613d000000000101043b000000000001004b00000ae60000c13d0000000801000029000000ff0110018f000000010010008c0000000a010000290000000501100270000000000100003f000000010100603f00000ae90000c13d000000000200041a000006900120019700000001011001bf000000090000006b0000ff010200608a000000000121616f00000100011061bf000000000010041b0000000b06000029000000000006004b00000afd0000c13d0000066d01000041000000000010043f000006590100004100001855000104300000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b0000000302100039000000000202041a000000000002004b00000ac70000c13d0000000402100039000000000202041a000000000002004b00000ac70000c13d0000000501100039000000000101041a000000000001004b00000ac70000c13d0000068f01000041000000000010043f000006590100004100001855000104300000066e01000041000000000010043f000006590100004100001855000104300000009c02000039000000000202041a000000000002004b00000b750000c13d0000067c01000041000000000010043f00000659010000410000185500010430000006740030009c000011a10000213d00000000030000190000008004100039000000400040043f000000200410003900000000000404350000000000010435000000400400043d0000065c0040009c000011a10000213d0000006005400039000000400050043f0000004005400039000000000005043500000020054000390000000000050435000000000004043500000040051000390000000000450435000000400400043d0000065d0040009c000011a10000213d0000004005400039000000400050043f00000020054000390000000000050435000000000004043500000060051000390000000000450435000000e00430003900000000001404350000002003300039000000000023004b000010740000813d000000400100043d000006500010009c00000aa30000a13d000011a10000013d00000001010003670000002402100370000000000202043b000000000002004b00000ad80000c13d0000004402100370000000000202043b000000000002004b00000ad80000c13d0000006402100370000000000202043b000000000002004b00000ad80000c13d0000068401000041000000000010043f000006590100004100001855000104300000008402100370000000000202043b000000000002004b00000b800000c13d000000a401100370000000000101043b0000065300100198000016f90000c13d000006530010009c00000b800000213d0000068301000041000000000010043f000006590100004100001855000104300000000a010000290000000501100270000000000100003f000000400100043d00000064021000390000066403000041000000000032043500000044021000390000066503000041000000000032043500000024021000390000002e03000039000000000032043500000666020000410000000000210435000000040210003900000020030000390000000000320435000006160010009c0000061601008041000000400110021000000667011001c700001855000104300000006501000039000000000201041a0000064502200197000000000021041b0000003301000039000000000201041a0000064503200197000000000363019f000000000031041b00000000010004140000064105200197000006160010009c0000061601008041000000c00110021000000646011001c70000800d0200003900000003030000390000066804000041185318490000040f0000000100200190000016f90000613d000000400500043d0000065d0050009c000011a10000213d0000004001500039000000400010043f000000010300003900000000073504360000000000070435000000400400043d0000065d0040009c000011a10000213d0000004001400039000000400010043f00000000063404360000000000060435000000400100043d0000065d0010009c000011a10000213d0000004002100039000000400020043f00000000023104360000000000020435000000400800043d000006690080009c000011a10000213d000000a009800039000000400090043f00000060098000390000000000190435000000200980003900000000004904350000008009800039000000000009043500000000005804350000004008800039000000000008043500000000050504330000064305500197000000a008000039000000000908041a0000066a09900197000000000559019f0000000007070433000000000007004b0000066b070000410000000007006019000000000575019f000000000058041b00000000040404330000064304400197000000a105000039000000000705041a0000066a07700197000000000447019f0000000006060433000000000006004b0000066b060000410000000006006019000000000464019f000000000045041b000000a204000039000000000504041a0000065e05500197000000000054041b00000000010104330000064301100197000000a304000039000000000504041a0000066a05500197000000000115019f0000000002020433000000000002004b0000066b020000410000000002006019000000000121019f000000000014041b000000a401000039000000000201041a0000065e02200197000000000021041b000000090000006b00000a360000c13d000000000200041a0000069201200197000000000010041b000000400100043d0000000000310435000006160010009c000006160100804100000040011002100000000002000414000006160020009c0000061602008041000000c002200210000000000112019f0000064e011001c70000800d020000390000066c04000041000009ba0000013d0000009d03000039000000000203041a0000064304200197000006430040009c00000e920000c13d0000068b01000041000000000010043f0000001101000039000000040010043f0000068c0100004100001855000104300000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000009e02000039000000000202041a000900000002001d000000000101043b000a00000001001d0000064a0100004100000000001004430000000001000414000006160010009c0000061601008041000000c0011002100000064b011001c70000800b020000391853184e0000040f0000000100200190000011980000613d0000009d02000039000000000202041a0000064302200197000000000101043b000000090010006c00000ba60000813d000000010220008a000006430020009c00000b7a0000213d0000000a030000290000001701300039000900000001001d000000000101041a0000064301100197000000000012004b000000010430003900000bb20000213d0000001001300039000000000101041a0000ff000010019000000bbe0000613d0000000f01300039000000000101041a0000064301100197000000000012004b00000bbb0000213d0000000801300039000000000101041a0000ff000010019000000bbe0000613d000000000104041a0000ff0000100190000012750000c13d000800000004001d000000000104041a0000ff000010019000000a360000c13d0000000a01000029000000050410003900000004021000390000000301100039000500000001001d000000000301041a000600000002001d000000000202041a000700000004001d000000000404041a000000400100043d00000060051000390000000000450435000000400410003900000000002404350000002002100039000000000032043500000060030000390000000000310435000006500010009c000011a10000213d0000008003100039000000400030043f000006160020009c000006160200804100000040022002100000000001010433000006160010009c00000616010080410000006001100210000000000121019f0000000002000414000006160020009c0000061602008041000000c002200210000000000112019f00000646011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000400000001001d00000001010003670000002402100370000000000302043b0000004402100370000000000202043b0000006401100370000000000401043b000000400100043d00000060051000390000000000450435000000400410003900000000002404350000002002100039000000000032043500000060030000390000000000310435000006500010009c000011a10000213d0000008003100039000000400030043f000006160020009c000006160200804100000040022002100000000001010433000006160010009c00000616010080410000006001100210000000000121019f0000000002000414000006160020009c0000061602008041000000c002200210000000000112019f00000646011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000201043b000300000002001d000000040020006b00000a360000613d0000000301000029000000000010043f0000009901000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000101041a000000ff00100190000016a00000c13d0000000401000029000000000010043f0000009901000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000201041a0000069002200197000000000021041b0000000301000029000000000010043f0000009901000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000201041a000006900220019700000001022001bf000000000021041b0000000a02000029000400060020003d0000000f03200039000000000403041a00000643064001970000009d01000039000000000101041a0000064301100197000000000016004b000300070020003d00000caf0000813d0000000a020000290000001007200039000000000507041a00000657095001970000000801200039000200000001001d000000000801041a000000ff00800190000000010990c1bf0000ff0000800190000001000990c1bf0000067000800198000006550a000041000000000a0060190000000009a9019f000000000097041b00000011092000390000000907200039000000000a07041a0000000000a9041b000000120a2000390000000a09200039000000000b09041a0000000000ba041b000000130b2000390000000b0a200039000000000c0a041a0000000000cb041b000000140c2000390000000c0b200039000000000d0b041a0000000000dc041b000000150d2000390000000d0c200039000000000e0c041a0000000000ed041b000000160f200039000000000d0f041a0000064201d001970000000e0d200039000000000e0d041a0000065305e00197000000000151019f00000000001f041b0000000905000029000000000105041a0000065e01100197000000000161019f000000000015041b00000657018001970000000805000029000000000505041a000000ff00500190000000010110c1bf0000ff0000500190000001000110c1bf000006700050019800000655050000410000000005006019000000000151019f0000000205000029000000000015041b0000000201200039000000000101041a000000000017041b0000000501000029000000000101041a000000000019041b0000000601000029000000000101041a00000000001a041b0000000701000029000000000101041a00000000001b041b0000000401000029000000000101041a00000000001c041b0000064201e001970000000302000029000000000502041a0000065305500197000000000115019f00000000001d041b0000065e014001970000009d02000039000000000402041a0000064304400197000000000114019f000000000013041b00000001010003670000002403100370000000000303043b0000000502000029000000000032041b0000004404100370000000000404043b0000000602000029000000000042041b0000006405100370000000000505043b0000000702000029000000000052041b0000008406100370000000000606043b0000000402000029000000000062041b000000a401100370000000000201043b0000065300200198000016f90000c13d00000080012002700000000306000029000000000206041a0000064202200197000000000112019f000000000016041b000000400100043d00000040021000390000000000520435000000200210003900000000004204350000000000310435000006160010009c000006160100804100000040011002100000000002000414000006160020009c0000061602008041000000c002200210000000000112019f00000681011001c70000800d0200003900000002030000390000068204000041000015c20000013d0000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000009e02000039000000000202041a000800000002001d000000000101043b000900000001001d0000064a0100004100000000001004430000000001000414000006160010009c0000061601008041000000c0011002100000064b011001c70000800b020000391853184e0000040f0000000100200190000011980000613d0000009d02000039000000000302041a0000064308300197000000000101043b000000080010006c000000000608001900000d040000813d000000010680008a000006430060009c00000b7a0000213d00000009020000290000001703200039000000000503041a0000064301500197000000000016004b0000000f01200039000000010420003900000d110000213d00000009020000290000001007200039000000000707041a0000ff000070019000000d1d0000613d000000000701041a0000064307700197000000000076004b00000d1a0000213d00000009020000290000000806200039000000000606041a0000ff000060019000000d1d0000613d000000000604041a0000ff0000600190000014970000c13d000000000704041a0000ff000070019000000a360000c13d0000000902000029000800020020003d000000000201041a000700000002001d0000064302200197000000000082004b00000d810000813d00000009090000290000001004900039000000000804041a000006570b8001970000000806900039000600000006001d000000000a06041a000000ff00a00190000000010bb0c1bf0000ff0000a00190000001000bb0c1bf0000067000a00198000006550c000041000000000c006019000000000bcb019f0000000000b4041b00000011049000390000000906900039000500000006001d000000000c06041a0000000000c4041b00000012049000390000000a06900039000400000006001d000000000d06041a0000000000d4041b00000013049000390000000b0d900039000000000e0d041a0000000000e4041b00000014049000390000000c0e900039000000000f0e041a0000000000f4041b00000015049000390000000d0f90003900000000080f041a000000000084041b0000001608900039000000000408041a00000642064001970000000e0c90003900000000040c041a000006530b4001970000000006b6019f000000000068041b0000065e05500197000000000552019f000000000053041b000000ff007001900000000003000039000000010300c039000006700070019800000655050000410000000005006019000000000335019f0000065705a00197000000000353019f0000000602000029000000000032041b0000000802000029000000000302041a0000000502000029000000000032041b0000000303900039000000000303041a0000000402000029000000000032041b0000000403900039000000000303041a00000000003d041b0000000503900039000000000303041a00000000003e041b0000000603900039000000000303041a00000000003f041b00000007039000390000064202400197000000000303041a0000065303300197000000000223019f00000000002c041b00000007020000290000065e022001970000009d03000039000000000303041a0000064303300197000000000223019f000000000021041b0000000a020000290000000801000029000000000021041b000000400100043d0000000000210435000006160010009c000006160100804100000040011002100000000002000414000006160020009c0000061602008041000000c002200210000000000112019f0000064e011001c70000800d0200003900000002030000390000067e04000041000015c20000013d0000000002000019000000400300043d000006500030009c000011a10000213d0000008004300039000000400040043f000000200430003900000000000404350000000000030435000000400400043d0000065c0040009c000011a10000213d0000006005400039000000400050043f0000004005400039000000000005043500000020054000390000000000050435000000000004043500000040053000390000000000450435000000400400043d0000065d0040009c000011a10000213d0000004005400039000000400050043f00000020054000390000000000050435000000000004043500000060053000390000000000450435000000000482001900000000003404350000002002200039000000000012004b00000d940000413d0000009d01000039000000000101041a000806430010019b0000000004000019000700000000001d000900000008001d00000dc20000013d0000000b0400002900000001044000390000000a0040006c0000062b0000813d0000009701000039000000000101041a000000000041004b000016d70000a13d000b00000004001d0000064d0140009a000000000101041a0000064101100197000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000400200043d0000065a0020009c0000000908000029000011a10000213d000000c003200039000000400030043f0000006003200039000000000003043500000040032000390000000000030435000000200320003900000000000304350000000000020435000000400300043d0000065c0030009c000011a10000213d0000006004300039000000400040043f0000004004300039000000000004043500000020043000390000000000040435000000000003043500000080042000390000000000340435000000400300043d0000065d0030009c000011a10000213d0000004004300039000000400040043f000000200430003900000000000404350000000000030435000000a0022000390000000000320435000000400200043d0000000f03100039000000000303041a0000064303300197000000080030006b000000200320003900000e2f0000a13d0000065a0020009c000011a10000213d000000c004200039000000400040043f0000000104100039000000000404041a00000670004001980000000005000039000000010500c039000000400620003900000000005604350000ff00004001900000000005000039000000010500c0390000000000530435000000ff004001900000000004000039000000010400c039000000000042043500000060042000390000000205100039000000000505041a0000000000540435000000400400043d0000065c0040009c000011a10000213d0000006005400039000000400050043f0000000305100039000000000505041a00000000055404360000000406100039000000000606041a00000000006504350000000505100039000000000505041a0000004006400039000000000056043500000080052000390000000000450435000000400400043d0000065d0040009c0000000605000039000000070600003900000e5c0000a13d000011a10000013d0000065a0020009c000011a10000213d000000c004200039000000400040043f0000000804100039000000000404041a00000670004001980000000005000039000000010500c039000000400620003900000000005604350000ff00004001900000000005000039000000010500c0390000000000530435000000ff004001900000000004000039000000010400c039000000000042043500000060042000390000000905100039000000000505041a0000000000540435000000400400043d0000065c0040009c000011a10000213d0000006005400039000000400050043f0000000a05100039000000000505041a00000000055404360000000b06100039000000000606041a00000000006504350000000c05100039000000000505041a0000004006400039000000000056043500000080052000390000000000450435000000400400043d0000065d0040009c0000000d050000390000000e06000039000011a10000213d0000004007400039000000400070043f0000000005150019000000000505041a00000000055404360000000001160019000000000101041a00000080011002100000000000150435000000a00120003900000000004104350000000001020433000000000001004b00000dbe0000613d0000000001030433000000000001004b00000dbe0000c13d000000400100043d000006500010009c000011a10000213d0000004003200039000000000303043300000060052000390000000005050433000000800220003900000000020204330000008006100039000000400060043f000000600610003900000000004604350000004004100039000000000024043500000020021000390000000000520435000000000003004b0000000002000039000000010200c039000000000021043500000006020000290000000002020433000000070020006c0000000b04000029000016d70000a13d000000070300002900000005023002100000000002820019000000000012043500000006010000290000000001010433000000000031004b000016d70000a13d0000000701000029000700010010003d00000dbf0000013d0000065e052001970000000102400039000000000452019f000000000043041b0000009f03000039000000000303041a000000000013001a00000b7a0000413d00000000011300190000009e03000039000000000013041b000000400300043d000000200430003900000000001404350000000000230435000006160030009c000006160300804100000040013002100000000002000414000006160020009c0000061602008041000000c002200210000000000112019f00000649011001c70000800d0200003900000001030000390000067b04000041000009ba0000013d0000000003000019000700000000001d000b00000003001d000006480130009a000600000001001d000000000101041a0000064101100197000a00000001001d000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b0000000302100039000000000202041a000000000002004b00000ecf0000c13d0000000402100039000000000202041a000000000002004b00000ecf0000c13d0000000501100039000000000101041a000000000001004b000010270000613d0000000a01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000009e02000039000000000202041a000800000002001d000000000101043b000900000001001d0000064a0100004100000000001004430000000001000414000006160010009c0000061601008041000000c0011002100000064b011001c70000800b020000391853184e0000040f0000000100200190000011980000613d0000009d02000039000000000202041a0000064302200197000000000101043b000000080010006c0000000b0300002900000ef80000813d000000010220008a000006430020009c000000090400002900000ef90000a13d00000b7a0000013d00000009040000290000001701400039000000000101041a0000064301100197000000000012004b00000f020000213d0000001001400039000000000101041a0000ff000010019000000fdb0000613d0000000f01400039000000000101041a0000064301100197000000000012004b00000f0b0000213d0000000801400039000000000101041a0000ff000010019000000fdb0000613d0000000101400039000000000101041a0000ff000010019000000fdb0000613d0000009701000039000000000101041a000000000001004b00000b7a0000613d000000000204041a0000061602200197000000000021004b000016d70000a13d0000064c0110009a000000000101041a000806410010019b0000064d0120009a000000000201041a000006450220019700000008022001af000000000021041b0000009701000039000000000101041a000500000001001d000000000001004b000014ad0000613d0000009701000039000000000010043f0000000001000414000006160010009c0000061601008041000000c0011002100000064e011001c700008010020000391853184e0000040f00000001002001900000000904000029000016f90000613d0000000502000029000000010220008a000000000101043b0000000001210019000000000301041a0000064503300197000000000031041b0000009701000039000000000021041b000000000104041a000500000001001d0000000801000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f00000009040000290000000100200190000016f90000613d00000005020000290000061602200197000000000101043b000000000301041a0000064f03300197000000000223019f000000000021041b0000000301400039000000000301041a0000000401400039000000000201041a0000000501400039000000000401041a000000400100043d0000006005100039000000000045043500000040041000390000000000240435000000600200003900000000022104360000000000320435000006500010009c000011a10000213d0000008003100039000000400030043f000006160020009c000006160200804100000040022002100000000001010433000006160010009c00000616010080410000006001100210000000000121019f0000000002000414000006160020009c0000061602008041000000c002200210000000000112019f00000646011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000010043f0000009901000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000201041a0000069002200197000000000021041b0000000a01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000001041b0000000102100039000000000002041b0000000202100039000000000002041b0000000302100039000000000002041b0000000402100039000000000002041b0000000502100039000000000002041b0000000602100039000000000002041b0000000702100039000000000002041b0000000802100039000000000002041b0000000902100039000000000002041b0000000a02100039000000000002041b0000000b02100039000000000002041b0000000c02100039000000000002041b0000000d02100039000000000002041b0000000e02100039000000000002041b0000000f02100039000000000002041b0000001002100039000000000002041b0000001102100039000000000002041b0000001202100039000000000002041b0000001302100039000000000002041b0000001402100039000000000002041b0000001502100039000000000002041b0000001602100039000000000002041b0000001701100039000000000001041b0000000001000414000006160010009c0000061601008041000000c00110021000000646011001c70000800d02000039000000020300003900000651040000410000000a05000029185318490000040f0000000100200190000016f90000613d0000009a01000039000000000501041a0000000b02000029000000000025004b000016d70000a13d0000000603000029000000000403041a000000010150008a000000000021004b000a00000004001d00000fdd0000c13d000900000005001d00000ff80000013d00000001033000390000101f0000013d0000064501400197000006520250009a000000000202041a0000064102200197000000000112019f000000000013041b000000000020043f0000009b01000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b0000000b020000290000000102200039000000000021041b0000009a01000039000000000101041a000900000001001d000000000001004b000014ad0000613d0000009a01000039000000000010043f0000000001000414000006160010009c0000061601008041000000c0011002100000064e011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000000a0200002900000641022001970000000903000029000000010330008a000000000101043b0000000001310019000000000401041a0000064504400197000000000041041b0000009a01000039000000000031041b000000000020043f0000009b01000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000001041b0000000701000029000700010010003d0000000b030000290000009a01000039000000000101041a000000000013004b000000ec0000813d0000000701000029000000010010008c00000eb00000a13d000000ec0000013d0000009a01000039000000000501041a0000000b02000029000000000025004b000016d70000a13d0000000603000029000000000403041a000000010150008a000000000021004b000a00000004001d000010340000c13d000900000005001d0000104f0000013d0000064501400197000006520250009a000000000202041a0000064102200197000000000112019f000000000013041b000000000020043f0000009b01000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b0000000b020000290000000102200039000000000021041b0000009a01000039000000000101041a000900000001001d000000000001004b000014ad0000613d0000009a01000039000000000010043f0000000001000414000006160010009c0000061601008041000000c0011002100000064e011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000000a0200002900000641022001970000000903000029000000010330008a000000000101043b0000000001310019000000000401041a0000064504400197000000000041041b0000009a01000039000000000031041b000000000020043f0000009b01000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000001041b0000101e0000013d0000000002000019000700000000001d0000107b0000013d00000009020000290000000102200039000000080020006c000014cb0000813d0000009701000039000000000101041a000000000021004b000016d70000a13d000900000002001d0000064d0120009a000000000101041a0000064101100197000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000401043b000000400100043d0000065a0010009c000011a10000213d000000c002100039000000400020043f0000006002100039000000000002043500000040021000390000000000020435000000200210003900000000000204350000000000010435000000400200043d0000065c0020009c000011a10000213d0000006003200039000000400030043f0000004003200039000000000003043500000020032000390000000000030435000000000002043500000080031000390000000000230435000000400200043d0000065d0020009c000011a10000213d000b00000004001d0000004003200039000000400030043f000000200320003900000000000304350000000000020435000000a00110003900000000002104350000009e01000039000000000101041a000a00000001001d0000064a0100004100000000001004430000000001000414000006160010009c0000061601008041000000c0011002100000064b011001c70000800b020000391853184e0000040f0000000100200190000011980000613d0000009d02000039000000000202041a0000064302200197000000000101043b0000000a0010006c000010cc0000813d000000010220008a000006430020009c0000000b06000029000010cd0000a13d00000b7a0000013d0000000b06000029000000400100043d0000000f03600039000000000303041a0000064303300197000000000032004b000011020000a13d0000065a0010009c000011a10000213d000000c002100039000000400020043f0000000102600039000000000202041a00000670002001980000000003000039000000010300c039000000400410003900000000003404350000ff00002001900000000003000039000000010300c03900000020041000390000000000340435000000ff002001900000000002000039000000010200c039000000000021043500000060021000390000000203600039000000000303041a0000000000320435000000400200043d0000065c0020009c000011a10000213d0000006003200039000000400030043f0000000303600039000000000303041a00000000033204360000000404600039000000000404041a00000000004304350000000503600039000000000303041a0000004004200039000000000034043500000080031000390000000000230435000000400200043d0000065d0020009c00000006030000390000000704000039000011640000a13d000011a10000013d0000001703600039000000000303041a0000064303300197000000000032004b000011360000a13d0000065a0010009c000011a10000213d000000c002100039000000400020043f0000000802600039000000000202041a00000670002001980000000003000039000000010300c039000000400410003900000000003404350000ff00002001900000000003000039000000010300c03900000020041000390000000000340435000000ff002001900000000002000039000000010200c039000000000021043500000060021000390000000903600039000000000303041a0000000000320435000000400200043d0000065c0020009c000011a10000213d0000006003200039000000400030043f0000000a03600039000000000303041a00000000033204360000000b04600039000000000404041a00000000004304350000000c03600039000000000303041a0000004004200039000000000034043500000080031000390000000000230435000000400200043d0000065d0020009c0000000d030000390000000e04000039000011640000a13d000011a10000013d0000065a0010009c000011a10000213d000000c002100039000000400020043f0000001002600039000000000202041a00000670002001980000000003000039000000010300c039000000400410003900000000003404350000ff00002001900000000003000039000000010300c03900000020041000390000000000340435000000ff002001900000000002000039000000010200c039000000000021043500000060021000390000001103600039000000000303041a0000000000320435000000400200043d0000065c0020009c000011a10000213d0000006003200039000000400030043f0000001203600039000000000303041a00000000033204360000001304600039000000000404041a00000000004304350000001403600039000000000303041a0000004004200039000000000034043500000080031000390000000000230435000000400200043d0000065d0020009c00000015030000390000001604000039000011a10000213d0000004005200039000000400050043f0000000003630019000000000303041a00000000033204360000000004640019000000000404041a00000080044002100000000000430435000000a00310003900000000002304350000000034010434000000000004004b000010770000613d0000000003030433000000000003004b000010770000c13d000000400300043d000006500030009c000011a10000213d0000004004100039000000000404043300000060051000390000000005050433000000800110003900000000010104330000008006300039000000400060043f000000600630003900000000002604350000004002300039000000000012043500000020013000390000000000510435000000000004004b0000000001000039000000010100c0390000000000130435000000c00100043d000000070010006c000016d70000a13d00000007020000290000000501200210000000e0011000390000000000310435000000c00100043d000000000021004b0000000902000029000016d70000a13d0000000701000029000700010010003d000010780000013d000000000001042f000000a401000039000000000101041a0000064301100197000000000012004b000000a301000039000000a1010020390000065d0030009c000011a70000a13d0000068b01000041000000000010043f0000004101000039000000040010043f0000068c0100004100001855000104300000004002300039000000400020043f000000000101041a00000671001001980000000002000039000000010200c0390000002004300039000000000024043500000643011001970000000000130435000000400100043d000b00000001001d000000c002000039185317430000040f0000000b020000290000000001210049000006160010009c00000616010080410000006001100210000006160020009c00000616020080410000004002200210000000000121019f000018540001042e0000009701000039000000000101041a000000000001004b00000b7a0000613d0000000a02000029000000000202041a0000061602200197000000000021004b000016d70000a13d0000064c0110009a000000000101041a000906410010019b0000064d0120009a000000000201041a000006450220019700000009022001af000000000021041b0000009701000039000000000101041a000800000001001d000000000001004b000014ad0000613d0000009701000039000000000010043f0000000001000414000006160010009c0000061601008041000000c0011002100000064e011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000000802000029000000010220008a000000000101043b0000000001210019000000000301041a0000064503300197000000000031041b0000009701000039000000000021041b0000000a01000029000000000101041a000800000001001d0000000901000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d00000008020000290000061602200197000000000101043b000000000301041a0000064f03300197000000000223019f000000000021041b0000000a040000290000000301400039000000000301041a0000000401400039000000000201041a0000000501400039000000000401041a000000400100043d0000006005100039000000000045043500000040041000390000000000240435000000600200003900000000022104360000000000320435000006500010009c000011a10000213d0000008003100039000000400030043f000006160020009c000006160200804100000040022002100000000001010433000006160010009c00000616010080410000006001100210000000000121019f0000000002000414000006160020009c0000061602008041000000c002200210000000000112019f00000646011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000010043f0000009901000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000201041a0000069002200197000000000021041b0000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000001041b0000000102100039000000000002041b0000000202100039000000000002041b0000000302100039000000000002041b0000000402100039000000000002041b0000000502100039000000000002041b0000000602100039000000000002041b0000000702100039000000000002041b0000000802100039000000000002041b0000000902100039000000000002041b0000000a02100039000000000002041b0000000b02100039000000000002041b0000000c02100039000000000002041b0000000d02100039000000000002041b0000000e02100039000000000002041b0000000f02100039000000000002041b0000001002100039000000000002041b0000001102100039000000000002041b0000001202100039000000000002041b0000001302100039000000000002041b0000001402100039000000000002041b0000001502100039000000000002041b0000001602100039000000000002041b0000001701100039000000000001041b0000000001000414000016630000013d0000009701000039000000000101041a000000000001004b00000b7a0000613d0000000a02000029000000000202041a0000061602200197000000000021004b000016d70000a13d0000064c0110009a000000000101041a000906410010019b0000064d0120009a000000000201041a000006450220019700000009022001af000000000021041b0000009701000039000000000101041a000800000001001d000000000001004b000014ad0000613d0000009701000039000000000010043f0000000001000414000006160010009c0000061601008041000000c0011002100000064e011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000000802000029000000010220008a000000000101043b0000000001210019000000000301041a0000064503300197000000000031041b0000009701000039000000000021041b0000000a01000029000000000101041a000800000001001d0000000901000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d00000008020000290000061602200197000000000101043b000000000301041a0000064f03300197000000000223019f000000000021041b0000000a040000290000000301400039000000000301041a0000000401400039000000000201041a0000000501400039000000000401041a000000400100043d0000006005100039000000000045043500000040041000390000000000240435000000600200003900000000022104360000000000320435000006500010009c000011a10000213d0000008003100039000000400030043f000006160020009c000006160200804100000040022002100000000001010433000006160010009c00000616010080410000006001100210000000000121019f0000000002000414000006160020009c0000061602008041000000c002200210000000000112019f00000646011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000010043f0000009901000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000201041a0000069002200197000000000021041b0000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000001041b0000000102100039000000000002041b0000000202100039000000000002041b0000000302100039000000000002041b0000000402100039000000000002041b0000000502100039000000000002041b0000000602100039000000000002041b0000000702100039000000000002041b0000000802100039000000000002041b0000000902100039000000000002041b0000000a02100039000000000002041b0000000b02100039000000000002041b0000000c02100039000000000002041b0000000d02100039000000000002041b0000000e02100039000000000002041b0000000f02100039000000000002041b0000001002100039000000000002041b0000001102100039000000000002041b0000001202100039000000000002041b0000001302100039000000000002041b0000001402100039000000000002041b0000001502100039000000000002041b0000001602100039000000000002041b0000001701100039000000000001041b0000000001000414000016630000013d0000009701000039000000000101041a000000000001004b00000b7a0000613d0000000902000029000000000202041a0000061602200197000000000021004b000016d70000a13d0000064c0110009a000000000101041a000a06410010019b0000064d0120009a000000000201041a00000645022001970000000a022001af000000000021041b0000009701000039000000000101041a000800000001001d000000000001004b000014ad0000613d0000009701000039000000000010043f0000000001000414000006160010009c0000061601008041000000c0011002100000064e011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000000802000029000000010220008a000000000101043b0000000001210019000000000301041a0000064503300197000000000031041b0000009701000039000000000021041b0000000901000029000000000101041a000800000001001d0000000a01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d00000008020000290000061602200197000000000101043b000000000301041a0000064f03300197000000000223019f000000000021041b00000009040000290000000301400039000000000301041a0000000401400039000000000201041a0000000501400039000000000401041a000000400100043d00000060051000390000000000450435000000400410003900000000002404350000006002000039000000000221043600000000003204350000068d0010009c000011a10000813d0000008003100039000000400030043f000006160020009c000006160200804100000040022002100000000001010433000006160010009c00000616010080410000006001100210000000000121019f0000000002000414000006160020009c0000061602008041000000c002200210000000000112019f00000646011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000010043f0000009901000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000201041a0000069002200197000000000021041b0000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000001041b0000000102100039000000000002041b0000000202100039000000000002041b0000000302100039000000000002041b0000000402100039000000000002041b0000000502100039000000000002041b0000000602100039000000000002041b0000000702100039000000000002041b0000000802100039000000000002041b0000000902100039000000000002041b0000000a02100039000000000002041b0000000b02100039000000000002041b0000000c02100039000000000002041b0000000d02100039000000000002041b0000000e02100039000000000002041b0000000f02100039000000000002041b0000001002100039000000000002041b0000001102100039000000000002041b0000001202100039000000000002041b0000001302100039000000000002041b0000001402100039000000000002041b0000001502100039000000000002041b0000001602100039000000000002041b0000001701100039000000000001041b0000000001000414000016630000013d0000009701000039000000000101041a000000000001004b00000b7a0000613d0000000902000029000000000202041a0000061602200197000000000021004b000016d70000a13d0000064c0110009a000000000101041a000a06410010019b0000064d0120009a000000000201041a00000645022001970000000a022001af000000000021041b0000009701000039000000000101041a000800000001001d000000000001004b000014ad0000613d0000009701000039000000000010043f0000000001000414000006160010009c0000061601008041000000c0011002100000064e011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000000802000029000000010220008a000000000101043b0000000001210019000000000301041a0000064503300197000000000031041b0000009701000039000000000021041b0000000901000029000000000101041a000800000001001d0000000a01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d00000008020000290000061602200197000000000101043b000000000301041a0000064f03300197000000000223019f000000000021041b00000009040000290000000301400039000000000301041a0000000401400039000000000201041a0000000501400039000000000401041a000000400100043d0000006005100039000000000045043500000040041000390000000000240435000000600200003900000000022104360000000000320435000006500010009c000011a10000213d0000008003100039000000400030043f000006160020009c000006160200804100000040022002100000000001010433000006160010009c00000616010080410000006001100210000000000121019f0000000002000414000006160020009c0000061602008041000000c002200210000000000112019f00000646011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000010043f0000009901000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000201041a0000069002200197000000000021041b0000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000001041b0000000102100039000000000002041b0000000202100039000000000002041b0000000302100039000000000002041b0000000402100039000000000002041b0000000502100039000000000002041b0000000602100039000000000002041b0000000702100039000000000002041b0000000802100039000000000002041b0000000902100039000000000002041b0000000a02100039000000000002041b0000000b02100039000000000002041b0000000c02100039000000000002041b0000000d02100039000000000002041b0000000e02100039000000000002041b0000000f02100039000000000002041b0000001002100039000000000002041b0000001102100039000000000002041b0000001202100039000000000002041b0000001302100039000000000002041b0000001402100039000000000002041b0000001502100039000000000002041b0000001602100039000000000002041b0000001701100039000000000001041b0000000001000414000016630000013d0000009701000039000000000101041a000000000001004b00000b7a0000613d0000000902000029000000000202041a0000061602200197000000000021004b000016d70000a13d0000064c0110009a000000000101041a000a06410010019b0000064d0120009a000000000201041a00000645022001970000000a022001af000000000021041b0000009701000039000000000101041a000800000001001d000000000001004b000015c40000c13d0000068b01000041000000000010043f0000003101000039000000040010043f0000068c0100004100001855000104300000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000a00000001001d0000000101100039000900000001001d000000000101041a0000ff0000100190000014d10000c13d0000065801000041000000000010043f00000659010000410000185500010430000000400100043d0000000702000029000000c00020043f0000065d0010009c000000940000a13d000011a10000013d0000000a01000029000000050410003900000004021000390000000301100039000600000001001d000000000301041a000700000002001d000000000202041a000800000004001d000000000404041a000000400100043d00000060051000390000000000450435000000400410003900000000002404350000002002100039000000000032043500000060030000390000000000310435000006500010009c000011a10000213d0000008003100039000000400030043f000006160020009c000006160200804100000040022002100000000001010433000006160010009c00000616010080410000006001100210000000000121019f0000000002000414000006160020009c0000061602008041000000c002200210000000000112019f00000646011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000500000001001d00000001010003670000008402100370000000000302043b000000a402100370000000000202043b000000c401100370000000000401043b000000400100043d00000060051000390000000000450435000000400410003900000000002404350000002002100039000000000032043500000060030000390000000000310435000006500010009c000011a10000213d0000008003100039000000400030043f000006160020009c000006160200804100000040022002100000000001010433000006160010009c00000616010080410000006001100210000000000121019f0000000002000414000006160020009c0000061602008041000000c002200210000000000112019f00000646011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000201043b000400000002001d000000050020006b0000166b0000c13d0000000a01000029185317b80000040f000000030000006b0000065501000041000000000100601900000002020000290000065602200197000000000112019f0000000903000029000000000203041a0000065702200197000000000121019f000000000013041b0000000a0400002900000002014000390000000102000029000000000021041b00000001010003670000008402100370000000000202043b0000000603000029000000000023041b000000a402100370000000000202043b0000000703000029000000000023041b000000c402100370000000000202043b0000000803000029000000000023041b0000000602400039000000e403100370000000000303043b000000000032041b0000010401100370000000000101043b0000065300100198000016f90000c13d00000080011002700000000a020000290000000702200039000000000302041a0000064203300197000000000113019f000000000012041b0000000b01000029000000000010043f0000009b01000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000101041a000b00000001001d000000000001004b000016a40000c13d000000030000006b0000156e0000613d000000020000006b0000156e0000613d0000009c01000039000000000201041a000000010220003a00000b7a0000613d000000000021041b0000064101000041000000100510017f000000400100043d00000040021000390000000c030000290000000d040000290000000000420435000000030000006b0000000002000039000000010200c03900000020041000390000000000240435000000020000006b0000000002000039000000010200c03900000000002104350000000104300367000000000404043b0000006006100039000000000046043500000020043000390000000104400367000000000404043b0000008006100039000000000046043500000040033000390000000102300367000000000202043b000000a0031000390000000000230435000006160010009c000006160100804100000040011002100000000002000414000006160020009c0000061602008041000000c002200210000000000112019f0000065f011001c70000800d0200003900000002030000390000066004000041000009ba0000013d000000000002004b00000b7a0000613d000000010300008a0000000002230019000000000021041b000000400100043d0000000a020000290000000000210435000006160010009c000006160100804100000040011002100000000002000414000006160020009c0000061602008041000000c002200210000000000112019f0000064e011001c70000800d0200003900000002030000390000068e04000041000015c20000013d000000000002004b00000b7a0000613d000000010300008a0000000002230019000000000021041b000000400100043d0000000a020000290000000000210435000006160010009c000006160100804100000040011002100000000002000414000006160020009c0000061602008041000000c002200210000000000112019f0000064e011001c70000800d02000039000000020300003900000686040000410000000b05000029000009ba0000013d0000009701000039000000000010043f0000000001000414000006160010009c0000061601008041000000c0011002100000064e011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000000802000029000000010220008a000000000101043b0000000001210019000000000301041a0000064503300197000000000031041b0000009701000039000000000021041b0000000901000029000000000101041a000800000001001d0000000a01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d00000008020000290000061602200197000000000101043b000000000301041a0000064f03300197000000000223019f000000000021041b00000009040000290000000301400039000000000301041a0000000401400039000000000201041a0000000501400039000000000401041a000000400100043d0000006005100039000000000045043500000040041000390000000000240435000000600200003900000000022104360000000000320435000006500010009c000011a10000213d0000008003100039000000400030043f000006160020009c000006160200804100000040022002100000000001010433000006160010009c00000616010080410000006001100210000000000121019f0000000002000414000006160020009c0000061602008041000000c002200210000000000112019f00000646011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000010043f0000009901000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000201041a0000069002200197000000000021041b0000000b01000029000000000010043f0000009801000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000001041b0000000102100039000000000002041b0000000202100039000000000002041b0000000302100039000000000002041b0000000402100039000000000002041b0000000502100039000000000002041b0000000602100039000000000002041b0000000702100039000000000002041b0000000802100039000000000002041b0000000902100039000000000002041b0000000a02100039000000000002041b0000000b02100039000000000002041b0000000c02100039000000000002041b0000000d02100039000000000002041b0000000e02100039000000000002041b0000000f02100039000000000002041b0000001002100039000000000002041b0000001102100039000000000002041b0000001202100039000000000002041b0000001302100039000000000002041b0000001402100039000000000002041b0000001502100039000000000002041b0000001602100039000000000002041b0000001701100039000000000001041b0000000001000414000006160010009c0000061601008041000000c00110021000000646011001c70000800d0200003900000002030000390000065104000041000015c20000013d0000000401000029000000000010043f0000009901000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000101041a000000ff00100190000016a00000c13d0000000501000029000000000010043f0000009901000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000201041a0000069002200197000000000021041b0000000401000029000000000010043f0000009901000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000201041a000006900220019700000001022001bf000000000021041b000015260000013d0000068001000041000000000010043f000006590100004100001855000104300000009a01000039000000000101041a0000000b02000029000000010220008a000000000021004b000016d70000a13d0000000b03000029000006520230009a000000000402041a000a00000004001d000000000031004b000016dd0000c13d0000009a01000039000000000010043f0000000001000414000006160010009c0000061601008041000000c0011002100000064e011001c700008010020000391853184e0000040f0000000100200190000016f90000613d0000000a0200002900000641022001970000000b03000029000000010330008a000000000101043b0000000001310019000000000401041a0000064504400197000000000041041b0000009a01000039000000000031041b000000000020043f0000009b01000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b000000000001041b000000030000006b000015670000c13d0000156e0000013d0000068b01000041000000000010043f0000003201000039000000040010043f0000068c0100004100001855000104300000000a030000290000064503300197000006520110009a000000000101041a0000064101100197000000000331019f000000000032041b000000000010043f0000009b01000039000000200010043f0000000001000414000006160010009c0000061601008041000000c00110021000000649011001c700008010020000391853184e0000040f0000000100200190000016f90000613d000000000101043b0000000b02000029000000000021041b0000009a01000039000000000101041a000b00000001001d000000000001004b000014ad0000613d000016b00000013d00000000010000190000185500010430000000400100043d000006930010009c0000170a0000813d0000004002100039000000400020043f000000a002000039000000000202041a00000671002001980000000003000039000000010300c0390000002004100039000000000034043500000643022001970000000000210435000000000001042d0000068b01000041000000000010043f0000004101000039000000040010043f0000068c010000410000185500010430000000400100043d000006930010009c0000171f0000813d0000004002100039000000400020043f000000a102000039000000000202041a00000671002001980000000003000039000000010300c0390000002004100039000000000034043500000643022001970000000000210435000000000001042d0000068b01000041000000000010043f0000004101000039000000040010043f0000068c010000410000185500010430000000400100043d000006930010009c000017340000813d0000004002100039000000400020043f000000a302000039000000000202041a00000671002001980000000003000039000000010300c0390000002004100039000000000034043500000643022001970000000000210435000000000001042d0000068b01000041000000000010043f0000004101000039000000040010043f0000068c0100004100001855000104300000000031010434000006430110019700000000011204360000000002030433000000000002004b0000000002000039000000010200c0390000000000210435000000000001042d000000600400003900000000054104360000000006020433000000600410003900000000006404350000008004100039000000000006004b0000176e0000613d00000000070000190000002002200039000000000802043300000000a9080434000000000009004b0000000009000039000000010900c0390000000009940436000000000a0a04330000000000a9043500000040098000390000000009090433000000400a40003900000000cb0904340000000000ba0435000000000a0c0433000000600b4000390000000000ab043500000040099000390000000009090433000000800a40003900000000009a043500000060088000390000000008080433000000a00940003900000000a8080434000000000089043500000000080a04330000064208800197000000c0094000390000000000890435000000e0044000390000000107700039000000000067004b0000174c0000413d00000000320304340000064302200197000000000025043500000040011000390000000002030433000000000002004b0000000002000039000000010200c03900000000002104350000000001040019000000000001042d0000000002010019000000400100043d000006940010009c000017b20000813d000000c003100039000000400030043f000000000302041a00000670003001980000000004000039000000010400c039000000400510003900000000004504350000ff00003001900000000004000039000000010400c03900000020051000390000000000450435000000ff003001900000000003000039000000010300c039000000000031043500000060031000390000000104200039000000000404041a0000000000430435000000400300043d0000065c0030009c000017b20000213d0000006004300039000000400040043f0000000204200039000000000404041a00000000044304360000000305200039000000000505041a00000000005404350000000404200039000000000404041a0000004005300039000000000045043500000080041000390000000000340435000000400300043d0000065d0030009c000017b20000213d0000004004300039000000400040043f0000000504200039000000000404041a00000000044304360000000602200039000000000202041a00000080022002100000000000240435000000a0021000390000000000320435000000000001042d0000068b01000041000000000010043f0000004101000039000000040010043f0000068c01000041000018550001043000010000000000020000000f02100039000000000302041a00000643063001970000009d04000039000000000504041a0000064305500197000000000056004b000018190000813d0000001007100039000000000507041a00000657085001970000000805100039000100000005001d000000000a05041a000000ff00a00190000000010880c1bf0000ff0000a00190000001000880c1bf0000067000a0019800000655090000410000000009006019000000000898019f000000000087041b00000011081000390000000907100039000000000907041a000000000098041b00000012091000390000000a08100039000000000b08041a0000000000b9041b000000130b1000390000000b09100039000000000c09041a0000000000cb041b000000140c1000390000000c0b100039000000000d0b041a0000000000dc041b000000150d1000390000000d0c100039000000000e0c041a0000000000ed041b000000160f100039000000000d0f041a0000064204d001970000000e0d100039000000000e0d041a0000065305e00197000000000454019f00000000004f041b0000001704100039000000000504041a0000065e05500197000000000565019f000000000054041b0000065704a001970000000105100039000000000505041a000000ff00500190000000010440c1bf0000ff0000500190000001000440c1bf000006700050019800000655050000410000000005006019000000000454019f0000000105000029000000000045041b0000000204100039000000000404041a000000000047041b0000000304100039000000000404041a000000000048041b0000000404100039000000000404041a000000000049041b0000000504100039000000000404041a00000000004b041b0000000604100039000000000404041a00000000004c041b00000007011000390000064204e00197000000000101041a0000065301100197000000000114019f00000000001d041b0000065e013001970000009d03000039000000000303041a0000064303300197000000000113019f000000000012041b000000000001042d0000006502000039000000000302041a0000064503300197000000000032041b00000641061001970000003301000039000000000201041a0000064503200197000000000363019f000000000031041b00000000010004140000064105200197000006160010009c0000061601008041000000c00110021000000646011001c70000800d0200003900000003030000390000066804000041185318490000040f0000000100200190000018310000613d000000000001042d00000000010000190000185500010430000000000001042f000006160010009c00000616010080410000004001100210000006160020009c00000616020080410000006002200210000000000112019f0000000002000414000006160020009c0000061602008041000000c002200210000000000112019f00000646011001c700008010020000391853184e0000040f0000000100200190000018470000613d000000000101043b000000000001042d000000000100001900001855000104300000184c002104210000000102000039000000000001042d0000000002000019000000000001042d00001851002104230000000102000039000000000001042d0000000002000019000000000001042d0000185300000432000018540001042e00001855000104300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000002000000000000000000000000000000400000010000000000000000000000000000000000000000000000000000000000000000000000000079ba509600000000000000000000000000000000000000000000000000000000c4d66de700000000000000000000000000000000000000000000000000000000e8de12de00000000000000000000000000000000000000000000000000000000f2fde38a00000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000fa52c7d800000000000000000000000000000000000000000000000000000000e8de12df00000000000000000000000000000000000000000000000000000000f223453600000000000000000000000000000000000000000000000000000000e30c397700000000000000000000000000000000000000000000000000000000e30c397800000000000000000000000000000000000000000000000000000000e39e6a8700000000000000000000000000000000000000000000000000000000c4d66de800000000000000000000000000000000000000000000000000000000dae20b27000000000000000000000000000000000000000000000000000000008da5cb5a00000000000000000000000000000000000000000000000000000000a1c0e1ad00000000000000000000000000000000000000000000000000000000a1c0e1ae00000000000000000000000000000000000000000000000000000000b7b44f79000000000000000000000000000000000000000000000000000000008da5cb5b0000000000000000000000000000000000000000000000000000000095570d120000000000000000000000000000000000000000000000000000000079ba5097000000000000000000000000000000000000000000000000000000007d5a75f2000000000000000000000000000000000000000000000000000000007e115549000000000000000000000000000000000000000000000000000000005875da2a000000000000000000000000000000000000000000000000000000005efc766d00000000000000000000000000000000000000000000000000000000715018a500000000000000000000000000000000000000000000000000000000715018a600000000000000000000000000000000000000000000000000000000740211ce000000000000000000000000000000000000000000000000000000005efc766e000000000000000000000000000000000000000000000000000000006a9d8029000000000000000000000000000000000000000000000000000000005875da2b000000000000000000000000000000000000000000000000000000005d593f8d000000000000000000000000000000000000000000000000000000005e19650e0000000000000000000000000000000000000000000000000000000029092d0d0000000000000000000000000000000000000000000000000000000040df5c5b0000000000000000000000000000000000000000000000000000000040df5c5c000000000000000000000000000000000000000000000000000000004c6942ea0000000000000000000000000000000000000000000000000000000029092d0e000000000000000000000000000000000000000000000000000000003fb566610000000000000000000000000000000000000000000000000000000006c827610000000000000000000000000000000000000000000000000000000008dc336000000000000000000000000000000000000000000000000000000000262d3bc3000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff00000000000000000000000000000000000003c0000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000038d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700bb25ea745d806dad8ed58b0095aa3a2ace0969f60e09180e83bbbc571df7641c020000000000000000000000000000000000004000000000000000000000000042cbb15ccdc3cad6266b0e7a08c0454b23bf29dc2df74b6f3c209e9336465bd10200000200000000000000000000000000000004000000000000000000000000cab57c12667708609fc72b3858252452750cd0b5292076c1f1a7f85e4e6bb008cab57c12667708609fc72b3858252452750cd0b5292076c1f1a7f85e4e6bb0070200000000000000000000000000000000000020000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000ffffffffffffff7fa7a579573d398d7b67cd7450121bb250bbd060b29eabafdebc3ce0918658635cbb25ea745d806dad8ed58b0095aa3a2ace0969f60e09180e83bbbc571df7641d00000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000028c100b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff3f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000ffffffffffffff9f000000000000000000000000000000000000000000000000ffffffffffffffbfffffffffffffffffffffffffffffffffffffffffffffffff000000000000000002000000000000000000000000000000000000c0000000000000000000000000f293ea770eb4f051068c9141fd2a5d8c847684af5c96b5a8cbf91a59887a7d2600000000000000000000000000000000000000200000008000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b830200000200000000000000000000000000000024000000000000000000000000647920696e697469616c697a6564000000000000000000000000000000000000496e697469616c697a61626c653a20636f6e747261637420697320616c72656108c379a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000840000000000000000000000008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0000000000000000000000000000000000000000000000000ffffffffffffff5fffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000100000000000000007f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249837254233000000000000000000000000000000000000000000000000000000005091be4d000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00000000000000000000000000000000000000000000000000000000000ff00000000000000000000000000000000000000000000000000ff00000000000000000200000000000000000000000000000000000040000000c000000000000000006df854e40cf454015fc499b7f67bd47a038a0b5baa88c73f93baaf68b576b737000000000000000000000000000000000000000000000000fffffffffffffebf0000000000000000000000000000000000000100000000000000000000000000020000000000000000000000000000000000002000000080000000000000000038e3e455b9de9dcacacac07616f49ce5b92acea345fe26d4e3f7e838ce4e6a364f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206e6577206f776e65720000000000000000000000000000000000000000000000000000000000000000000000000000000000008400000080000000000000000028914be75ddbbcccaa1356058796c382704cfa36ab8fad25b914a6bb750aa28d2ca5de35000000000000000000000000000000000000000000000000000000005a11724900000000000000000000000000000000000000000000000000000000e3490611629a41809c531d61c4adf71d3e682bfe292318e23f7227f1570d921b7e6f3f30000000000000000000000000000000000000000000000000000000001a956ace000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000060000000000000000000000000e8b2bacca9db4d72946969d39378d630292ba36ed6ecf8d88493163baf1c2e5a1088e0c600000000000000000000000000000000000000000000000000000000c5cbf87000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff2945e1800cc9f7b9d4d3213a5f7ceaa01c3d5c63d348a238a2d8d50d2001e9da4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65720000000000000000000000000000000000000064000000800000000000000000e1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f1769b3a51000000000000000000000000000000000000000000000000000000004e487b71000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff80e55bba6c56010a6b5be11c128beb3858d6f2d844715ad93fe0392920241bd5941c31fae200000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff000000000000000000000000000000000000000000000000ffffffffffffffc0000000000000000000000000000000000000000000000000ffffffffffffff400000000000000000000000000000000000000000000000000000000000000000bdf145cbe6955286365e577f23d5b6ed295b07830de6ca93ac10d330d1372a5a", + "entries": [ + { + "constructorArgs": [], + "salt": "0x0000000000000000000000000000000000000000000000000000000000000000", + "deploymentType": "create", + "factoryDeps": [], + "address": "0x158d33FbddA2263FE08d8f4955f13cd9F20B4c05", + "txHash": "0x4237d3b8627ac2b29bbe3386fb97c148f43e5e06e6841e35d07e01474ffc420f" + } + ] +} diff --git a/deployments-zk/zkSyncTestnet/src/ZkStaker.sol/ZkStaker.json b/deployments-zk/zkSyncTestnet/src/ZkStaker.sol/ZkStaker.json new file mode 100644 index 0000000..8f3c4f5 --- /dev/null +++ b/deployments-zk/zkSyncTestnet/src/ZkStaker.sol/ZkStaker.json @@ -0,0 +1,2509 @@ +{ + "sourceName": "src/ZkStaker.sol", + "contractName": "ZkStaker", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "_rewardsToken", + "type": "address" + }, + { + "internalType": "contract IERC20Staking", + "name": "_stakeToken", + "type": "address" + }, + { + "internalType": "contract IEarningPowerCalculator", + "name": "_earningPowerCalculator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_maxBumpTip", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_initialTotalStakeCap", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_admin", + "type": "address" + }, + { + "internalType": "address", + "name": "_validatorStakeAuthority", + "type": "address" + }, + { + "internalType": "string", + "name": "_name", + "type": "string" + }, + { + "internalType": "uint256", + "name": "_initialValidatorWeightThreshold", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_initialIsLeaderDefault", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "AddressInsufficientBalance", + "type": "error" + }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "currentNonce", + "type": "uint256" + } + ], + "name": "InvalidAccountNonce", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidShortString", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidValidatorKeys", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "bits", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "SafeCastOverflowedUintDowncast", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "SafeERC20FailedOperation", + "type": "error" + }, + { + "inputs": [], + "name": "StakerCapDeposits__CapExceeded", + "type": "error" + }, + { + "inputs": [], + "name": "StakerDelegateSurrogateVotes__UnauthorizedToken", + "type": "error" + }, + { + "inputs": [], + "name": "StakerOnBehalf__ExpiredDeadline", + "type": "error" + }, + { + "inputs": [], + "name": "StakerOnBehalf__InvalidSignature", + "type": "error" + }, + { + "inputs": [], + "name": "StakerPermitAndStake__UnauthorizedToken", + "type": "error" + }, + { + "inputs": [], + "name": "Staker__ExpiredDeadline", + "type": "error" + }, + { + "inputs": [], + "name": "Staker__InsufficientRewardBalance", + "type": "error" + }, + { + "inputs": [], + "name": "Staker__InsufficientUnclaimedRewards", + "type": "error" + }, + { + "inputs": [], + "name": "Staker__InvalidAddress", + "type": "error" + }, + { + "inputs": [], + "name": "Staker__InvalidClaimFeeParameters", + "type": "error" + }, + { + "inputs": [], + "name": "Staker__InvalidRewardRate", + "type": "error" + }, + { + "inputs": [], + "name": "Staker__InvalidSignature", + "type": "error" + }, + { + "inputs": [], + "name": "Staker__InvalidTip", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "reason", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "Staker__Unauthorized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "score", + "type": "uint256" + } + ], + "name": "Staker__Unqualified", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "str", + "type": "string" + } + ], + "name": "StringTooLong", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "oldFeeAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "newFeeAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "address", + "name": "oldFeeCollector", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newFeeCollector", + "type": "address" + } + ], + "name": "ClaimFeeParametersSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "Staker.DepositIdentifier", + "name": "depositId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "oldClaimer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newClaimer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "earningPower", + "type": "uint256" + } + ], + "name": "ClaimerAltered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "Staker.DepositIdentifier", + "name": "depositId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "oldDelegatee", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newDelegatee", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "earningPower", + "type": "uint256" + } + ], + "name": "DelegateeAltered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "EIP712DomainChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "Staker.DepositIdentifier", + "name": "depositId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "oldEarningPower", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newEarningPower", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "bumper", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "tipReceiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tipAmount", + "type": "uint256" + } + ], + "name": "EarningPowerBumped", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldEarningPowerCalculator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newEarningPowerCalculator", + "type": "address" + } + ], + "name": "EarningPowerCalculatorSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "oldIsLeaderDefault", + "type": "bool" + }, + { + "indexed": false, + "internalType": "bool", + "name": "newIsLeaderDefault", + "type": "bool" + } + ], + "name": "IsLeaderDefaultSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldMaxBumpTip", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMaxBumpTip", + "type": "uint256" + } + ], + "name": "MaxBumpTipSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldRegistry", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newRegistry", + "type": "address" + } + ], + "name": "RegistrySet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "Staker.DepositIdentifier", + "name": "depositId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "claimer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "earningPower", + "type": "uint256" + } + ], + "name": "RewardClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "notifier", + "type": "address" + } + ], + "name": "RewardNotified", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isEnabled", + "type": "bool" + } + ], + "name": "RewardNotifierSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "Staker.DepositIdentifier", + "name": "depositId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "depositBalance", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "earningPower", + "type": "uint256" + } + ], + "name": "StakeDeposited", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "Staker.DepositIdentifier", + "name": "depositId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "depositBalance", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "earningPower", + "type": "uint256" + } + ], + "name": "StakeWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "delegatee", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "surrogate", + "type": "address" + } + ], + "name": "SurrogateDeployed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldTotalStakeCap", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newTotalStakeCap", + "type": "uint256" + } + ], + "name": "TotalStakeCapSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "Staker.DepositIdentifier", + "name": "depositId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "oldValidator", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newValidator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "earningPower", + "type": "uint256" + } + ], + "name": "ValidatorAltered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "bonusWeight", + "type": "uint256" + } + ], + "name": "ValidatorBonusWeightSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validatorOwner", + "type": "address" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "b", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "c", + "type": "bytes32" + } + ], + "indexed": false, + "internalType": "struct IConsensusRegistry.BLS12_381PublicKey", + "name": "newPubKey", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes16", + "name": "b", + "type": "bytes16" + } + ], + "indexed": false, + "internalType": "struct IConsensusRegistry.BLS12_381Signature", + "name": "newPop", + "type": "tuple" + } + ], + "name": "ValidatorKeysSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldAuthority", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newAuthority", + "type": "address" + } + ], + "name": "ValidatorStakeAuthoritySet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "newWeight", + "type": "uint256" + } + ], + "name": "ValidatorTotalWeightUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldThreshold", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newThreshold", + "type": "uint256" + } + ], + "name": "ValidatorWeightThresholdSet", + "type": "event" + }, + { + "inputs": [], + "name": "ALTER_CLAIMER_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ALTER_DELEGATEE_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ALTER_VALIDATOR_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "CLAIM_REWARD_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_CLAIM_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "REWARD_DURATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "REWARD_TOKEN", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SCALE_FACTOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "STAKE_MORE_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "STAKE_TOKEN", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "STAKE_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "STAKE_WITH_VALIDATOR_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WITHDRAW_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_newClaimer", + "type": "address" + } + ], + "name": "alterClaimer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_newClaimer", + "type": "address" + }, + { + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_deadline", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "alterClaimerOnBehalf", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_newDelegatee", + "type": "address" + } + ], + "name": "alterDelegatee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_newDelegatee", + "type": "address" + }, + { + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_deadline", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "alterDelegateeOnBehalf", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_newValidator", + "type": "address" + } + ], + "name": "alterValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_newValidator", + "type": "address" + }, + { + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_deadline", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "alterValidatorOnBehalf", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_tipReceiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_requestedTip", + "type": "uint256" + } + ], + "name": "bumpEarningPower", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_validatorOwner", + "type": "address" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "b", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "c", + "type": "bytes32" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381PublicKey", + "name": "_validatorPubKey", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes16", + "name": "b", + "type": "bytes16" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381Signature", + "name": "_validatorPoP", + "type": "tuple" + } + ], + "name": "changeValidatorKey", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_validatorOwner", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isLeader", + "type": "bool" + } + ], + "name": "changeValidatorLeader", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "claimFeeParameters", + "outputs": [ + { + "internalType": "uint96", + "name": "feeAmount", + "type": "uint96" + }, + { + "internalType": "address", + "name": "feeCollector", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + } + ], + "name": "claimReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_deadline", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "claimRewardOnBehalf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "commitValidatorCommittee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "depositor", + "type": "address" + } + ], + "name": "depositorTotalEarningPower", + "outputs": [ + { + "internalType": "uint256", + "name": "earningPower", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "depositor", + "type": "address" + } + ], + "name": "depositorTotalStaked", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "depositId", + "type": "uint256" + } + ], + "name": "deposits", + "outputs": [ + { + "internalType": "uint96", + "name": "balance", + "type": "uint96" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint96", + "name": "earningPower", + "type": "uint96" + }, + { + "internalType": "address", + "name": "delegatee", + "type": "address" + }, + { + "internalType": "address", + "name": "claimer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "rewardPerTokenCheckpoint", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "scaledUnclaimedRewardCheckpoint", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "earningPowerCalculator", + "outputs": [ + { + "internalType": "contract IEarningPowerCalculator", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "eip712Domain", + "outputs": [ + { + "internalType": "bytes1", + "name": "fields", + "type": "bytes1" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }, + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "verifyingContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "extensions", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "invalidateNonce", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "isLeaderDefault", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "rewardNotifier", + "type": "address" + } + ], + "name": "isRewardNotifier", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastCheckpointTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastTimeRewardDistributed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxBumpTip", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "notifyRewardAmount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_delegatee", + "type": "address" + }, + { + "internalType": "address", + "name": "_claimer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "_v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "_r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "_s", + "type": "bytes32" + } + ], + "name": "permitAndStake", + "outputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "_v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "_r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "_s", + "type": "bytes32" + } + ], + "name": "permitAndStakeMore", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validator", + "type": "address" + } + ], + "name": "registeredValidators", + "outputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "b", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "c", + "type": "bytes32" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381PublicKey", + "name": "pubKey", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "a", + "type": "bytes32" + }, + { + "internalType": "bytes16", + "name": "b", + "type": "bytes16" + } + ], + "internalType": "struct IConsensusRegistry.BLS12_381Signature", + "name": "pop", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "registry", + "outputs": [ + { + "internalType": "contract IConsensusRegistryExtended", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rewardEndTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rewardPerTokenAccumulated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rewardPerTokenAccumulatedCheckpoint", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "scaledRewardRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_validator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_newBonusWeight", + "type": "uint256" + } + ], + "name": "setBonusWeight", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint96", + "name": "feeAmount", + "type": "uint96" + }, + { + "internalType": "address", + "name": "feeCollector", + "type": "address" + } + ], + "internalType": "struct Staker.ClaimFeeParameters", + "name": "_params", + "type": "tuple" + } + ], + "name": "setClaimFeeParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_delay", + "type": "uint256" + } + ], + "name": "setCommitteeActivationDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newEarningPowerCalculator", + "type": "address" + } + ], + "name": "setEarningPowerCalculator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_isLeaderDefault", + "type": "bool" + } + ], + "name": "setIsLeaderDefault", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newMaxBumpTip", + "type": "uint256" + } + ], + "name": "setMaxBumpTip", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IConsensusRegistryExtended", + "name": "_registry", + "type": "address" + } + ], + "name": "setRegistry", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_rewardNotifier", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isEnabled", + "type": "bool" + } + ], + "name": "setRewardNotifier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newTotalStakeCap", + "type": "uint256" + } + ], + "name": "setTotalStakeCap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newAuthority", + "type": "address" + } + ], + "name": "setValidatorStakeAuthority", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newValidatorWeightThreshold", + "type": "uint256" + } + ], + "name": "setValidatorWeightThreshold", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_delegatee", + "type": "address" + } + ], + "name": "stake", + "outputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_delegatee", + "type": "address" + }, + { + "internalType": "address", + "name": "_claimer", + "type": "address" + } + ], + "name": "stake", + "outputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_delegatee", + "type": "address" + }, + { + "internalType": "address", + "name": "_claimer", + "type": "address" + }, + { + "internalType": "address", + "name": "_validator", + "type": "address" + } + ], + "name": "stake", + "outputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "stakeMore", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_deadline", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "stakeMoreOnBehalf", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_delegatee", + "type": "address" + }, + { + "internalType": "address", + "name": "_claimer", + "type": "address" + }, + { + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_deadline", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "stakeOnBehalf", + "outputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_delegatee", + "type": "address" + }, + { + "internalType": "address", + "name": "_claimer", + "type": "address" + }, + { + "internalType": "address", + "name": "_validator", + "type": "address" + }, + { + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_deadline", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "stakeOnBehalf", + "outputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_delegatee", + "type": "address" + } + ], + "name": "surrogates", + "outputs": [ + { + "internalType": "contract DelegationSurrogate", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalEarningPower", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalStakeCap", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalStaked", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + } + ], + "name": "unclaimedReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_frequency", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "_weighted", + "type": "bool" + } + ], + "name": "updateLeaderSelection", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validator", + "type": "address" + } + ], + "name": "validatorBonusWeight", + "outputs": [ + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "validatorForAtomicEarningPowerCalculation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "depositId", + "type": "uint256" + } + ], + "name": "validatorForDeposit", + "outputs": [ + { + "internalType": "address", + "name": "validator", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "validatorStakeAuthority", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validator", + "type": "address" + } + ], + "name": "validatorStakeWeight", + "outputs": [ + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_validator", + "type": "address" + } + ], + "name": "validatorTotalWeight", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "validatorWeightThreshold", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Staker.DepositIdentifier", + "name": "_depositId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_deadline", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "withdrawOnBehalf", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x000200000000000200140000000000020001000000010355000000600310027000000d390030019d00000d39033001970000000100200190000000660000c13d0000008008000039000000400080043f000000040030008c000010460000413d000000000201043b000000e00220027000000d5a0020009c0000016a0000213d00000d940020009c000001860000213d00000db10020009c000001ae0000a13d00000db20020009c000003200000a13d00000db30020009c000003ae0000213d00000db70020009c000008fb0000613d00000db80020009c0000085c0000613d00000db90020009c000010460000c13d000000440030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000402100370000000000202043b000e00000002001d00000d3c0020009c000010460000213d0000002401100370000000000201043b000000000002004b0000000001000039000000010100c039000d00000002001d000000000012004b000010460000c13d0000001a01000039000000000101041a00000d3c021001970000000001000411000000000021004b00000b5b0000c13d0000001801000039000000000101041a00000de502000041000000000020044300000d3c01100197000c00000001001d0000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b000000000001004b000010460000613d000000400300043d00000024013000390000000d02000029000000000021043500000e0d01000041000000000013043500000004013000390000000e02000029000000000021043500000d390030009c000e00000003001d00000d390100004100000000010340190000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000de1011001c70000000c0200002934dd34ce0000040f000000010020019000000f1a0000613d0000000e01000029000000000200001934dd16fd0000040f0000000001000019000034de0001042e000001c004000039000000400040043f0000000002000416000000000002004b000010460000c13d0000001f0230003900000d3a02200197000001c002200039000000400020043f0000001f0530018f00000d3b06300198000001c002600039000000780000613d000000000701034f000000007807043c0000000004840436000000000024004b000000740000c13d000000000005004b000000850000613d000000000161034f0000000304500210000000000502043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000120435000001400030008c000010460000413d000001c00100043d00000d3c0010009c000010460000213d000001e00400043d00000d3c0040009c000010460000213d000002000200043d000e00000002001d00000d3c0020009c000010460000213d000002600200043d00000d3c0020009c000010460000213d000002800500043d000d00000005001d00000d3c0050009c000010460000213d000002a00600043d00000d3d0060009c000010460000213d0000001f05600039000000000035004b000000000700001900000d3e0700804100000d3e05500197000000000005004b000000000800001900000d3e0800404100000d3e0050009c000000000807c019000000000008004b000010460000c13d000001c005600039000000000505043300000d3d0050009c000010850000213d0000001f0750003900000e22077001970000003f0770003900000e2207700197000000400900043d0000000007790019000000000097004b0000000008000039000000010800403900000d3d0070009c000010850000213d0000000100800190000010850000c13d000001c008300039000002400300043d000900000003001d000002200300043d000b00000003001d000000400070043f000a00000009001d0000000003590436000c00000003001d000001e0036000390000000006350019000000000086004b000010460000213d000000000005004b0000000c09000029000000d00000613d000000000600001900000000079600190000000008360019000000000808043300000000008704350000002006600039000000000056004b000000c90000413d00000000035900190000000000030435000002e00500043d000000000005004b0000000003000039000000010300c039000800000005001d000000000035004b000010460000c13d000000400500043d00000d3f0050009c000010850000213d00000d3c04400197000002c00300043d000300000003001d0000004003500039000000400030043f0000000103000039000500000005001d000000000535043600000d4003000041000400000005001d0000000000350435000000800010043f000600000004001d000000a00040043f00070d3c0020019c000008010000613d0000000101000039000000000201041a000000400100043d000200000001001d000000000100041400000d390010009c00000d3901008041000000c00110021000000d41011001c7000100000002001d00000d3c052001970000800d02000039000000030300003900000d4204000041000000070600002934dd34ce0000040f0000000100200190000010460000613d000000010100002900000d430110019700000007011001af0000000104000039000000000014041b0000000201000039000000000101041a000000020500002900000020025000390000000b030000290000000000320435000000000015043500000d390050009c00000d39050080410000004001500210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d44011001c70000800d02000039000000000304001900000d450400004134dd34ce0000040f0000000100200190000010460000613d0000000e01000029000e0d3c0010019c0000000b010000290000000202000039000000000012041b000008010000613d0000000501000039000000000201041a000000000100041400000d390010009c00000d3901008041000000c00110021000000d41011001c7000b00000002001d00000d3c052001970000800d02000039000000030300003900000d46040000410000000e0600002934dd34ce0000040f0000000100200190000010460000613d0000000b0100002900000d43011001970000000e011001af0000000502000039000000000012041b000000a00100043d00000d3c01100197000000060010006c0000114b0000c13d0000000a010000290000000001010433000e00000001001d000000200010008c000011930000413d0000000e0100002900000d3d0010009c000010850000213d0000000f01000039000000000101041a000000010210019000000001011002700000007f0110618f0000001f0010008c00000000030000390000000103002039000000000032004b000006150000c13d000000200010008c000001590000413d0000001f0110003900000005011002700000000e020000290000001f022000390000000502200270000000000012004b000001590000813d00000d490110009a00000d490220009a000000000002041b0000000102200039000000000012004b000001550000413d0000000f01000039000000000010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d4a011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000200200008a0000000e02200180000000000101043b000014d60000c13d0000002003000039000014e30000013d00000d5b0020009c000001970000213d00000d780020009c000001c30000a13d00000d790020009c000003490000a13d00000d7a0020009c000003dd0000213d00000d7e0020009c0000094b0000613d00000d7f0020009c000008610000613d00000d800020009c000010460000c13d000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b000000000010043f0000001401000039000000200010043f0000004002000039000000000100001934dd349b0000040f000008f90000013d00000d950020009c000001d20000a13d00000d960020009c000003780000a13d00000d970020009c000004070000213d00000d9b0020009c000009860000613d00000d9c0020009c000008660000613d00000d9d0020009c000010460000c13d0000000001000416000000000001004b000010460000c13d0000001801000039000008f90000013d00000d5c0020009c000001e10000a13d00000d5d0020009c000003870000a13d00000d5e0020009c000004180000213d00000d620020009c0000098b0000613d00000d630020009c000008750000613d00000d640020009c000010460000c13d000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b00000d3c0010009c000010460000213d34dd18cd0000040f000009b00000013d00000dc00020009c000002570000213d00000dc70020009c000004700000a13d00000dc80020009c000007290000613d00000dc90020009c000005ef0000613d00000dca0020009c000010460000c13d0000000001000416000000000001004b000010460000c13d0000000001000412001400000001001d001300200000003d000080050100003900000044030000390000000004000415000000140440008a00000b190000013d00000d870020009c000002660000213d00000d8e0020009c000004980000a13d00000d8f0020009c000007450000613d00000d900020009c000005f40000613d00000d910020009c000010460000c13d0000000001000416000000000001004b000010460000c13d0000001b0100003900000ade0000013d00000da40020009c000002900000213d00000dab0020009c000004a10000a13d00000dac0020009c000007840000613d00000dad0020009c0000061b0000613d00000dae0020009c000010460000c13d0000000001000416000000000001004b000010460000c13d0000000a0100003900000ade0000013d00000d6b0020009c0000029d0000213d00000d720020009c000004ac0000a13d00000d730020009c0000078b0000613d00000d740020009c0000065b0000613d00000d750020009c000010460000c13d000000e40030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000402100370000000000202043b000e00000002001d0000002402100370000000000202043b000d00000002001d00000d3c0020009c000010460000213d0000004402100370000000000202043b000c00000002001d00000d3c0020009c000010460000213d0000008401100370000000000101043b000b00000001001d000000ff0010008c000010460000213d00000dd10100004100000000001004430000000001000412000000040010044300000020010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b00000de502000041000000000020044300000d3c01100197000a00000001001d0000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b000000000001004b000010460000613d000000400500043d00000de701000041000000000015043500000001010003670000006402100370000000000202043b000000a403100370000000000303043b000000c401100370000000000101043b000000c4045000390000000000140435000000a401500039000000000031043500000084015000390000000b0300002900000000003104350000006401500039000000000021043500000044015000390000000e020000290000000000210435000000000100041000000d3c0110019700000024025000390000000000120435000000000100041100000d3c011001970000000402500039000000000012043500000d390050009c000b00000005001d00000d390100004100000000010540190000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000de8011001c70000000a0200002934dd34ce0000040f0000000100200190000002550000613d0000000b0100002900000d3d0010009c000010850000213d0000000b01000029000000400010043f0000000001000411000009460000013d00000dc10020009c000004c60000a13d00000dc20020009c000007a70000613d00000dc30020009c000006820000613d00000dc40020009c000010460000c13d0000000001000416000000000001004b000010460000c13d00000dcf01000041000000800010043f00000ddd01000041000034de0001042e00000d880020009c000005090000a13d00000d890020009c000007ae0000613d00000d8a0020009c000006a40000613d00000d8b0020009c000010460000c13d000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000301043b0000000101000039000000000101041a00000d3c021001970000000001000411000000000021004b00000ab80000c13d0000001301000039000000000101041a000000800010043f000e00000003001d000000a00030043f000000000100041400000d390010009c00000d3901008041000000c00110021000000df5011001c70000800d02000039000000010300003900000d510400004134dd34ce0000040f0000000100200190000010460000613d0000000e010000290000001302000039000000000012041b0000000001000019000034de0001042e00000da50020009c000005120000a13d00000da60020009c000007ee0000613d00000da70020009c000006eb0000613d00000da80020009c000010460000c13d0000000001000416000000000001004b000010460000c13d0000000501000039000008f90000013d00000d6c0020009c0000052c0000a13d00000d6d0020009c000008050000613d00000d6e0020009c000006f00000613d00000d6f0020009c000010460000c13d000000c40030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000002402100370000000000202043b000d00000002001d0000000402100370000000000202043b000e00000002001d0000006401100370000000000101043b000c00000001001d000000ff0010008c000010460000213d0000000e01000029000000000010043f0000000801000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000200041100000d3c02200197000000000301043b000000000103041a0000006001100270000000000012004b00000c830000c13d000b00000001001d000a00000003001d00000dd10100004100000000001004430000000001000412000000040010044300000020010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b00000de502000041000000000020044300000d3c01100197000900000001001d0000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b000000000001004b000010460000613d000000400500043d00000de701000041000000000015043500000001010003670000004402100370000000000202043b0000008403100370000000000303043b000000a401100370000000000101043b000000c4045000390000000000140435000000a401500039000000000031043500000084015000390000000c0300002900000000003104350000006401500039000000000021043500000044015000390000000d020000290000000000210435000000000100041000000d3c011001970000002402500039000000000012043500000004015000390000000b02000029000000000021043500000d390050009c000c00000005001d00000d390100004100000000010540190000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000de8011001c7000000090200002934dd34ce0000040f00000001002001900000031d0000613d0000000c0100002900000d3d0010009c000010850000213d0000000c01000029000000400010043f0000000a010000290000000e02000029000007800000013d00000dba0020009c000005350000a13d00000dbb0020009c0000080a0000613d00000dbc0020009c000007000000613d00000dbd0020009c000010460000c13d000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b000e00000001001d0000000001000411000000000010043f0000000d01000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000000000101041a000000ff0010019000000b620000c13d00000ddf01000041000000000010043f00000e1501000041000000040010043f0000000001000411000000240010043f00000de101000041000034df0001043000000d810020009c0000053e0000a13d00000d820020009c0000080f0000613d00000d830020009c000007070000613d00000d840020009c000010460000c13d000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b00000d3c0010009c000010460000213d0000000102000039000000000202041a00000d3c032001970000000002000411000000000032004b00000b8d0000c13d00000d3c061001970000001801000039000000000201041a000000000100041400000d390010009c00000d3901008041000000c00110021000000d41011001c7000d00000002001d00000d3c052001970000800d02000039000000030300003900000df204000041000e00000006001d34dd34ce0000040f0000000100200190000010460000613d0000000d0100002900000d43011001970000000e011001af0000001802000039000000000012041b0000000001000019000034de0001042e00000d9e0020009c0000058d0000a13d00000d9f0020009c000008160000613d00000da00020009c000007190000613d00000da10020009c000010460000c13d0000000001000416000000000001004b000010460000c13d00000dfd01000041000000800010043f00000ddd01000041000034de0001042e00000d650020009c000005bf0000a13d00000d660020009c0000081d0000613d00000d670020009c000007240000613d00000d680020009c000010460000c13d000000440030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000002402100370000000000202043b00000d3c0020009c000010460000213d000e00000002001d0000001904000039000000000204041a00000d43022001970000000e022001af0000000401100370000000000101043b000d00000001001d000000000024041b000000000010043f0000000801000039000000200010043f0000004002000039000000000100001934dd349b0000040f000c00000001001d000000000200041134dd18e00000040f0000000c010000290000000d020000290000000e03000029000006e40000013d00000db40020009c000009960000613d00000db50020009c000008810000613d00000db60020009c000010460000c13d000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b000e00000001001d00000d3c0010009c000010460000213d0000000101000039000000000101041a00000d3c021001970000000001000411000000000021004b00000ab80000c13d0000000e06000029000000000006004b000008010000613d0000000501000039000000000201041a000000000100041400000d390010009c00000d3901008041000000c00110021000000d41011001c7000d00000002001d00000d3c052001970000800d02000039000000030300003900000d460400004134dd34ce0000040f0000000100200190000010460000613d0000000d0100002900000d43011001970000000e011001af0000000502000039000000000012041b0000000001000019000034de0001042e00000d7b0020009c000009ac0000613d00000d7c0020009c000008910000613d00000d7d0020009c000010460000c13d000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b000000000010043f0000000801000039000000200010043f0000004002000039000000000100001934dd349b0000040f0000000402100039000000000202041a0000000303100039000000000303041a0000000204100039000000000404041a0000000105100039000000000505041a000000000101041a00000d5306100197000000800060043f0000006001100270000000a00010043f00000d5301500197000000c00010043f0000006001500270000000e00010043f00000d3c01400197000001000010043f000001200030043f000001400020043f00000deb01000041000034de0001042e00000d980020009c000009b70000613d00000d990020009c000008b30000613d00000d9a0020009c000010460000c13d000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b00000d3c0010009c000010460000213d34dd18450000040f000009b00000013d00000d5f0020009c000009be0000613d00000d600020009c000008f50000613d00000d610020009c000010460000c13d000000640030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000004402100370000000000402043b00000d3d0040009c000010460000213d0000002302400039000000000032004b000010460000813d0000000405400039000000000251034f000000000202043b00000d3d0020009c000010850000213d0000001f0620003900000e22066001970000003f0660003900000e220660019700000dcd0060009c000010850000213d0000008006600039000000400060043f000000800020043f00000000042400190000002404400039000000000034004b000010460000213d000c00000008001d0000002003500039000000000431034f00000e22052001980000001f0620018f000000a003500039000004490000613d000000a007000039000000000804034f000000008908043c0000000007970436000000000037004b000004450000c13d000000000006004b000004560000613d000000000454034f0000000305600210000000000603043300000000065601cf000000000656022f000000000404043b0000010005500089000000000454022f00000000045401cf000000000464019f0000000000430435000000a00220003900000000000204350000000402100370000000000202043b000d00000002001d0000002401100370000000000101043b000e00000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b0000000e0010006c00000f270000a13d00000ddc01000041000000000010043f00000d4801000041000034df0001043000000dcb0020009c000009d40000613d00000dcc0020009c000010460000c13d000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b00000d3c0010009c000010460000213d000000000010043f0000001701000039000000200010043f0000004002000039000000000100001934dd349b0000040f000e00000001001d34dd170f0000040f000d00000001001d0000000e01000029000000030110003934dd17250000040f000c00000001001d000000400200043d000e00000002001d0000000d0100002934dd17380000040f0000000e0100002900000060021000390000000c0100002934dd17410000040f0000000e0100002900000d390010009c00000d3901008041000000400110021000000e20011001c7000034de0001042e00000d920020009c00000a0a0000613d00000d930020009c000010460000c13d0000000001000416000000000001004b000010460000c13d000000030100003900000ade0000013d00000daf0020009c00000a160000613d00000db00020009c000010460000c13d0000000001000416000000000001004b000010460000c13d000000000100041134dd1c690000040f0000000001000019000034de0001042e00000d760020009c00000a3d0000613d00000d770020009c000010460000c13d000000840030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000002402100370000000000302043b00000d3c0030009c000010460000213d0000004402100370000000000402043b00000d3c0040009c000010460000213d0000006402100370000000000502043b00000d3c0050009c000010460000213d0000000401100370000000000201043b000000000100041134dd2c340000040f000009b00000013d00000dc50020009c00000a960000613d00000dc60020009c000010460000c13d000000440030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000402100370000000000202043b000e00000002001d00000d3c0020009c000010460000213d0000002401100370000000000201043b000000000002004b0000000001000039000000010100c039000d00000002001d000000000012004b000010460000c13d0000000101000039000000000101041a00000d3c021001970000000001000411000000000021004b00000ab80000c13d0000000e01000029000000000010043f0000000d01000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000000000201041a00000e23022001970000000d03000029000000000232019f000000000021041b000000400100043d000000000031043500000d390010009c00000d39010080410000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d4a011001c70000800d02000039000000020300003900000e1f040000410000000e0500002934dd34ce0000040f0000000100200190000010460000613d0000000001000019000034de0001042e00000d8c0020009c00000abc0000613d00000d8d0020009c000010460000c13d0000000001000416000000000001004b000010460000c13d0000001a01000039000008f90000013d00000da90020009c00000ac30000613d00000daa0020009c000010460000c13d0000000001000416000000000001004b000010460000c13d000000000103001934dd17910000040f000d00000001001d000e00000002001d000000000010043f0000000801000039000000200010043f0000004002000039000000000100001934dd349b0000040f000c00000001001d000000000200041134dd18e00000040f0000000c010000290000000d020000290000000e0300002934dd20a00000040f0000000001000019000034de0001042e00000d700020009c00000acf0000613d00000d710020009c000010460000c13d0000000001000416000000000001004b000010460000c13d0000000b0100003900000ade0000013d00000dbe0020009c00000ae20000613d00000dbf0020009c000010460000c13d0000000001000416000000000001004b000010460000c13d34dd1bac0000040f000009b00000013d00000d850020009c00000b0f0000613d00000d860020009c000010460000c13d000000440030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000402100370000000000202043b000e00000002001d00000d3d0020009c000010460000213d0000002401100370000000000201043b000000000002004b0000000001000039000000010100c039000d00000002001d000000000012004b000010460000c13d0000001a01000039000000000101041a00000d3c021001970000000001000411000000000021004b00000b5b0000c13d0000001801000039000000000101041a00000de502000041000000000020044300000d3c01100197000c00000001001d0000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b000000000001004b000010460000613d0000000e0100002900000d3d01100197000000400400043d00000024024000390000000d03000029000000000032043500000df40200004100000000002404350000000402400039000000000012043500000d390040009c000e00000004001d00000d390100004100000000010440190000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000de1011001c70000000c0200002934dd34ce0000040f000000010020019000000fb30000613d0000000e0100002900000d3d0010009c000010850000213d0000000e01000029000000400010043f0000000001000019000034de0001042e00000da20020009c00000b200000613d00000da30020009c000010460000c13d000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000201043b000000000002004b0000000001000039000000010100c039000e00000002001d000000000012004b000010460000c13d0000001a01000039000000000101041a00000d3c021001970000000001000411000000000021004b00000b5b0000c13d0000001c01000039000000000101041a000d00000001001d000000ff001001900000000001000039000000010100c039000000800010043f0000000e01000029000000a00010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000df5011001c70000800d02000039000000010300003900000d580400004134dd34ce0000040f0000000100200190000010460000613d000001000100008a0000000d0110017f0000000e011001af0000001c02000039000000000012041b0000000001000019000034de0001042e00000d690020009c00000b540000613d00000d6a0020009c000010460000c13d000000440030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000402100370000000000202043b000e00000002001d00000d3c0020009c000010460000213d0000002401100370000000000601043b0000001a01000039000000000101041a00000d3c021001970000000001000411000000000021004b00000b5b0000c13d000000000100041400000d390010009c00000d3901008041000000c00110021000000d41011001c70000800d02000039000000030300003900000de2040000410000000e05000029000d00000006001d34dd34ce0000040f0000000100200190000010460000613d0000000e01000029000000000010043f0000001601000039000000200010043f0000004002000039000000000100001934dd349b0000040f0000000d02000029000000000021041b0000000e0100002934dd2f9f0000040f0000000001000019000034de0001042e0000000001000416000000000001004b000010460000c13d000000040100003900000ade0000013d0000000001000416000000000001004b000010460000c13d00000dd10100004100000000001004430000000001000412000000040010044300000100010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b000000ff0010008c00000b910000c13d0000000f04000039000000000304041a000000010630019000000001013002700000007f0510018f00000000010560190000001f0010008c00000000020000390000000102002039000000000223013f000000010020019000000cae0000613d00000def01000041000000000010043f0000002201000039000000040010043f00000df001000041000034df000104300000000001000416000000000001004b000010460000c13d000000000103001934dd179d0000040f000c00000001001d000d00000002001d000e00000003001d000b00000004001d000a00000005001d000000000010043f0000000801000039000000200010043f0000004002000039000000000100001934dd349b0000040f000900000001001d0000000e0200002934dd18e00000040f0000000b0100002934dd1c530000040f0000000e0100002934dd1c690000040f0000000d0200002900000d3c02200197000000400400043d000700000004001d000000600340003900000000002304350000000e0200002900000d3c0220019700000080034000390000000000230435000000a0024000390000000000120435000000c0010000390000000002140436000800000002001d00000e0101000041000000000012043500000040014000390000000c020000290000000000210435000000c0014000390000000b020000290000000000210435000000e002000039000000000104001934dd16fd0000040f00000007010000290000000002010433000000080100002934dd349b0000040f34dd1c7d0000040f00000000020100190000000e010000290000000a0300002934dd1d3b0000040f00000009010000290000000c020000290000000d0300002934dd18ed0000040f0000000001000019000034de0001042e000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b000e00000001001d00000d3c0010009c000010460000213d0000000101000039000000000101041a00000d3c021001970000000001000411000000000021004b00000ab80000c13d0000001a01000039000000000201041a000000000100041400000d390010009c00000d3901008041000000c00110021000000d41011001c7000d00000002001d00000d3c052001970000800d02000039000000030300003900000d56040000410000000e0600002934dd34ce0000040f0000000100200190000010460000613d0000000d0100002900000d43011001970000000e011001af0000001a02000039000000000012041b0000000001000019000034de0001042e000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000301043b0000000101000039000000000101041a00000d3c021001970000000001000411000000000021004b00000ab80000c13d0000000201000039000000000101041a000000800010043f000e00000003001d000000a00030043f000000000100041400000d390010009c00000d3901008041000000c00110021000000df5011001c70000800d02000039000000010300003900000d450400004134dd34ce0000040f0000000100200190000010460000613d0000000e010000290000000202000039000000000012041b0000000001000019000034de0001042e0000000001000416000000000001004b000010460000c13d000000000103001934dd179d0000040f000e00000001001d000c00000002001d000d00000003001d0000000001040019000900000004001d000b00000005001d34dd1c530000040f0000000d0100002934dd1c690000040f0000000d0200002900000d3c02200197000000400400043d000700000004001d00000080034000390000000000230435000000a0024000390000000000120435000000c0010000390000000002140436000800000002001d00000df301000041000000000012043500000040014000390000000e0200002900000000002104350000000c0100002900000d3c02100197000a00000002001d00000060014000390000000000210435000000c00140003900000009020000290000000000210435000000e002000039000000000104001934dd16fd0000040f00000007010000290000000002010433000000080100002934dd349b0000040f34dd1c7d0000040f00000000020100190000000d010000290000000b0300002934dd1d3b0000040f0000001903000039000000000103041a00000d43011001970000000a011001af000000000013041b0000000e01000029000000000010043f0000000801000039000000200010043f0000004002000039000000000100001934dd349b0000040f0000000e020000290000000c0300002934dd24c30000040f0000001902000039000000000102041a00000d4301100197000000000012041b0000000001000019000034de0001042e0000000001000416000000000001004b000010460000c13d0000001901000039000008f90000013d000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b000000000010043f0000000801000039000000200010043f0000004002000039000000000100001934dd349b0000040f34dd2f520000040f00000de30110012a000009b00000013d0000000001000416000000000001004b000010460000c13d00000e0101000041000000800010043f00000ddd01000041000034de0001042e000000640030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000002402100370000000000302043b00000d3c0030009c000010460000213d0000004402100370000000000402043b00000d3c0040009c000010460000213d0000000401100370000000000201043b000000000100041134dd29240000040f000009b00000013d0000000001000416000000000001004b000010460000c13d0000000e01000039000000000101041a00000d5302100197000000800020043f0000006001100270000000a00010043f00000dff01000041000034de0001042e0000000001000416000000000001004b000010460000c13d34dd188d0000040f000009b00000013d000000440030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000002402100370000000000202043b000e00000002001d00000d3c0020009c000010460000213d0000000401100370000000000101043b000d00000001001d000000000010043f0000000801000039000000200010043f0000004002000039000000000100001934dd349b0000040f000c00000001001d000000000200041134dd18e00000040f0000000c010000290000000d020000290000000e0300002934dd18ed0000040f0000000001000019000034de0001042e0000000001000416000000000001004b000010460000c13d000000000103001934dd17f20000040f000c00000001001d000d00000002001d000e00000003001d000b00000004001d000a00000005001d000000000010043f0000000801000039000000200010043f0000004002000039000000000100001934dd349b0000040f000900000001001d0000000e0200002934dd18e00000040f0000000b0100002934dd1c530000040f0000000e0100002934dd1c690000040f0000000e0200002900000d3c02200197000000400400043d000700000004001d00000080034000390000000000230435000000a0024000390000000000120435000000c0010000390000000002140436000800000002001d00000dfd01000041000000000012043500000040014000390000000c02000029000000000021043500000060014000390000000d020000290000000000210435000000c0014000390000000b020000290000000000210435000000e002000039000000000104001934dd16fd0000040f00000007010000290000000002010433000000080100002934dd349b0000040f34dd1c7d0000040f00000000020100190000000e010000290000000a0300002934dd1d3b0000040f00000009010000290000000c020000290000000d0300002934dd20a00000040f0000000001000019000034de0001042e0000000001000416000000000001004b000010460000c13d00000e0201000041000000800010043f00000ddd01000041000034de0001042e000000440030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000002402100370000000000202043b000e00000002001d00000d3c0020009c000010460000213d0000000401100370000000000101043b000d00000001001d000000000010043f0000000801000039000000200010043f0000004002000039000000000100001934dd349b0000040f000c00000001001d000000000200041134dd18e00000040f0000000c010000290000000d020000290000000e0300002934dd23320000040f0000000001000019000034de0001042e0000000001000416000000000001004b000010460000c13d00000df601000041000000800010043f00000ddd01000041000034de0001042e0000000001000416000000000001004b000010460000c13d000000000103001934dd179d0000040f000c00000001001d000d00000002001d000e00000003001d000b00000004001d000a00000005001d000000000010043f0000000801000039000000200010043f0000004002000039000000000100001934dd349b0000040f000900000001001d0000000e0200002934dd18e00000040f0000000b0100002934dd1c530000040f0000000e0100002934dd1c690000040f0000000d0200002900000d3c02200197000000400400043d000700000004001d000000600340003900000000002304350000000e0200002900000d3c0220019700000080034000390000000000230435000000a0024000390000000000120435000000c0010000390000000002140436000800000002001d00000df601000041000000000012043500000040014000390000000c020000290000000000210435000000c0014000390000000b020000290000000000210435000000e002000039000000000104001934dd16fd0000040f00000007010000290000000002010433000000080100002934dd349b0000040f34dd1c7d0000040f00000000020100190000000e010000290000000a0300002934dd1d3b0000040f00000009010000290000000c020000290000000d0300002934dd23320000040f0000000001000019000034de0001042e000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b000e00000001001d00000d3c0010009c000010460000213d0000000101000039000000000201041a00000d3c052001970000000001000411000000000051004b00000ab80000c13d0000000e06000029000000000006004b00000cc20000c13d00000e0c01000041000000000010043f00000d4801000041000034df000104300000000001000416000000000001004b000010460000c13d0000000c0100003900000ade0000013d0000000001000416000000000001004b000010460000c13d000000090100003900000ade0000013d0000000001000416000000000001004b000010460000c13d00000df301000041000000800010043f00000ddd01000041000034de0001042e0000000001000416000000000001004b000010460000c13d00000dde01000041000000800010043f00000ddd01000041000034de0001042e0000000001000416000000000001004b000010460000c13d000000000103001934dd17f20000040f000c00000001001d000d00000002001d000e00000003001d000b00000004001d000a00000005001d000000000010043f0000000801000039000000200010043f0000004002000039000000000100001934dd349b0000040f000900000001001d0000000e0200002934dd18e00000040f0000000b0100002934dd1c530000040f0000000e0100002934dd1c690000040f0000000e0200002900000d3c02200197000000400400043d000700000004001d00000080034000390000000000230435000000a0024000390000000000120435000000c0010000390000000002140436000800000002001d00000dde01000041000000000012043500000040014000390000000c02000029000000000021043500000060014000390000000d020000290000000000210435000000c0014000390000000b020000290000000000210435000000e002000039000000000104001934dd16fd0000040f00000007010000290000000002010433000000080100002934dd349b0000040f34dd1c7d0000040f00000000020100190000000e010000290000000a0300002934dd1d3b0000040f00000009010000290000000c020000290000000d0300002934dd1e230000040f0000000001000019000034de0001042e0000000001000416000000000001004b000010460000c13d0000001c01000039000009cd0000013d0000000001000416000000000001004b000010460000c13d000000130100003900000ade0000013d000000440030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000002402100370000000000302043b00000d3c0030009c000010460000213d0000000401100370000000000201043b0000000001000411000000000401001934dd29240000040f000009b00000013d000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b00000d3c0010009c000010460000213d000000000010043f000000160100003900000ada0000013d0000000001000416000000000001004b000010460000c13d0000000001000412001200000001001d001100400000003d000080050100003900000044030000390000000004000415000000120440008a000000050440021000000dd10200004134dd34b00000040f000000800010043f00000ddd01000041000034de0001042e000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b000e00000001001d000000000010043f0000000801000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000201043b0000000201200039000000000101041a00000d3c011001970000000003000411000000000031004b000008b00000613d000000000102041a0000006001100270000000000031004b00000cd50000c13d0000000e0100002934dd26840000040f000009b00000013d000000240030008c000010460000413d0000000001000416000000000001004b000010460000c13d0000001a01000039000000000101041a00000d3c021001970000000001000411000000000021004b00000b5b0000c13d0000001801000039000000000101041a00000de502000041000000000020044300000d3c01100197000e00000001001d0000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b000000000001004b000010460000613d000000400300043d00000dfe01000041000000000013043500000004010000390000000101100367000000000101043b0000000402300039000000000012043500000d390030009c000d00000003001d00000d390100004100000000010340190000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000df0011001c70000000e0200002934dd34ce0000040f000000010020019000000b4e0000c13d00000060061002700000001f0460018f00000d3b05600198000000400200043d000000000352001900000fbf0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000008f00000c13d00000fbf0000013d0000000001000416000000000001004b000010460000c13d0000000101000039000000000101041a00000b1c0000013d000000c40030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000402100370000000000202043b000e00000002001d0000002402100370000000000202043b000d00000002001d00000d3c0020009c000010460000213d0000004402100370000000000202043b000c00000002001d00000d3c0020009c000010460000213d0000006402100370000000000202043b000b00000002001d00000d3c0020009c000010460000213d000000a402100370000000000202043b00000d3d0020009c000010460000213d0000008401100370000000000101043b000a00000001001d0000000401200039000000000203001934dd17470000040f000900000001001d0000000a0100002934dd1c530000040f0000000b0100002934dd1c690000040f000000400300043d000800000003001d000000c0023000390000000000120435000000e0013000390000000a020000290000000000210435000000e0010000390000000002130436000a00000002001d00000df701000041000000000012043500000040013000390000000e02000029000000000021043500000060013000390000000d02000029000000000021043500000080013000390000000c020000290000000000210435000000a0013000390000000b0200002900000000002104350000010002000039000000000103001934dd16fd0000040f000000080100002900000000020104330000000a0100002934dd349b0000040f34dd1c7d0000040f00000000020100190000000b01000029000000090300002934dd1d3b0000040f0000000b010000290000000e020000290000000d030000290000000c0400002934dd29240000040f000009b00000013d000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000402100370000000000202043b000c00000002001d00000d3d0020009c000010460000213d0000000c020000290000002302200039000000000032004b000010460000813d0000000c020000290000000402200039000000000121034f000000000101043b000b00000001001d00000d3d0010009c000010460000213d0000000c01000029000a00240010003d0000000b0100002900000005021002100000000a01200029000000000031004b000010460000213d000000a001000039000000400010043f000000800000043f0000003f0120003900000ded0110019700000dd00010009c000010850000213d000000a001100039000000400010043f0000000b04000029000000a00040043f000000000004004b00000e360000c13d00000020020000390000000003210436000000a00200043d0000000000230435000000400310003900000005042002100000000007340019000000000002004b00000efe0000c13d000000000217004900000d390020009c00000d3902008041000000600220021000000d390010009c00000d39010080410000004001100210000000000112019f000034de0001042e0000000001000416000000000001004b000010460000c13d000000020100003900000ade0000013d000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b00000d3c0010009c000010460000213d34dd18a20000040f000009b00000013d0000000001000416000000000001004b000010460000c13d000000000103001934dd17910000040f000d00000001001d000e00000002001d000000000010043f0000000801000039000000200010043f0000004002000039000000000100001934dd349b0000040f000c00000001001d000000000200041134dd18e00000040f0000000c010000290000000d020000290000000e0300002934dd1e230000040f0000000001000019000034de0001042e0000000001000416000000000001004b000010460000c13d34dd18570000040f000000400200043d000000000012043500000d390020009c00000d3902008041000000400120021000000ddb011001c7000034de0001042e0000000001000416000000000001004b000010460000c13d00000dea01000041000000800010043f00000ddd01000041000034de0001042e000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b00000d3c0010009c000010460000213d000000000010043f0000000d01000039000000200010043f0000004002000039000000000100001934dd349b0000040f000000000101041a000000ff001001900000000001000039000000010100c039000000800010043f00000ddd01000041000034de0001042e000000440030008c000010460000413d0000000002000416000000000002004b000010460000c13d000000c002000039000000400020043f0000000402100370000000000202043b000e00000002001d00000d530020009c000010460000213d0000000e02000029000000800020043f0000002401100370000000000101043b00000d3c0010009c000010460000213d000000a00010043f0000000101000039000000000101041a00000d3c021001970000000001000411000000000021004b00000ab80000c13d00000dd10100004100000000001004430000000001000412000000040010044300000040010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b0000000e02000029000000000012004b00000a060000213d000000a00100043d00000d3c01100197000000000002004b00000fd30000613d000000000001004b00000fd30000c13d00000e2101000041000000000010043f00000d4801000041000034df00010430000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b00000d3c0010009c000010460000213d000000000010043f000000150100003900000ada0000013d000000c40030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000402100370000000000202043b000e00000002001d00000d3c0020009c000010460000213d00000000020004110000000e0020006c00000a280000613d0000001a03000039000000000303041a00000d3c03300197000000000032004b00000cdc0000c13d000000e002000039000000400020043f0000002402100370000000000202043b000000800020043f0000004403100370000000000303043b000000a00030043f0000006404100370000000000404043b000000c00040043f000000000002004b00000b980000c13d000000000003004b00000b980000c13d000000000004004b00000b980000c13d00000e0b01000041000000000010043f00000d4801000041000034df00010430000000e40030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000402100370000000000202043b000e00000002001d0000002402100370000000000202043b000d00000002001d00000d3c0020009c000010460000213d0000004402100370000000000202043b000c00000002001d00000d3c0020009c000010460000213d0000006402100370000000000202043b000b00000002001d00000d3c0020009c000010460000213d0000008402100370000000000202043b000a00000002001d00000d3c0020009c000010460000213d000000c402100370000000000202043b00000d3d0020009c000010460000213d000000a401100370000000000101043b000900000001001d0000000401200039000000000203001934dd17470000040f000800000001001d000000090100002934dd1c530000040f0000000a0100002934dd1c690000040f000000400300043d000700000003001d000000e002300039000000000012043500000100013000390000000902000029000000000021043500000100010000390000000002130436000900000002001d00000dea01000041000000000012043500000040013000390000000e02000029000000000021043500000060013000390000000d02000029000000000021043500000080013000390000000c020000290000000000210435000000a0013000390000000b020000290000000000210435000000c0013000390000000a0200002900000000002104350000012002000039000000000103001934dd16fd0000040f00000007010000290000000002010433000000090100002934dd349b0000040f34dd1c7d0000040f00000000020100190000000a01000029000000080300002934dd1d3b0000040f0000000a010000290000000e020000290000000d030000290000000c040000290000000b0500002934dd2c340000040f000009b00000013d000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000301043b0000000101000039000000000101041a00000d3c021001970000000001000411000000000021004b00000ab80000c13d0000001b01000039000000000101041a000000800010043f000e00000003001d000000a00030043f000000000100041400000d390010009c00000d3901008041000000c00110021000000df5011001c70000800d02000039000000010300003900000d570400004134dd34ce0000040f0000000100200190000010460000613d0000000e010000290000001b02000039000000000012041b0000000001000019000034de0001042e00000ddf02000041000000000020043f00000de90200004100000b5e0000013d0000000001000416000000000001004b000010460000c13d00000df701000041000000800010043f00000ddd01000041000034de0001042e000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b00000d3c0010009c000010460000213d000000000010043f000000070100003900000ada0000013d000000240030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000401100370000000000101043b00000d3c0010009c000010460000213d000000000010043f0000000601000039000000200010043f0000004002000039000000000100001934dd349b0000040f000000000101041a000000800010043f00000ddd01000041000034de0001042e000000640030008c000010460000413d0000000002000416000000000002004b000010460000c13d0000000402100370000000000202043b000e00000002001d0000002402100370000000000202043b000d00000002001d00000d3c0020009c000010460000213d0000004401100370000000000101043b000c00000001001d0000000e01000029000000000010043f0000001401000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d0000001903000039000000000203041a00000d4302200197000000000101043b000000000101041a00000d3c01100197000000000112019f000000000013041b0000000201000039000000000101041a0000000c0010006b00000ce30000a13d00000e1e01000041000000000010043f00000d4801000041000034df000104300000000001000416000000000001004b000010460000c13d0000000001000412001000000001001d000f00000000003d000080050100003900000044030000390000000004000415000000100440008a000000050440021000000dd10200004134dd34b00000040f00000d3c01100197000000800010043f00000ddd01000041000034de0001042e0000000001000416000000000001004b000010460000c13d0000001a01000039000000000101041a00000d3c021001970000000001000411000000000021004b00000b5b0000c13d0000001801000039000000000101041a00000de502000041000000000020044300000d3c01100197000e00000001001d0000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b000000000001004b000010460000613d000000400200043d00000e0001000041000000000012043500000d390020009c000d00000002001d00000d390100004100000000010240190000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d48011001c70000000e0200002934dd34ce0000040f000000010020019000000ddf0000613d0000000d0100002900000d3d0010009c000010850000213d000000400010043f0000000001000019000034de0001042e0000000001000416000000000001004b000010460000c13d00000de301000041000000800010043f00000ddd01000041000034de0001042e00000ddf02000041000000000020043f00000de002000041000000040020043f000000240010043f00000de101000041000034df000104300000000c02000039000000000302041a0000000401000039000000000401041a000000000004004b000000090100003900000c870000c13d000000000032041b000000000101041a000d00000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b0000000d0210006b00000dec0000a13d0000000b03000039000000000403041a00000000032400a9000000000004004b00000b820000613d00000000044300d9000000000024004b000010610000c13d0000000e0500002900000de3045000d10000000002430019000000000005004b00000df40000613d0000000e044000fa00000de30040009c000010610000c13d000000000032004b00000df40000813d000010610000013d00000ddf01000041000000000010043f00000de90100004100000cdf0000013d000000ff0210018f000000200020008c00000cb80000413d00000df901000041000000000010043f00000d4801000041000034df000104300000012005000039000000400050043f0000008405100370000000000505043b000000e00050043f000000a401100370000000000101043b00000e0300100198000010460000c13d000001000010043f000000000005004b00000ba60000c13d00000e030010009c00000a390000a13d000001600020043f000001800030043f000001a00040043f0000016002000039000001200020043f0000020002000039000000400020043f000001c00050043f000001e00010043f000001c001000039000001400010043f0000000e01000029000000000010043f0000001701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000001200200043d0000000043020434000000000031041b00000000030404330000000104100039000000000034041b000000400220003900000000020204330000000203100039000000000023041b000001400200043d00000000320204340000000304100039000000000024041b000000040110003900000000020304330000008002200270000000000301041a00000e0403300197000000000223019f000000000021041b00000001020003670000002401200370000000000301043b000000400100043d00000000033104360000004404200370000000000404043b00000000004304350000006403200370000000000303043b000000400410003900000000003404350000008403200370000000000303043b00000060041000390000000000340435000000a402200370000000000202043b00000e0300200198000010460000c13d0000008003100039000000000023043500000d390010009c00000d39010080410000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000e05011001c70000800d02000039000000020300003900000e06040000410000000e0500002934dd34ce0000040f0000000100200190000010460000613d0000001801000039000000000101041a00000d3c00100198000005070000613d0000000e0100002934dd332c0000040f0000000e02000029000000000020043f0000001502000039000000200020043f000d00000001001d000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000000000101041a000c00000001001d0000001601000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000000000101041a0000000c0010002a000010610000413d0000000d0000006b0000114f0000c13d000d000c0010002d0000001b01000039000000000101041a0000000d0010006b000005070000413d0000001c01000039000000000101041a000c00000001001d0000001801000039000000000101041a00000de502000041000000000020044300000d3c01100197000b00000001001d0000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b000000000001004b000010460000613d0000000c01000029000000ff00100190000000400400043d00000064014000390000000d0200002900000000002104350000004401400039000000010200003900000000002104350000000001000039000000010100c0390000002402400039000000000012043500000e0901000041000000000014043500000004014000390000000e02000029000000000021043500000001010003670000002402100370000000000202043b000000840340003900000000002304350000004402100370000000000202043b000000a40340003900000000002304350000006402100370000000000202043b000000c40340003900000000002304350000008402100370000000000202043b000e00000004001d000000e4034000390000000000230435000000a401100370000000000101043b00000e0300100198000010460000c13d0000000e030000290000010402300039000000000012043500000d390030009c00000d390100004100000000010340190000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000e0a011001c70000000b0200002934dd34ce0000040f00000001002001900000118f0000c13d00000060061002700000001f0460018f00000d3b05600198000000400200043d000000000352001900000fbf0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b00000c7e0000c13d00000fbf0000013d00000ddf01000041000000000010043f00000de40100004100000cdf0000013d000a00000004001d000c00000003001d000000000101041a000d00000001001d0000000b01000039000000000101041a000b00000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b0000000d0010006b00000000020100190000000d020040290000000a01000039000000000101041a000000000212004b000010610000413d0000000b012000b90000000b0000006b00000ca70000613d0000000b031000fa000000000023004b000010610000c13d0000000a011000fa0000000c0010002a000010610000413d0000000c0310002900000009010000390000000c0200003900000b690000013d000000400700043d0000000002170436000000000006004b00000d9e0000c13d00000e23013001970000000000120435000000000005004b0000002003000039000000000300603900000dab0000013d000000400400043d00000d3f0040009c000010850000213d0000004003400039000000400030043f00000020034000390000000000130435000e00000004001d000000000024043500000db70000013d000d00000002001d000000000100041400000d390010009c00000d3901008041000000c00110021000000d41011001c70000800d02000039000000030300003900000d420400004134dd34ce0000040f0000000100200190000010460000613d0000000d0100002900000d43011001970000000e011001af0000000102000039000000000012041b0000000001000019000034de0001042e00000ddf01000041000000000010043f00000dec01000041000000040010043f000000240030043f00000de101000041000034df0001043000000ddf01000041000000000010043f00000de001000041000000040010043f000000240020043f00000de101000041000034df000104300000000e01000029000000000010043f0000000801000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d0000000c02000039000000000202041a000b00000002001d000000000101043b000a00000001001d0000000401000039000000000101041a000900000001001d000000000001004b00000e120000c13d0000000c010000390000000b02000029000000000021041b0000000901000039000000000101041a000b00000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b0000000b0010006b00000000020100190000000b020040290000000a01000039000000000021041b0000000c01000039000000000101041a000b00000001001d0000000a020000290000000401200039000600000001001d000000000101041a000900000001001d0000000101200039000700000001001d000000000101041a000800000001001d0000000401000039000000000101041a000500000001001d000000000001004b000010480000c13d0000000a010000290000000301100039000000000201041a0000000b0320006b000010610000413d000000080200002900000d530420019800000000024300a900000d2e0000613d00000000044200d9000000000034004b000010610000c13d000000090020002a000010610000413d00000009032000290000000602000029000500000003001d000000000032041b0000000c02000039000000000202041a000000000021041b0000000501000039000000000201041a0000000a01000029000000000101041a0000000703000029000000000303041a0000006004300270000000400600043d000b00000006001d0000004405600039000000000045043500000060041002700000002405600039000000000045043500000e16040000410000000004460436000900000004001d00000d53011001970000000404600039000000000014043500000d53033001970000006401600039000800000003001d000000000031043500000d390060009c00000d390100004100000000010640190000004001100210000000000300041400000d390030009c00000d3903008041000000c003300210000000000113019f00000e17011001c700000d3c0220019734dd34d30000040f000000600310027000000d3903300197000000400030008c000000400400003900000000040340190000001f0640018f00000060074001900000000b0b0000290000000b0570002900000d6b0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b00000d670000c13d000000000006004b00000d780000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000011120000613d0000001f01400039000000e00210018f0000000001b20019000000000021004b0000000002000039000000010200403900000d3d0010009c000010850000213d0000000100200190000010850000c13d000000400010043f000000400030008c000010460000413d00000009020000290000000002020433000000000002004b0000000003000039000000010300c039000000000032004b000010460000c13d00000000030b0433000b00000003001d000000000002004b0000145c0000613d0000000b03000029000000080030006c0000145c0000613d000000050200002900000de30220012a000014620000a13d0000000c0020006c000014620000813d00000e1c01000041000000000010043f00000d4801000041000034df00010430000000000040043f000000020030008c000000000300001900000dab0000413d00000df80400004100000000030000190000000005320019000000000604041a000000000065043500000001044000390000002003300039000000000013004b00000da40000413d0000003f0130003900000e22021001970000000001720019000000000021004b0000000002000039000000010200403900000d3d0010009c000010850000213d0000000100200190000010850000c13d000e00000007001d000000400010043f00000dd10100004100000000001004430000000001000412000000040010044300000120010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000168d0000613d000000000201043b000000ff0020008c00000e040000c13d0000001005000039000000000405041a000000010740019000000001024002700000007f0620018f00000000020660190000001f0020008c00000000010000390000000101002039000000000114013f0000000100100190000006150000c13d000000400100043d0000000003210436000000000007004b000010670000c13d00000e23024001970000000000230435000000000006004b00000020040000390000000004006039000010740000013d00000060061002700000001f0460018f00000d3b05600198000000400200043d000000000352001900000fbf0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b00000de70000c13d00000fbf0000013d0000000e0000006b000000000200001900000df40000613d0000000e0300002900000de3023000d100000000033200d900000de30030009c000010610000c13d00000e020420012a0000000b03000039000d00000004001d000000000043041b00000e0f0310009c000010610000813d0000000904000039000000000034041b0000000a03000039000000000013041b00000e100020009c00000ff90000213d00000e1401000041000000000010043f00000d4801000041000034df00010430000000ff0320018f0000001f0030008c00000b940000213d000000400100043d00000d3f0010009c000010850000213d0000004004100039000000400040043f000000200410003900000000002404350000000000310435000000400200043d000d00000002001d000010810000013d0000000901000039000000000101041a000800000001001d0000000b01000039000000000101041a000700000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b000000080010006b000000000201001900000008020040290000000a01000039000000000101041a000000000212004b000010610000413d00000007012000b9000000070000006b00000e310000613d00000007031000fa000000000023004b000010610000c13d00000009011000fa0000000b0010002a000010610000413d000b000b0010002d00000cfa0000013d00000060050000390000000001000019000000c00410003900000000005404350000002001100039000000000021004b00000e380000413d0000000c0130006a000000430110008a000900000001001d00080d3e0010019b0000000002000019000e00000002001d0000000502200210000d00000002001d0000000a012000290000000101100367000000000101043b00000d3e02100197000000080320014f000000080020006c000000000200001900000d3e02004041000000090010006c000000000400001900000d3e0400804100000d3e0030009c000000000204c019000000000002004b000010460000c13d0000000c0210002900000024052000390000000101500367000000000101043b00000d3d0010009c000010460000213d00000000031000790000004402200039000000000032004b000000000400001900000d3e0400204100000d3e0330019700000d3e02200197000000000632013f000000000032004b000000000200001900000d3e0200404100000d3e0060009c000000000204c019000000000002004b000010460000c13d00000e2206100198000000400200043d000000200320003900000000046300190000002005500039000000010550036700000e760000613d000000000705034f0000000008030019000000007907043c0000000008980436000000000048004b00000e720000c13d0000001f0710019000000e830000613d000000000565034f0000000306700210000000000704043300000000076701cf000000000767022f000000000505043b0000010006600089000000000565022f00000000056501cf000000000575019f000000000054043500000000041300190000000000040435000000800500043d000000000005004b00000e900000613d00000000060000190000000007460019000000a008600039000000000808043300000000008704350000002006600039000000000056004b00000e890000413d00000000044500190000000000040435000000000115001900000000001204350000003f0110003900000e22041001970000000001240019000000000041004b0000000004000039000000010400403900000d3d0010009c000010850000213d0000000100400190000010850000c13d000000400010043f00000d390030009c00000d39030080410000004001300210000000000202043300000d390020009c00000d39020080410000006002200210000000000112019f000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f000000000200041034dd34d80000040f000000600a000039000000600310027000000d3904300198000000800300003900000ed80000613d0000001f0340003900000d3a033001970000003f0330003900000dd803300197000000400a00043d00000000033a00190000000000a3004b0000000005000039000000010500403900000d3d0030009c000010850000213d0000000100500190000010850000c13d000000400030043f00000000034a043600000d3b06400198000000000563001900000ecb0000613d000000000701034f0000000008030019000000007907043c0000000008980436000000000058004b00000ec70000c13d0000001f0440019000000ed80000613d000000000161034f0000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f000000000015043500000000010a04330000000100200190000010f50000613d000000000001004b00000eef0000c13d00070000000a001d00000de501000041000000000010044300000000010004100000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b000000000001004b000000070a000029000011340000613d000000a00100043d0000000e02000029000000000021004b000010ef0000a13d0000000d01000029000000c0011000390000000000a10435000000a00100043d000000000021004b000010ef0000a13d00000001022000390000000b0020006c00000e420000413d000000400100043d000009740000013d000000c004000039000000000600001900000f090000013d0000001f0980003900000e22099001970000000008780019000000000008043500000000077900190000000106600039000000000026004b0000097d0000813d0000000008170049000000400880008a0000000003830436000000004804043400000000980804340000000007870436000000000008004b00000f010000613d000000000a000019000000000b7a0019000000000ca90019000000000c0c04330000000000cb0435000000200aa0003900000000008a004b00000f120000413d00000f010000013d00000060061002700000001f0460018f00000d3b05600198000000400200043d000000000352001900000fbf0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b00000f220000c13d00000fbf0000013d0000000d01000029000000000010043f0000000801000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000a00000001001d0000000201100039000800000001001d000000000101041a000900000001001d00000d3c01100197000b00000001001d000000000010043f0000001101000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f00000080040000390000000100200190000010460000613d000000000101043b000000000201041a000000400100043d00000080031000390000000e0500002900000000005304350000006003100039000000000023043500000040021000390000000d030000290000000000320435000000200210003900000dcf030000410000000000320435000000000041043500000dd00010009c000010850000213d000000a003100039000000400030043f00000d390020009c00000d39020080410000004002200210000000000101043300000d390010009c00000d39010080410000006001100210000000000121019f000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d41011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000700000001001d00000dd101000041000000000010044300000000010004120000000400100443000000a0010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b00000d3c011001970000000002000410000000000012004b000011e60000c13d00000dd10100004100000000001004430000000001000412000000040010044300000080010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b000600000001001d00000d4c010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b000000060010006c000011e60000c13d00000dd10100004100000000001004430000000001000412000000040010044300000060010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000123e0000c13d0000168d0000013d00000060061002700000001f0460018f00000d3b05600198000000400200043d000000000352001900000fbf0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b00000fbb0000c13d00000d3906600197000000000004004b00000fcd0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000000600160021000000d390020009c00000d39020080410000004002200210000000000112019f000034df000104300000000e02000039000000000202041a000000400300043d0000006004300039000000800500043d000000000014043500000d53015001970000002004300039000000000014043500000040013000390000006004200270000000000041043500000d5301200197000000000013043500000d390030009c00000d39030080410000004001300210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d54011001c70000800d02000039000000010300003900000d550400004134dd34ce0000040f0000000100200190000010460000613d000000800100043d00000d5301100197000000a00200043d0000006002200210000000000112019f0000000e02000039000000000012041b0000000001000019000034de0001042e000000400200043d00000e11010000410000000000120435000c00000002001d00000004012000390000000002000410000000000021043500000dd1010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000168d0000613d000000000201043b0000000c0100002900000d390010009c00000d39010080410000004001100210000000000300041400000d390030009c00000d3903008041000000c003300210000000000113019f00000df0011001c700000d3c0220019734dd34d30000040f000000600310027000000d3903300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000c057000290000102a0000613d000000000801034f0000000c09000029000000008a08043c0000000009a90436000000000059004b000010260000c13d000000000006004b000010370000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000010fb0000613d0000001f01400039000000600210018f0000000c01200029000000000021004b0000000002000039000000010200403900000d3d0010009c000010850000213d0000000100200190000010850000c13d000000400010043f000000200030008c0000113b0000813d0000000001000019000034df000104300000000901000039000000000101041a000400000001001d0000000b01000039000000000101041a000300000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b000000040010006b000000000201001900000004020040290000000a01000039000000000101041a000000000212004b000011070000813d00000def01000041000000000010043f0000001101000039000000040010043f00000df001000041000034df00010430000000000050043f000000020040008c0000000004000019000010740000413d00000dfa0500004100000000040000190000000006430019000000000705041a000000000076043500000001055000390000002004400039000000000024004b0000106d0000413d0000003f0240003900000e22022001970000000003120019000000000023004b00000000020000390000000102004039000d00000003001d00000d3d0030009c000010850000213d0000000100200190000010850000c13d0000000d02000029000000400020043f0000000d0200002900000dfb0020009c0000000e040000290000108b0000a13d00000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df000104300000000d020000290000002003200039000a00000003001d000000400030043f0000000000020435000000400500043d0000002002500039000000e003000039000000000032043500000dfc020000410000000000250435000000e00250003900000000430404340000000000320435000e00000005001d0000010002500039000000000003004b000010a50000613d000000000500001900000000062500190000000007540019000000000707043300000000007604350000002005500039000000000035004b0000109e0000413d000000000423001900000000000404350000001f0330003900000e220330019700000000022300190000000e0400002900000000034200490000004004400039000000000034043500000000160104340000000005620436000000000006004b000010ba0000613d000000000200001900000000035200190000000004210019000000000404043300000000004304350000002002200039000000000062004b000010b30000413d000c00000005001d000b00000006001d0000000001560019000000000001043500000d4c010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b0000000e04000029000000800240003900000000030004100000000000320435000000600240003900000000001204350000000b010000290000001f0110003900000e22011001970000000c011000290000000002410049000000c0034000390000000000230435000000a00240003900000000000204350000000d0200002900000000020204330000000001210436000000000002004b000010e50000613d00000000030000190000000a05000029000000005405043400000000014104360000000103300039000000000023004b000010e00000413d0000000e02000029000000000121004900000d390010009c00000d3901008041000000600110021000000d390020009c00000d39020080410000004002200210000000000121019f000034de0001042e00000def01000041000000000010043f0000003201000039000000040010043f00000df001000041000034df00010430000000000001004b0000112c0000c13d00000dee01000041000000000010043f00000d4801000041000034df000104300000001f0530018f00000d3b06300198000000400200043d00000000046200190000111d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000011020000c13d0000111d0000013d00000003012000b9000000030000006b0000110d0000613d00000003031000fa000000000023004b000010610000c13d00000005011000fa0000000b0010002a000010610000413d000b000b0010002d00000d220000013d0000001f0530018f00000d3b06300198000000400200043d00000000046200190000111d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000011190000c13d000000000005004b0000112a0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000fce0000013d00000d390030009c00000d3903008041000000400230021000000d390010009c00000d39010080410000006001100210000000000121019f000034df0001043000000df101000041000000000010043f000000000100041000000d3c01100197000000040010043f00000df001000041000034df000104300000000c02000029000000000302043300000de3023000d1000000000003004b000011430000613d00000000033200d900000de30030009c000010610000c13d0000000d0300002900000e02033000d1000000000023004b000011d10000a13d00000e1301000041000000000010043f00000d4801000041000034df0001043000000d4701000041000000000010043f00000d4801000041000034df000104300000001801000039000000000101041a00000de502000041000000000020044300000d3c01100197000d00000001001d0000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b000000000001004b000010460000613d000000400400043d00000e0701000041000000000014043500000004014000390000000e02000029000000000021043500000001010003670000002402100370000000000202043b000000240340003900000000002304350000004402100370000000000202043b000000440340003900000000002304350000006402100370000000000202043b000000640340003900000000002304350000008402100370000000000202043b000e00000004001d00000084034000390000000000230435000000a401100370000000000101043b00000e0300100198000010460000c13d0000000e03000029000000a402300039000000000012043500000d390030009c00000d390100004100000000010340190000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000e08011001c70000000d0200002934dd34ce0000040f0000000100200190000014c90000613d0000000e0100002900000d3d0010009c000010850000213d000005890000013d0000000e030000290000000301300210000001000110008900000e240110021f000000000003004b00000000010060190000000c020000290000000002020433000000000112016f000000000131019f000001800010043f00000005010000290000000001010433000e00000001001d000000200010008c000013210000413d0000000e0100002900000d3d0010009c000010850000213d0000001001000039000000000201041a000000010020019000000001012002700000007f0110618f0000001f0010008c00000000030000390000000103002039000000000232013f0000000100200190000006150000c13d000000200010008c000011c00000413d0000001f0110003900000005011002700000000e020000290000001f022000390000000502200270000000000012004b000011c00000813d00000d4b0110009a00000d4b0220009a000000000002041b0000000102200039000000000012004b000011bc0000413d0000001001000039000000000010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d4a011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000200200008a0000000e02200180000000000101043b000014f50000c13d0000002003000039000015020000013d0000002002100039000000000300041100000000003204350000000e02000029000000000021043500000d390010009c00000d39010080410000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d44011001c70000800d02000039000000010300003900000e120400004134dd34ce0000040f0000000100200190000010460000613d000005070000013d000000400100043d000600000001001d000000200210003900000d4e01000041000500000002001d000000000012043500000dd101000041000000000010044300000000010004120000000400100443000000c0010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b00000006020000290000004002200039000000000012043500000dd101000041000000000010044300000000010004120000000400100443000000e0010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b00000006020000290000006002200039000000000012043500000d4c010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b0000000604000029000000a0024000390000000003000410000000000032043500000080024000390000000000120435000000a001000039000000000014043500000d4f0040009c000010850000213d0000000602000029000000c001200039000000400010043f000000050100002900000d390010009c00000d39010080410000004001100210000000000202043300000d390020009c00000d39020080410000006002200210000000000112019f000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d41011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000000400200043d00000022032000390000000704000029000000000043043500000dd30300004100000000003204350000000203200039000000000013043500000d390020009c00000d39020080410000004001200210000000000200041400000d390020009c00000d3902008041000000c002200210000000000121019f00000dd4011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000700000001001d000000800100043d000000410010008c0000125c0000c13d000000c00100043d00000dd50010009c000015180000a13d000000400100043d000000440210003900000040030000390000000000320435000000200210003900000dd70300004100000000003204350000002403100039000000070400002900000000004304350000006404100039000000800300043d00000000003404350000008404100039000000000003004b000012740000613d00000000050000190000000006450019000000a007500039000000000707043300000000007604350000002005500039000000000035004b0000126d0000413d000000000443001900000000000404350000001f0330003900000e220330019700000064043000390000000000410435000000a30330003900000e22043001970000000003140019000000000043004b0000000004000039000000010400403900000d3d0030009c000010850000213d0000000100400190000010850000c13d000000400030043f00000d390020009c00000d39020080410000004002200210000000000101043300000d390010009c00000d39010080410000006001100210000000000121019f000000000200041400000d390020009c00000d3902008041000000c002200210000000000121019f0000000b0200002934dd34d30000040f000000600310027000000d39043001980000156d0000c13d00000060030000390000000100200190000012a50000613d0000000001030433000000200010008c000012a50000413d00000dd90010009c0000000c02000029000010460000213d000000200010008c000010460000413d000000000102043300000dd70010009c000015540000613d0000000a01000029000000000101041a0000006001100270000000000010043f0000001101000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000000000201041a0000000103200039000000000031041b000000400100043d00000080031000390000000e0400002900000000004304350000006003100039000000000023043500000040021000390000000d0300002900000000003204350000008002000039000e00000002001d000000000221043600000dcf03000041000000000032043500000dd00010009c000010850000213d000000a003100039000000400030043f00000d390020009c00000d39020080410000004002200210000000000101043300000d390010009c00000d39010080410000006001100210000000000121019f000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d41011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000c00000001001d00000dd101000041000000000010044300000000010004120000000400100443000000a0010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b00000d3c011001970000000002000410000000000012004b000015c70000c13d00000dd10100004100000000001004430000000001000412000000040010044300000080010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b000b00000001001d00000d4c010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b0000000b0010006c000015c70000c13d00000dd10100004100000000001004430000000001000412000000040010044300000060010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000168d0000613d0000161f0000013d0000000e030000290000000301300210000001000110008900000e240110021f000000000003004b000000000100601900000004020000290000000002020433000000000112016f000000000131019f000001a00010043f0000000c0100002900000d390010009c00000d390100804100000040011002100000000a02000029000000000202043300000d390020009c00000d39020080410000006002200210000000000112019f000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d41011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000e00000001001d000001400010043f000000040100002900000d390010009c00000d390100804100000040011002100000000502000029000000000202043300000d390020009c00000d39020080410000006002200210000000000112019f000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d41011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000c00000001001d000001600010043f00000d4c010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f00000001002001900000168d0000613d000000000201043b000001000020043f000000400100043d0000008003100039000000000023043500000060021000390000000c03000029000000000032043500000040021000390000000e030000290000000000320435000000a0020000390000000002210436000000a0031000390000000004000410000000000043043500000d4e03000041000000000032043500000d4f0010009c000010850000213d000000c003100039000000400030043f00000d390020009c00000d39020080410000004002200210000000000101043300000d390010009c00000d39010080410000006001100210000000000121019f000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d41011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000000e00010043f0000000001000410000001200010043f000000a00100043d00000d3c01100197000000060010006c000015140000c13d0000001301000039000000000101041a000000400200043d000000200320003900000009040000290000000000430435000000000012043500000d390020009c00000d39020080410000004001200210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d44011001c70000800d02000039000000010300003900000d510400004134dd34ce0000040f0000000100200190000010460000613d00000009010000290000001302000039000000000012041b00000d5201000041000000c00010043f000000400100043d000e00000001001d00000d3f0010009c000010850000213d0000000e020000290000004001200039000000400010043f0000000001020436000c00000001001d00000000000104350000000e01000039000000000101041a0000006002100270000000400300043d0000004004300039000000000024043500000d5301100197000000000113043600000060023000390000000000020435000000000001043500000d390030009c00000d39030080410000004001300210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d54011001c70000800d02000039000000010300003900000d550400004134dd34ce0000040f0000000100200190000010460000613d0000000e01000029000000000101043300000d53011001970000000c0200002900000000020204330000006002200210000000000112019f0000000e02000039000000000012041b0000001a01000039000000000301041a000000400100043d000e00000001001d000000000100041400000d390010009c00000d39010080410000000d0200002900000d3c06200197000000c00110021000000d41011001c7000d00000003001d00000d3c053001970000800d02000039000000030300003900000d5604000041000c00000006001d34dd34ce0000040f0000000100200190000010460000613d0000000d0100002900000d43011001970000000c011001af0000001a02000039000000000012041b0000001b01000039000000000101041a0000000e04000029000000200240003900000003030000290000000000320435000000000014043500000d390040009c00000d39040080410000004001400210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d44011001c70000800d02000039000000010300003900000d570400004134dd34ce0000040f0000000100200190000010460000613d00000003010000290000001b02000039000000000012041b0000001c01000039000000000401041a000000400100043d000000200210003900000008030000290000000000320435000e00000004001d000000ff004001900000000002000039000000010200c039000000000021043500000d390010009c00000d39010080410000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d44011001c70000800d02000039000000010300003900000d580400004134dd34ce0000040f0000000100200190000010460000613d000001000100008a0000000e0110017f0000000802000029000000ff0220018f000000000121019f0000001c02000039000000000012041b000000800100043d000001400000044300000160001004430000002001000039000000a00200043d0000018000100443000001a0002004430000004002000039000000c00300043d000001c000200443000001e0003004430000006002000039000000e00300043d000002000020044300000220003004430000008002000039000001000300043d00000240002004430000026000300443000001200200043d000000a0030000390000028000300443000002a000200443000000c002000039000001400300043d000002c000200443000002e000300443000000e002000039000001600300043d000003000020044300000320003004430000010002000039000001800300043d000003400020044300000360003004430000012002000039000001a00300043d0000038000200443000003a00030044300000100001004430000000a01000039000001200010044300000d5901000041000034de0001042e00000e1d01000041000000000010043f0000000b01000029000000040010043f00000df001000041000034df000104300000000b04000029000000080040006c0000146b0000813d0000000c0220006c000010610000413d0000000203000039000000000303041a000000000032004b00000d9a0000413d00000080021000390000000c03000029000000000032043500000060021000390000000d03000029000000000032043500000040021000390000000003000411000000000032043500000020021000390000000b0300002900000000003204350000000802000029000000000021043500000d390010009c00000d39010080410000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000e05011001c70000800d02000039000000020300003900000e18040000410000000e0500002934dd34ce0000040f0000000100200190000010460000613d0000000401000039000000000101041a0000000b0010002a000010610000413d0000000b01100029000000080110006c000010610000413d0000000402000039000000000012041b0000000701000029000000000101041a000e00000001001d0000000a01000029000000000101041a0000006001100270000a00000001001d000000000010043f0000000701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000000000101041a0000000b0010002a000010610000413d0000000e0200002900000d53022001970000000b01100029000e000000210053000010610000413d0000000a01000029000000000010043f0000000701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b0000000e02000029000000000021041b0000000b0100002900000e190010009c000015a10000413d00000e1b01000041000000000010043f0000006001000039000000040010043f0000000b01000029000000240010043f00000de101000041000034df0001043000000060061002700000001f0460018f00000d3b05600198000000400200043d000000000352001900000fbf0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000014d10000c13d00000fbf0000013d000000010320008a00000005033002700000000004310019000000200300003900000001044000390000000a0600002900000000056300190000000005050433000000000051041b00000020033000390000000101100039000000000041004b000014dc0000c13d0000000e0020006c000014ee0000813d0000000e020000290000000302200210000000f80220018f00000e240220027f00000e24022001670000000a033000290000000003030433000000000223016f000000000021041b0000000e01000029000000010110021000000001011001bf0000000f02000039000000000012041b000000ff010000390000119d0000013d000000010320008a0000000503300270000000000431001900000020030000390000000104400039000000050600002900000000056300190000000005050433000000000051041b00000020033000390000000101100039000000000041004b000014fb0000c13d0000000e0020006c0000150d0000813d0000000e020000290000000302200210000000f80220018f00000e240220027f00000e240220016700000005033000290000000003030433000000000223016f000000000021041b0000000e01000029000000010110021000000001011001bf0000001002000039000000000012041b000000ff010000390000132b0000013d00000d5001000041000000000010043f00000d4801000041000034df00010430000000400200043d0000006003200039000000e00400043d000000a00500043d000000000013043500000040012000390000000000510435000000f8014002700000002003200039000000000013043500000007010000290000000000120435000000000000043f00000d390020009c00000d39020080410000004001200210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000dd6011001c7000000010200003934dd34d30000040f000000600310027000000d3903300197000000200030008c000000200400003900000000040340190000001f0540018f00000020044001900000153e0000613d000000000601034f0000000007000019000000006806043c0000000007870436000000000047004b0000153a0000c13d000000000005004b0000154b0000613d000000000641034f0000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f00000000005404350000000100200190000015950000613d000000000100043d00000d3c0010019800000000010060190000125c0000613d000000090110014f00000d3c001001980000125c0000c13d0000000b01000029000000000010043f0000001101000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000000000201041a0000000102200039000000000021041b0000000801000029000000000101041a000c0d3c0010019b0000000d010000290000000a020000290000000c0300002934dd26840000040f000009b00000013d0000001f0340003900000d3a033001970000003f0330003900000dd805300197000000400300043d0000000005530019000000000035004b0000000006000039000000010600403900000d3d0050009c000010850000213d0000000100600190000010850000c13d000000400050043f0000001f0540018f000000000743043600000d3b06400198000c00000007001d0000000004670019000015870000613d000000000701034f0000000c08000029000000007907043c0000000008980436000000000048004b000015830000c13d000000000005004b000012980000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000012980000013d0000001f0530018f00000d3b06300198000000400200043d00000000046200190000111d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000159c0000c13d0000111d0000013d0000000702000029000000000102041a00000e1a011001970000000b011001af000000000012041b00000dd1010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b0000000d020000290000000c0300002934dd32970000040f0000000c0300002900000de3013000d10000000602000029000000000202041a000000000003004b000015c10000613d0000000c031000fa00000de30030009c000010610000c13d000000000012004b000010610000413d00000000011200490000000602000029000000000012041b000006e50000013d000000400100043d000b00000001001d000000200210003900000d4e01000041000900000002001d000000000012043500000dd101000041000000000010044300000000010004120000000400100443000000c0010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b0000000b020000290000004002200039000000000012043500000dd101000041000000000010044300000000010004120000000400100443000000e0010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b0000000b020000290000006002200039000000000012043500000d4c010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f00000001002001900000168d0000613d000000000101043b0000000b04000029000000a0024000390000000003000410000000000032043500000080024000390000000000120435000000a001000039000000000014043500000d4f0040009c000010850000213d0000000b02000029000000c001200039000000400010043f000000090100002900000d390010009c00000d39010080410000004001100210000000000202043300000d390020009c00000d39020080410000006002200210000000000112019f000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d41011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000000400200043d00000022032000390000000c04000029000000000043043500000dd30300004100000000003204350000000203200039000000000013043500000d390020009c00000d39020080410000004001200210000000000200041400000d390020009c00000d3902008041000000c002200210000000000121019f00000dd4011001c7000080100200003934dd34d30000040f0000000100200190000010460000613d000000000101043b000b00000001001d0000000a01000029000000000101041a000c006000100278000000800100043d000000410010008c000016400000c13d000000c00100043d00000dd50010009c0000168e0000a13d000000400100043d000000440210003900000040030000390000000000320435000000200210003900000dd703000041000000000032043500000024031000390000000b0400002900000000004304350000006404100039000000800300043d00000000003404350000008404100039000000000003004b000016580000613d00000000050000190000000006450019000000a007500039000000000707043300000000007604350000002005500039000000000035004b000016510000413d000000000443001900000000000404350000001f0330003900000e220330019700000064043000390000000000410435000000a30330003900000e22043001970000000003140019000000000043004b0000000004000039000000010400403900000d3d0030009c000010850000213d0000000100400190000010850000c13d000000400030043f00000d390020009c00000d39020080410000004002200210000000000101043300000d390010009c00000d39010080410000006001100210000000000121019f000000000200041400000d390020009c00000d3902008041000000c002200210000000000121019f0000000c0200002934dd34d30000040f000000600310027000000d3904300198000016c90000c13d00000060030000390000000100200190000016890000613d0000000001030433000000200010008c000016890000413d00000dd90010009c000010460000213d000000200010008c000010460000413d0000000e01000029000000000101043300000dd70010009c000015680000613d00000dda01000041000000000010043f00000d4801000041000034df00010430000000000001042f000000400200043d0000006003200039000000e00400043d000000a00500043d000000000013043500000040012000390000000000510435000000f801400270000000200320003900000000001304350000000b010000290000000000120435000000000000043f00000d390020009c00000d39020080410000004001200210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000dd6011001c7000000010200003934dd34d30000040f000000600310027000000d3903300197000000200030008c000000200400003900000000040340190000001f0540018f0000002004400190000016b40000613d000000000601034f0000000007000019000000006806043c0000000007870436000000000047004b000016b00000c13d000000000005004b000016c10000613d000000000641034f0000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f00000000005404350000000100200190000016f10000613d000000000100043d00000d3c01100198000016400000613d0000000c0010006c000015680000613d000016400000013d0000001f0340003900000d3a033001970000003f0330003900000dd805300197000000400300043d0000000005530019000000000035004b0000000006000039000000010600403900000d3d0050009c000010850000213d0000000100600190000010850000c13d000000400050043f0000001f0540018f000000000743043600000d3b06400198000e00000007001d0000000004670019000016e30000613d000000000701034f0000000e08000029000000007907043c0000000008980436000000000048004b000016df0000c13d000000000005004b0000167c0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000167c0000013d0000001f0530018f00000d3b06300198000000400200043d00000000046200190000111d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000016f80000c13d0000111d0000013d0000001f0220003900000e22022001970000000001120019000000000021004b0000000002000039000000010200403900000d3d0010009c000017090000213d0000000100200190000017090000c13d000000400010043f000000000001042d00000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df000104300000000002010019000000400100043d00000e250010009c0000171f0000813d0000006003100039000000400030043f000000000302041a00000000033104360000000104200039000000000404041a00000000004304350000000202200039000000000202041a00000040031000390000000000230435000000000001042d00000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df000104300000000002010019000000400100043d00000e260010009c000017320000813d0000004003100039000000400030043f000000000302041a00000000033104360000000102200039000000000202041a00000080022002100000000000230435000000000001042d00000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df0001043000000000430104340000000003320436000000000404043300000000004304350000004002200039000000400110003900000000010104330000000000120435000000000001042d00000000310104340000000001120436000000000203043300000e04022001970000000000210435000000000001042d00000000030100190000001f01100039000000000021004b000000000400001900000d3e0400404100000d3e0520019700000d3e01100197000000000651013f000000000051004b000000000100001900000d3e0100204100000d3e0060009c000000000104c019000000000001004b0000178f0000613d0000000106000367000000000136034f000000000401043b00000e270040009c000017890000813d0000001f0140003900000e22011001970000003f0110003900000e2205100197000000400100043d0000000005510019000000000015004b0000000008000039000000010800403900000d3d0050009c000017890000213d0000000100800190000017890000c13d000000400050043f000000000541043600000020033000390000000008430019000000000028004b0000178f0000213d000000000336034f00000e22064001980000001f0740018f0000000002650019000017790000613d000000000803034f0000000009050019000000008a08043c0000000009a90436000000000029004b000017750000c13d000000000007004b000017860000613d000000000363034f0000000306700210000000000702043300000000076701cf000000000767022f000000000303043b0000010006600089000000000363022f00000000036301cf000000000373019f000000000032043500000000024500190000000000020435000000000001042d00000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df000104300000000001000019000034df0001043000000dd90010009c0000179b0000213d000000430010008c0000179b0000a13d00000001020003670000000401200370000000000101043b0000002402200370000000000202043b000000000001042d0000000001000019000034df0001043000000dd90010009c000017ea0000213d0000000006010019000000a30010008c000017ea0000a13d00000001080003670000000401800370000000000101043b0000002402800370000000000202043b00000d3c0020009c000017ea0000213d0000004403800370000000000303043b00000d3c0030009c000017ea0000213d0000008404800370000000000a04043b00000d3d00a0009c000017ea0000213d0000006404800370000000000404043b0000002305a00039000000000065004b000017ea0000813d000000040ba000390000000005b8034f000000000705043b00000e270070009c000017ec0000813d0000001f0570003900000e22055001970000003f0550003900000e2209500197000000400500043d0000000009950019000000000059004b000000000d000039000000010d00403900000d3d0090009c000017ec0000213d0000000100d00190000017ec0000c13d000000400090043f0000000009750436000000000a7a0019000000240aa0003900000000006a004b000017ea0000213d0000002006b00039000000000868034f00000e220a7001980000001f0b70018f0000000006a90019000017da0000613d000000000c08034f000000000d09001900000000ce0c043c000000000ded043600000000006d004b000017d60000c13d00000000000b004b000017e70000613d0000000008a8034f000000030ab00210000000000b060433000000000bab01cf000000000bab022f000000000808043b000001000aa000890000000008a8022f0000000008a801cf0000000008b8019f000000000086043500000000067900190000000000060435000000000001042d0000000001000019000034df0001043000000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df0001043000000dd90010009c0000183d0000213d0000000006010019000000a30010008c0000183d0000a13d00000001080003670000002401800370000000000201043b0000000401800370000000000101043b0000004403800370000000000303043b00000d3c0030009c0000183d0000213d0000008404800370000000000a04043b00000d3d00a0009c0000183d0000213d0000006404800370000000000404043b0000002305a00039000000000065004b0000183d0000813d000000040ba000390000000005b8034f000000000705043b00000e270070009c0000183f0000813d0000001f0570003900000e22055001970000003f0550003900000e2209500197000000400500043d0000000009950019000000000059004b000000000d000039000000010d00403900000d3d0090009c0000183f0000213d0000000100d001900000183f0000c13d000000400090043f0000000009750436000000000a7a0019000000240aa0003900000000006a004b0000183d0000213d0000002006b00039000000000868034f00000e220a7001980000001f0b70018f0000000006a900190000182d0000613d000000000c08034f000000000d09001900000000ce0c043c000000000ded043600000000006d004b000018290000c13d00000000000b004b0000183a0000613d0000000008a8034f000000030ab00210000000000b060433000000000bab01cf000000000bab022f000000000808043b000001000aa000890000000008a8022f0000000008a801cf0000000008b8019f000000000086043500000000067900190000000000060435000000000001042d0000000001000019000034df0001043000000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df0001043000000d3c01100197000000000010043f0000001101000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000018550000613d000000000101043b000000000101041a000000000001042d0000000001000019000034df0001043000040000000000020000000c01000039000000000101041a0000000402000039000000000202041a000000000002004b000018850000613d000100000002001d000400000001001d0000000901000039000000000101041a000200000001001d0000000b01000039000000000101041a000300000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f00000001002001900000188c0000613d000000000101043b000000020010006b000000000201001900000002020040290000000a01000039000000000101041a000000000212004b00000004010000290000000303000029000018860000413d00000000043200a9000000000003004b000018810000613d00000000033400d9000000000023004b000018860000c13d00000001024000fa000000000012001a000018860000413d0000000001120019000000000001042d00000def01000041000000000010043f0000001101000039000000040010043f00000df001000041000034df00010430000000000001042f00010000000000020000000901000039000000000101041a000100000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f0000000100200190000018a10000613d000000000201043b000000010020006b00000000010200190000000101004029000000000001042d000000000001042f000100000000000200000d3c01100197000000000010043f0000001501000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000018c50000613d000000000101043b000000000101041a000100000001001d0000001601000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000018c50000613d000000000101043b000000000101041a0000000102000029000000000021001a000018c70000413d0000000001210019000000000001042d0000000001000019000034df0001043000000def01000041000000000010043f0000001101000039000000040010043f00000df001000041000034df0001043000000d3c01100197000000000010043f0000001201000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000018de0000613d000000000101043b000000000101041a00000d3c01100197000000000001042d0000000001000019000034df0001043000000d3c02200197000000000101041a0000006001100270000000000012004b000018e60000c13d000000000001042d00000ddf01000041000000000010043f00000de401000041000000040010043f000000240020043f00000de101000041000034df00010430000c000000000002000c00000001001d000b0d3c0030019c00001b4a0000613d000700000003001d0000000c01000039000000000401041a0000000401000039000000000501041a000000000005004b00000009030000390000000b01000039000800000002001d000019220000613d000900000005001d000a00000004001d000000000203041a000500000002001d000000000101041a000600000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f000000010020019000001b430000613d000000000101043b000000050010006b000000000201001900000005020040290000000a01000039000000000101041a000000000212004b0000000a040000290000000905000029000000060300002900001b3d0000413d00000000013200a9000000000003004b0000191d0000613d00000000033100d9000000000023004b00001b3d0000c13d00000000015100d9000000000041001a00001b3d0000413d000000000441001900000009030000390000000c01000039000000000041041b000000000103041a000a00000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f000000010020019000001b430000613d000000000101043b0000000a0010006b00000000020100190000000a020040290000000a01000039000000000021041b0000000c01000039000000000701041a0000000c010000290000000405100039000000000605041a0000000101100039000a00000001001d000000000401041a0000000401000039000000000101041a000000000001004b000019700000613d000100000001001d000400000007001d000500000004001d000600000006001d000900000005001d0000000901000039000000000101041a000200000001001d0000000b01000039000000000101041a000300000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f000000010020019000001b430000613d000000000101043b000000020010006b000000000201001900000002020040290000000a01000039000000000101041a000000000212004b0000000905000029000000060600002900000005040000290000000407000029000000030300002900001b3d0000413d00000000013200a9000000000003004b0000196c0000613d00000000033100d9000000000023004b00001b3d0000c13d00000001011000fa000000000071001a00001b3d0000413d00000000077100190000000c010000290000000301100039000000000201041a000000000327004b00001b3d0000413d00000d530440019800000000024300a90000197b0000613d00000000044200d9000000000034004b00001b3d0000c13d000000000062001a00001b3d0000413d0000000002620019000000000025041b0000000c02000039000000000202041a000000000021041b0000000a01000029000000000101041a000600000001001d0000006001100270000000000010043f0000001201000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000001b3b0000613d000000000101043b000000000101041a000400000001001d0000000501000039000000000101041a0000000c02000029000000000202041a000000400500043d000900000005001d00000044035000390000000b04000029000000000043043500000024035000390000006004200270000000000043043500000e2803000041000000000035043500000d53022001970000000403500039000000000023043500000d390050009c00000d390200004100000000020540190000004002200210000000000300041400000d390030009c00000d3903008041000000c003300210000000000323019f00000d3c0210019700000e29013001c734dd34d30000040f000000090b000029000000600310027000000d3903300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000019c20000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000019be0000c13d000000000006004b000019cf0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000001b4e0000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000d3d0010009c00001b440000213d000000010020019000001b440000c13d000000400010043f000000200030008c00001b3b0000413d00000000030b04330000000401000039000000000101041a000000000031001a00001b3d0000413d000000060200002900000d53022001970000000001310019000000000121004b00001b3d0000413d000900000003001d0000000402000039000000000012041b0000000a01000029000000000101041a000600000001001d0000000c01000029000000000101041a0000006001100270000500000001001d000000000010043f0000000701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000001b3b0000613d000000000101043b000000000101041a0000000903000029000000000031001a00001b3d0000413d000000060200002900000d53022001970000000001310019000600000021005300001b3d0000413d0000000501000029000000000010043f0000000701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000001b3b0000613d000000000101043b0000000602000029000000000021041b0000000a01000029000000000101041a000000400200043d00000040032000390000000904000029000000000043043500000020032000390000000b0400002900000000004304350000006001100270000000000012043500000d390020009c00000d39020080410000004001200210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000e2a011001c70000800d02000039000000020300003900000e2b04000041000000080500002934dd34ce0000040f000000010020019000001b3b0000613d000000070100002900000060011002100000000a03000029000000000203041a00000d5302200197000000000212019f000000000023041b000000090200002900000e190020009c00001b6c0000813d000000000112019f000000000013041b0000000b01000029000000000010043f0000001201000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000001b3b0000613d000000000101043b000000000101041a00000d3c071001980000000004000412000000200500003900001aaf0000c13d000000400100043d00000e2c0010009c00001b440000213d000a00000001001d000000240110003900000d3802000041000000000021043500000dd101000041000000000010044300000004004004430000002400500443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f000000010020019000001b430000613d0000000a040000290000008402400039000000000101043b00000d3c011001970000000000120435000000a4014000390000000b020000290000000000210435000000640140003900000000020004140000004003000039000000000031043500000044014000390000006003000039000000000031043500000e2d0100004100000000001404350000000401400039000000000001043500000d390040009c00000d3904008041000000400140021000000d390020009c00000d3902008041000000c002200210000000000121019f00000e2e011001c7000080060200003934dd34ce0000040f000000010020019000001b830000613d00000000020000310000000103200367000000000101043b000a00000001001d000000000001004b00001b860000613d0000000b01000029000000000010043f0000001201000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000001b3b0000613d0000000a0200002900000d3c06200197000000000101043b000000000201041a00000d4302200197000000000262019f000a00000006001d000000000021041b000000000100041400000d390010009c00000d3901008041000000c00110021000000d41011001c70000800d02000039000000030300003900000e2f040000410000000b0500002934dd34ce0000040f0000000a0700002900000020050000390000000004000412000000010020019000001b3b0000613d000000040100002900000d3c011001970000000c02000029000000000202041a000000400600043d0000004403600039000000000073043500000d530220019700000064036000390000000000230435000000200360003900000e3002000041000c00000003001d0000000000230435000000240260003900000000001204350000006401000039000000000016043500000dd00060009c00001b440000213d000b00000006001d000000a001600039000000400010043f00000dd101000041000000000010044300000004004004430000002400500443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f000000010020019000001b430000613d0000000c0200002900000d390020009c00000d390200804100000040022002100000000b03000029000000000303043300000d390030009c00000d39030080410000006003300210000000000223019f000000000301043b000000000100041400000d390010009c00000d3901008041000000c001100210000000000112019f00000d3c02300197000c00000002001d34dd34ce0000040f000000600310027000000d390330019800001b100000613d0000001f0430003900000d3a044001970000003f0440003900000dd804400197000000400a00043d00000000044a00190000000000a4004b0000000005000039000000010500403900000d3d0040009c00001b440000213d000000010050019000001b440000c13d000000400040043f0000001f0430018f00000000093a043600000d3b05300198000000000359001900001b020000613d000000000601034f0000000007090019000000006806043c0000000007870436000000000037004b00001afe0000c13d000000000004004b00001b120000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f000000000013043500001b120000013d000000600a000039000000800900003900000000010a0433000000010020019000001b730000613d000000000001004b00001b2e0000c13d000b0000000a001d000a00000009001d00000de50100004100000000001004430000000c010000290000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f000000010020019000001b430000613d000000000101043b000000000001004b0000000b0100002900001ba60000613d0000000001010433000000000001004b0000000a0900002900001b3a0000613d00000dd90010009c00001b3b0000213d000000200010008c00001b3b0000413d0000000001090433000000000001004b0000000002000039000000010200c039000000000021004b00001b3b0000c13d000000000001004b00001b790000613d000000000001042d0000000001000019000034df0001043000000def01000041000000000010043f0000001101000039000000040010043f00000df001000041000034df00010430000000000001042f00000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df0001043000000e0c01000041000000000010043f00000d4801000041000034df000104300000001f0530018f00000d3b06300198000000400200043d000000000462001900001b590000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001b550000c13d000000000005004b00001b660000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000d390020009c00000d39020080410000004002200210000000000112019f000034df0001043000000e1b01000041000000000010043f0000006001000039000000040010043f000000240020043f00000de101000041000034df00010430000000000001004b00001b7b0000c13d00000dee01000041000000000010043f00000d4801000041000034df0001043000000e310100004100001ba70000013d00000d390090009c00000d3909008041000000400290021000000d390010009c00000d39010080410000006001100210000000000121019f000034df00010430000000600210027000000d390220019700001b880000013d0000000002000019000000000103034f0000001f0520018f00000d3b06200198000000400300043d000000000463001900001b930000613d000000000701034f0000000008030019000000007907043c0000000008980436000000000048004b00001b8f0000c13d000000000005004b00001ba00000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600120021000000d390030009c00000d39030080410000004002300210000000000112019f000034df0001043000000df101000041000000000010043f0000000c01000029000000040010043f00000df001000041000034df00010430000200000000000200000dd101000041000000000010044300000000010004120000000400100443000000a0010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f000000010020019000001c4a0000613d000000000101043b00000d3c011001970000000002000410000000000012004b00001bf00000c13d00000dd10100004100000000001004430000000001000412000000040010044300000080010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f000000010020019000001c4a0000613d000000000101043b000200000001001d00000d4c010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f000000010020019000001c4a0000613d000000000101043b000000020010006c00001bf00000c13d00000dd10100004100000000001004430000000001000412000000040010044300000060010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f000000010020019000001c480000c13d00001c4a0000013d000000400100043d000200000001001d000000200210003900000d4e01000041000100000002001d000000000012043500000dd101000041000000000010044300000000010004120000000400100443000000c0010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f000000010020019000001c4a0000613d000000000101043b00000002020000290000004002200039000000000012043500000dd101000041000000000010044300000000010004120000000400100443000000e0010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f000000010020019000001c4a0000613d000000000101043b00000002020000290000006002200039000000000012043500000d4c010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f000000010020019000001c4a0000613d000000000101043b0000000204000029000000a0024000390000000003000410000000000032043500000080024000390000000000120435000000a001000039000000000014043500000e320040009c00001c4b0000813d0000000202000029000000c001200039000000400010043f000000010100002900000d390010009c00000d39010080410000004001100210000000000202043300000d390020009c00000d39020080410000006002200210000000000112019f000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d41011001c7000080100200003934dd34d30000040f000000010020019000001c510000613d000000000101043b000000000001042d000000000001042f00000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df000104300000000001000019000034df000104300001000000000002000100000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f000000010020019000001c640000613d000000000101043b000000010010006c00001c650000213d000000000001042d000000000001042f00000ddc01000041000000000010043f00000d4801000041000034df0001043000000d3c01100197000000000010043f0000001101000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000001c7b0000613d000000000201043b000000000102041a0000000103100039000000000032041b000000000001042d0000000001000019000034df000104300003000000000002000200000001001d00000dd101000041000000000010044300000000010004120000000400100443000000a0010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f000000010020019000001d320000613d000000000101043b00000d3c011001970000000002000410000000000012004b00001cc20000c13d00000dd10100004100000000001004430000000001000412000000040010044300000080010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f000000010020019000001d320000613d000000000101043b000300000001001d00000d4c010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f000000010020019000001d320000613d000000000101043b000000030010006c00001cc20000c13d00000dd10100004100000000001004430000000001000412000000040010044300000060010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f000000010020019000001d1a0000c13d00001d320000013d000000400100043d000300000001001d000000200210003900000d4e01000041000100000002001d000000000012043500000dd101000041000000000010044300000000010004120000000400100443000000c0010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f000000010020019000001d320000613d000000000101043b00000003020000290000004002200039000000000012043500000dd101000041000000000010044300000000010004120000000400100443000000e0010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f000000010020019000001d320000613d000000000101043b00000003020000290000006002200039000000000012043500000d4c010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f000000010020019000001d320000613d000000000101043b0000000304000029000000a0024000390000000003000410000000000032043500000080024000390000000000120435000000a001000039000000000014043500000e320040009c00001d350000813d0000000302000029000000c001200039000000400010043f000000010100002900000d390010009c00000d39010080410000004001100210000000000202043300000d390020009c00000d39020080410000006002200210000000000112019f000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d41011001c7000080100200003934dd34d30000040f000000010020019000001d330000613d000000000101043b000000400200043d00000022032000390000000204000029000000000043043500000dd30300004100000000003204350000000203200039000000000013043500000d390020009c00000d39020080410000004001200210000000000200041400000d390020009c00000d3902008041000000c002200210000000000121019f00000dd4011001c7000080100200003934dd34d30000040f000000010020019000001d330000613d000000000101043b000000000001042d000000000001042f0000000001000019000034df0001043000000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df00010430000400000000000200000000080100190000000091030434000000410010008c00001d440000c13d0000004001300039000000000101043300000dd50010009c00001db40000a13d000000400100043d000000440510003900000040040000390000000000450435000000200a10003900000dd70400004100000000004a0435000000240410003900000000002404350000006404100039000000000303043300000000003404350000008404100039000000000003004b00001d5b0000613d000000000500001900000000064500190000000007590019000000000707043300000000007604350000002005500039000000000035004b00001d540000413d000000000443001900000000000404350000001f0330003900000e220330019700000064053000390000000000510435000000a30330003900000e22043001970000000003140019000000000043004b0000000004000039000000010400403900000d3d0030009c00001dfd0000213d000000010040019000001dfd0000c13d000000400030043f00000d3900a0009c00000d390a0080410000004002a00210000000000101043300000d390010009c00000d39010080410000006001100210000000000121019f000000000200041400000d390020009c00000d3902008041000000c002200210000000000121019f000000000208001934dd34d30000040f000000600310027000000d390530019800001da50000613d0000001f0350003900000d3a033001970000003f0330003900000dd804300197000000400300043d0000000004430019000000000034004b0000000006000039000000010600403900000d3d0040009c00001dfd0000213d000000010060019000001dfd0000c13d000000400040043f0000001f0650018f000000000453043600000d3b07500198000000000574001900001d970000613d000000000801034f0000000009040019000000008a08043c0000000009a90436000000000059004b00001d930000c13d000000000006004b00001da70000613d000000000171034f0000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f000000000015043500001da70000013d00000060030000390000008004000039000000010020019000001df90000613d0000000001030433000000200010008c00001df90000413d00000dd90010009c00001e030000213d0000001f0010008c00001e030000a13d000000000104043300000dd70010009c00001df90000c13d000000000001042d000400000008001d000200000003001d00000060033000390000000006030433000300000009001d0000000003090433000000400400043d0000006005400039000000000015043500000040014000390000000000310435000000f80160027000000020034000390000000000130435000100000002001d0000000000240435000000000000043f00000d390040009c00000d39040080410000004001400210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000dd6011001c7000000010200003934dd34d30000040f000000600310027000000d3903300197000000200030008c000000200400003900000000040340190000001f0540018f000000200440019000001dde0000613d000000000601034f0000000007000019000000006806043c0000000007870436000000000047004b00001dda0000c13d000000000005004b00001deb0000613d000000000641034f0000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f000000000054043500000001002001900000000408000029000000030900002900001e050000613d000000000100043d00000d3c0010019800000000010060190000000203000029000000010200002900001d440000613d000000000181013f00000d3c0010019800001db30000613d00001d440000013d00000dda01000041000000000010043f00000d4801000041000034df0001043000000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df000104300000000001000019000034df000104300000001f0530018f00000d3b06300198000000400200043d000000000462001900001e100000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001e0c0000c13d000000000005004b00001e1d0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000d390020009c00000d39020080410000004002200210000000000112019f000034df00010430000b000000000002000a00000003001d000b00000001001d000600000002001d000000000020043f0000001401000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f00000001002001900000204f0000613d0000001903000039000000000203041a00000d4302200197000000000101043b000000000101041a00000d3c04100198000000000142019f000000000013041b00001e500000613d000900000004001d000000000040043f0000001501000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f00000001002001900000204f0000613d000000000101043b000000000201041a0000000a0220006c000020510000413d000000000021041b000000090100002934dd2f9f0000040f0000000c01000039000000000401041a0000000401000039000000000301041a000000000003004b00000009020000390000000b0100003900001e7e0000613d000500000003001d000900000004001d000000000202041a000700000002001d000000000101041a000800000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f0000000100200190000020570000613d000000000101043b000000070010006b000000000201001900000007020040290000000a01000039000000000101041a000000000212004b00000009040000290000000803000029000020510000413d00000000013200a9000000000003004b00001e790000613d00000000033100d9000000000023004b000020510000c13d00000005011000fa000000000041001a000020510000413d000000000441001900000009020000390000000c01000039000000000041041b000000000102041a000900000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f0000000100200190000020570000613d000000000101043b000000090010006b000000000201001900000009020040290000000a01000039000000000021041b0000000c01000039000000000701041a0000000b010000290000000405100039000000000605041a0000000101100039000900000001001d000000000401041a0000000401000039000000000101041a000000000001004b00001ecc0000613d000100000001001d000400000007001d000500000004001d000700000006001d000800000005001d0000000901000039000000000101041a000200000001001d0000000b01000039000000000101041a000300000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f0000000100200190000020570000613d000000000101043b000000020010006b000000000201001900000002020040290000000a01000039000000000101041a000000000212004b00000008050000290000000706000029000000050400002900000004070000290000000303000029000020510000413d00000000013200a9000000000003004b00001ec80000613d00000000033100d9000000000023004b000020510000c13d00000001011000fa000000000071001a000020510000413d00000000077100190000000b010000290000000301100039000000000201041a000000000327004b000020510000413d00000d530440019800000000024300a900001ed70000613d00000000044200d9000000000034004b000020510000c13d000000000062001a000020510000413d0000000002620019000000000025041b0000000c02000039000000000202041a000000000021041b0000000b01000029000000000101041a00000d53021001970008000a00200074000020510000413d0000000502000039000000000202041a0000000903000029000000000303041a0000006001100270000000400500043d000700000005001d0000002404500039000000000014043500000060013002700000004403500039000000000013043500000e2801000041000000000015043500000004015000390000000803000029000000000031043500000d390050009c00000d390100004100000000010540190000004001100210000000000300041400000d390030009c00000d3903008041000000c003300210000000000113019f00000e29011001c700000d3c0220019734dd34d30000040f000000070b000029000000600310027000000d3903300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b001900001f100000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b00001f0c0000c13d000000000006004b00001f1d0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f000000000065043500000001002001900000205e0000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000d3d0010009c000020580000213d0000000100200190000020580000c13d000000400010043f000000200030008c0000204f0000413d0000000301000039000000000201041a0000000a0220006c000020510000413d00000000030b0433000000000021041b0000000401000039000000000101041a000000000031001a000020510000413d00000000013100190000000902000029000000000202041a00000d5302200197000000000121004b000020510000413d000700000003001d0000000402000039000000000012041b0000000b01000029000000000101041a0000006001100270000000000010043f0000000601000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f00000001002001900000204f0000613d000000000101043b000000000201041a0000000a0220006c000020510000413d000000000021041b0000000901000029000000000101041a000500000001001d0000000b01000029000000000101041a0000006001100270000400000001001d000000000010043f0000000701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f00000001002001900000204f0000613d000000000101043b000000000101041a0000000703000029000000000031001a000020510000413d000000050200002900000d530220019700000000013100190005000000210053000020510000413d0000000401000029000000000010043f0000000701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f00000001002001900000204f0000613d000000000101043b0000000502000029000000000021041b000000080300002900000e190030009c0000207c0000813d0000000b02000029000000000102041a00000e1a01100197000000000131019f000000000012041b000000070200002900000e190020009c000020830000813d0000000903000029000000000103041a00000e1a01100197000000000121019f000000000013041b0000006001100270000000000010043f0000001201000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f00000001002001900000204f0000613d000000000101043b000000000101041a0000000b02000029000000000202041a000000400500043d00000064035000390000000a040000290000000000430435000000600220027000000044035000390000000000230435000000200350003900000e3002000041000900000003001d000000000023043500000d3c01100197000000240250003900000000001204350000006401000039000000000015043500000dd00050009c000020580000213d000500000005001d000000a001500039000000400010043f00000dd10100004100000000001004430000000001000412000000040010044300000020010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f0000000100200190000020570000613d000000090200002900000d390020009c00000d390200804100000040022002100000000503000029000000000303043300000d390030009c00000d39030080410000006003300210000000000223019f000000000301043b000000000100041400000d390010009c00000d3901008041000000c001100210000000000112019f00000d3c02300197000900000002001d34dd34ce0000040f000000600310027000000d3903300198000020020000613d0000001f0430003900000d3a044001970000003f0440003900000dd804400197000000400a00043d00000000044a00190000000000a4004b0000000005000039000000010500403900000d3d0040009c000020580000213d0000000100500190000020580000c13d000000400040043f0000001f0430018f00000000093a043600000d3b05300198000000000359001900001ff40000613d000000000601034f0000000007090019000000006806043c0000000007870436000000000037004b00001ff00000c13d000000000004004b000020040000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000020040000013d000000600a000039000000800900003900000000010a043300000001002001900000208a0000613d000000000001004b000020200000c13d00050000000a001d000400000009001d00000de501000041000000000010044300000009010000290000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f0000000100200190000020570000613d000000000101043b000000000001004b00000005010000290000209a0000613d0000000001010433000000000001004b00000004090000290000202c0000613d00000dd90010009c0000204f0000213d000000200010008c0000204f0000413d0000000001090433000000000001004b0000000002000039000000010200c039000000000021004b0000204f0000c13d000000000001004b000020900000613d0000000b01000029000000000101041a000000400200043d00000060032000390000000704000029000000000043043500000040032000390000000804000029000000000043043500000020032000390000000a0400002900000000004304350000006001100270000000000012043500000d390020009c00000d39020080410000004001200210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d54011001c70000800d02000039000000020300003900000e3304000041000000060500002934dd34ce0000040f00000001002001900000204f0000613d0000001902000039000000000102041a00000d4301100197000000000012041b000000000001042d0000000001000019000034df0001043000000def01000041000000000010043f0000001101000039000000040010043f00000df001000041000034df00010430000000000001042f00000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df000104300000001f0530018f00000d3b06300198000000400200043d0000000004620019000020690000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000020650000c13d000000000005004b000020760000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000d390020009c00000d39020080410000004002200210000000000112019f000034df0001043000000e1b01000041000000000010043f0000006001000039000000040010043f000000240030043f00000de101000041000034df0001043000000e1b01000041000000000010043f0000006001000039000000040010043f000000240020043f00000de101000041000034df00010430000000000001004b000020920000c13d00000dee01000041000000000010043f00000d4801000041000034df0001043000000e31010000410000209b0000013d00000d390090009c00000d3909008041000000400290021000000d390010009c00000d39010080410000006001100210000000000121019f000034df0001043000000df101000041000000000010043f0000000901000029000000040010043f00000df001000041000034df00010430000b000000000002000b00000003001d000a00000001001d000400000002001d000000000020043f0000001401000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000022dd0000613d0000001903000039000000000203041a00000d4302200197000000000101043b000000000101041a00000d3c04100197000000000142019f000000000013041b000900000004001d000000000040043f0000001501000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000022dd0000613d000000000101043b000000000201041a0000000b0020002a000022df0000413d0000000b02200029000000000021041b000000090100002934dd2f9f0000040f0000000301000039000000000201041a0000000b01200029000000000021004b00000000020000390000000102004039000000010020008c000022df0000613d0000001302000039000000000202041a000000000021004b000022ec0000213d0000000c01000039000000000401041a0000000401000039000000000301041a000000000003004b00000009020000390000000b01000039000021070000613d000600000003001d000900000004001d000000000202041a000700000002001d000000000101041a000800000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f0000000100200190000022e50000613d000000000101043b000000070010006b000000000201001900000007020040290000000a01000039000000000101041a000000000212004b00000009040000290000000803000029000022df0000413d00000000013200a9000000000003004b000021020000613d00000000033100d9000000000023004b000022df0000c13d00000006011000fa000000000041001a000022df0000413d000000000441001900000009020000390000000c01000039000000000041041b000000000102041a000900000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f0000000100200190000022e50000613d000000000101043b000000090010006b000000000201001900000009020040290000000a01000039000000000021041b0000000c01000039000000000701041a0000000a010000290000000405100039000000000605041a0000000101100039000900000001001d000000000401041a0000000401000039000000000101041a000000000001004b000021550000613d000100000001001d000500000007001d000600000004001d000700000006001d000800000005001d0000000901000039000000000101041a000200000001001d0000000b01000039000000000101041a000300000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f0000000100200190000022e50000613d000000000101043b000000020010006b000000000201001900000002020040290000000a01000039000000000101041a000000000212004b00000008050000290000000706000029000000060400002900000005070000290000000303000029000022df0000413d00000000013200a9000000000003004b000021510000613d00000000033100d9000000000023004b000022df0000c13d00000001011000fa000000000071001a000022df0000413d00000000077100190000000a010000290000000301100039000000000201041a000000000327004b000022df0000413d00000d530440019800000000024300a9000021600000613d00000000044200d9000000000034004b000022df0000c13d000000000062001a000022df0000413d0000000002620019000000000025041b0000000c02000039000000000202041a000000000021041b0000000901000029000000000101041a000500000001001d0000006001100270000800000001001d000000000010043f0000001201000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000022dd0000613d0000000a02000029000000000202041a00000d5303200197000000000101043b0000000b0030002a000022df0000413d0000000b04300029000000000101041a000300000001001d0000000501000039000000000301041a000000400600043d000600000006001d00000044016000390000000805000029000000000051043500000060012002700000002402600039000000000012043500000e280100004100000000001604350000000401600039000700000004001d000000000041043500000d390060009c00000d390100004100000000010640190000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000e29011001c700000d3c0230019734dd34d30000040f000000060b000029000000600310027000000d3903300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000021ac0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000021a80000c13d000000000006004b000021b90000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000022f00000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000d3d0010009c000022e60000213d0000000100200190000022e60000c13d000000400010043f000000200030008c000022dd0000413d00000000030b04330000000401000039000000000101041a000000000031001a000022df0000413d000000050200002900000d53022001970000000001310019000000000121004b000022df0000413d0000000402000039000000000012041b0000000301000039000000000101041a0000000b0010002a000022df0000413d000800000003001d0000000b011000290000000302000039000000000012041b0000000a01000029000000000101041a0000006001100270000000000010043f0000000601000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000022dd0000613d000000000101043b000000000201041a0000000b0020002a000022df0000413d0000000b02200029000000000021041b0000000901000029000000000101041a000600000001001d0000000a01000029000000000101041a0000006001100270000500000001001d000000000010043f0000000701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000022dd0000613d000000000101043b000000000101041a0000000803000029000000000031001a000022df0000413d000000060200002900000d530220019700000000013100190006000000210053000022df0000413d0000000501000029000000000010043f0000000701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000022dd0000613d000000000101043b0000000602000029000000000021041b000000080200002900000e190020009c0000230e0000813d0000000903000029000000000103041a00000e1a01100197000000000121019f000000000013041b000000070400002900000e190040009c000023150000813d000000030100002900000d3c011001970000000a03000029000000000203041a00000e1a02200197000000000242019f000000000023041b000000400500043d00000064035000390000000b04000029000000000043043500000044035000390000000000130435000000200350003900000e3001000041000900000003001d00000000001304350000006001200270000000240250003900000000001204350000006401000039000000000015043500000dd00050009c000022e60000213d000600000005001d000000a001500039000000400010043f00000dd10100004100000000001004430000000001000412000000040010044300000020010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f0000000100200190000022e50000613d000000090200002900000d390020009c00000d390200804100000040022002100000000603000029000000000303043300000d390030009c00000d39030080410000006003300210000000000223019f000000000301043b000000000100041400000d390010009c00000d3901008041000000c001100210000000000112019f00000d3c02300197000900000002001d34dd34ce0000040f000000600310027000000d3903300198000022900000613d0000001f0430003900000d3a044001970000003f0440003900000dd804400197000000400a00043d00000000044a00190000000000a4004b0000000005000039000000010500403900000d3d0040009c000022e60000213d0000000100500190000022e60000c13d000000400040043f0000001f0430018f00000000093a043600000d3b053001980000000003590019000022820000613d000000000601034f0000000007090019000000006806043c0000000007870436000000000037004b0000227e0000c13d000000000004004b000022920000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000022920000013d000000600a000039000000800900003900000000010a043300000001002001900000231c0000613d000000000001004b000022ae0000c13d00060000000a001d000500000009001d00000de501000041000000000010044300000009010000290000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f0000000100200190000022e50000613d000000000101043b000000000001004b00000006010000290000232c0000613d0000000001010433000000000001004b0000000509000029000022ba0000613d00000dd90010009c000022dd0000213d000000200010008c000022dd0000413d0000000001090433000000000001004b0000000002000039000000010200c039000000000021004b000022dd0000c13d000000000001004b000023220000613d0000000a01000029000000000101041a000000400200043d00000060032000390000000804000029000000000043043500000040032000390000000704000029000000000043043500000020032000390000000b0400002900000000004304350000006001100270000000000012043500000d390020009c00000d39020080410000004001200210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d54011001c70000800d02000039000000020300003900000e3404000041000000040500002934dd34ce0000040f0000000100200190000022dd0000613d0000001902000039000000000102041a00000d4301100197000000000012041b000000000001042d0000000001000019000034df0001043000000def01000041000000000010043f0000001101000039000000040010043f00000df001000041000034df00010430000000000001042f00000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df0001043000000e3501000041000000000010043f00000d4801000041000034df000104300000001f0530018f00000d3b06300198000000400200043d0000000004620019000022fb0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000022f70000c13d000000000005004b000023080000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000d390020009c00000d39020080410000004002200210000000000112019f000034df0001043000000e1b01000041000000000010043f0000006001000039000000040010043f000000240020043f00000de101000041000034df0001043000000e1b01000041000000000010043f0000006001000039000000040010043f000000240040043f00000de101000041000034df00010430000000000001004b000023240000c13d00000dee01000041000000000010043f00000d4801000041000034df0001043000000e31010000410000232d0000013d00000d390090009c00000d3909008041000000400290021000000d390010009c00000d39010080410000006001100210000000000121019f000034df0001043000000df101000041000000000010043f0000000901000029000000040010043f00000df001000041000034df00010430000b000000000002000a00000003001d000b00000001001d000700000002001d000000000020043f0000001401000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000024910000613d0000001903000039000000000203041a00000d4302200197000000000101043b000000000101041a00000d3c01100197000000000112019f000000000013041b0000000a0100002900090d3c0010019c000024940000613d0000000c01000039000000000401041a0000000401000039000000000301041a000000000003004b00000009020000390000000b010000390000237b0000613d000500000003001d000a00000004001d000000000202041a000600000002001d000000000101041a000800000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f0000000100200190000024930000613d000000000101043b000000060010006b000000000201001900000006020040290000000a01000039000000000101041a000000000212004b0000000a0400002900000008030000290000248b0000413d00000000013200a9000000000003004b000023760000613d00000000033100d9000000000023004b0000248b0000c13d00000005011000fa000000000041001a0000248b0000413d000000000441001900000009020000390000000c01000039000000000041041b000000000102041a000a00000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f0000000100200190000024930000613d000000000101043b0000000a0010006b00000000020100190000000a020040290000000a01000039000000000021041b0000000c01000039000000000701041a0000000b010000290000000405100039000000000605041a0000000101100039000a00000001001d000000000401041a0000000401000039000000000101041a000000000001004b000023c90000613d000100000001001d000400000007001d000500000004001d000600000006001d000800000005001d0000000901000039000000000101041a000200000001001d0000000b01000039000000000101041a000300000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f0000000100200190000024930000613d000000000101043b000000020010006b000000000201001900000002020040290000000a01000039000000000101041a000000000212004b000000080500002900000006060000290000000504000029000000040700002900000003030000290000248b0000413d00000000013200a9000000000003004b000023c50000613d00000000033100d9000000000023004b0000248b0000c13d00000001011000fa000000000071001a0000248b0000413d00000000077100190000000b010000290000000301100039000000000201041a000000000327004b0000248b0000413d00000d530440019800000000024300a9000023d40000613d00000000044200d9000000000034004b0000248b0000c13d000000000062001a0000248b0000413d0000000002620019000000000025041b0000000c02000039000000000202041a000000000021041b0000000501000039000000000201041a0000000b01000029000000000101041a0000000a03000029000000000303041a000600000003001d0000006003300270000000400500043d000800000005001d0000004404500039000000000034043500000060031002700000002404500039000000000034043500000e2803000041000000000035043500000d53011001970000000403500039000000000013043500000d390050009c00000d390100004100000000010540190000004001100210000000000300041400000d390030009c00000d3903008041000000c003300210000000000113019f00000e29011001c700000d3c0220019734dd34d30000040f000000080b000029000000600310027000000d3903300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b00190000240b0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000024070000c13d000000000006004b000024180000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000024980000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000d3d0010009c000024b60000213d0000000100200190000024b60000c13d000000400010043f000000200030008c000024910000413d00000000030b04330000000401000039000000000101041a000000000031001a0000248b0000413d000000060200002900000d53022001970000000001310019000000000121004b0000248b0000413d000800000003001d0000000402000039000000000012041b0000000a01000029000000000101041a000600000001001d0000000b01000029000000000101041a0000006001100270000500000001001d000000000010043f0000000701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000024910000613d000000000101043b000000000101041a0000000803000029000000000031001a0000248b0000413d000000060200002900000d5302200197000000000131001900060000002100530000248b0000413d0000000501000029000000000010043f0000000701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000024910000613d000000000101043b0000000602000029000000000021041b000000080300002900000e190030009c000024bc0000813d0000000a02000029000000000102041a00000e1a01100197000000000131019f000000000012041b0000000b010000290000000201100039000b00000001001d000000000201041a000000400100043d000000000031043500000d390010009c00000d39010080410000004001100210000000000300041400000d390030009c00000d3903008041000000c003300210000000000113019f00000d4a011001c700000d3c062001970000800d02000039000000040300003900000e36040000410000000705000029000000090700002934dd34ce0000040f0000000100200190000024910000613d0000000b03000029000000000103041a00000d430110019700000009011001af000000000013041b0000001902000039000000000102041a00000d4301100197000000000012041b000000000001042d00000def01000041000000000010043f0000001101000039000000040010043f00000df001000041000034df000104300000000001000019000034df00010430000000000001042f00000e0c01000041000000000010043f00000d4801000041000034df000104300000001f0530018f00000d3b06300198000000400200043d0000000004620019000024a30000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000249f0000c13d000000000005004b000024b00000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000d390020009c00000d39020080410000004002200210000000000112019f000034df0001043000000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df0001043000000e1b01000041000000000010043f0000006001000039000000040010043f000000240030043f00000de101000041000034df00010430000b000000000002000700000003001d000800000002001d000b00000001001d0000000c01000039000000000401041a0000000401000039000000000301041a000000000003004b00000009020000390000000b01000039000024f50000613d000500000003001d000a00000004001d000000000202041a000600000002001d000000000101041a000900000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f0000000100200190000026580000613d000000000101043b000000060010006b000000000201001900000006020040290000000a01000039000000000101041a000000000212004b0000000a040000290000000903000029000026520000413d00000000013200a9000000000003004b000024f00000613d00000000033100d9000000000023004b000026520000c13d00000005011000fa000000000041001a000026520000413d000000000441001900000009020000390000000c01000039000000000041041b000000000102041a000a00000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f0000000100200190000026580000613d000000000101043b0000000a0010006b00000000020100190000000a020040290000000a01000039000000000021041b0000000c01000039000000000701041a0000000b010000290000000405100039000000000605041a0000000101100039000900000001001d000000000401041a0000000401000039000000000101041a000000000001004b000025430000613d000100000001001d000400000007001d000500000004001d000600000006001d000a00000005001d0000000901000039000000000101041a000200000001001d0000000b01000039000000000101041a000300000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f0000000100200190000026580000613d000000000101043b000000020010006b000000000201001900000002020040290000000a01000039000000000101041a000000000212004b0000000a050000290000000606000029000000050400002900000004070000290000000303000029000026520000413d00000000013200a9000000000003004b0000253f0000613d00000000033100d9000000000023004b000026520000c13d00000001011000fa000000000071001a000026520000413d00000000077100190000000b010000290000000301100039000000000201041a000000000327004b000026520000413d00000d530440019800000000024300a90000254e0000613d00000000044200d9000000000034004b000026520000c13d000000000062001a000026520000413d0000000002620019000000000025041b0000000c02000039000000000202041a000000000021041b0000000501000039000000000201041a0000000b01000029000000000101041a0000000903000029000000000303041a000600000003001d0000006003300270000000400500043d000a00000005001d0000004404500039000000000034043500000060031002700000002404500039000000000034043500000e2803000041000000000035043500000d53011001970000000403500039000000000013043500000d390050009c00000d390100004100000000010540190000004001100210000000000300041400000d390030009c00000d3903008041000000c003300210000000000113019f00000e29011001c700000d3c0220019734dd34d30000040f0000000a0b000029000000600310027000000d3903300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000025850000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000025810000c13d000000000006004b000025920000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000026590000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000d3d0010009c000026770000213d0000000100200190000026770000c13d000000400010043f0000001f0030008c000026500000a13d00000000020b04330000000401000039000000000101041a000a00000002001d000000000021001a000026520000413d000000060200002900000d53022001970000000a01100029000000000121004b000026520000413d0000000402000039000000000012041b0000000901000029000000000101041a000600000001001d0000000b01000029000000000101041a0000006001100270000500000001001d000000000010043f0000000701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000026500000613d000000000101043b000000000101041a0000000a0010002a000026520000413d000000060200002900000d53022001970000000a011000290006000000210053000026520000413d0000000501000029000000000010043f0000000701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000026500000613d000000000101043b0000000602000029000000000021041b0000000a0300002900000e190030009c0000267d0000813d0000000902000029000000000102041a00000e1a01100197000000000131019f000000000012041b0000000b01000029000000000101041a000900000001001d0000000801000029000000000010043f0000001401000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000026500000613d000000000101043b000000000101041a00000d3c01100197000b00000001001d000000000010043f0000001501000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000026500000613d000000090200002900000d5303200197000000000101043b000000000201041a000000000232004b000026520000413d000600000003001d000000000021041b000000070100002900000d3c01100197000900000001001d000000000010043f0000001501000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000026500000613d000000000101043b000000000201041a0000000603000029000000000032001a000026520000413d0000000002320019000000000021041b0000000b0100002934dd2f9f0000040f000000070100002934dd2f9f0000040f000000400100043d00000040021000390000000a0300002900000000003204350000002002100039000000090300002900000000003204350000000b02000029000000000021043500000d390010009c00000d39010080410000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000e2a011001c70000800d02000039000000020300003900000e3704000041000000080500002934dd34ce0000040f0000000100200190000026500000613d0000000801000029000000000010043f0000001401000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000026500000613d000000000101043b000000000201041a00000d430220019700000009022001af000000000021041b000000000001042d0000000001000019000034df0001043000000def01000041000000000010043f0000001101000039000000040010043f00000df001000041000034df00010430000000000001042f0000001f0530018f00000d3b06300198000000400200043d0000000004620019000026640000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000026600000c13d000000000005004b000026710000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000d390020009c00000d39020080410000004002200210000000000112019f000034df0001043000000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df0001043000000e1b01000041000000000010043f0000006001000039000000040010043f000000240030043f00000de101000041000034df00010430000b000000000002000600000003001d000b00000002001d000700000001001d000000000010043f0000001401000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000028e00000613d0000001903000039000000000203041a00000d4302200197000000000101043b000000000101041a00000d3c01100197000000000112019f000000000013041b0000000c01000039000000000401041a0000000401000039000000000301041a000000000003004b00000009020000390000000b01000039000026ca0000613d000500000003001d000a00000004001d000000000202041a000800000002001d000000000101041a000900000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f0000000100200190000028e20000613d000000000101043b000000080010006b000000000201001900000008020040290000000a01000039000000000101041a000000000212004b0000000a040000290000000903000029000028da0000413d00000000013200a9000000000003004b000026c50000613d00000000033100d9000000000023004b000028da0000c13d00000005011000fa000000000041001a000028da0000413d000000000441001900000009020000390000000c01000039000000000041041b000000000102041a000a00000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f0000000100200190000028e20000613d000000000101043b0000000a0010006b00000000020100190000000a020040290000000a01000039000000000021041b0000000c01000039000000000701041a0000000b010000290000000405100039000000000605041a0000000101100039000900000001001d000000000401041a0000000401000039000000000101041a000000000001004b000027180000613d000100000001001d000400000007001d000500000004001d000800000006001d000a00000005001d0000000901000039000000000101041a000200000001001d0000000b01000039000000000101041a000300000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f0000000100200190000028e20000613d000000000101043b000000020010006b000000000201001900000002020040290000000a01000039000000000101041a000000000212004b0000000a050000290000000806000029000000050400002900000004070000290000000303000029000028da0000413d00000000013200a9000000000003004b000027140000613d00000000033100d9000000000023004b000028da0000c13d00000001011000fa000000000071001a000028da0000413d00000000077100190000000b010000290000000301100039000000000201041a000000000327004b000028da0000413d00000d530440019800000000024300a9000027230000613d00000000044200d9000000000034004b000028da0000c13d000000000062001a000028da0000413d0000000002620019000000000025041b0000000c03000039000000000303041a000000000031041b00000de31320012a0000000e04000039000000000404041a00000d5304400197000a000000430053000028da0000413d000028d40000613d00000de3033000d1000000000023004b000028da0000213d000000000015041b0000000501000039000000000201041a0000000b01000029000000000101041a0000000903000029000000000303041a000500000003001d0000006003300270000000400500043d000800000005001d0000004404500039000000000034043500000060031002700000002404500039000000000034043500000e2803000041000000000035043500000d53011001970000000403500039000000000013043500000d390050009c00000d390100004100000000010540190000004001100210000000000300041400000d390030009c00000d3903008041000000c003300210000000000113019f00000e29011001c700000d3c0220019734dd34d30000040f000000080b000029000000600310027000000d3903300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000027650000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000027610000c13d000000000006004b000027720000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000028f10000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000d3d0010009c000028e30000213d0000000100200190000028e30000c13d000000400010043f000000200030008c000028e00000413d00000000030b04330000002002100039000800000003001d00000000003204350000000a02000029000000000021043500000d390010009c00000d39010080410000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d44011001c7000000060200002900000d3c062001970000800d02000039000000030300003900000e38040000410000000705000029000600000006001d34dd34ce0000040f0000000100200190000028e00000613d0000000401000039000000000101041a0000000803000029000000000031001a000028da0000413d000000050200002900000d53022001970000000001310019000000000121004b000028da0000413d0000000402000039000000000012041b0000000901000029000000000101041a000700000001001d0000000b01000029000000000101041a0000006001100270000b00000001001d000000000010043f0000000701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000028e00000613d000000000101043b000000000101041a0000000803000029000000000031001a000028da0000413d000000070200002900000d530220019700000000013100190007000000210053000028da0000413d0000000b01000029000000000010043f0000000701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f0000000100200190000028e00000613d000000000101043b0000000702000029000000000021041b000000080300002900000e190030009c0000290f0000813d0000000902000029000000000102041a00000e1a01100197000000000131019f000000000012041b00000dd1010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f0000000100200190000028e20000613d000000000201043b000000400100043d00000044031000390000000a040000290000000000430435000000200310003900000e390400004100000000004304350000002404100039000000060500002900000000005404350000004404000039000000000041043500000dcd0010009c000028e30000213d0000008004100039000000400040043f00000d390030009c00000d39030080410000004003300210000000000101043300000d390010009c00000d39010080410000006001100210000000000131019f000000000300041400000d390030009c00000d3903008041000000c003300210000000000131019f00000d3c02200197000b00000002001d34dd34ce0000040f000000600310027000000d3903300198000028340000613d0000001f0430003900000d3a044001970000003f0440003900000dd804400197000000400a00043d00000000044a00190000000000a4004b0000000005000039000000010500403900000d3d0040009c000028e30000213d0000000100500190000028e30000c13d000000400040043f0000001f0430018f00000000093a043600000d3b053001980000000003590019000028260000613d000000000601034f0000000007090019000000006806043c0000000007870436000000000037004b000028220000c13d000000000004004b000028360000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000028360000013d000000600a000039000000800900003900000000010a04330000000100200190000028e90000613d000000000001004b000028520000c13d00090000000a001d000800000009001d00000de50100004100000000001004430000000b010000290000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f0000000100200190000028e20000613d000000000101043b000000000001004b00000009010000290000291e0000613d0000000001010433000000000001004b00000008090000290000285e0000613d00000dd90010009c000028e00000213d000000200010008c000028e00000413d0000000001090433000000000001004b0000000002000039000000010200c039000000000021004b000028e00000c13d000000000001004b000028ef0000613d0000000e01000039000000000301041a00000d5302300198000028d40000613d000000400100043d00000044041000390000000000240435000000200210003900000e390400004100000000004204350000006003300270000000240410003900000000003404350000004403000039000000000031043500000dcd0010009c000028e30000213d0000008003100039000000400030043f00000d390020009c00000d39020080410000004002200210000000000101043300000d390010009c00000d39010080410000006001100210000000000121019f000000000200041400000d390020009c00000d3902008041000000c002200210000000000121019f0000000b0200002934dd34ce0000040f000000600310027000000d3903300198000028aa0000613d0000001f0430003900000d3a044001970000003f0440003900000dd804400197000000400a00043d00000000044a00190000000000a4004b0000000005000039000000010500403900000d3d0040009c000028e30000213d0000000100500190000028e30000c13d000000400040043f0000001f0430018f00000000093a043600000d3b0530019800000000035900190000289c0000613d000000000601034f0000000007090019000000006806043c0000000007870436000000000037004b000028980000c13d000000000004004b000028ac0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000028ac0000013d000000600a000039000000800900003900000000010a04330000000100200190000028e90000613d000000000001004b000028c80000c13d00090000000a001d000800000009001d00000de50100004100000000001004430000000b010000290000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f0000000100200190000028e20000613d000000000101043b000000000001004b00000009010000290000291e0000613d0000000001010433000000000001004b0000000809000029000028d40000613d00000dd90010009c000028e00000213d000000200010008c000028e00000413d0000000001090433000000000001004b0000000002000039000000010200c039000000000021004b000028e00000c13d000000000001004b000028ef0000613d0000001902000039000000000102041a00000d4301100197000000000012041b0000000a01000029000000000001042d00000def01000041000000000010043f0000001101000039000000040010043f00000df001000041000034df000104300000000001000019000034df00010430000000000001042f00000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df00010430000000000001004b000029160000c13d00000dee01000041000000000010043f00000d4801000041000034df0001043000000e31010000410000291f0000013d0000001f0530018f00000d3b06300198000000400200043d0000000004620019000028fc0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000028f80000c13d000000000005004b000029090000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000d390020009c00000d39020080410000004002200210000000000112019f000034df0001043000000e1b01000041000000000010043f0000006001000039000000040010043f000000240030043f00000de101000041000034df0001043000000d390090009c00000d3909008041000000400290021000000d390010009c00000d39010080410000006001100210000000000121019f000034df0001043000000df101000041000000000010043f0000000b01000029000000040010043f00000df001000041000034df00010430000e000000000002000b00000001001d0000001905000039000000000105041a00000d4301100197000000000015041b0000000301000039000000000101041a000e00000002001d000000000021001a00002bbf0000413d0000000e011000290000001302000039000000000202041a000000000021004b00002bc90000213d000c0d3c0030019c00002bc50000613d00090d3c0040019c00002bc50000613d0000000c01000039000000000401041a0000000401000039000000000101041a000000000001004b0000000902000039000029660000613d000700000001001d000d00000004001d000000000102041a000800000001001d0000000b01000039000000000101041a000a00000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f000000010020019000002bbe0000613d000000000101043b000000080010006b000000000201001900000008020040290000000a01000039000000000101041a000000000212004b0000000d040000290000000a0300002900002bbf0000413d00000000013200a9000000000003004b000029610000613d00000000033100d9000000000023004b00002bbf0000c13d00000007011000fa000000000041001a00002bbf0000413d000000000441001900000009020000390000000c01000039000000000041041b000000000102041a000d00000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f000000010020019000002bbe0000613d000000000101043b0000000d0010006b00000000020100190000000d020040290000000a01000039000000000021041b0000000c01000029000000000010043f0000001201000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000002bb60000613d000000000101043b000000000101041a00080d3c0010019c000029e80000c13d000000400100043d00000e3a0010009c00002bb80000813d000d00000001001d000000240110003900000d3802000041000000000021043500000dd10100004100000000001004430000000001000412000000040010044300000020010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f000000010020019000002bbe0000613d0000000d040000290000008402400039000000000101043b00000d3c011001970000000000120435000000a4014000390000000c020000290000000000210435000000640140003900000000020004140000004003000039000000000031043500000044014000390000006003000039000000000031043500000e2d0100004100000000001404350000000401400039000000000001043500000d390040009c00000d3904008041000000400140021000000d390020009c00000d3902008041000000c002200210000000000121019f00000e2e011001c7000080060200003934dd34ce0000040f000000010020019000002c0b0000613d00000000020000310000000103200367000000000101043b000d00000001001d000000000001004b00002c0e0000613d0000000c01000029000000000010043f0000001201000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000002bb60000613d0000000d0200002900000d3c06200197000000000101043b000000000201041a00000d4302200197000000000262019f000000000021041b000000000100041400000d390010009c00000d3901008041000000c00110021000000d41011001c70000800d02000039000000030300003900000e2f040000410000000c05000029000800000006001d34dd34ce0000040f000000010020019000002bb60000613d000000000100041a000d00000001001d000000010110003a00002bbf0000613d000000000010041b0000000501000039000000000201041a000000400400043d000a00000004001d00000044014000390000000c03000029000000000031043500000e2801000041000000000014043500000004014000390000000e0300002900000000003104350000000b0100002900000d3c031001970000002401400039000b00000003001d000000000031043500000d390040009c00000d390100004100000000010440190000004001100210000000000300041400000d390030009c00000d3903008041000000c003300210000000000113019f00000e29011001c700000d3c0220019734dd34d30000040f0000000a0b000029000000600310027000000d3903300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b001900002a1a0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b00002a160000c13d000000000006004b00002a270000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000002bcd0000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000d3d0010009c00002bb80000213d000000010020019000002bb80000c13d000000400010043f000000200030008c00002bb60000413d0000000301000039000000000101041a0000000e0010002a00002bbf0000413d00000000030b04330000000e011000290000000302000039000000000012041b0000000401000039000000000101041a000000000031001a00002bbf0000413d000a00000003001d00000000013100190000000402000039000000000012041b0000000b01000029000000000010043f0000000601000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000002bb60000613d000000000101043b000000000201041a0000000e0020002a00002bbf0000413d0000000e02200029000000000021041b0000000b01000029000000000010043f0000000701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000002bb60000613d000000000101043b000000000201041a0000000a03000029000000000032001a00002bbf0000413d0000000002320019000000000021041b0000000e0100002900000e190010009c00002beb0000813d00000e190030009c00002bf30000813d000000400300043d00000e3b0030009c00002bb80000213d0000000c01000039000000000101041a000000e002300039000000400020043f000000a002300039000700000002001d000000000012043500000080023000390000000901000029000500000002001d000000000012043500000060023000390000000c01000029000300000002001d000000000012043500000040023000390000000a01000029000200000002001d000000000012043500000020023000390000000b01000029000100000002001d00000000001204350000000e010000290000000000130435000400000003001d000000c001300039000600000001001d00000000000104350000000d01000029000000000010043f0000000801000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000002bb60000613d0000000402000029000000000202043300000d5302200197000000010300002900000000030304330000006003300210000000000223019f000000000101043b000000000021041b0000000202000029000000000202043300000d5302200197000000030300002900000000030304330000006003300210000000000223019f0000000103100039000000000023041b0000000502000029000000000202043300000d3c022001970000000203100039000000000403041a00000d4304400197000000000224019f000000000023041b000000070200002900000000020204330000000303100039000000000023041b000000040110003900000006020000290000000002020433000000000021041b000000400300043d00000064013000390000000e02000029000000000021043500000044013000390000000802000029000000000021043500000e30010000410000002002300039000800000002001d000000000012043500000024013000390000000b0200002900000000002104350000006401000039000000000013043500000dd00030009c00002bb80000213d000700000003001d000000a001300039000000400010043f00000dd10100004100000000001004430000000001000412000000040010044300000020010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f000000010020019000002bbe0000613d000000080200002900000d390020009c00000d390200804100000040022002100000000703000029000000000303043300000d390030009c00000d39030080410000006003300210000000000223019f000000000301043b000000000100041400000d390010009c00000d3901008041000000c001100210000000000112019f00000d3c02300197000800000002001d34dd34ce0000040f000000600310027000000d390330019800002b220000613d0000001f0430003900000d3a044001970000003f0440003900000dd804400197000000400a00043d00000000044a00190000000000a4004b0000000005000039000000010500403900000d3d0040009c00002bb80000213d000000010050019000002bb80000c13d000000400040043f0000001f0430018f00000000093a043600000d3b05300198000000000359001900002b140000613d000000000601034f0000000007090019000000006806043c0000000007870436000000000037004b00002b100000c13d000000000004004b00002b240000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f000000000013043500002b240000013d000000600a000039000000800900003900000000010a0433000000010020019000002bfb0000613d000000000001004b00002b400000c13d00070000000a001d000600000009001d00000de501000041000000000010044300000008010000290000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f000000010020019000002bbe0000613d000000000101043b000000000001004b000000070100002900002c2e0000613d0000000001010433000000000001004b000000060900002900002b4c0000613d00000dd90010009c00002bb60000213d000000200010008c00002bb60000413d0000000001090433000000000001004b0000000002000039000000010200c039000000000021004b00002bb60000c13d000000000001004b00002c010000613d000000400100043d00000060021000390000000a03000029000000000032043500000040021000390000000e030000290000000000320435000000200210003900000000003204350000000b02000029000000000021043500000d390010009c00000d39010080410000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d54011001c70000800d02000039000000020300003900000e34040000410000000d0500002934dd34ce0000040f000000010020019000002bb60000613d000000400100043d0000000a02000029000000000021043500000d390010009c00000d39010080410000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d4a011001c70000800d02000039000000040300003900000e36040000410000000d050000290000000006000019000000090700002934dd34ce0000040f000000010020019000002bb60000613d000000400100043d00000040021000390000000a03000029000000000032043500000020021000390000000c030000290000000000320435000000000001043500000d390010009c00000d39010080410000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000e2a011001c70000800d02000039000000020300003900000e2b040000410000000d0500002934dd34ce0000040f000000010020019000002bb60000613d0000000d01000029000000000010043f0000001401000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000002bb60000613d000000000101043b000000000201041a00000d4302200197000000000021041b000000000000043f0000001501000039000000200010043f00000e3c01000041000000000201041a0000000e0020002a00002bbf0000413d0000000e02200029000000000021041b000000000100001934dd2f9f0000040f0000001902000039000000000102041a00000d4301100197000000000012041b0000000d01000029000000000001042d0000000001000019000034df0001043000000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df00010430000000000001042f00000def01000041000000000010043f0000001101000039000000040010043f00000df001000041000034df0001043000000e0c01000041000000000010043f00000d4801000041000034df0001043000000e3501000041000000000010043f00000d4801000041000034df000104300000001f0530018f00000d3b06300198000000400200043d000000000462001900002bd80000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00002bd40000c13d000000000005004b00002be50000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000d390020009c00000d39020080410000004002200210000000000112019f000034df0001043000000e1b01000041000000000010043f0000006001000039000000040010043f0000000e01000029000000240010043f00000de101000041000034df0001043000000e1b01000041000000000010043f0000006001000039000000040010043f0000000a01000029000000240010043f00000de101000041000034df00010430000000000001004b00002c030000c13d00000dee01000041000000000010043f00000d4801000041000034df0001043000000e310100004100002c2f0000013d00000d390090009c00000d3909008041000000400290021000000d390010009c00000d39010080410000006001100210000000000121019f000034df00010430000000600210027000000d390220019700002c100000013d0000000002000019000000000103034f0000001f0520018f00000d3b06200198000000400300043d000000000463001900002c1b0000613d000000000701034f0000000008030019000000007907043c0000000008980436000000000048004b00002c170000c13d000000000005004b00002c280000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600120021000000d390030009c00000d39030080410000004002300210000000000112019f000034df0001043000000df101000041000000000010043f0000000801000029000000040010043f00000df001000041000034df000104300010000000000002000d00000001001d000800000005001d00090d3c0050019b0000001905000039000000000105041a00000d430110019700000009011001af000000000015041b0000000301000039000000000101041a001000000002001d000000000021001a00002edd0000413d00000010011000290000001302000039000000000202041a000000000021004b00002ee70000213d000e0d3c0030019c00002ee30000613d000b0d3c0040019c00002ee30000613d0000000c01000039000000000401041a0000000401000039000000000101041a000000000001004b000000090200003900002c790000613d000700000001001d000f00000004001d000000000102041a000a00000001001d0000000b01000039000000000101041a000c00000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f000000010020019000002edc0000613d000000000101043b0000000a0010006b00000000020100190000000a020040290000000a01000039000000000101041a000000000212004b0000000f040000290000000c0300002900002edd0000413d00000000013200a9000000000003004b00002c740000613d00000000033100d9000000000023004b00002edd0000c13d00000007011000fa000000000041001a00002edd0000413d000000000441001900000009020000390000000c01000039000000000041041b000000000102041a000f00000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f000000010020019000002edc0000613d000000000101043b0000000f0010006b00000000020100190000000f020040290000000a01000039000000000021041b0000000e01000029000000000010043f0000001201000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000002ed40000613d000000000101043b000000000101041a000a0d3c0010019c00002cfb0000c13d000000400100043d00000e3a0010009c00002ed60000813d000f00000001001d000000240110003900000d3802000041000000000021043500000dd10100004100000000001004430000000001000412000000040010044300000020010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f000000010020019000002edc0000613d0000000f040000290000008402400039000000000101043b00000d3c011001970000000000120435000000a4014000390000000e020000290000000000210435000000640140003900000000020004140000004003000039000000000031043500000044014000390000006003000039000000000031043500000e2d0100004100000000001404350000000401400039000000000001043500000d390040009c00000d3904008041000000400140021000000d390020009c00000d3902008041000000c002200210000000000121019f00000e2e011001c7000080060200003934dd34ce0000040f000000010020019000002f290000613d00000000020000310000000103200367000000000101043b000f00000001001d000000000001004b00002f2c0000613d0000000e01000029000000000010043f0000001201000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000002ed40000613d0000000f0200002900000d3c06200197000000000101043b000000000201041a00000d4302200197000000000262019f000000000021041b000000000100041400000d390010009c00000d3901008041000000c00110021000000d41011001c70000800d02000039000000030300003900000e2f040000410000000e05000029000a00000006001d34dd34ce0000040f000000010020019000002ed40000613d000000000100041a000f00000001001d000000010110003a00002edd0000613d000000000010041b0000000501000039000000000201041a000000400400043d000c00000004001d00000044014000390000000e03000029000000000031043500000e280100004100000000001404350000000401400039000000100300002900000000003104350000000d0100002900000d3c031001970000002401400039000d00000003001d000000000031043500000d390040009c00000d390100004100000000010440190000004001100210000000000300041400000d390030009c00000d3903008041000000c003300210000000000113019f00000e29011001c700000d3c0220019734dd34d30000040f0000000c0b000029000000600310027000000d3903300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b001900002d2d0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b00002d290000c13d000000000006004b00002d3a0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000002eeb0000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000d3d0010009c00002ed60000213d000000010020019000002ed60000c13d000000400010043f000000200030008c00002ed40000413d0000000301000039000000000101041a000000100010002a00002edd0000413d00000000030b043300000010011000290000000302000039000000000012041b0000000401000039000000000101041a000000000031001a00002edd0000413d000c00000003001d00000000013100190000000402000039000000000012041b0000000d01000029000000000010043f0000000601000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000002ed40000613d000000000101043b000000000201041a000000100020002a00002edd0000413d0000001002200029000000000021041b0000000d01000029000000000010043f0000000701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000002ed40000613d000000000101043b000000000201041a0000000c03000029000000000032001a00002edd0000413d0000000002320019000000000021041b000000100100002900000e190010009c00002f090000813d00000e190030009c00002f110000813d000000400300043d00000e3b0030009c00002ed60000213d0000000c01000039000000000101041a000000e002300039000000400020043f000000a002300039000700000002001d000000000012043500000080023000390000000b01000029000500000002001d000000000012043500000060023000390000000e01000029000300000002001d000000000012043500000040023000390000000c01000029000200000002001d000000000012043500000020023000390000000d01000029000100000002001d000000000012043500000010010000290000000000130435000400000003001d000000c001300039000600000001001d00000000000104350000000f01000029000000000010043f0000000801000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000002ed40000613d0000000402000029000000000202043300000d5302200197000000010300002900000000030304330000006003300210000000000223019f000000000101043b000000000021041b0000000202000029000000000202043300000d5302200197000000030300002900000000030304330000006003300210000000000223019f0000000103100039000000000023041b0000000502000029000000000202043300000d3c022001970000000203100039000000000403041a00000d4304400197000000000224019f000000000023041b000000070200002900000000020204330000000303100039000000000023041b000000040110003900000006020000290000000002020433000000000021041b000000400300043d00000064013000390000001002000029000000000021043500000044013000390000000a02000029000000000021043500000e30010000410000002002300039000a00000002001d000000000012043500000024013000390000000d0200002900000000002104350000006401000039000000000013043500000dd00030009c00002ed60000213d000700000003001d000000a001300039000000400010043f00000dd10100004100000000001004430000000001000412000000040010044300000020010000390000002400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000dd2011001c7000080050200003934dd34d30000040f000000010020019000002edc0000613d0000000a0200002900000d390020009c00000d390200804100000040022002100000000703000029000000000303043300000d390030009c00000d39030080410000006003300210000000000223019f000000000301043b000000000100041400000d390010009c00000d3901008041000000c001100210000000000112019f00000d3c02300197000a00000002001d34dd34ce0000040f000000600310027000000d390330019800002e350000613d0000001f0430003900000d3a044001970000003f0440003900000dd804400197000000400a00043d00000000044a00190000000000a4004b0000000005000039000000010500403900000d3d0040009c00002ed60000213d000000010050019000002ed60000c13d000000400040043f0000001f0430018f00000000093a043600000d3b05300198000000000359001900002e270000613d000000000601034f0000000007090019000000006806043c0000000007870436000000000037004b00002e230000c13d000000000004004b00002e370000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f000000000013043500002e370000013d000000600a000039000000800900003900000000010a0433000000010020019000002f190000613d000000000001004b00002e530000c13d00070000000a001d000600000009001d00000de50100004100000000001004430000000a010000290000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f000000010020019000002edc0000613d000000000101043b000000000001004b000000070100002900002f4c0000613d0000000001010433000000000001004b000000060900002900002e5f0000613d00000dd90010009c00002ed40000213d000000200010008c00002ed40000413d0000000001090433000000000001004b0000000002000039000000010200c039000000000021004b00002ed40000c13d000000000001004b00002f1f0000613d000000400100043d00000060021000390000000c030000290000000000320435000000400210003900000010030000290000000000320435000000200210003900000000003204350000000d02000029000000000021043500000d390010009c00000d39010080410000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d54011001c70000800d02000039000000020300003900000e34040000410000000f0500002934dd34ce0000040f000000010020019000002ed40000613d000000400100043d0000000c02000029000000000021043500000d390010009c00000d39010080410000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d4a011001c70000800d02000039000000040300003900000e36040000410000000f0500002900000000060000190000000b0700002934dd34ce0000040f000000010020019000002ed40000613d000000400100043d00000040021000390000000c03000029000000000032043500000020021000390000000e030000290000000000320435000000000001043500000d390010009c00000d39010080410000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000e2a011001c70000800d02000039000000020300003900000e2b040000410000000f0500002934dd34ce0000040f000000010020019000002ed40000613d0000000f01000029000000000010043f0000001401000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000002ed40000613d000000000101043b000000000201041a00000d43022001970000000903000029000000000232019f000000000021041b000000000030043f0000001501000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f000000010020019000002ed40000613d000000000101043b000000000201041a000000100020002a00002edd0000413d0000001002200029000000000021041b000000080100002934dd2f9f0000040f0000001902000039000000000102041a00000d4301100197000000000012041b0000000f01000029000000000001042d0000000001000019000034df0001043000000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df00010430000000000001042f00000def01000041000000000010043f0000001101000039000000040010043f00000df001000041000034df0001043000000e0c01000041000000000010043f00000d4801000041000034df0001043000000e3501000041000000000010043f00000d4801000041000034df000104300000001f0530018f00000d3b06300198000000400200043d000000000462001900002ef60000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00002ef20000c13d000000000005004b00002f030000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000d390020009c00000d39020080410000004002200210000000000112019f000034df0001043000000e1b01000041000000000010043f0000006001000039000000040010043f0000001001000029000000240010043f00000de101000041000034df0001043000000e1b01000041000000000010043f0000006001000039000000040010043f0000000c01000029000000240010043f00000de101000041000034df00010430000000000001004b00002f210000c13d00000dee01000041000000000010043f00000d4801000041000034df0001043000000e310100004100002f4d0000013d00000d390090009c00000d3909008041000000400290021000000d390010009c00000d39010080410000006001100210000000000121019f000034df00010430000000600210027000000d390220019700002f2e0000013d0000000002000019000000000103034f0000001f0520018f00000d3b06200198000000400300043d000000000463001900002f390000613d000000000701034f0000000008030019000000007907043c0000000008980436000000000048004b00002f350000c13d000000000005004b00002f460000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600120021000000d390030009c00000d39030080410000004002300210000000000112019f000034df0001043000000df101000041000000000010043f0000000a01000029000000040010043f00000df001000041000034df0001043000070000000000020000000c02000039000000000502041a0000000402100039000000000402041a0000000102100039000000000602041a0000000402000039000000000202041a000000000002004b00002f8a0000613d000200000002001d000500000006001d000100000001001d000600000005001d000700000004001d0000000901000039000000000101041a000300000001001d0000000b01000039000000000101041a000400000001001d00000dce010000410000000000100443000000000100041400000d390010009c00000d3901008041000000c00110021000000d4d011001c70000800b0200003934dd34d30000040f000000010020019000002f9e0000613d000000000101043b000000030010006b000000000201001900000003020040290000000a01000039000000000101041a000000000212004b000000070400002900000006050000290000000506000029000000040300002900002f980000413d00000000013200a9000000000003004b00002f850000613d00000000033100d9000000000023004b00002f980000c13d00000002011000fa000000000051001a00002f980000413d000000000551001900000001010000290000000301100039000000000101041a000000000215004b00002f980000413d00000d530360019800000000013200a900002f940000613d00000000033100d9000000000023004b00002f980000c13d000000000041001a00002f980000413d0000000001410019000000000001042d00000def01000041000000000010043f0000001101000039000000040010043f00000df001000041000034df00010430000000000001042f000600000000000200000d3c01100197000600000001001d000000000010043f0000001501000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f00000001002001900000324e0000613d000000000101043b000000000101041a000500000001001d0000001601000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f00000001002001900000324e0000613d000000000101043b000000000101041a0000000502000029000000000021001a000032910000413d0000000006210019000000400100043d000500000001001d000000000100041400000d390010009c00000d3901008041000000c00110021000000d41011001c70000800d02000039000000030300003900000e3d040000410000000605000029000400000006001d34dd34ce0000040f00000001002001900000324e0000613d0000000601000029000000000010043f0000001701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f00000001002001900000324e0000613d000000000101043b000000050500002900000e260050009c000032500000813d0000004002500039000000400020043f00000dd00050009c000032500000213d000000a003500039000000400030043f000000000301041a00000000003204350000000103100039000000000303041a000000600450003900000000003404350000000203100039000000000303041a000000000425043600000080025000390000000000320435000000400200043d00000d3f0020009c000032500000213d0000004003200039000000400030043f0000000303100039000000000303041a00000000033204360000000401100039000000000101041a00000080011002100000000000130435000000000024043500000000010504330000000045010434000000000005004b000030110000c13d0000000004040433000000000004004b000030110000c13d00000040011000390000000001010433000000000001004b000030110000c13d0000000001020433000000000001004b000030110000c13d000000000103043300000e3e0010009c000032480000413d0000001801000039000000000101041a00000d3c00100198000032480000613d0000000601000029000000000010043f0000001701000039000000200010043f000000000100041400000d390010009c00000d3901008041000000c00110021000000d44011001c7000080100200003934dd34d30000040f00000001002001900000324e0000613d000000000101043b000000400500043d00000d3f0050009c000032500000213d0000004002500039000000400020043f00000dd00050009c000032500000213d000000a003500039000000400030043f000000000301041a00000000003204350000000103100039000000000303041a000000600450003900000000003404350000000203100039000000000303041a000000000425043600000080025000390000000000320435000000400200043d00000d3f0020009c000032500000213d000200000005001d0000004003200039000000400030043f0000000303100039000000000303041a00000000033204360000000401100039000000000101041a00000080011002100000000000130435000500000004001d00000000002404350000001801000039000000000201041a00000e3f01000041000000400400043d000300000004001d0000000001140436000100000001001d00000004014000390000000603000029000000000031043500000d390040009c00000d390100004100000000010440190000004001100210000000000300041400000d390030009c00000d3903008041000000c003300210000000000113019f00000df0011001c700000d3c0220019734dd34ce0000040f000000030b000029000000600310027000000d3903300197000003c00030008c000003c00400003900000000040340190000001f0640018f000003e00740019000000000057b00190000306c0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000030680000c13d000000000006004b000030790000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f000000000065043500000001002001900000000509000029000032560000613d0000001f01400039000007e00210018f0000000001b20019000000000021004b0000000002000039000000010200403900000d3d0010009c00000002080000290000000106000029000032500000213d0000000100200190000032500000c13d000000400010043f000003c00030008c0000324e0000413d00000d4f0010009c000032500000213d000000c002100039000000400020043f00000000020b043300000d390020009c0000324e0000213d0000000003b400190000000002210436000000000463004900000dd90040009c0000324e0000213d000001200040008c0000324e0000413d000000400400043d00000d4f0040009c000032500000213d000000c005400039000000400050043f0000000005060433000000000005004b0000000006000039000000010600c039000000000065004b0000324e0000c13d00000000055404360000004006b000390000000006060433000000000006004b0000000007000039000000010700c039000000000076004b0000324e0000c13d00000000006504350000006005b000390000000005050433000000000005004b0000000006000039000000010600c039000000000065004b0000324e0000c13d0000004006400039000000000056043500000060054000390000008006b0003900000000060604330000000000650435000000400500043d00000e400050009c000032500000213d0000006006500039000000400060043f000000a006b0003900000000060604330000000006650436000000c007b0003900000000070704330000000000760435000000e006b0003900000000060604330000004007500039000000000067043500000080064000390000000000560435000000400500043d00000d3f0050009c000032500000213d0000004006500039000000400060043f0000010006b00039000000000606043300000000066504360000012007b00039000000000707043300000e03007001980000324e0000c13d0000000000760435000000a006400039000000000056043500000000004204350000014005b00039000000000453004900000dd90040009c0000324e0000213d000001200040008c0000324e0000413d000000400400043d00000d4f0040009c000032500000213d000000c006400039000000400060043f0000000005050433000000000005004b0000000006000039000000010600c039000000000065004b0000324e0000c13d00000000055404360000016006b000390000000006060433000000000006004b0000000007000039000000010700c039000000000076004b0000324e0000c13d00000000006504350000018005b000390000000005050433000000000005004b0000000006000039000000010600c039000000000065004b0000324e0000c13d000000400640003900000000005604350000006005400039000001a006b0003900000000060604330000000000650435000000400500043d00000e400050009c000032500000213d0000006006500039000000400060043f000001c006b0003900000000060604330000000006650436000001e007b00039000000000707043300000000007604350000020006b0003900000000060604330000004007500039000000000067043500000080064000390000000000560435000000400500043d00000d3f0050009c000032500000213d0000004006500039000000400060043f0000022006b00039000000000606043300000000066504360000024007b00039000000000707043300000e03007001980000324e0000c13d0000000000760435000000a0064000390000000000560435000000400510003900000000004504350000026004b00039000000000404043300000d3d0040009c0000324e0000213d000000600510003900000000004504350000028004b00039000000000343004900000dd90030009c0000324e0000213d000001200030008c0000324e0000413d000000400300043d00000d4f0030009c000032500000213d000000c005300039000000400050043f0000000004040433000000000004004b0000000005000039000000010500c039000000000054004b0000324e0000c13d0000000004430436000002a005b000390000000005050433000000000005004b0000000006000039000000010600c039000000000065004b0000324e0000c13d0000000000540435000002c004b000390000000004040433000000000004004b0000000005000039000000010500c039000000000054004b0000324e0000c13d000000400530003900000000004504350000006004300039000002e005b0003900000000050504330000000000540435000000400400043d00000e400040009c000032500000213d0000006005400039000000400050043f0000030005b00039000000000505043300000000055404360000032006b00039000000000606043300000000006504350000034005b0003900000000050504330000004006400039000000000056043500000080053000390000000000450435000000400400043d00000d3f0040009c000032500000213d0000004005400039000000400050043f0000036005b00039000000000505043300000000055404360000038006b00039000000000606043300000e03006001980000324e0000c13d0000000000650435000000a005300039000000000045043500000080041000390000000000340435000003a003b00039000000000303043300000d3d0030009c0000324e0000213d000000a00110003900000000003104350000000001020433000000800210003900000000020204330000000034020434000000000004004b000031860000c13d0000000003030433000000000003004b000031860000c13d00000040022000390000000002020433000000000002004b000032490000613d0000001b02000039000000000202041a00000020011000390000000001010433000000000001004b000031e90000613d000000040020006b000032480000413d0000000001090433000300000001001d0000000001080433000200000001001d0000001c01000039000000000101041a000100000001001d0000001801000039000000000101041a00000de502000041000000000020044300000d3c01100197000500000001001d0000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f0000000100200190000032700000613d000000000101043b000000000001004b0000324e0000613d0000000101000029000000ff00100190000000400400043d0000006401400039000000040200002900000000002104350000004401400039000000010200003900000000002104350000000001000039000000010100c0390000002402400039000000000012043500000e0901000041000000000014043500000004014000390000000602000029000000000021043500000084014000390000000205000029000000003205043400000000002104350000000001030433000000a402400039000000000012043500000040015000390000000001010433000000c4024000390000000000120435000000e401400039000000030200002900000000320204340000000000210435000000000103043300000e04011001970000010402400039000000000012043500000d390040009c000600000004001d00000d390100004100000000010440190000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000e0a011001c7000000050200002934dd34ce0000040f0000000100200190000032440000c13d00000060061002700000001f0460018f00000d3b05600198000000400200043d00000000035200190000327d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000031e40000c13d0000327d0000013d0000001801000039000000000101041a00000de503000041000000000030044300000d3c01100197000500000001001d0000000400100443000000040020006b000032200000813d000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f0000000100200190000032700000613d000000000101043b000000000001004b0000324e0000613d000000400300043d00000e4201000041000000000013043500000004013000390000000602000029000000000021043500000d390030009c000600000003001d00000d390100004100000000010340190000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000df0011001c7000000050200002934dd34ce0000040f0000000100200190000032440000c13d00000060061002700000001f0460018f00000d3b05600198000000400200043d00000000035200190000327d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b0000321b0000c13d0000327d0000013d000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f0000000100200190000032700000613d000000000101043b000000000001004b0000324e0000613d000000400300043d00000024013000390000000402000029000000000021043500000e4101000041000000000013043500000004013000390000000602000029000000000021043500000d390030009c000600000003001d00000d390100004100000000010340190000004001100210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000de1011001c7000000050200002934dd34ce0000040f0000000100200190000032710000613d000000060100002900000d3d0010009c000032500000213d000000400010043f000000000001042d0000001b01000039000000000101041a000000040010006b0000318e0000813d000032480000013d0000000001000019000034df0001043000000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df000104300000001f0530018f00000d3b06300198000000400200043d0000000004620019000032610000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000325d0000c13d000000000005004b0000326e0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f000000000014043500000060013002100000328c0000013d000000000001042f00000060061002700000001f0460018f00000d3b05600198000000400200043d00000000035200190000327d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000032790000c13d00000d3906600197000000000004004b0000328b0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000000600160021000000d390020009c00000d39020080410000004002200210000000000112019f000034df0001043000000def01000041000000000010043f0000001101000039000000040010043f00000df001000041000034df000104300003000000000002000000400400043d00000044054000390000000000350435000000200340003900000e3905000041000000000053043500000d3c02200197000000240540003900000000002504350000004402000039000000000024043500000e430040009c0000330f0000813d0000008002400039000000400020043f00000d390030009c00000d39030080410000004002300210000000000304043300000d390030009c00000d39030080410000006003300210000000000223019f000000000300041400000d390030009c00000d3903008041000000c003300210000000000332019f00000d3c021001970000000001030019000300000002001d34dd34ce0000040f000000600310027000000d3903300198000032e20000613d0000001f0430003900000d3a044001970000003f0440003900000dd804400197000000400a00043d00000000044a00190000000000a4004b0000000005000039000000010500403900000d3d0040009c0000330f0000213d00000001005001900000330f0000c13d000000400040043f0000001f0430018f00000000093a043600000d3b053001980000000003590019000032d40000613d000000000601034f0000000007090019000000006806043c0000000007870436000000000037004b000032d00000c13d000000000004004b000032e40000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000032e40000013d000000600a000039000000800900003900000000010a04330000000100200190000033150000613d000000000001004b000033000000c13d00020000000a001d000100000009001d00000de501000041000000000010044300000003010000290000000400100443000000000100041400000d390010009c00000d3901008041000000c00110021000000de6011001c7000080020200003934dd34d30000040f0000000100200190000033250000613d000000000101043b000000000001004b0000000201000029000033260000613d0000000001010433000000000001004b00000001090000290000330c0000613d00000dd90010009c0000330d0000213d000000200010008c0000330d0000413d0000000001090433000000000001004b0000000002000039000000010200c039000000000021004b0000330d0000c13d000000000001004b0000331b0000613d000000000001042d0000000001000019000034df0001043000000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df00010430000000000001004b0000331d0000c13d00000dee01000041000000000010043f00000d4801000041000034df0001043000000e3101000041000033270000013d00000d390090009c00000d3909008041000000400290021000000d390010009c00000d39010080410000006001100210000000000121019f000034df00010430000000000001042f00000df101000041000000000010043f0000000301000029000000040010043f00000df001000041000034df0001043000020000000000020000001802000039000000000202041a000000400400043d000200000004001d00000e3f030000410000000003340436000100000003001d00000d3c011001970000000403400039000000000013043500000d390040009c00000d390100004100000000010440190000004001100210000000000300041400000d390030009c00000d3903008041000000c003300210000000000113019f00000df0011001c700000d3c0220019734dd34ce0000040f000000020b000029000000600310027000000d3903300197000003c00030008c000003c00400003900000000040340190000001f0640018f000003e00740019000000000057b0019000033530000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b0000334f0000c13d000000000006004b000033600000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f000000000065043500000001002001900000347c0000613d0000001f01400039000007e00210018f0000000001b20019000000000021004b0000000002000039000000010200403900000d3d0010009c0000000106000029000034760000213d0000000100200190000034760000c13d000000400010043f000003bf0030008c000034740000a13d00000d4f0010009c000034760000213d000000c002100039000000400020043f00000000020b043300000d390020009c000034740000213d0000000003b400190000000002210436000000000463004900000dd90040009c000034740000213d000001200040008c000034740000413d000000400400043d00000d4f0040009c000034760000213d000000c005400039000000400050043f0000000005060433000000000005004b0000000006000039000000010600c039000000000065004b000034740000c13d00000000055404360000004006b000390000000006060433000000000006004b0000000007000039000000010700c039000000000076004b000034740000c13d00000000006504350000006005b000390000000005050433000000000005004b0000000006000039000000010600c039000000000065004b000034740000c13d0000004006400039000000000056043500000060054000390000008006b0003900000000060604330000000000650435000000400500043d00000e400050009c000034760000213d0000006006500039000000400060043f000000a006b0003900000000060604330000000006650436000000c007b0003900000000070704330000000000760435000000e006b0003900000000060604330000004007500039000000000067043500000080064000390000000000560435000000400500043d00000d3f0050009c000034760000213d0000004006500039000000400060043f0000010006b00039000000000606043300000000066504360000012007b00039000000000707043300000e0300700198000034740000c13d0000000000760435000000a006400039000000000056043500000000004204350000014005b00039000000000453004900000dd90040009c000034740000213d000001200040008c000034740000413d000000400400043d00000d4f0040009c000034760000213d000000c006400039000000400060043f0000000005050433000000000005004b0000000006000039000000010600c039000000000065004b000034740000c13d00000000055404360000016006b000390000000006060433000000000006004b0000000007000039000000010700c039000000000076004b000034740000c13d00000000006504350000018005b000390000000005050433000000000005004b0000000006000039000000010600c039000000000065004b000034740000c13d000000400640003900000000005604350000006005400039000001a006b0003900000000060604330000000000650435000000400500043d00000e400050009c000034760000213d0000006006500039000000400060043f000001c006b0003900000000060604330000000006650436000001e007b00039000000000707043300000000007604350000020006b0003900000000060604330000004007500039000000000067043500000080064000390000000000560435000000400500043d00000d3f0050009c000034760000213d0000004006500039000000400060043f0000022006b00039000000000606043300000000066504360000024007b00039000000000707043300000e0300700198000034740000c13d0000000000760435000000a0064000390000000000560435000000400510003900000000004504350000026004b00039000000000404043300000d3d0040009c000034740000213d000000600510003900000000004504350000028004b00039000000000343004900000dd90030009c000034740000213d000001200030008c000034740000413d000000400300043d00000d4f0030009c000034760000213d000000c005300039000000400050043f0000000004040433000000000004004b0000000005000039000000010500c039000000000054004b000034740000c13d0000000004430436000002a005b000390000000005050433000000000005004b0000000006000039000000010600c039000000000065004b000034740000c13d0000000000540435000002c004b000390000000004040433000000000004004b0000000005000039000000010500c039000000000054004b000034740000c13d000000400530003900000000004504350000006004300039000002e005b0003900000000050504330000000000540435000000400400043d00000e400040009c000034760000213d0000006005400039000000400050043f0000030005b00039000000000505043300000000055404360000032006b00039000000000606043300000000006504350000034005b0003900000000050504330000004006400039000000000056043500000080053000390000000000450435000000400400043d00000d3f0040009c000034760000213d0000004005400039000000400050043f0000036005b00039000000000505043300000000055404360000038006b00039000000000606043300000e0300600198000034740000c13d0000000000650435000000a005300039000000000045043500000080041000390000000000340435000003a003b00039000000000303043300000d3d0030009c000034740000213d000000a00110003900000000003104350000000001020433000000800210003900000000020204330000000034020434000000000004004b0000346b0000c13d0000000003030433000000000003004b0000346b0000c13d00000040022000390000000002020433000000000002004b000034720000613d00000020011000390000000001010433000000000001004b00000000010000390000000101006039000000010110018f000000000001042d000000010100018f000000000001042d0000000001000019000034df0001043000000def01000041000000000010043f0000004101000039000000040010043f00000df001000041000034df000104300000001f0530018f00000d3b06300198000000400200043d0000000004620019000034870000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000034830000c13d000000000005004b000034940000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000d390020009c00000d39020080410000004002200210000000000112019f000034df00010430000000000001042f00000d390010009c00000d3901008041000000400110021000000d390020009c00000d39020080410000006002200210000000000112019f000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000d41011001c7000080100200003934dd34d30000040f0000000100200190000034ae0000613d000000000101043b000000000001042d0000000001000019000034df0001043000000000050100190000000000200443000000050030008c000034be0000413d000000040100003900000000020000190000000506200210000000000664001900000005066002700000000006060031000000000161043a0000000102200039000000000031004b000034b60000413d00000d390030009c00000d39030080410000006001300210000000000200041400000d390020009c00000d3902008041000000c002200210000000000112019f00000e44011001c7000000000205001934dd34d30000040f0000000100200190000034cd0000613d000000000101043b000000000001042d000000000001042f000034d1002104210000000102000039000000000001042d0000000002000019000000000001042d000034d6002104230000000102000039000000000001042d0000000002000019000000000001042d000034db002104250000000102000039000000000001042d0000000002000019000000000001042d000034dd00000432000034de0001042e000034df0001043001000051ec50906736a34d40f5b162fb9f8741101127900ee80b966a3ef9c27700000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000000ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000ffffffffffffffff8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffbf31000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000bf265e8326285a2747e33e54d5945f7111f2b5edb826eb8c08d4677779b3ff97ffffffffffffffffffffffff00000000000000000000000000000000000000000200000000000000000000000000000000000040000000000000000000000000aeea2b5ee5fb4e4473cc85584d77137f4c6f996691f89746291ce55425120015b7c75e18483153b6b8c9c9a379610df50999c601b86f112f162ea62bc86787240f465a2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000072eef71ef43483d822203fd126296c5f8bfc62fd930b15bdbf4bf082a7e537fe0200000000000000000000000000000000000020000000000000000000000000e497b8238be5e4f32f72d877ba0627e627848cb8a6504aa01d21a347d565198e9a8a0592ac89c5ad3bc6df8224c17b485976f597df104ee20d0df415241f670b02000002000000000000000000000000000000040000000000000000000000008b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f000000000000000000000000000000000000000000000000ffffffffffffff3fbd3c3a6e0000000000000000000000000000000000000000000000000000000036e33f05f94cdde1742a801b4cab547a33af5d67a0b137be6aaac18572ce87760000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000ffffffffffffffffffffffff02000000000000000000000000000000000000800000000000000000000000002b9fb16353eaf3b33538b5a2635d05cee2876d96ddd81b0d2ea647b44594a11b26e2887dc46dee8b9b529b38ad93e3286aef0ac85cbb1ef9ba993e66d5cfa34466f95e8f8292afe63e5c4ab90b6b269f66c07ea737c955f76b598f4e25f5341d1fe3d1c37a8bb4158ae4f841b31f5c0e3db514e48da1a83c25b669081d628fb300000002000000000000000000000000000002c0000001000000000000000000000000000000000000000000000000000000000000000000000000007f319a4000000000000000000000000000000000000000000000000000000000ba4eeee900000000000000000000000000000000000000000000000000000000ce4b5bbd00000000000000000000000000000000000000000000000000000000e4b2e5fc00000000000000000000000000000000000000000000000000000000e70f944400000000000000000000000000000000000000000000000000000000e70f944500000000000000000000000000000000000000000000000000000000f851a44000000000000000000000000000000000000000000000000000000000fd6fe8a800000000000000000000000000000000000000000000000000000000e4b2e5fd00000000000000000000000000000000000000000000000000000000e4b97fad00000000000000000000000000000000000000000000000000000000e6dec27000000000000000000000000000000000000000000000000000000000da755f0100000000000000000000000000000000000000000000000000000000da755f0200000000000000000000000000000000000000000000000000000000ddda8a1100000000000000000000000000000000000000000000000000000000e216668900000000000000000000000000000000000000000000000000000000ce4b5bbe00000000000000000000000000000000000000000000000000000000d3acd27b00000000000000000000000000000000000000000000000000000000c3be997700000000000000000000000000000000000000000000000000000000c6f6173a00000000000000000000000000000000000000000000000000000000c6f6173b00000000000000000000000000000000000000000000000000000000cb3056ad00000000000000000000000000000000000000000000000000000000cd2ee8f700000000000000000000000000000000000000000000000000000000c3be997800000000000000000000000000000000000000000000000000000000c3c16e4e00000000000000000000000000000000000000000000000000000000bb60030c00000000000000000000000000000000000000000000000000000000bb60030d00000000000000000000000000000000000000000000000000000000bc59169700000000000000000000000000000000000000000000000000000000c21f637500000000000000000000000000000000000000000000000000000000ba4eeeea00000000000000000000000000000000000000000000000000000000bb329c460000000000000000000000000000000000000000000000000000000099248ea600000000000000000000000000000000000000000000000000000000ac9650d700000000000000000000000000000000000000000000000000000000ae0d27b500000000000000000000000000000000000000000000000000000000ae0d27b600000000000000000000000000000000000000000000000000000000ae169a5000000000000000000000000000000000000000000000000000000000b02c43d000000000000000000000000000000000000000000000000000000000ac9650d800000000000000000000000000000000000000000000000000000000adb7b75600000000000000000000000000000000000000000000000000000000ae02500f00000000000000000000000000000000000000000000000000000000a34ee94c00000000000000000000000000000000000000000000000000000000a34ee94d00000000000000000000000000000000000000000000000000000000a7d545db00000000000000000000000000000000000000000000000000000000a91ee0dc0000000000000000000000000000000000000000000000000000000099248ea700000000000000000000000000000000000000000000000000000000a1c0e1ae0000000000000000000000000000000000000000000000000000000089ee09ef000000000000000000000000000000000000000000000000000000008fa13834000000000000000000000000000000000000000000000000000000008fa13835000000000000000000000000000000000000000000000000000000009062c64c0000000000000000000000000000000000000000000000000000000090ac60ad0000000000000000000000000000000000000000000000000000000089ee09f0000000000000000000000000000000000000000000000000000000008c725fd00000000000000000000000000000000000000000000000000000000083ce85100000000000000000000000000000000000000000000000000000000083ce85110000000000000000000000000000000000000000000000000000000084b0196e00000000000000000000000000000000000000000000000000000000894d0e4a000000000000000000000000000000000000000000000000000000007f319a4100000000000000000000000000000000000000000000000000000000817b1cd2000000000000000000000000000000000000000000000000000000005875da2a00000000000000000000000000000000000000000000000000000000740211cd000000000000000000000000000000000000000000000000000000007aa23c51000000000000000000000000000000000000000000000000000000007bd53d4f000000000000000000000000000000000000000000000000000000007bd53d50000000000000000000000000000000000000000000000000000000007d5a75f2000000000000000000000000000000000000000000000000000000007ecebe00000000000000000000000000000000000000000000000000000000007aa23c52000000000000000000000000000000000000000000000000000000007acb7757000000000000000000000000000000000000000000000000000000007b1039990000000000000000000000000000000000000000000000000000000076c5d7570000000000000000000000000000000000000000000000000000000076c5d75800000000000000000000000000000000000000000000000000000000774da6740000000000000000000000000000000000000000000000000000000077d7a92100000000000000000000000000000000000000000000000000000000740211ce0000000000000000000000000000000000000000000000000000000074ad53dc0000000000000000000000000000000000000000000000000000000064b5c91b00000000000000000000000000000000000000000000000000000000704b6c0100000000000000000000000000000000000000000000000000000000704b6c020000000000000000000000000000000000000000000000000000000071f19acc0000000000000000000000000000000000000000000000000000000072a35df90000000000000000000000000000000000000000000000000000000064b5c91c00000000000000000000000000000000000000000000000000000000703762da000000000000000000000000000000000000000000000000000000005ade2289000000000000000000000000000000000000000000000000000000005ade228a000000000000000000000000000000000000000000000000000000005ba8fcfe0000000000000000000000000000000000000000000000000000000061dc0549000000000000000000000000000000000000000000000000000000005875da2b000000000000000000000000000000000000000000000000000000005a57b46f0000000000000000000000000000000000000000000000000000000034560e4f000000000000000000000000000000000000000000000000000000003d4bd89e00000000000000000000000000000000000000000000000000000000441a3e6f00000000000000000000000000000000000000000000000000000000441a3e700000000000000000000000000000000000000000000000000000000046800f750000000000000000000000000000000000000000000000000000000049583576000000000000000000000000000000000000000000000000000000003d4bd89f000000000000000000000000000000000000000000000000000000003d5961260000000000000000000000000000000000000000000000000000000040df5c5c0000000000000000000000000000000000000000000000000000000037e9f6490000000000000000000000000000000000000000000000000000000037e9f64a0000000000000000000000000000000000000000000000000000000039aab4b0000000000000000000000000000000000000000000000000000000003c6b16ab0000000000000000000000000000000000000000000000000000000034560e50000000000000000000000000000000000000000000000000000000003644e515000000000000000000000000000000000000000000000000000000002008787500000000000000000000000000000000000000000000000000000000276d733300000000000000000000000000000000000000000000000000000000276d7334000000000000000000000000000000000000000000000000000000002c4f88cd0000000000000000000000000000000000000000000000000000000031cb4bea000000000000000000000000000000000000000000000000000000002008787600000000000000000000000000000000000000000000000000000000255a4f7300000000000000000000000000000000000000000000000000000000073a2ae800000000000000000000000000000000000000000000000000000000073a2ae90000000000000000000000000000000000000000000000000000000008484dee000000000000000000000000000000000000000000000000000000001c39b672000000000000000000000000000000000000000000000000000000000495d72500000000000000000000000000000000000000000000000000000000051dd7a7000000000000000000000000000000000000000000000000ffffffffffffff7f796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d95539132ed72e8b8797645ac76e0741da7d8d0afc24dddb21ca6338d5c5520b05b192306000000000000000000000000000000000000000000000000ffffffffffffff5f310ab089e4439a4c15d089f94afb7896ff553aecb10793d0ab882de59d99a32e0200000200000000000000000000000000000044000000000000000000000000190100000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000420000000000000000000000007fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a000000000000000000000000000000000000000800000000000000000000000001626ba7e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ffffffe07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5d29e1bd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000762ef75f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000008000000000000000004aa66922cb54c64ed3272a327b8339c58555b41169c1fb39efb4535c6f9d1703581a50f0000000000000000000000000000000000000000000000000000000006e6f742076616c696461746f72207374616b6520617574686f726974790000000000000000000000000000000000000000000044000000000000000000000000eaebcdc3908a11d1e73d3fa13f3529f7b046946d90241ffef8d9192d0f6a5ea10000000000000000000000000000000000c097ce7bc90715b34b9f10000000006e6f74206f776e657200000000000000000000000000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b830200000200000000000000000000000000000024000000000000000000000000d505accf0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e40000000000000000000000006e6f742061646d696e000000000000000000000000000000000000000000000035625ebe5d7aa03ef314c78900b3fa8038ff900c3d6785fc89afb0de8c8f648900000000000000000000000000000000000000e00000008000000000000000006e6f7420636c61696d6572206f72206f776e65720000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01425ea42000000000000000000000000000000000000000000000000000000004e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000009996b31500000000000000000000000000000000000000000000000000000000363c56730e510c61b9b1c8da206585b5f5fa0eb1f76e05c2fcf82ee006fff9f519274dec09bfec1b2f1e9a1ed115e65d973b956a753a97fd146b88196c8f6a87a1c0e1ae000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000040000000800000000000000000867b6c541e0f40dd4e47d08157ce464787a92cf2aa13644ecf51331804fc0847613950e00b9e6a31ffbad41bdf66f194d1a276b1e117790800eaca48ebdd1d558d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac802b3512b0c000000000000000000000000000000000000000000000000000000001b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae672000000000000000000000000000000000000000000000000ffffffffffffffdf0f000000000000000000000000000000000000000000000000000000000000000b1db0ab4204ded87d69d4fe6739295ee2fef3e78103e2099d8e18e112053b207d5a75f2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000800000000000000000740211ce00000000000000000000000000000000000000000000000000000000300c1a75d358323d4ec7b212cd1e88afbd0250186b09c957b383ee5e6ad897f50000000000000000000000000000000000000000000000000000000000278d0000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000002000000000000000000000000000000000000a00000000000000000000000008679794114d50ebc439c2050b2be66d4b7954e7ae8e8e0c9448c42facf629e425875da2b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c4000000000000000000000000f2234536000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000124000000000000000000000000f280f6c800000000000000000000000000000000000000000000000000000000084cae8e0000000000000000000000000000000000000000000000000000000040df5c5c00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd872ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd8730000000000000000000000000000001dc1341195cdcd354445e20bcfffffffffff70a082310000000000000000000000000000000000000000000000000000000048f411442545d43fc993afadc0fd408cf0d1c606f3d10d1de7b05c994463ed97e8e7ff4800000000000000000000000000000000000000000000000000000000d4de7fe8000000000000000000000000000000000000000000000000000000006e6f74206e6f7469666965720000000000000000000000000000000000000000ff78bc3a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008400000000000000000000000004d2114cbff027138003f7a9e452588f683397107f4d4ab1a83f17e80ebad12e0000000000000000000000000000000000000001000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000006dfcc65000000000000000000000000000000000000000000000000000000000b219487700000000000000000000000000000000000000000000000000000000aca01fbc00000000000000000000000000000000000000000000000000000000c9280d5800000000000000000000000000000000000000000000000000000000b33ca1dabfb28a2e1bd06b332c396b1a3d538278691341a5503bbad53f91919700000000000000000000000000000000000000a0000000000000000000000000ffafa56d00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000ffffffffffffffa0000000000000000000000000000000000000000000000000ffffffffffffffc0000000000000000000000000000000000000000000000001000000000000000041a77e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000200000000000000000000000000000000000060000000000000000000000000e03d018e6f94071d97d5befc6a430dedbb1792ef805cf2042edbc2bb75b44528000000000000000000000000000000000000000000000000ffffffffffffff7b9c4d535bdea7cd8a978f128b93471df48c7dbab89d703809115bdc118c235bfd02000000000000000000000000000000000000c400000000000000000000000053ff145c5d53f9465a0d97719aeab68428f349b2cf0b009e9dd75b94b315d7be23b872dd000000000000000000000000000000000000000000000000000000005274afe700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff405d89f707c2087d1f0c2ec0ef87eb3bbf3c0eac23c0028df006c7de091258544d1a325385f16807e99fb688b597db78b00faee313dcf02e882dd16daab6fc3e1f23dadb4c0000000000000000000000000000000000000000000000000000000076ecb53d27210f298c33177d8fc8947b65cc94a2d54f65112683d2369058af90552a8fb1716255f7eb88700d6afa5d7ee7ae2857cfa8e1e4a9aac5b6234e2746fc6ecd966b430510beae9124efe7dd517ed5286d7ed0ae258f8556c7a9765a44a9059cbb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7c000000000000000000000000000000000000000000000000ffffffffffffff1fa31547ce6245cdb9ecea19cf8c7eb9f5974025bb4075011409251ae855b30aed7e4ade39d7ae662490a912c6aa9e28114a32891b492177b1da5f7980d1ce57070000000000000000000000000000000100000000000000000000000000000000fa52c7d800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff9f6a9d80290000000000000000000000000000000000000000000000000000000029092d0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff8002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000501799c3df680847e7c444ddaa6d5ab3b1d0d410f67181a9c4a7fb7c5fffbb0c", + "entries": [ + { + "constructorArgs": [ + "0x69e5DC39E2bCb1C17053d2A4ee7CAEAAc5D36f96", + "0x69e5DC39E2bCb1C17053d2A4ee7CAEAAc5D36f96", + "0xe192Df724AF629f2569bb71e8e7906e7aE311eeC", + 0, + "1000000000000000000000000", + "0xaecd4410c9b69E34F4365bc2FBd489675F739d83", + "0xaecd4410c9b69E34F4365bc2FBd489675F739d83", + "ZkStaker", + "1000000000000000000", + true + ], + "salt": "0x0000000000000000000000000000000000000000000000000000000000000000", + "deploymentType": "create", + "factoryDeps": [ + "0x000300000000000200000001002001900000002c0000613d0000008003000039000000400030043f0000000002000416000000000002004b0000002c0000c13d000000600210027000000042022001970000001f0420003900000043044001970000008004400039000000400040043f0000001f0520018f00000044062001980000008004600039000000170000613d000000000701034f000000007807043c0000000003830436000000000043004b000000130000c13d000000000005004b000000240000613d000000000161034f0000000303500210000000000504043300000000053501cf000000000535022f000000000101043b0000010003300089000000000131022f00000000013101cf000000000151019f0000000000140435000000400020008c0000002c0000413d000000800100043d000000450010009c0000002c0000213d000000a00200043d000000450020009c0000002e0000a13d00000000010000190000010600010430000100000002001d0000004502100197000000400400043d000300000004001d0000002401400039000000010300008a000000000031043500000046010000410000000000140435000000040140003900000000030004110000000000310435000000420040009c0000004201000041000000000104401900000040011002100000000003000414000000420030009c0000004203008041000000c003300210000000000113019f00000047011001c7000200000002001d010400fa0000040f000000030b00002900000060031002700000004203300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000000560000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000000520000c13d000000000006004b000000630000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000000a60000613d0000001f01400039000000600210018f0000000001b20019000000000021004b00000000020000390000000102004039000000480010009c000000c40000213d0000000100200190000000c40000c13d000000400010043f000000200030008c0000002c0000413d00000000010b0433000000000001004b0000000002000039000000010200c039000000000021004b0000002c0000c13d00000049010000410000000000100443000000020100002900000004001004430000000001000414000000420010009c0000004201008041000000c0011002100000004a011001c70000800202000039010400ff0000040f0000000100200190000000ca0000613d000000000101043b000000000001004b00000001010000290000002c0000613d0000004501100197000000400300043d0000004b02000041000000000023043500000004023000390000000000120435000000420030009c000300000003001d0000004201000041000000000103401900000040011002100000000002000414000000420020009c0000004202008041000000c002200210000000000112019f0000004c011001c70000000202000029010400fa0000040f0000000100200190000000cb0000613d00000003010000290000000002000019010400e70000040f0000002001000039000001000010044300000120000004430000004d01000041000001050001042e0000001f0530018f0000004406300198000000400200043d0000000004620019000000b10000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000000ad0000c13d000000000005004b000000be0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000006001300210000000420020009c00000042020080410000004002200210000000000112019f00000106000104300000004e01000041000000000010043f0000004101000039000000040010043f0000004c010000410000010600010430000000000001042f00000060061002700000001f0460018f0000004405600198000000400200043d0000000003520019000000d70000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000000d30000c13d0000004206600197000000000004004b000000e50000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000006001600210000000bf0000013d0000001f022000390000004f022001970000000001120019000000000021004b00000000020000390000000102004039000000480010009c000000f30000213d0000000100200190000000f30000c13d000000400010043f000000000001042d0000004e01000041000000000010043f0000004101000039000000040010043f0000004c010000410000010600010430000000000001042f000000fd002104210000000102000039000000000001042d0000000002000019000000000001042d00000102002104230000000102000039000000000001042d0000000002000019000000000001042d0000010400000432000001050001042e0000010600010430000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000000ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffff095ea7b3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff1806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b8302000002000000000000000000000000000000240000000000000000000000005c19a95c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000002000000000000000000000000000000400000010000000000000000004e487b7100000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe060c451954c97efc2297a2e8338d941630d684470dd4f41054f45b5ed45c054de" + ], + "address": "0x8a2fb7De07d55001FafBe885c2A2Ee00b2cFB484", + "txHash": "0xc85e0c4769d508f56c49e769b730759687612b883c1e9035628ae0d07a52daef" + } + ] +} diff --git a/deployments-zk/zkSyncTestnet/staker/calculators/IdentityEarningPowerCalculator.sol/IdentityEarningPowerCalculator.json b/deployments-zk/zkSyncTestnet/staker/calculators/IdentityEarningPowerCalculator.sol/IdentityEarningPowerCalculator.json new file mode 100644 index 0000000..9d2efd3 --- /dev/null +++ b/deployments-zk/zkSyncTestnet/staker/calculators/IdentityEarningPowerCalculator.sol/IdentityEarningPowerCalculator.json @@ -0,0 +1,85 @@ +{ + "sourceName": "staker/calculators/IdentityEarningPowerCalculator.sol", + "contractName": "IdentityEarningPowerCalculator", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amountStaked", + "type": "uint256" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "getEarningPower", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amountStaked", + "type": "uint256" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "getNewEarningPower", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + } + ], + "bytecode": "0x0000008003000039000000400030043f0000000100200190000000200000c13d00000060021002700000001002200197000000040020008c000000350000413d000000000301043b000000e003300270000000120030009c000000280000613d000000130030009c000000350000c13d000000640020008c000000350000413d0000000002000416000000000002004b000000350000c13d0000002402100370000000000202043b000000140020009c000000350000213d0000004402100370000000000202043b000000140020009c000000350000213d0000000401100370000000000101043b000000800010043f00000016010000410000003e0001042e0000000001000416000000000001004b000000350000c13d00000020010000390000010000100443000001200000044300000011010000410000003e0001042e000000840020008c000000350000413d0000000002000416000000000002004b000000350000c13d0000002402100370000000000202043b000000140020009c000000350000213d0000004402100370000000000202043b000000140020009c000000370000a13d00000000010000190000003f000104300000000401100370000000000101043b000000800010043f000000a00000043f00000015010000410000003e0001042e0000003d000004320000003e0001042e0000003f0001043000000000000000000000000000000000000000000000000000000000ffffffff000000020000000000000000000000000000004000000100000000000000000000000000000000000000000000000000000000000000000000000000ff78bc3a0000000000000000000000000000000000000000000000000000000041a77e80000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000040000000800000000000000000000000000000000000000000000000000000002000000080000000000000000000000000000000000000000000000000000000000000000000000000000000002e890477273ef4703ab82e3ca69b704ae962f6b9d9f10020c5dea5f2cc4182e9", + "entries": [ + { + "constructorArgs": [], + "salt": "0x0000000000000000000000000000000000000000000000000000000000000000", + "deploymentType": "create", + "factoryDeps": [], + "address": "0xe192Df724AF629f2569bb71e8e7906e7aE311eeC", + "txHash": "0x9b71836f6cd72fd61715baf9b27320e1a0c8dabae8b384e27536586a32781813" + } + ] +} diff --git a/deployments-zk/zkSyncTestnet/staker/notifiers/MintRewardNotifier.sol/MintRewardNotifier.json b/deployments-zk/zkSyncTestnet/staker/notifiers/MintRewardNotifier.sol/MintRewardNotifier.json new file mode 100644 index 0000000..ac2c888 --- /dev/null +++ b/deployments-zk/zkSyncTestnet/staker/notifiers/MintRewardNotifier.sol/MintRewardNotifier.json @@ -0,0 +1,364 @@ +{ + "sourceName": "staker/notifiers/MintRewardNotifier.sol", + "contractName": "MintRewardNotifier", + "abi": [ + { + "inputs": [ + { + "internalType": "contract INotifiableRewardReceiver", + "name": "_receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_initialRewardAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_initialRewardInterval", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_initialOwner", + "type": "address" + }, + { + "internalType": "contract IMintable", + "name": "_minter", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnableInvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "OwnableUnauthorizedAccount", + "type": "error" + }, + { + "inputs": [], + "name": "RewardTokenNotifierBase__InvalidParameter", + "type": "error" + }, + { + "inputs": [], + "name": "RewardTokenNotifierBase__RewardIntervalNotElapsed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract IMintable", + "name": "oldMinter", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract IMintable", + "name": "newMinter", + "type": "address" + } + ], + "name": "MinterSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "rewardAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nextRewardTime", + "type": "uint256" + } + ], + "name": "Notified", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldRewardAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newRewardAmount", + "type": "uint256" + } + ], + "name": "RewardAmountSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldRewardAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newRewardAmount", + "type": "uint256" + } + ], + "name": "RewardIntervalSet", + "type": "event" + }, + { + "inputs": [], + "name": "MAX_REWARD_INTERVAL", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_REWARD_INTERVAL", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "RECEIVER", + "outputs": [ + { + "internalType": "contract INotifiableRewardReceiver", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TOKEN", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minter", + "outputs": [ + { + "internalType": "contract IMintable", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nextRewardTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "notify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "rewardAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rewardInterval", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IMintable", + "name": "_minter", + "type": "address" + } + ], + "name": "setMinter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newRewardAmount", + "type": "uint256" + } + ], + "name": "setRewardAmount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newRewardInterval", + "type": "uint256" + } + ], + "name": "setRewardInterval", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x000d0000000000020000006003100270000000e3033001970000000100200190000000200000c13d0000008002000039000000400020043f000000040030008c0000031b0000413d000000000201043b000000e002200270000000f40020009c000000510000a13d000000f50020009c000000670000213d000000fb0020009c000000b30000213d000000fe0020009c000001100000613d000000ff0020009c0000031b0000c13d0000000001000416000000000001004b0000031b0000c13d0000000001000412000900000001001d000800000000003d000080050100003900000044030000390000000004000415000000090440008a000000630000013d0000010004000039000000400040043f0000000002000416000000000002004b0000031b0000c13d0000001f02300039000000e4022001970000010002200039000000400020043f0000001f0530018f000000e5063001980000010002600039000000320000613d000000000701034f000000007807043c0000000004840436000000000024004b0000002e0000c13d000000000005004b0000003f0000613d000000000161034f0000000304500210000000000502043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000120435000000a00030008c0000031b0000413d000001000400043d000000e60040009c0000031b0000213d000001600100043d000000e60010009c0000031b0000213d000001800700043d000000e60070009c0000031b0000213d000000e606100198000001760000c13d0000010d01000041000000000010043f000000040000043f0000010a010000410000038a00010430000001000020009c0000008c0000a13d000001010020009c000000aa0000213d000001040020009c000000e80000613d000001050020009c0000031b0000c13d0000000001000416000000000001004b0000031b0000c13d0000000001000412000b00000001001d000a00200000003d0000800501000039000000440300003900000000040004150000000b0440008a00000005044002100000010e02000041038803600000040f000001720000013d000000f60020009c000000bc0000213d000000f90020009c000001320000613d000000fa0020009c0000031b0000c13d000000240030008c0000031b0000413d0000000002000416000000000002004b0000031b0000c13d0000000401100370000000000101043b000000e60010009c0000031b0000213d000000000200041a000000e6052001970000000003000411000000000035004b0000029b0000c13d000000e6061001980000004c0000613d000000e701200197000000000161019f000000000010041b0000000001000414000000e30010009c000000e301008041000000c001100210000000e8011001c70000800d020000390000000303000039000000e9040000410388037e0000040f0000000100200190000000a80000c13d0000031b0000013d000001060020009c0000016d0000613d000001070020009c000001050000613d000001080020009c0000031b0000c13d0000000001000416000000000001004b0000031b0000c13d000000000100041a000000e6051001970000000002000411000000000025004b000002440000c13d000000e701100197000000000010041b0000000001000414000000e30010009c000000e301008041000000c001100210000000e8011001c70000800d020000390000000303000039000000e90400004100000000060000190388037e0000040f00000001002001900000031b0000613d0000000001000019000003890001042e000001020020009c000000ed0000613d000001030020009c0000031b0000c13d0000000001000416000000000001004b0000031b0000c13d000000000100041a000001720000013d000000fc0020009c000001550000613d000000fd0020009c0000031b0000c13d0000000001000416000000000001004b0000031b0000c13d0000000201000039000001690000013d000000f70020009c000001650000613d000000f80020009c0000031b0000c13d000000240030008c0000031b0000413d0000000002000416000000000002004b0000031b0000c13d0000000401100370000000000101043b000000e60010009c0000031b0000213d000000000200041a000000e6032001970000000002000411000000000023004b000002440000c13d000000e6021001970000000401000039000000000101041a000400000001001d000000e601100197000000800010043f000500000002001d000000a00020043f0000000001000414000000e30010009c000000e301008041000000c0011002100000010b011001c70000800d020000390000000103000039000000f2040000410388037e0000040f00000001002001900000031b0000613d0000000401000029000000e70110019700000005011001af0000000402000039000000000012041b0000000001000019000003890001042e0000000001000416000000000001004b0000031b0000c13d0000000301000039000001690000013d0000000001000416000000000001004b0000031b0000c13d0000000301000039000000000101041a000500000001001d000001110100004100000000001004430000000001000414000000e30010009c000000e301008041000000c00110021000000112011001c70000800b02000039038803830000040f00000001002001900000031d0000613d000000000101043b000000050010006c000002490000813d0000011a01000041000000000010043f000000ed010000410000038a000104300000000001000416000000000001004b0000031b0000c13d0000000001000412000d00000001001d000c00600000003d0000800501000039000000440300003900000000040004150000000d0440008a0000015f0000013d000000240030008c0000031b0000413d0000000002000416000000000002004b0000031b0000c13d0000000401100370000000000401043b000000000100041a000000e6021001970000000001000411000000000012004b0000023f0000c13d000000000004004b000001510000613d0000000103000039000000000103041a000000800010043f000500000004001d000000a00040043f0000000001000414000000e30010009c000000e301008041000000c0011002100000010b011001c70000800d02000039000000f0040000410388037e0000040f00000001002001900000031b0000613d00000005010000290000000102000039000000000012041b0000000001000019000003890001042e000000240030008c0000031b0000413d0000000002000416000000000002004b0000031b0000c13d0000000401100370000000000301043b000000000100041a000000e6021001970000000001000411000000000012004b0000023f0000c13d000500000003001d0000010e01000041000000000010044300000000010004120000000400100443000000400100003900000024001004430000000001000414000000e30010009c000000e301008041000000c0011002100000010f011001c70000800502000039038803830000040f00000001002001900000031d0000613d000000000101043b000000050010006b000002be0000813d0000011001000041000000000010043f000000ed010000410000038a000104300000000001000416000000000001004b0000031b0000c13d0000000001000412000700000001001d000600400000003d000080050100003900000044030000390000000004000415000000070440008a00000005044002100000010e02000041038803600000040f000000800010043f0000010c01000041000003890001042e0000000001000416000000000001004b0000031b0000c13d0000000101000039000000000101041a000000800010043f0000010c01000041000003890001042e0000000001000416000000000001004b0000031b0000c13d0000000401000039000000000101041a000000e601100197000000800010043f0000010c01000041000003890001042e000001400100043d000200000001001d000001200100043d000300000001001d000000000100041a000000e702100197000000000262019f000000000020041b000000400200043d000500000002001d0000000002000414000000e605100197000000e30020009c000000e302008041000000c001200210000000e8011001c70000800d020000390000000303000039000100000007001d000400000004001d000000e9040000410388037e0000040f000000040300002900000001002001900000031b0000613d000000e602300197000000ea01000041000000c00010043f000000eb01000041000000e00010043f0000000301000039000000000001041b000000800030043f000000ec0100004100000005030000290000000000130435000000e30030009c000000e301000041000000000103401900000040011002100000000003000414000000e30030009c000000e303008041000000c003300210000000000113019f000000ed011001c7038803830000040f0000006003100270000000e303300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000050b00002900000000057b0019000001b50000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000001b10000c13d000000000006004b000001c20000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000002a00000613d0000001f01400039000000600210018f0000000001b20019000000000021004b00000000020000390000000102004039000000ee0010009c000002950000213d0000000100200190000002950000c13d000000400010043f000000200030008c0000031b0000413d00000000020b0433000000e60020009c0000031b0000213d000000a00020043f0000000304000029000000000004004b000001510000613d0000000103000039000000000203041a000000200510003900000000004504350000000000210435000000e30010009c000000e30100804100000040011002100000000002000414000000e30020009c000000e302008041000000c002200210000000000112019f000000ef011001c70000800d02000039000000f0040000410388037e0000040f00000001002001900000031b0000613d00000003010000290000000102000039000000000012041b000000c00100043d000000020010006b000001510000413d000000e00100043d000000020010006b000001510000213d0000000201000039000000000101041a000000400200043d0000002003200039000000020400002900000000004304350000000000120435000000e30020009c000000e30200804100000040012002100000000002000414000000e30020009c000000e302008041000000c002200210000000000112019f000000ef011001c70000800d020000390000000103000039000000f1040000410388037e0000040f000000010100002900000001002001900000031b0000613d000000e60310019700000002010000290000000202000039000000000012041b0000000401000039000000000401041a000000400100043d0000002002100039000500000003001d0000000000320435000400000004001d000000e6024001970000000000210435000000e30010009c000000e30100804100000040011002100000000002000414000000e30020009c000000e302008041000000c002200210000000000112019f000000ef011001c70000800d020000390000000103000039000000f2040000410388037e0000040f00000001002001900000031b0000613d0000000401000029000000e70110019700000005011001af0000000404000039000000000014041b000000800100043d000001400000044300000160001004430000002001000039000000a00200043d0000018000100443000001a0002004430000004002000039000000c00300043d000001c000200443000001e0003004430000006002000039000000e00300043d0000020000200443000002200030044300000100001004430000012000400443000000f301000041000003890001042e0000010902000041000000000020043f000000040010043f0000010a010000410000038a000104300000010901000041000000000010043f000000040020043f0000010a010000410000038a000104300000000202000039000000000202041a000000000012001a000003590000413d00000000011200190000000302000039000000000012041b0000000401000039000000000101041a000500000001001d0000010e0100004100000000001004430000000001000412000000040010044300000024000004430000000001000414000000e30010009c000000e301008041000000c0011002100000010f011001c70000800502000039038803830000040f00000001002001900000031d0000613d0000000502000029000000e6032001970000000102000039000000000202041a000400000002001d000000000101043b000300000001001d00000113010000410000000000100443000500000003001d00000004003004430000000001000414000000e30010009c000000e301008041000000c00110021000000114011001c70000800202000039038803830000040f00000001002001900000031d0000613d000000000101043b000000000001004b0000031b0000613d0000000301000029000000e602100197000000400400043d000000240140003900000004030000290000000000310435000001150100004100000000001404350000000401400039000300000002001d0000000000210435000000e30040009c000400000004001d000000e301000041000000000104401900000040011002100000000002000414000000e30020009c000000e302008041000000c002200210000000000112019f00000116011001c700000005020000290388037e0000040f0000000100200190000002eb0000613d0000000401000029000000ee0010009c000003070000a13d0000011901000041000000000010043f0000004101000039000000040010043f0000010a010000410000038a000104300000010901000041000000000010043f000000040030043f0000010a010000410000038a000104300000001f0530018f000000e506300198000000400200043d0000000004620019000002ab0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000002a70000c13d000000000005004b000002b80000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000006001300210000000e30020009c000000e3020080410000004002200210000000000112019f0000038a000104300000010e01000041000000000010044300000000010004120000000400100443000000600100003900000024001004430000000001000414000000e30010009c000000e301008041000000c0011002100000010f011001c70000800502000039038803830000040f00000001002001900000031d0000613d000000000101043b0000000504000029000000000014004b000001510000213d0000000201000039000000000101041a000000400200043d000000200320003900000000004304350000000000120435000000e30020009c000000e30200804100000040012002100000000002000414000000e30020009c000000e302008041000000c002200210000000000112019f000000ef011001c70000800d020000390000000103000039000000f1040000410388037e0000040f00000001002001900000031b0000613d00000002010000390000000502000029000000000021041b0000000001000019000003890001042e00000060061002700000001f0460018f000000e505600198000000400200043d0000000003520019000002f70000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000002f30000c13d000000e306600197000000000004004b000003050000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000006001600210000002b90000013d000000400010043f0000000101000039000000000101041a000500000001001d00000113010000410000000000100443000000030100002900000004001004430000000001000414000000e30010009c000000e301008041000000c00110021000000114011001c70000800202000039038803830000040f00000001002001900000031d0000613d000000000101043b000000000001004b0000031e0000c13d00000000010000190000038a00010430000000000001042f000000400200043d00000117010000410000000001120436000200000001001d000000040120003900000005030000290000000000310435000000e30020009c000500000002001d000000e301000041000000000102401900040040001002180000000001000414000000e30010009c000000e301008041000000c00110021000000004011001af0000010a011001c700000003020000290388037e0000040f00000001002001900000034c0000613d0000000501000029000000ee0010009c000002950000213d0000000504000029000000400040043f0000000301000039000000000101041a0000000103000039000000000203041a0000000205000029000000000015043500000000002404350000000001000414000000e30010009c000000e301008041000000c00110021000000004011001af000000ef011001c70000800d0200003900000118040000410388037e0000040f0000000100200190000000a80000c13d0000031b0000013d00000060061002700000001f0460018f000000e505600198000000400200043d0000000003520019000002f70000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000003540000c13d000002f70000013d0000011901000041000000000010043f0000001101000039000000040010043f0000010a010000410000038a00010430000000000001042f00000000050100190000000000200443000000050030008c0000036e0000413d000000040100003900000000020000190000000506200210000000000664001900000005066002700000000006060031000000000161043a0000000102200039000000000031004b000003660000413d000000e30030009c000000e30300804100000060013002100000000002000414000000e30020009c000000e302008041000000c002200210000000000112019f0000011b011001c70000000002050019038803830000040f00000001002001900000037d0000613d000000000101043b000000000001042d000000000001042f00000381002104210000000102000039000000000001042d0000000002000019000000000001042d00000386002104230000000102000039000000000001042d0000000002000019000000000001042d0000038800000432000003890001042e0000038a00010430000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000000ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e000000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000001e1338099248ea7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff020000000000000000000000000000000000004000000000000000000000000053ec5ac14ec827c0859f27c3d22f4ea8c29f6d64cbe2f92aeb55210ce6f89b35e79d576837a40cc1dc753b1b3e79d5c33582fc2c5d5950e15f26a055534889c902b23d62d8f733974f8cb13eb804b20135521322b70997c991fc01406632389f000000020000000000000000000000000000014000000100000000000000000000000000000000000000000000000000000000000000000000000000a8a65a7700000000000000000000000000000000000000000000000000000000e3e8421200000000000000000000000000000000000000000000000000000000f7b2a7bd00000000000000000000000000000000000000000000000000000000f7b2a7be00000000000000000000000000000000000000000000000000000000fca3b5aa00000000000000000000000000000000000000000000000000000000e3e8421300000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000b1ff9ba000000000000000000000000000000000000000000000000000000000b1ff9ba100000000000000000000000000000000000000000000000000000000bec4de3f00000000000000000000000000000000000000000000000000000000a8a65a7800000000000000000000000000000000000000000000000000000000ad7430cc000000000000000000000000000000000000000000000000000000007f68e19400000000000000000000000000000000000000000000000000000000899f589700000000000000000000000000000000000000000000000000000000899f5898000000000000000000000000000000000000000000000000000000008da5cb5b000000000000000000000000000000000000000000000000000000007f68e1950000000000000000000000000000000000000000000000000000000082bfefc80000000000000000000000000000000000000000000000000000000007546172000000000000000000000000000000000000000000000000000000003a3eab6400000000000000000000000000000000000000000000000000000000715018a6118cdaa7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000000000000000000000020000000000000000000000000000000000004000000080000000000000000000000000000000000000000000000000000000200000008000000000000000001e4fbdf700000000000000000000000000000000000000000000000000000000310ab089e4439a4c15d089f94afb7896ff553aecb10793d0ab882de59d99a32e02000002000000000000000000000000000000440000000000000000000000007e6b1fec00000000000000000000000000000000000000000000000000000000796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d9553913202000002000000000000000000000000000000040000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b83020000020000000000000000000000000000002400000000000000000000000040c10f190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000000000003c6b16ab000000000000000000000000000000000000000000000000000000000fd7bb2818b0aaa42a4064edb68964c3e29810804cf8cce3060a3bac23fb9d794e487b710000000000000000000000000000000000000000000000000000000002dfb46900000000000000000000000000000000000000000000000000000000020000020000000000000000000000000000000000000000000000000000000093917519bcff773ef39768c83f7e211140ce4dba46ad3156ed1ec4bdfaba6fe8", + "entries": [ + { + "constructorArgs": [ + "0x8a2fb7De07d55001FafBe885c2A2Ee00b2cFB484", + "1000000000000000000", + 2592000, + "0xaecd4410c9b69E34F4365bc2FBd489675F739d83", + "0x329CE320a0Ef03F8c0E01195604b5ef7D3Fb150E" + ], + "salt": "0x0000000000000000000000000000000000000000000000000000000000000000", + "deploymentType": "create", + "factoryDeps": [], + "address": "0x41d549a2ec18d18cFef0357AE945D9788871CDb0", + "txHash": "0xc99e7f1aaacbfdf7c62c329eea0d3c35b3fb7449b952172b859acebf1fdd5ca7" + } + ] +} diff --git a/foundry.toml b/foundry.toml index 5a0b52d..a5b1136 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,12 +1,14 @@ [profile.default] - evm_version = "paris" + evm_version = "cancun" + fuzz = { no_zksync_reserved_addresses = true } optimizer = true - optimizer_runs = 10_000_000 + optimizer_runs = 4000 remappings = [ "forge-std/=lib/forge-std/src/", "openzeppelin/=lib/staker/lib/openzeppelin-contracts/contracts/", "staker/=lib/staker/src/", "staker-test/=lib/staker/test/", + "@openzeppelin/contracts-upgradeable-v4/=lib/era-contracts/lib/openzeppelin-contracts-upgradeable-v4/contracts/", ] solc_version = "0.8.28" verbosity = 3 diff --git a/lib/era-contracts b/lib/era-contracts new file mode 160000 index 0000000..9bfc6a6 --- /dev/null +++ b/lib/era-contracts @@ -0,0 +1 @@ +Subproject commit 9bfc6a65ed0dba7b90d67a3af1792e0066846e03 diff --git a/package.json b/package.json index 996b9ae..93236c5 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "local-node": "npx hardhat node-zksync", "script": "node script/RunScript.js", "foundry-test": "forge test --no-match-path 'test/*.integration.t.sol' --zksync", + "foundry-integration": "forge test --match-path 'test/*.integration.t.sol' --zksync", "test": "forge test --zksync && npx hardhat test", "lint": "scopelint check", "lint:fix": "scopelint fmt" diff --git a/script/DeployConsensusRegistry.sepolia.ts b/script/DeployConsensusRegistry.sepolia.ts new file mode 100644 index 0000000..df34384 --- /dev/null +++ b/script/DeployConsensusRegistry.sepolia.ts @@ -0,0 +1,53 @@ +import { config as dotEnvConfig } from "dotenv"; +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import { Wallet, Provider } from "zksync-ethers"; +import * as hre from "hardhat"; + +const ZKSTAKER_ADDRESS = "0x8a2fb7De07d55001FafBe885c2A2Ee00b2cFB484"; + +// TODO: This ConsensusRegistry deployment file NOT MEANT FOR PRODUCTION PURPOSES. +// It does not use the proxy pattern as intended, and also, initializes in a separate transaction +// (risking hostile takeover on prod). We only wrote this for an e2e sepolia deployment of ZkStaker. +async function main() { + dotEnvConfig(); + + const deployerPrivateKey = process.env.DEPLOYER_PRIVATE_KEY; + if (!deployerPrivateKey) { + throw "Please set DEPLOYER_PRIVATE_KEY in your .env file"; + } + + const provider = new Provider(process.env.ZKSYNC_RPC_URL); + const zkWallet = new Wallet(deployerPrivateKey, provider); + const deployer = new Deployer(hre, zkWallet); + + const consensusRegistryName = "ConsensusRegistry"; + console.log("Deploying " + consensusRegistryName + "..."); + const consensusRegistryArtifact = await deployer.loadArtifact( + consensusRegistryName + ); + const constructorArgs: any[] = []; + const consensusRegistry = await deployer.deploy( + consensusRegistryArtifact, + constructorArgs, + "create", + undefined + ); + + await consensusRegistry.deploymentTransaction()?.wait(); + const consensusRegistryContractAddress = await consensusRegistry.getAddress(); + console.log( + `${consensusRegistryName} was deployed to ${consensusRegistryContractAddress}` + ); + + const tx = await consensusRegistry.initialize(ZKSTAKER_ADDRESS); + await tx.wait(); + console.log( + "ConsensusRegistry initialized with ZkStaker address: ", + ZKSTAKER_ADDRESS + ); +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/script/DeployZkStaker.sepolia.ts b/script/DeployZkStaker.sepolia.ts new file mode 100644 index 0000000..e730f3a --- /dev/null +++ b/script/DeployZkStaker.sepolia.ts @@ -0,0 +1,124 @@ +import { config as dotEnvConfig } from "dotenv"; +import * as zk from "zksync-ethers"; +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import { Wallet, utils } from "zksync-ethers"; +import * as hre from "hardhat"; + +// Before executing a real deployment, be sure to set these values as appropriate for the environment being deploying +// to. The values used in the script at the time of deployment can be checked in along with the deployment artifacts +// produced by running the scripts. + +// EarningPowerCalculator deployment constructor arguments +const EARNING_POWER_CALCULATOR_NAME = "IdentityEarningPowerCalculator"; + +// Notifier deployment constructor arguments +const NUMBER_OF_SECONDS_IN_A_DAY = 86400; +const REWARD_AMOUNT = "1000000000000000000"; +const REWARD_INTERVAL = 30 * NUMBER_OF_SECONDS_IN_A_DAY; // 30 days + +// ZkStaker deployment constructor arguments +const ZK_TOKEN_ADDRESS = "0x69e5DC39E2bCb1C17053d2A4ee7CAEAAc5D36f96"; // Sepolia ZK Token Address +const ZK_CAPPED_MINTER = "0x329CE320a0Ef03F8c0E01195604b5ef7D3Fb150E"; // Sepolia Capped Minter Address +const MAX_BUMP_TIP = 0; +const INITIAL_TOTAL_STAKE_CAP = "1000000000000000000000000"; +const STAKER_NAME = "ZkStaker"; +// commenting out, set instead to deployer address +// const VALIDATOR_STAKE_AUTHORITY = "0x0000000000000000000000000000000000000000"; +const INITIAL_VALIDATOR_WEIGHT_THRESHOLD = "1000000000000000000"; +const IS_LEADER_DEFAULT = true; + +async function main() { + dotEnvConfig(); + + const deployerPrivateKey = process.env.DEPLOYER_PRIVATE_KEY; + if (!deployerPrivateKey) { + throw "Please set DEPLOYER_PRIVATE_KEY in your .env file"; + } + const zkWallet = new Wallet(deployerPrivateKey); + const deployer = new Deployer(hre, zkWallet); + + // Deploy EarningPowerCalculator contract using create + const earningPowerCalculatorName = EARNING_POWER_CALCULATOR_NAME; + console.log("Deploying " + earningPowerCalculatorName + "..."); + const earningPowerCalculatorContractArtifact = await deployer.loadArtifact( + earningPowerCalculatorName + ); + const earningPowerCalculator = await deployer.deploy( + earningPowerCalculatorContractArtifact, + [], + "create", + undefined + ); + await earningPowerCalculator.deploymentTransaction()?.wait(); + const earningPowerCalculaterContractAddress = + await earningPowerCalculator.getAddress(); + console.log( + `${earningPowerCalculatorName} was deployed to ${earningPowerCalculaterContractAddress}` + ); + + // Deploy ZkStaker contract using create + const zkStakerContractName = "ZkStaker"; + const zkStakerContractArtifact = await deployer.loadArtifact( + zkStakerContractName + ); + const constructorArgs = [ + ZK_TOKEN_ADDRESS, + ZK_TOKEN_ADDRESS, + earningPowerCalculaterContractAddress, + MAX_BUMP_TIP, + INITIAL_TOTAL_STAKE_CAP, + zkWallet.address, + zkWallet.address, + STAKER_NAME, + INITIAL_VALIDATOR_WEIGHT_THRESHOLD, + IS_LEADER_DEFAULT, + ]; + const zkStaker = await deployer.deploy( + zkStakerContractArtifact, + constructorArgs, + "create", + undefined + ); + await zkStaker.deploymentTransaction()?.wait(); + const zkStakerContractAddress = await zkStaker.getAddress(); + console.log( + `${zkStakerContractName} was deployed to ${zkStakerContractAddress}` + ); + + // Deploy the MintRewardNotifier contract using create + const mintRewardNotifierContractName = "MintRewardNotifier"; + const mintRewardNotifierContractArtifact = await deployer.loadArtifact( + mintRewardNotifierContractName + ); + const mintRewardNotifier = await deployer.deploy( + mintRewardNotifierContractArtifact, + [ + zkStakerContractAddress, + REWARD_AMOUNT, + REWARD_INTERVAL, + zkWallet.address, + ZK_CAPPED_MINTER, + ], + "create", + undefined + ); + await mintRewardNotifier.deploymentTransaction()?.wait(); + const mintRewardNotifierContractAddress = + await mintRewardNotifier.getAddress(); + console.log( + `${mintRewardNotifierContractName} was deployed to ${mintRewardNotifierContractAddress}` + ); + + // Set the notifier of the ZkStaker contract to the MintRewardNotifier + await zkStaker.setRewardNotifier(mintRewardNotifierContractAddress, true); + + // Output the contract addresses to be captured by the calling script + console.log( + `ZKSTAKER_ADDRESS=${zkStakerContractAddress}\nEARNING_POWER_CALCULATOR_ADDRESS=${earningPowerCalculaterContractAddress}\nMINT_REWARD_NOTIFIER_ADDRESS=${mintRewardNotifierContractAddress}\n` + ); +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/script/DeployZkStaker.ts b/script/DeployZkStaker.ts index b18004b..435bdf9 100644 --- a/script/DeployZkStaker.ts +++ b/script/DeployZkStaker.ts @@ -24,6 +24,9 @@ const ZK_CAPPED_MINTER = "0x721b6d77a58FaaF540bE49F28D668a46214Ba44c"; //TODO: V const MAX_BUMP_TIP = 0; const INITIAL_TOTAL_STAKE_CAP = "1000000000000000000000000"; // TODO: Verify this value (placeholder for now) const STAKER_NAME = "ZkStaker"; +const VALIDATOR_STAKE_AUTHORITY = "0x0000000000000000000000000000000000000000"; // TODO: Update this value (placeholder for now) +const INITIAL_VALIDATOR_WEIGHT_THRESHOLD = 0; // TODO: Update this value (placeholder for now) +const IS_LEADER_DEFAULT = true; // TODO: Verify this value (placeholder for now) async function main() { @@ -50,7 +53,7 @@ async function main() { // Deploy ZkStaker contract using create const zkStakerContractName = "ZkStaker"; const zkStakerContractArtifact = await deployer.loadArtifact(zkStakerContractName ); - const constructorArgs = [ZK_TOKEN_ADDRESS, ZK_TOKEN_ADDRESS, earningPowerCalculaterContractAddress, MAX_BUMP_TIP, INITIAL_TOTAL_STAKE_CAP, zkWallet.address, STAKER_NAME]; + const constructorArgs = [ZK_TOKEN_ADDRESS, ZK_TOKEN_ADDRESS, earningPowerCalculaterContractAddress, MAX_BUMP_TIP, INITIAL_TOTAL_STAKE_CAP, zkWallet.address, VALIDATOR_STAKE_AUTHORITY, STAKER_NAME, INITIAL_VALIDATOR_WEIGHT_THRESHOLD, IS_LEADER_DEFAULT]; const zkStaker = await deployer.deploy(zkStakerContractArtifact, constructorArgs, "create", undefined); await zkStaker.deploymentTransaction()?.wait(); const zkStakerContractAddress = await zkStaker.getAddress(); diff --git a/script/SetZkStakerAdmin.ts b/script/SetZkStakerAdmin.ts new file mode 100644 index 0000000..bb6da8d --- /dev/null +++ b/script/SetZkStakerAdmin.ts @@ -0,0 +1,37 @@ +import { config as dotEnvConfig } from "dotenv"; +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import { Wallet, Provider, Contract } from "zksync-ethers"; +import * as hre from "hardhat"; + +const ZK_STAKER_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000000000"; +const INTENDED_ADMIN = "0xC3e970cB015B5FC36edDf293D2370ef5D00F7a19"; + +async function main() { + dotEnvConfig(); + + const deployerPrivateKey = process.env.DEPLOYER_PRIVATE_KEY; + if (!deployerPrivateKey) { + throw "Please set DEPLOYER_PRIVATE_KEY in your .env file"; + } + + const provider = new Provider(process.env.ZKSYNC_RPC_URL); + const zkWallet = new Wallet(deployerPrivateKey, provider); + const deployer = new Deployer(hre, zkWallet); + + const zkStaker = new Contract( + ZK_STAKER_CONTRACT_ADDRESS, + await deployer.loadArtifact("ZkStaker").then((val) => val.abi), + zkWallet + ); + + console.log( + `Setting admin of ${ZK_STAKER_CONTRACT_ADDRESS} to ${INTENDED_ADMIN}` + ); + await zkStaker.setAdmin(INTENDED_ADMIN); + console.log(`Admin set to ${INTENDED_ADMIN}`); +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/script/SetZkStakerRegistry.ts b/script/SetZkStakerRegistry.ts new file mode 100644 index 0000000..b3a145b --- /dev/null +++ b/script/SetZkStakerRegistry.ts @@ -0,0 +1,35 @@ +import { config as dotEnvConfig } from "dotenv"; +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import { Wallet, Provider, Contract } from "zksync-ethers"; +import * as hre from "hardhat"; + +const ZK_STAKER_CONTRACT_ADDRESS = "0x8a2fb7De07d55001FafBe885c2A2Ee00b2cFB484"; +const CONSENSUS_REGISTRY = "0x158d33FbddA2263FE08d8f4955f13cd9F20B4c05"; + +async function main() { + dotEnvConfig(); + + const deployerPrivateKey = process.env.DEPLOYER_PRIVATE_KEY; + if (!deployerPrivateKey) { + throw "Please set DEPLOYER_PRIVATE_KEY in your .env file"; + } + + const provider = new Provider(process.env.ZKSYNC_RPC_URL); + const zkWallet = new Wallet(deployerPrivateKey, provider); + const deployer = new Deployer(hre, zkWallet); + + const zkStaker = new Contract( + ZK_STAKER_CONTRACT_ADDRESS, + await deployer.loadArtifact("ZkStaker").then((val) => val.abi), + zkWallet + ); + + // Set the consensus registry of the ZkStaker contract + await zkStaker.setRegistry(CONSENSUS_REGISTRY); + console.log(`Registry set to ${CONSENSUS_REGISTRY}`); +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/src/ZkStaker.sol b/src/ZkStaker.sol index 77a2904..bc70a7e 100644 --- a/src/ZkStaker.sol +++ b/src/ZkStaker.sol @@ -8,11 +8,12 @@ import {StakerDelegateSurrogateVotes} from "staker/extensions/StakerDelegateSurr import {StakerCapDeposits} from "staker/extensions/StakerCapDeposits.sol"; import {IERC20Staking} from "staker/interfaces/IERC20Staking.sol"; import {IEarningPowerCalculator} from "staker/interfaces/IEarningPowerCalculator.sol"; - -// these imports needed to get hardhat to include the contracts into the zk-artifacts so the -// deploy script could find them -import {IdentityEarningPowerCalculator} from "staker/calculators/IdentityEarningPowerCalculator.sol"; -import {MintRewardNotifier} from "staker/notifiers/MintRewardNotifier.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import { + IConsensusRegistryExtended, + IConsensusRegistry +} from "src/interfaces/IConsensusRegistryExtended.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; /// @title ZkStaker /// @author [ScopeLift](https://scopelift.co) @@ -28,6 +29,113 @@ contract ZkStaker is StakerDelegateSurrogateVotes, StakerCapDeposits { + using SafeCast for uint256; + + /// @notice Emitted when a validator is altered. + /// @param depositId The deposit identifier of the altered validator. + /// @param oldValidator The address of the old validator. + /// @param newValidator The address of the new validator. + /// @param earningPower The earning power of the new validator. + event ValidatorAltered( + Staker.DepositIdentifier indexed depositId, + address oldValidator, + address newValidator, + uint256 earningPower + ); + + /// @notice Emitted when the validator stake authority is set. + /// @param oldAuthority The address of the old validator stake authority. + /// @param newAuthority The address of the new validator stake authority. + event ValidatorStakeAuthoritySet(address indexed oldAuthority, address indexed newAuthority); + + /// @notice Emitted when the bonus weight of a validator is set. + /// @param validator The address of the validator. + /// @param bonusWeight The new bonus weight of the validator. + event ValidatorBonusWeightSet(address indexed validator, uint256 indexed bonusWeight); + + /// @notice Emitted when the validator weight is updated. + /// @param validator The address of the validator. + /// @param newWeight The new weight of the validator. + event ValidatorTotalWeightUpdated(address indexed validator, uint256 indexed newWeight); + + /// @notice Emitted when the validator weight threshold is set. + /// @param oldThreshold The previous validator weight threshold. + /// @param newThreshold The new validator weight threshold. + event ValidatorWeightThresholdSet(uint256 oldThreshold, uint256 newThreshold); + + /// @notice Emitted when the state of `isLeaderDefault` is changed. + /// @param oldIsLeaderDefault The previous state of the `isLeaderDefault`. + /// @param newIsLeaderDefault The new state for the `isLeaderDefault`. + event IsLeaderDefaultSet(bool oldIsLeaderDefault, bool newIsLeaderDefault); + + /// @notice Emitted when the validator keys are set. + /// @param validatorOwner The address of the validator owner. + /// @param newPubKey The new BLS12-381 public key of the validator. + /// @param newPop The new BLS12-381 proof-of-possession signature of the validator. + event ValidatorKeysSet( + address indexed validatorOwner, + IConsensusRegistry.BLS12_381PublicKey newPubKey, + IConsensusRegistry.BLS12_381Signature newPop + ); + + /// @notice Emitted when the registry is set. + /// @param oldRegistry The address of the old registry. + /// @param newRegistry The address of the new registry. + event RegistrySet(address indexed oldRegistry, address indexed newRegistry); + + /// @notice Thrown when the validator keys are invalid. + error InvalidValidatorKeys(); + + /// @notice Type hash used when encoding data for `stakeOnBehalf` calls. + bytes32 public constant STAKE_WITH_VALIDATOR_TYPEHASH = keccak256( + "Stake(uint256 amount,address delegatee,address claimer,address validator,address depositor,uint256 nonce,uint256 deadline)" + ); + + /// @notice Type hash used when encoding data for `alterValidatorOnBehalf` calls. + bytes32 public constant ALTER_VALIDATOR_TYPEHASH = keccak256( + "AlterValidator(uint256 depositId,address newValidator,address depositor,uint256 nonce,uint256 deadline)" + ); + + /// @notice Struct to store the validator keys. + /// @param pubKey The BLS12-381 public key of the validator. + /// @param pop The BLS12-381 proof-of-possession signature of the validator. + struct ValidatorKeys { + IConsensusRegistry.BLS12_381PublicKey pubKey; + IConsensusRegistry.BLS12_381Signature pop; + } + + /// @notice Maps a deposit identifier to the validator associated with it. + mapping(Staker.DepositIdentifier depositId => address validator) public validatorForDeposit; + + /// @notice Maps a validator to its stake weight. + mapping(address validator => uint256 weight) public validatorStakeWeight; + + /// @notice Maps a validator to its bonus weight. + mapping(address validator => uint256 weight) public validatorBonusWeight; + + /// @notice Maps a validator address to its corresponding BLS12-381 public key and proof of + /// possession signature. + mapping(address validator => ValidatorKeys keys) public registeredValidators; + + /// @notice The consensus registry interface used for validator operations. + IConsensusRegistryExtended public registry; + + /// @notice Address used for atomic earning power calculation. + address public validatorForAtomicEarningPowerCalculation; + + /// @notice Address managing validator bonus weights and registry interactions. + /// @dev The authority can set bonus weights for validators and execute registry operations such + /// as changing validator leadership and committee settings. It includes pass-through methods for + /// registry interactions like changing validator leadership, committing the validator committee, + /// setting committee activation delay, updating leader selection, and changing validator keys. + address public validatorStakeAuthority; + + /// @notice The minimum weight required for a validator to be considered active in the registry. + uint256 public validatorWeightThreshold; + + /// @notice The default value for the `isLeader` flag in the registry for actions that require it. + bool public isLeaderDefault; + /// @notice Initializes the ZkStaker contract with required parameters. /// @param _rewardsToken ERC20 token in which rewards will be denominated. /// @param _stakeToken Delegable governance token which users will stake to earn rewards. @@ -35,6 +143,12 @@ contract ZkStaker is /// @param _maxBumpTip Maximum tip that can be paid to bumpers for updating earning power. /// @param _initialTotalStakeCap The initial maximum total stake allowed. /// @param _admin Address which will have permission to manage reward notifiers. + /// @param _validatorStakeAuthority Address managing validator bonus weights and registry + /// interactions. + /// @param _initialValidatorWeightThreshold The minimum weight required for a validator to be + /// considered active in the registry. + /// @param _initialIsLeaderDefault The default value for the `isLeader` flag in the registry for + /// actions that require it. /// @param _name Name used in the EIP712 domain separator for permit functionality. constructor( IERC20 _rewardsToken, @@ -43,7 +157,10 @@ contract ZkStaker is uint256 _maxBumpTip, uint256 _initialTotalStakeCap, address _admin, - string memory _name + address _validatorStakeAuthority, + string memory _name, + uint256 _initialValidatorWeightThreshold, + bool _initialIsLeaderDefault ) Staker(_rewardsToken, _stakeToken, _earningPowerCalculator, _maxBumpTip, _admin) StakerPermitAndStake(_stakeToken) @@ -53,17 +170,343 @@ contract ZkStaker is { MAX_CLAIM_FEE = 1e18; _setClaimFeeParameters(ClaimFeeParameters({feeAmount: 0, feeCollector: address(0)})); + _setValidatorStakeAuthority(_validatorStakeAuthority); + _setValidatorWeightThreshold(_initialValidatorWeightThreshold); + _setIsLeaderDefault(_initialIsLeaderDefault); + } + + /// @notice Allows a user to stake a specified amount of tokens, delegate voting power, and + /// specify a validator. + /// @param _amount The amount of tokens to stake. + /// @param _delegatee The address to which voting power is delegated. + /// @param _claimer The address that can claim rewards on behalf of the staker. + /// @param _validator The address of the validator associated with the stake. + /// @return _depositId The identifier of the created deposit. + function stake(uint256 _amount, address _delegatee, address _claimer, address _validator) + external + virtual + returns (Staker.DepositIdentifier _depositId) + { + return _stake(msg.sender, _amount, _delegatee, _claimer, _validator); + } + + /// @notice Allows a third party to stake tokens on behalf of a depositor. + /// @param _amount The amount of tokens to stake. + /// @param _delegatee The address to which voting power is delegated. + /// @param _claimer The address that can claim rewards on behalf of the staker. + /// @param _validator The address of the validator associated with the stake. + /// @param _depositor The address of the depositor on whose behalf the stake is made. + /// @param _deadline The timestamp by which the transaction must be completed. + /// @param _signature The signature proving the depositor's consent. + /// @return _depositId The identifier of the created deposit. + function stakeOnBehalf( + uint256 _amount, + address _delegatee, + address _claimer, + address _validator, + address _depositor, + uint256 _deadline, + bytes memory _signature + ) external virtual returns (DepositIdentifier _depositId) { + _revertIfPastDeadline(_deadline); + _revertIfSignatureIsNotValidNow( + _depositor, + _hashTypedDataV4( + keccak256( + abi.encode( + STAKE_WITH_VALIDATOR_TYPEHASH, + _amount, + _delegatee, + _claimer, + _validator, + _depositor, + _useNonce(_depositor), + _deadline + ) + ) + ), + _signature + ); + _depositId = _stake(_depositor, _amount, _delegatee, _claimer, _validator); + } + + /// @notice Allows a user to alter the validator associated with a deposit. + /// @param _depositId The deposit identifier of the deposit to alter. + /// @param _newValidator The address of the new validator. + /// @dev Reverts if the deposit is not owned by the caller. + function alterValidator(Staker.DepositIdentifier _depositId, address _newValidator) + external + virtual + { + validatorForAtomicEarningPowerCalculation = _newValidator; + + Deposit storage deposit = deposits[_depositId]; + _revertIfNotDepositOwner(deposit, msg.sender); + _alterValidator(deposit, _depositId, _newValidator); + + validatorForAtomicEarningPowerCalculation = address(0); + } + + /// @notice Allows an external party to alter the validator associated with a deposit on behalf of + /// the depositor. + /// @param _depositId The identifier of the deposit to alter. + /// @param _newValidator The address of the new validator to associate with the deposit. + /// @param _depositor The address of the depositor who owns the deposit. + /// @param _deadline The timestamp by which the operation must be completed. + /// @param _signature The signature proving the depositor's consent for the operation. + function alterValidatorOnBehalf( + Staker.DepositIdentifier _depositId, + address _newValidator, + address _depositor, + uint256 _deadline, + bytes memory _signature + ) external virtual { + _revertIfPastDeadline(_deadline); + _revertIfSignatureIsNotValidNow( + _depositor, + _hashTypedDataV4( + keccak256( + abi.encode( + ALTER_VALIDATOR_TYPEHASH, + _depositId, + _newValidator, + _depositor, + _useNonce(_depositor), + _deadline + ) + ) + ), + _signature + ); + validatorForAtomicEarningPowerCalculation = _newValidator; + Deposit storage deposit = deposits[_depositId]; + _alterValidator(deposit, _depositId, _newValidator); + validatorForAtomicEarningPowerCalculation = address(0); + } + + /// @notice Sets a new validator stake authority. + /// @param _newAuthority The address of the new validator stake authority. + /// @dev This function can only be called by the current admin. + function setValidatorStakeAuthority(address _newAuthority) external virtual { + _revertIfNotAdmin(); + _setValidatorStakeAuthority(_newAuthority); + } + + /// @notice Updates the minimum weight required for a validator to be added to the registry. + /// @param _newValidatorWeightThreshold The new weight threshold for validators, which must be met + /// or exceeded for a validator to be considered active in the registry. + /// @dev This function can only be called by the current admin. + function setValidatorWeightThreshold(uint256 _newValidatorWeightThreshold) external virtual { + _revertIfNotAdmin(); + _setValidatorWeightThreshold(_newValidatorWeightThreshold); + } + + /// @notice Sets the bonus weight for a given validator. + /// @param _validator The address of the validator whose bonus weight is being set. + /// @param _newBonusWeight The new bonus weight to assign to the validator. + /// @dev This function can only be called by the validator stake authority. + function setBonusWeight(address _validator, uint256 _newBonusWeight) external virtual { + _revertIfNotValidatorStakeAuthority(); + emit ValidatorBonusWeightSet(_validator, _newBonusWeight); + validatorBonusWeight[_validator] = _newBonusWeight; + _changeValidatorWeight(_validator); + } + + /// @notice Sets the consensus registry for the ZkStaker contract. + /// @param _registry The new consensus registry to set. + /// @dev This function can only be called by the current admin. + function setRegistry(IConsensusRegistryExtended _registry) external virtual { + _revertIfNotAdmin(); + emit RegistrySet(address(registry), address(_registry)); + registry = _registry; + } + + /// @notice Returns the total weight of a validator, including both stake and bonus weights. + /// @param _validator The address of the validator to calculate the total weight for. + /// @return The total weight of the validator, which is the sum of its stake and bonus weights. + function validatorTotalWeight(address _validator) public view virtual returns (uint256) { + return (validatorStakeWeight[_validator] + validatorBonusWeight[_validator]); + } + + /// @notice Sets the default leader status for validators. + /// @param _isLeaderDefault The new default leader status to set. + /// @dev This function can only be called by the validator stake authority. + function setIsLeaderDefault(bool _isLeaderDefault) external virtual { + _revertIfNotValidatorStakeAuthority(); + _setIsLeaderDefault(_isLeaderDefault); + } + + /// @notice Registers or changes the validator key for a given validator owner. + /// @param _validatorOwner The address of the validator owner. + /// @param _validatorPubKey The BLS12-381 public key of the validator. + /// @param _validatorPoP The proof-of-possession (PoP) of the validator's public key. + /// @dev This function can be called by the validator owner or the validator stake authority. + /// It checks for a valid BLS12-381 public key and signature before proceeding. + /// If a registry is set, it updates the registry with the new validator key. + function changeValidatorKey( + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) external virtual { + if (msg.sender != _validatorOwner) _revertIfNotValidatorStakeAuthority(); + if (_isEmptyBLS12_381PublicKey(_validatorPubKey) || _isEmptyBLS12_381Signature(_validatorPoP)) { + revert InvalidValidatorKeys(); + } + + _setValidatorKey(_validatorOwner, _validatorPubKey, _validatorPoP); + if (address(registry) != address(0)) { + _setValidatorKeyOnRegistry(_validatorOwner, _validatorPubKey, _validatorPoP); + } + } + + /// @notice Changes the leader status of a validator. + /// @dev This function can only be called by the validator stake authority. + /// @param _validatorOwner The address of the validator owner. + /// @param _isLeader The new leader status to set for the validator. + function changeValidatorLeader(address _validatorOwner, bool _isLeader) external virtual { + _revertIfNotValidatorStakeAuthority(); + registry.changeValidatorLeader(_validatorOwner, _isLeader); + } + + /// @notice Commits the current validator committee. + /// @dev This function can only be called by the validator stake authority. + function commitValidatorCommittee() external virtual { + _revertIfNotValidatorStakeAuthority(); + registry.commitValidatorCommittee(); + } + + /// @notice Sets the delay for committee activation. + /// @dev This function can only be called by the validator stake authority. + /// @param _delay The new delay in seconds for committee activation. + function setCommitteeActivationDelay(uint256 _delay) external virtual { + _revertIfNotValidatorStakeAuthority(); + registry.setCommitteeActivationDelay(_delay); + } + + /// @notice Updates the leader selection parameters. + /// @dev This function can only be called by the validator stake authority. + /// @param _frequency The frequency of leader selection. + /// @param _weighted A boolean indicating if the selection should be weighted. + function updateLeaderSelection(uint64 _frequency, bool _weighted) external virtual { + _revertIfNotValidatorStakeAuthority(); + registry.updateLeaderSelection(_frequency, _weighted); + } + + /// @notice Sets the validator keys for a given validator owner. + /// @param _validatorOwner The address of the validator owner. + /// @param _validatorPubKey The BLS12-381 public key of the validator. + /// @param _validatorPoP The proof-of-possession (PoP) of the validator's public key. + function _setValidatorKey( + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) internal virtual { + registeredValidators[_validatorOwner] = + ValidatorKeys({pubKey: _validatorPubKey, pop: _validatorPoP}); + emit ValidatorKeysSet(_validatorOwner, _validatorPubKey, _validatorPoP); + } + + /// @notice Registers or changes the validator key on the registry. + /// @param _validatorOwner The address of the validator owner. + /// @param _validatorPubKey The BLS12-381 public key of the validator. + /// @param _validatorPoP The proof-of-possession (PoP) of the validator's public key. + function _setValidatorKeyOnRegistry( + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) internal virtual { + bool _isInRegistry = _isValidatorRegisteredAndNotRemovedOnTheRegistry(_validatorOwner); + uint256 _weight = validatorTotalWeight(_validatorOwner); + bool _isAboveThreshold = _weight >= validatorWeightThreshold; + + if (!_isInRegistry && _isAboveThreshold) { + registry.add(_validatorOwner, isLeaderDefault, true, _weight, _validatorPubKey, _validatorPoP); + } else if (_isInRegistry) { + registry.changeValidatorKey(_validatorOwner, _validatorPubKey, _validatorPoP); + } + // if not in registry and not above threshold, refrain from registering the validator on the + // registry + } + + /// @notice Checks if a validator is registered and not removed on the registry. + /// @param _validatorOwner The address of the validator owner. + /// @return True if the validator is registered and not removed on the registry, false otherwise. + function _isValidatorRegisteredAndNotRemovedOnTheRegistry(address _validatorOwner) + internal + virtual + returns (bool) + { + IConsensusRegistry.Validator memory _validator = registry.validators(_validatorOwner); + return !_isEmptyBLS12_381PublicKey(_validator.latest.pubKey) && !_validator.latest.removed; + } + + /// @notice Allows a user to alter the validator associated with a deposit. + /// @param _depositId The deposit identifier of the deposit to alter. + /// @param _newValidator The address of the new validator. + function _alterValidator( + Deposit storage deposit, + Staker.DepositIdentifier _depositId, + address _newValidator + ) internal virtual { + _checkpointGlobalReward(); + _checkpointReward(deposit); + + uint256 _newEarningPower = + earningPowerCalculator.getEarningPower(deposit.balance, deposit.owner, deposit.delegatee); + totalEarningPower = + _calculateTotalEarningPower(deposit.earningPower, _newEarningPower, totalEarningPower); + depositorTotalEarningPower[deposit.owner] = _calculateTotalEarningPower( + deposit.earningPower, _newEarningPower, depositorTotalEarningPower[deposit.owner] + ); + deposit.earningPower = _newEarningPower.toUint96(); + + uint256 _depositBalance = deposit.balance; + address _oldValidator = validatorForDeposit[_depositId]; + + validatorStakeWeight[_oldValidator] -= _depositBalance; + validatorStakeWeight[_newValidator] += _depositBalance; + + _changeValidatorWeight(_oldValidator); + _changeValidatorWeight(_newValidator); + + emit ValidatorAltered(_depositId, _oldValidator, _newValidator, _newEarningPower); + validatorForDeposit[_depositId] = _newValidator; } /// @inheritdoc Staker /// @dev We override this function to resolve ambiguity between inherited contracts. + /// The validator is assumed to be address(0) when not explicitly specified. function _stake(address _depositor, uint256 _amount, address _delegatee, address _claimer) internal virtual override(Staker, StakerCapDeposits) returns (DepositIdentifier _depositId) { - return StakerCapDeposits._stake(_depositor, _amount, _delegatee, _claimer); + return _stake(_depositor, _amount, _delegatee, _claimer, address(0)); + } + + /// @notice Internal function to handle staking with validator specification. + /// @param _depositor The address of the depositor who is staking tokens. + /// @param _amount The amount of tokens to be staked. + /// @param _delegatee The address to which voting power is delegated. + /// @param _claimer The address that can claim rewards on behalf of the staker. + /// @param _validator The address of the validator associated with the stake. + /// @return _depositId The identifier of the created deposit. + function _stake( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator + ) internal virtual returns (DepositIdentifier _depositId) { + validatorForAtomicEarningPowerCalculation = _validator; + + _depositId = StakerCapDeposits._stake(_depositor, _amount, _delegatee, _claimer); + validatorForDeposit[_depositId] = _validator; + validatorStakeWeight[_validator] += _amount; + _changeValidatorWeight(_validator); + + validatorForAtomicEarningPowerCalculation = address(0); } /// @inheritdoc Staker @@ -73,6 +516,233 @@ contract ZkStaker is virtual override(Staker, StakerCapDeposits) { + address _depositValidator = validatorForDeposit[_depositId]; + validatorForAtomicEarningPowerCalculation = _depositValidator; + + validatorStakeWeight[_depositValidator] += _amount; + _changeValidatorWeight(_depositValidator); StakerCapDeposits._stakeMore(deposit, _depositId, _amount); + + validatorForAtomicEarningPowerCalculation = address(0); + } + + /// @notice Withdraws a specified amount from a deposit. + /// @param deposit The deposit from which the amount is to be withdrawn. + /// @param _depositId The identifier of the deposit. + /// @param _amount The amount to be withdrawn from the deposit. + /// @dev This function updates the validator's stake weight and adjusts the validator's weight + /// on the registry. It overrides the _withdraw function from the Staker contract. + function _withdraw(Deposit storage deposit, DepositIdentifier _depositId, uint256 _amount) + internal + virtual + override(Staker) + { + address _depositValidator = validatorForDeposit[_depositId]; + validatorForAtomicEarningPowerCalculation = _depositValidator; + + if (_depositValidator != address(0)) { + validatorStakeWeight[_depositValidator] -= _amount; + _changeValidatorWeight(_depositValidator); + } + + Staker._withdraw(deposit, _depositId, _amount); + + validatorForAtomicEarningPowerCalculation = address(0); + } + + /// @notice Updates the validator's weight on the registry. + /// @dev This function checks if the validator is registered and updates its weight on the + /// registry. + /// If the validator is not in the registry and its weight is above the threshold, it is added. + /// If the validator is in the registry, its weight is updated, and it is removed if below the + /// threshold. + /// @param _validatorOwner The address of the validator owner whose weight is being updated. + function _changeValidatorWeight(address _validatorOwner) internal virtual { + uint256 _newWeight = validatorTotalWeight(_validatorOwner); + emit ValidatorTotalWeightUpdated(_validatorOwner, _newWeight); + + if (!_isValidatorRegistered(_validatorOwner)) return; + if (address(registry) == address(0)) return; + ValidatorKeys memory _keys = registeredValidators[_validatorOwner]; + + bool _isInRegistry = _isValidatorRegisteredAndNotRemovedOnTheRegistry(_validatorOwner); + bool _isAboveThreshold = _newWeight >= validatorWeightThreshold; + + if (!_isInRegistry && _isAboveThreshold) { + registry.add(_validatorOwner, isLeaderDefault, true, _newWeight, _keys.pubKey, _keys.pop); + } + + if (_isInRegistry) { + // We don't need to update the weight on the registry if the validator is below the threshold, + // as it will be removed. When it's re-added, its weight will get overwritten. + if (!_isAboveThreshold) return registry.remove(_validatorOwner); + registry.changeValidatorWeight(_validatorOwner, _newWeight); + } + } + + /// @notice Internal helper method to set the validator stake authority. + /// @param _newAuthority The address of the new validator stake authority. + function _setValidatorStakeAuthority(address _newAuthority) internal virtual { + emit ValidatorStakeAuthoritySet(validatorStakeAuthority, _newAuthority); + validatorStakeAuthority = _newAuthority; + } + + /// @notice Internal function to set the validator weight threshold. + /// @param _newValidatorWeightThreshold The new threshold value for validator weight. + function _setValidatorWeightThreshold(uint256 _newValidatorWeightThreshold) internal virtual { + emit ValidatorWeightThresholdSet(validatorWeightThreshold, _newValidatorWeightThreshold); + validatorWeightThreshold = _newValidatorWeightThreshold; + } + + /// @notice Internal function to set the default leader status. + /// @param _newIsLeaderDefault The new default leader status to be set. + function _setIsLeaderDefault(bool _newIsLeaderDefault) internal virtual { + emit IsLeaderDefaultSet(isLeaderDefault, _newIsLeaderDefault); + isLeaderDefault = _newIsLeaderDefault; + } + + /// @inheritdoc Staker + /// @dev We override this function to atomically store the validator for atomic earning power + /// calculation. + function _alterClaimer(Deposit storage deposit, DepositIdentifier _depositId, address _newClaimer) + internal + virtual + override(Staker) + { + address _depositValidator = validatorForDeposit[_depositId]; + validatorForAtomicEarningPowerCalculation = _depositValidator; + + Staker._alterClaimer(deposit, _depositId, _newClaimer); + + validatorForAtomicEarningPowerCalculation = address(0); + } + + /// @inheritdoc Staker + /// @dev We override this function to atomically store the validator for atomic earning power + /// calculation. + function _claimReward(DepositIdentifier _depositId, Deposit storage deposit, address _claimer) + internal + virtual + override(Staker) + returns (uint256) + { + address _depositValidator = validatorForDeposit[_depositId]; + validatorForAtomicEarningPowerCalculation = _depositValidator; + + uint256 _payout = Staker._claimReward(_depositId, deposit, _claimer); + + validatorForAtomicEarningPowerCalculation = address(0); + + return _payout; + } + + /// @inheritdoc Staker + /// @dev We override this function to atomically store the validator for atomic earning power + /// calculation. + function bumpEarningPower( + DepositIdentifier _depositId, + address _tipReceiver, + uint256 _requestedTip + ) external virtual override(Staker) { + address _depositValidator = validatorForDeposit[_depositId]; + validatorForAtomicEarningPowerCalculation = _depositValidator; + + _bumpEarningPower(_depositId, _tipReceiver, _requestedTip); + + validatorForAtomicEarningPowerCalculation = address(0); + } + + /// @notice Increases the earning power of a deposit. + /// @dev Validates the requested tip and updates the deposit's earning power and unclaimed + /// rewards. Same as Staker.bumpEarningPower(). + /// @param _depositId The identifier of the deposit. + /// @param _tipReceiver The address to receive the tip. + /// @param _requestedTip The tip amount requested. + function _bumpEarningPower( + DepositIdentifier _depositId, + address _tipReceiver, + uint256 _requestedTip + ) internal virtual { + if (_requestedTip > maxBumpTip) revert Staker__InvalidTip(); + + Deposit storage deposit = deposits[_depositId]; + + _checkpointGlobalReward(); + _checkpointReward(deposit); + + uint256 _unclaimedRewards = deposit.scaledUnclaimedRewardCheckpoint / SCALE_FACTOR; + + (uint256 _newEarningPower, bool _isQualifiedForBump) = earningPowerCalculator.getNewEarningPower( + deposit.balance, deposit.owner, deposit.delegatee, deposit.earningPower + ); + if (!_isQualifiedForBump || _newEarningPower == deposit.earningPower) { + revert Staker__Unqualified(_newEarningPower); + } + + if (_newEarningPower > deposit.earningPower && _unclaimedRewards < _requestedTip) { + revert Staker__InsufficientUnclaimedRewards(); + } + + // Note: underflow causes a revert if the requested tip is more than unclaimed rewards + if (_newEarningPower < deposit.earningPower && (_unclaimedRewards - _requestedTip) < maxBumpTip) + { + revert Staker__InsufficientUnclaimedRewards(); + } + + emit EarningPowerBumped( + _depositId, deposit.earningPower, _newEarningPower, msg.sender, _tipReceiver, _requestedTip + ); + + // Update global earning power & deposit earning power based on this bump + totalEarningPower = + _calculateTotalEarningPower(deposit.earningPower, _newEarningPower, totalEarningPower); + depositorTotalEarningPower[deposit.owner] = _calculateTotalEarningPower( + deposit.earningPower, _newEarningPower, depositorTotalEarningPower[deposit.owner] + ); + deposit.earningPower = _newEarningPower.toUint96(); + + // Send tip to the receiver + SafeERC20.safeTransfer(REWARD_TOKEN, _tipReceiver, _requestedTip); + deposit.scaledUnclaimedRewardCheckpoint = + deposit.scaledUnclaimedRewardCheckpoint - (_requestedTip * SCALE_FACTOR); + } + + /// @notice Helper method that reverts if the caller is not the validator stake authority. + function _revertIfNotValidatorStakeAuthority() internal virtual { + if (msg.sender != validatorStakeAuthority) { + revert Staker__Unauthorized("not validator stake authority", msg.sender); + } + } + + /// @notice Checks if a validator is registered. + /// @param _validator The address of the validator to check. + /// @dev A validator is considered registered if both its BLS12-381 public key and proof of + /// possession signature are non-empty. + /// @return True if the validator is registered, false otherwise. + function _isValidatorRegistered(address _validator) internal virtual returns (bool) { + ValidatorKeys memory _keys = registeredValidators[_validator]; + return !(_isEmptyBLS12_381PublicKey(_keys.pubKey) && _isEmptyBLS12_381Signature(_keys.pop)); + } + + /// @notice Checks if a BLS12-381 public key is empty. + /// @param _pubKey The BLS12-381 public key to check. + /// @return True if the public key is empty, false otherwise. + function _isEmptyBLS12_381PublicKey(IConsensusRegistry.BLS12_381PublicKey memory _pubKey) + private + pure + returns (bool) + { + return _pubKey.a == bytes32(0) && _pubKey.b == bytes32(0) && _pubKey.c == bytes32(0); + } + + /// @notice Checks if a BLS12-381 signature is empty. + /// @param _pop The BLS12-381 proof-of-possession signature to check. + /// @return True if the signature is empty, false otherwise. + function _isEmptyBLS12_381Signature(IConsensusRegistry.BLS12_381Signature memory _pop) + private + pure + returns (bool) + { + return _pop.a == bytes32(0) && _pop.b == bytes16(0); } } diff --git a/src/hardhat.imports.sol b/src/hardhat.imports.sol new file mode 100644 index 0000000..ed53546 --- /dev/null +++ b/src/hardhat.imports.sol @@ -0,0 +1,7 @@ +pragma solidity ^0.8.28; + +// these imports needed to get hardhat to include the contracts into the zk-artifacts so the +// deploy script could find them +import {ConsensusRegistry} from "era-contracts/l2-contracts/contracts/ConsensusRegistry.sol"; +import {IdentityEarningPowerCalculator} from "staker/calculators/IdentityEarningPowerCalculator.sol"; +import {MintRewardNotifier} from "staker/notifiers/MintRewardNotifier.sol"; diff --git a/src/interfaces/IConsensusRegistryExtended.sol b/src/interfaces/IConsensusRegistryExtended.sol new file mode 100644 index 0000000..971cdf6 --- /dev/null +++ b/src/interfaces/IConsensusRegistryExtended.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with +// the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.20; + +import {IConsensusRegistry} from + "era-contracts/l2-contracts/contracts/interfaces/IConsensusRegistry.sol"; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +/// @title ConsensusRegistry contract interface +interface IConsensusRegistryExtended is IConsensusRegistry { + /// @notice Retrieves the validator information for a given validator owner. + /// @dev This function is included in the extended interface to make it easier to access validator + /// details directly. This is important for tasks that need to check and confirm the status and + /// attributes of a validator. + /// @param _validatorOwner The address of the validator owner whose information is being queried. + /// @return _validator A struct containing the validator's details, including status and other + /// relevant attributes. + function validators(address _validatorOwner) external returns (Validator memory _validator); + + /// @notice Retrieves the current validator commit number. + /// @dev This function is used to track the number of validator commits. + /// @return The current validator commit number. + function validatorsCommit() external view returns (uint64); + + /// @notice Retrieves the current committee activation delay. + /// @dev This function is used to track the delay before a committee commit becomes active. + /// @return The current committee activation delay. + function committeeActivationDelay() external view returns (uint256); + + /// @notice Retrieves the current leader selection configuration. + /// @dev This function is used to track the leader selection configuration. + /// @return The current leader selection configuration. + function leaderSelection() external view returns (LeaderSelection memory); +} diff --git a/test/ZkStaker.integration.t.sol b/test/ZkStaker.integration.t.sol index cfd04e5..68a1dd0 100644 --- a/test/ZkStaker.integration.t.sol +++ b/test/ZkStaker.integration.t.sol @@ -1,213 +1,508 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.23; -import {Test} from "forge-std/Test.sol"; -import {ZkStaker, IERC20} from "src/ZkStaker.sol"; -import {IntegrationTest} from "test/helpers/IntegrationTest.sol"; +import {Test, console2} from "forge-std/Test.sol"; +import {Staker, ZkStaker} from "src/ZkStaker.sol"; +import {IConsensusRegistry} from + "era-contracts/l2-contracts/contracts/interfaces/IConsensusRegistry.sol"; +import {ConsensusRegistry} from "era-contracts/l2-contracts/contracts/ConsensusRegistry.sol"; import {PercentAssertions} from "staker-test/helpers/PercentAssertions.sol"; +import {IConsensusRegistryExtended} from "src/interfaces/IConsensusRegistryExtended.sol"; +import {ZkStakerTestBase} from "test/ZkStaker.t.sol"; + +contract IntegrationTest is ZkStakerTestBase { + ConsensusRegistry CONSENSUS_REGISTRY; + + function setUp() public virtual override { + super.setUp(); + + // TODO: deploy mock identity earning power calculator that can be used to assert on our temp + // storage var + // calculator = new IdentityEarningPowerCalculator(); + + CONSENSUS_REGISTRY = new ConsensusRegistry(); + CONSENSUS_REGISTRY.initialize(address(zkStaker)); + vm.prank(admin); + zkStaker.setRegistry(IConsensusRegistryExtended(address(CONSENSUS_REGISTRY))); + } + + function _getValidatorOnRegistry(address _validator) + internal + view + returns (IConsensusRegistry.ValidatorAttr memory _latest) + { + (, _latest,,,,) = CONSENSUS_REGISTRY.validators(_validator); + } + + function _registerValidatorWithBonusWeightAboveThreshold( + address _validator, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP, + uint256 _bonusWeightAboveThreshold + ) internal returns (uint256 boundedBonusWeightAboveThreshold) { + _assumeValidKeys(_validatorPubKey, _validatorPoP); + boundedBonusWeightAboveThreshold = + _boundAndSetBonusWeightAboveThreshold(_validator, _bonusWeightAboveThreshold); + _registerValidator(_validator, _validatorPubKey, _validatorPoP); + } +} contract Stake is IntegrationTest, PercentAssertions { - function testForkFuzz_CorrectlyStakeAndEarnRewardsAfterDuration( + function testFuzz_AddsValidatorToRegistry( address _depositor, - uint96 _amount, + uint256 _amount, address _delegatee, - uint256 _rewardAmount, - uint256 _percentDuration, - uint256 _eligibilityScore + address _claimer, + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP ) public { - vm.assume(_depositor != address(0) && _delegatee != address(0)); - vm.assume(_depositor != address(zkStaker)); - _amount = _dealStakingToken(_depositor, _amount); - zkStaker.setTotalStakeCap(zkStaker.totalStakeCap() + _amount); - _rewardAmount = _boundToRealisticReward(_rewardAmount); - _percentDuration = bound(_percentDuration, 0, 100); - _eligibilityScore = _boundEligibilityScore(_eligibilityScore); - + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _amount = bound( + _amount, initialValidatorWeightThreshold, zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + _mintGovToken(_depositor, _amount); + + // Register validator on ZkStaker + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + + // assert that validator is not on ConsensusRegistry + IConsensusRegistry.ValidatorAttr memory _validator = _getValidatorOnRegistry(_validatorOwner); + assertEq(_validator.pubKey, IConsensusRegistry.BLS12_381PublicKey(0, 0, 0)); + assertEq(_validator.proofOfPossession, IConsensusRegistry.BLS12_381Signature(0, 0)); + + // Stake to validator, adding it to ConsensusRegistry vm.startPrank(_depositor); - IERC20(address(zkStaker.STAKE_TOKEN())).approve(address(zkStaker), _amount); - ZkStaker.DepositIdentifier _depositId = zkStaker.stake(_amount, _delegatee); + govToken.approve(address(zkStaker), _amount); + zkStaker.stake(_amount, _delegatee, _claimer, _validatorOwner); vm.stopPrank(); - _mintTransferAndNotifyReward(_rewardAmount); - _jumpAheadByPercentOfRewardDuration(_percentDuration); - - // Calculate expected rewards based on percentage of duration - uint256 expectedRewards = (_rewardAmount * _percentDuration) / 100; - assertLteWithinOnePercent(zkStaker.unclaimedReward(_depositId), expectedRewards); + // assert that validator is on ConsensusRegistry + _validator = _getValidatorOnRegistry(_validatorOwner); + assertEq(_validator.pubKey, _validatorPubKey); + assertEq(_validator.proofOfPossession, _validatorPoP); } - function testForkFuzz_CorrectlyStakeMoreAndEarnRewardsAfterDuration( + function testFuzz_UpdatesValidatorWeightOnRegistry( address _depositor, - uint96 _initialAmount, - uint96 _additionalAmount, + uint256 _bonusWeightAboveThreshold, + uint256 _bonusWeightBelowThreshold, + uint256 _amount, address _delegatee, - uint256 _rewardAmount, - uint256 _percentDuration, - uint256 _eligibilityScore + address _claimer, + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP ) public { - vm.assume(_depositor != address(0) && _delegatee != address(0)); - vm.assume(_depositor != address(zkStaker)); - _rewardAmount = _boundToRealisticReward(_rewardAmount); - _percentDuration = bound(_percentDuration, 0, 100); - _eligibilityScore = _boundEligibilityScore(_eligibilityScore); + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _amount = bound( + _amount, initialValidatorWeightThreshold, zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + _mintGovToken(_depositor, _amount); + + _bonusWeightAboveThreshold = _registerValidatorWithBonusWeightAboveThreshold( + _validatorOwner, _validatorPubKey, _validatorPoP, _bonusWeightAboveThreshold + ); + _bonusWeightBelowThreshold = + _boundAndSetBonusWeightBelowThreshold(_validatorOwner, _bonusWeightBelowThreshold); - // Only deal the initial amount first - _initialAmount = _dealStakingToken(_depositor, _initialAmount); - zkStaker.setTotalStakeCap(zkStaker.totalStakeCap() + _initialAmount); - - // Approve and stake initial amount vm.startPrank(_depositor); - IERC20(address(zkStaker.STAKE_TOKEN())).approve(address(zkStaker), _initialAmount); - ZkStaker.DepositIdentifier _depositId = zkStaker.stake(_initialAmount, _delegatee); + govToken.approve(address(zkStaker), _amount); + zkStaker.stake(_amount, _delegatee, _claimer, _validatorOwner); vm.stopPrank(); - _mintTransferAndNotifyReward(_rewardAmount); - _percentDuration = bound(_percentDuration, 0, 100); - _jumpAheadByPercentOfRewardDuration(_percentDuration); - - // Deal the additional tokens just before staking more - _additionalAmount = _dealStakingToken(_depositor, _additionalAmount); - zkStaker.setTotalStakeCap(zkStaker.totalStakeCap() + _additionalAmount); + IConsensusRegistry.ValidatorAttr memory _validator = _getValidatorOnRegistry(_validatorOwner); + assertEq(_validator.weight, _bonusWeightBelowThreshold + _amount); + } +} - // Approve and stake additional amount +contract StakeMore is IntegrationTest { + function testFuzz_AddsValidatorToRegistry( + address _depositor, + uint256 _amount, + uint256 _stakeMoreAmountAboveThreshold, + address _delegatee, + address _claimer, + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _amount = _boundAndMintGovToken(_depositor, _amount); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + ZkStaker.DepositIdentifier _depositId; + _amount = bound(_amount, 0, initialValidatorWeightThreshold - 1); + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validatorOwner); + + _stakeMoreAmountAboveThreshold = bound( + _stakeMoreAmountAboveThreshold, + initialValidatorWeightThreshold, + zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + _mintGovToken(_depositor, _stakeMoreAmountAboveThreshold); vm.startPrank(_depositor); - IERC20(address(zkStaker.STAKE_TOKEN())).approve(address(zkStaker), _additionalAmount); - zkStaker.stakeMore(_depositId, _additionalAmount); + govToken.approve(address(zkStaker), _stakeMoreAmountAboveThreshold); + zkStaker.stakeMore(_depositId, _stakeMoreAmountAboveThreshold); vm.stopPrank(); - // Jump ahead to complete the reward duration - _jumpAheadByPercentOfRewardDuration(100 - _percentDuration); - - // Calculate expected rewards: - // 1. Rewards earned with initial amount during first period - uint256 expectedRewardsPeriod1 = - (_rewardAmount * _percentDuration * _initialAmount) / (100 * (_initialAmount)); - // 2. Rewards earned with combined amount during second period - uint256 expectedRewardsPeriod2 = (_rewardAmount * (100 - _percentDuration)) / 100; - uint256 totalExpectedRewards = expectedRewardsPeriod1 + expectedRewardsPeriod2; + IConsensusRegistry.ValidatorAttr memory _validator = _getValidatorOnRegistry(_validatorOwner); - // Assert that the unclaimed rewards are within one percent of the expected amount - assertLteWithinOnePercent(zkStaker.unclaimedReward(_depositId), totalExpectedRewards); + assertEq(_validator.pubKey, _validatorPubKey); + assertEq(_validator.proofOfPossession, _validatorPoP); + assertEq(_validator.weight, _amount + _stakeMoreAmountAboveThreshold); } } -contract Unstake is IntegrationTest, PercentAssertions { - function testForkFuzz_CorrectlyUnstakeAfterDuration( +contract Withdraw is IntegrationTest { + function testFuzz_UpdatesValidatorWeightOnRegistry( address _depositor, - uint96 _amount, - address _delegatee, - uint256 _rewardAmount, + uint256 _stakeAmount, uint256 _withdrawAmount, - uint256 _percentDuration, - uint256 _eligibilityScore + address _delegatee, + address _claimer, + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP ) public { - vm.assume(_depositor != address(0) && _delegatee != address(0)); - vm.assume(_depositor != address(zkStaker)); - _amount = _dealStakingToken(_depositor, _amount); - zkStaker.setTotalStakeCap(zkStaker.totalStakeCap() + _amount); - _rewardAmount = _boundToRealisticReward(_rewardAmount); - _withdrawAmount = bound(_withdrawAmount, 1e17, _amount); - _percentDuration = bound(_percentDuration, 0, 100); - _eligibilityScore = _boundEligibilityScore(_eligibilityScore); + vm.assume(_validatorOwner != address(0)); + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + _stakeAmount = bound( + _stakeAmount, + initialValidatorWeightThreshold, + zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + ZkStaker.DepositIdentifier _depositId; + (_stakeAmount, _depositId) = + _boundMintAndStake(_depositor, _stakeAmount, _delegatee, _claimer, _validatorOwner); + _withdrawAmount = bound(_withdrawAmount, 0, _stakeAmount - 1); - vm.startPrank(_depositor); - IERC20(address(zkStaker.STAKE_TOKEN())).approve(address(zkStaker), _amount); - ZkStaker.DepositIdentifier _depositId = zkStaker.stake(_amount, _delegatee); - vm.stopPrank(); + vm.prank(_depositor); + zkStaker.withdraw(_depositId, _withdrawAmount); - _mintTransferAndNotifyReward(_rewardAmount); - _jumpAheadByPercentOfRewardDuration(_percentDuration); + IConsensusRegistry.ValidatorAttr memory _validator = _getValidatorOnRegistry(_validatorOwner); + assertValidatorRemovedOrWeightIfAboveThreshold(_validator, _stakeAmount - _withdrawAmount); + } - uint256 oldBalance = IERC20(address(zkStaker.STAKE_TOKEN())).balanceOf(_depositor); + function testFuzz_RemovesValidatorFromRegistry( + address _depositor, + uint256 _stakeAmount, + uint256 _withdrawAmount, + address _delegatee, + address _claimer, + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + vm.assume(_validatorOwner != address(0)); + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + _stakeAmount = bound( + _stakeAmount, + initialValidatorWeightThreshold, + zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + ZkStaker.DepositIdentifier _depositId; + (_stakeAmount, _depositId) = + _boundMintAndStake(_depositor, _stakeAmount, _delegatee, _claimer, _validatorOwner); + _withdrawAmount = + bound(_withdrawAmount, _stakeAmount - initialValidatorWeightThreshold + 1, _stakeAmount - 1); vm.prank(_depositor); zkStaker.withdraw(_depositId, _withdrawAmount); - uint256 newBalance = IERC20(address(zkStaker.STAKE_TOKEN())).balanceOf(_depositor); - assertEq(newBalance - oldBalance, _withdrawAmount); + IConsensusRegistry.ValidatorAttr memory _validator = _getValidatorOnRegistry(_validatorOwner); + assertEq(_validator.removed, true); } -} -contract ClaimRewards is IntegrationTest, PercentAssertions { - function testForkFuzz_CorrectlyStakeAndClaimRewardsAfterDuration( + function testFuzz_DoesNotAddValidatorToRegistryWhenValidatorWeightIsBelowThreshold( address _depositor, - uint96 _amount, + uint256 _amount, + uint256 _stakeMoreAmountAboveThreshold, address _delegatee, - uint256 _rewardAmount, - uint256 _percentDuration, - uint256 _eligibilityScore + address _claimer, + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP ) public { - vm.assume(_depositor != address(0) && _delegatee != address(0)); - vm.assume(_depositor != address(zkStaker)); - _amount = _dealStakingToken(_depositor, _amount); - zkStaker.setTotalStakeCap(zkStaker.totalStakeCap() + _amount); - _rewardAmount = _boundToRealisticReward(_rewardAmount); - _percentDuration = bound(_percentDuration, 0, 100); - _eligibilityScore = _boundEligibilityScore(_eligibilityScore); - + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _amount = _boundAndMintGovToken(_depositor, _amount); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + ZkStaker.DepositIdentifier _depositId; + _amount = bound(_amount, 0, initialValidatorWeightThreshold - 1); + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validatorOwner); + + _stakeMoreAmountAboveThreshold = + bound(_stakeMoreAmountAboveThreshold, 0, initialValidatorWeightThreshold - _amount - 1); + _mintGovToken(_depositor, _stakeMoreAmountAboveThreshold); vm.startPrank(_depositor); - IERC20(address(zkStaker.STAKE_TOKEN())).approve(address(zkStaker), _amount); - ZkStaker.DepositIdentifier _depositId = zkStaker.stake(_amount, _delegatee); + govToken.approve(address(zkStaker), _stakeMoreAmountAboveThreshold); + zkStaker.stakeMore(_depositId, _stakeMoreAmountAboveThreshold); vm.stopPrank(); - _mintTransferAndNotifyReward(_rewardAmount); - _jumpAheadByPercentOfRewardDuration(_percentDuration); + IConsensusRegistry.ValidatorAttr memory _validator = _getValidatorOnRegistry(_validatorOwner); + IConsensusRegistry.BLS12_381PublicKey memory _pubKey = _validator.pubKey; + IConsensusRegistry.BLS12_381Signature memory _pop = _validator.proofOfPossession; + assertEq(_isEmptyBLS12_381PublicKey(_pubKey), true); + assertEq(_isEmptyBLS12_381Signature(_pop), true); + } +} - uint256 oldBalance = IERC20(address(zkStaker.REWARD_TOKEN())).balanceOf(_depositor); +contract AlterValidator is IntegrationTest { + function testFuzz_AddsValidatorToRegistry( + address _depositor, + uint256 _stakeAmountAboveThreshold, + address _delegatee, + address _claimer, + address _validator, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _registerValidator(_validator, _validatorPubKey, _validatorPoP); + _stakeAmountAboveThreshold = bound( + _stakeAmountAboveThreshold, + initialValidatorWeightThreshold, + zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + ZkStaker.DepositIdentifier _depositId; + (, _depositId) = + _boundMintAndStake(_depositor, _stakeAmountAboveThreshold, _delegatee, _claimer, _validator); vm.prank(_depositor); - zkStaker.claimReward(_depositId); + zkStaker.alterValidator(_depositId, _validator); + + IConsensusRegistry.ValidatorAttr memory _validatorOnRegistry = + _getValidatorOnRegistry(_validator); + assertEq(_validatorOnRegistry.weight, _stakeAmountAboveThreshold); + } + + function testFuzz_ChangesValidatorWeightOnRegistry( + address _depositor, + uint256 _amount, + uint256 _bonusWeightAboveThreshold, + address _delegatee, + address _claimer, + address _validator, + address _newValidator, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP, + IConsensusRegistry.BLS12_381PublicKey calldata _newValidatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _newValidatorPoP + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + vm.assume(_validator != _newValidator); + _amount = bound( + _amount, initialValidatorWeightThreshold, zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + _registerValidator(_validator, _validatorPubKey, _validatorPoP); + _bonusWeightAboveThreshold = _registerValidatorWithBonusWeightAboveThreshold( + _newValidator, _newValidatorPubKey, _newValidatorPoP, _bonusWeightAboveThreshold + ); + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); - uint256 newBalance = IERC20(address(zkStaker.REWARD_TOKEN())).balanceOf(_depositor); + vm.prank(_depositor); + zkStaker.alterValidator(_depositId, _newValidator); - // Calculate expected rewards based on percentage of duration - uint256 expectedRewards = (_rewardAmount * _percentDuration) / 100; - assertLteWithinOnePercent(newBalance - oldBalance, expectedRewards); - assertEq(zkStaker.unclaimedReward(_depositId), 0); + IConsensusRegistry.ValidatorAttr memory _previousValidator = _getValidatorOnRegistry(_validator); + IConsensusRegistry.ValidatorAttr memory _currentValidator = + _getValidatorOnRegistry(_newValidator); + assertValidatorRemovedOrWeightIfAboveThreshold(_previousValidator, 0); + assertEq(_currentValidator.weight, _amount + _bonusWeightAboveThreshold); } - function testForkFuzz_CorrectlyUnstakeAndClaimRewardsAfterDuration( + function testFuzz_RemovesValidatorFromRegistry( address _depositor, - uint96 _amount, + uint256 _amount, + uint256 _bonusWeightAboveThreshold, address _delegatee, - uint256 _rewardAmount, - uint256 _withdrawAmount, - uint256 _percentDuration, - uint256 _eligibilityScore + address _claimer, + address _validator, + address _newValidator, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP, + IConsensusRegistry.BLS12_381PublicKey calldata _newValidatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _newValidatorPoP ) public { - vm.skip(true); - vm.assume(_depositor != address(0) && _delegatee != address(0)); - vm.assume(_depositor != address(zkStaker)); - _amount = _dealStakingToken(_depositor, _amount); - zkStaker.setTotalStakeCap(zkStaker.totalStakeCap() + _amount); - _rewardAmount = _boundToRealisticReward(_rewardAmount); - _withdrawAmount = bound(_withdrawAmount, 1e17, _amount); - _percentDuration = bound(_percentDuration, 0, 100); - _eligibilityScore = _boundEligibilityScore(_eligibilityScore); + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + vm.assume(_validator != _newValidator); + _amount = bound( + _amount, initialValidatorWeightThreshold, zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + _registerValidator(_validator, _validatorPubKey, _validatorPoP); + _bonusWeightAboveThreshold = _registerValidatorWithBonusWeightAboveThreshold( + _newValidator, _newValidatorPubKey, _newValidatorPoP, _bonusWeightAboveThreshold + ); + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); - vm.startPrank(_depositor); - IERC20(address(zkStaker.STAKE_TOKEN())).approve(address(zkStaker), _amount); - ZkStaker.DepositIdentifier _depositId = zkStaker.stake(_amount, _delegatee); - vm.stopPrank(); + vm.prank(_depositor); + zkStaker.alterValidator(_depositId, _newValidator); - _mintTransferAndNotifyReward(_rewardAmount); - _jumpAheadByPercentOfRewardDuration(_percentDuration); + IConsensusRegistry.ValidatorAttr memory _validatorOnRegistry = + _getValidatorOnRegistry(_validator); + assertEq(_validatorOnRegistry.removed, true); + } +} - uint256 oldStakeBalance = IERC20(address(zkStaker.STAKE_TOKEN())).balanceOf(_depositor); - uint256 oldRewardBalance = IERC20(address(zkStaker.REWARD_TOKEN())).balanceOf(_depositor); +contract SetBonusWeight is IntegrationTest { + function testFuzz_AddsValidatorToRegistry( + address _validatorOwner, + uint256 _bonusWeightAboveThreshold, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + _bonusWeightAboveThreshold = + _boundAndSetBonusWeightAboveThreshold(_validatorOwner, _bonusWeightAboveThreshold); - vm.startPrank(_depositor); - zkStaker.withdraw(_depositId, _withdrawAmount); - zkStaker.claimReward(_depositId); - vm.stopPrank(); + IConsensusRegistry.ValidatorAttr memory _validator = _getValidatorOnRegistry(_validatorOwner); + assertEq(_validator.weight, _bonusWeightAboveThreshold); + } +} + +contract ChangeValidatorKey is IntegrationTest { + function testFuzz_AddsValidatorAsOwnerOnTheRegistry( + address _validatorOwner, + uint256 _bonusWeightAboveThreshold, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _boundAndSetBonusWeightAboveThreshold(_validatorOwner, _bonusWeightAboveThreshold); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + + vm.prank(_validatorOwner); + zkStaker.changeValidatorKey(_validatorOwner, _validatorPubKey, _validatorPoP); + + IConsensusRegistry.ValidatorAttr memory _validator = _getValidatorOnRegistry(_validatorOwner); + + assertEq(_validator.pubKey, _validatorPubKey); + assertEq(_validator.proofOfPossession, _validatorPoP); + } + + function testFuzz_AddsValidatorAsValidatorStakeAuthorityOnTheRegistry( + address _validatorOwner, + uint256 _bonusWeightAboveThreshold, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _boundAndSetBonusWeightAboveThreshold(_validatorOwner, _bonusWeightAboveThreshold); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + + vm.prank(validatorStakeAuthority); + zkStaker.changeValidatorKey(_validatorOwner, _validatorPubKey, _validatorPoP); + + IConsensusRegistry.ValidatorAttr memory _validator = _getValidatorOnRegistry(_validatorOwner); + + assertEq(_validator.pubKey, _validatorPubKey); + assertEq(_validator.proofOfPossession, _validatorPoP); + } + + function testFuzz_ChangesValidatorKeysAsOwnerOnTheRegistry( + address _validatorOwner, + uint256 _bonusWeightAboveThreshold, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP, + IConsensusRegistry.BLS12_381PublicKey calldata _newValidatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _newValidatorPoP + ) public { + _boundAndSetBonusWeightAboveThreshold(_validatorOwner, _bonusWeightAboveThreshold); + + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _assumeValidKeys(_newValidatorPubKey, _newValidatorPoP); + vm.prank(_validatorOwner); + zkStaker.changeValidatorKey(_validatorOwner, _validatorPubKey, _validatorPoP); - uint256 newStakeBalance = IERC20(address(zkStaker.STAKE_TOKEN())).balanceOf(_depositor); - uint256 newRewardBalance = IERC20(address(zkStaker.REWARD_TOKEN())).balanceOf(_depositor); + vm.prank(_validatorOwner); + zkStaker.changeValidatorKey(_validatorOwner, _newValidatorPubKey, _newValidatorPoP); + + IConsensusRegistry.ValidatorAttr memory _validator = _getValidatorOnRegistry(_validatorOwner); + + assertEq(_validator.pubKey, _newValidatorPubKey); + assertEq(_validator.proofOfPossession, _newValidatorPoP); + } + + function testFuzz_ChangesValidatorKeysAsStakeAuthorityOnTheRegistry( + address _validatorOwner, + uint256 _bonusWeightAboveThreshold, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP, + IConsensusRegistry.BLS12_381PublicKey calldata _newValidatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _newValidatorPoP + ) public { + _bonusWeightAboveThreshold = + bound(_bonusWeightAboveThreshold, initialValidatorWeightThreshold, type(uint256).max); + + vm.prank(validatorStakeAuthority); + zkStaker.setBonusWeight(_validatorOwner, _bonusWeightAboveThreshold); + + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _assumeValidKeys(_newValidatorPubKey, _newValidatorPoP); + vm.prank(_validatorOwner); + zkStaker.changeValidatorKey(_validatorOwner, _validatorPubKey, _validatorPoP); + + vm.prank(validatorStakeAuthority); + zkStaker.changeValidatorKey(_validatorOwner, _newValidatorPubKey, _newValidatorPoP); + + IConsensusRegistry.ValidatorAttr memory _validator = _getValidatorOnRegistry(_validatorOwner); + + assertEq(_validator.pubKey, _newValidatorPubKey); + assertEq(_validator.proofOfPossession, _newValidatorPoP); + } +} + +contract ChangeValidatorLeader is IntegrationTest { + function testFuzz_ChangesValidatorLeader( + address _validator, + uint256 _bonusWeightAboveThreshold, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + vm.assume(_validator != address(this)); + + _registerValidatorWithBonusWeightAboveThreshold( + _validator, _validatorPubKey, _validatorPoP, _bonusWeightAboveThreshold + ); + + vm.prank(validatorStakeAuthority); + zkStaker.changeValidatorLeader(_validator, true); + + IConsensusRegistry.ValidatorAttr memory _validatorOnRegistry = + _getValidatorOnRegistry(_validator); + assertEq(_validatorOnRegistry.leader, true); + } +} + +contract SetCommitteeActivationDelay is IntegrationTest { + function testFuzz_SetsCommitteeActivationDelay(uint256 _delay) public { + vm.prank(validatorStakeAuthority); + zkStaker.setCommitteeActivationDelay(_delay); + + assertEq(CONSENSUS_REGISTRY.committeeActivationDelay(), _delay); + } +} - assertEq(newStakeBalance - oldStakeBalance, _withdrawAmount); +contract UpdateLeaderSelection is IntegrationTest { + function testFuzz_UpdatesLeaderSelection(uint64 _frequency, bool _weighted) public { + vm.prank(validatorStakeAuthority); + zkStaker.updateLeaderSelection(_frequency, _weighted); + (IConsensusRegistry.LeaderSelectionAttr memory _validator,,,,) = + CONSENSUS_REGISTRY.leaderSelection(); - uint256 expectedRewards = (_rewardAmount * _percentDuration) / 100; - assertLteWithinOnePercent(newRewardBalance - oldRewardBalance, expectedRewards); - assertEq(zkStaker.unclaimedReward(_depositId), 0); + assertEq(_validator.frequency, _frequency); + assertEq(_validator.weighted, _weighted); } } diff --git a/test/ZkStaker.old.integration.t.sol b/test/ZkStaker.old.integration.t.sol new file mode 100644 index 0000000..b907b5c --- /dev/null +++ b/test/ZkStaker.old.integration.t.sol @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity ^0.8.23; + +import {Test, console2} from "forge-std/Test.sol"; +import {ZkStaker, IERC20} from "src/ZkStaker.sol"; +import {PercentAssertions} from "staker-test/helpers/PercentAssertions.sol"; +import {IERC20Staking} from "staker/interfaces/IERC20Staking.sol"; +import {IdentityEarningPowerCalculator} from "staker/calculators/IdentityEarningPowerCalculator.sol"; + +contract IntegrationTest is Test { + address constant ZK_TOKEN_ADDRESS = 0x5A7d6b2F92C77FAD6CCaBd7EE0624E64907Eaf3E; + string constant ZKSYNC_RPC_URL = "https://mainnet.era.zksync.io"; + ZkStaker zkStaker; + IdentityEarningPowerCalculator calculator; + // ArbitrumDeploy deployScript; + uint256 constant REWARD_DURATION = 30 days; + uint256 constant SCALE_FACTOR = 1e36; + + function setUp() public virtual { + uint256 _forkId = vm.createFork(vm.rpcUrl(ZKSYNC_RPC_URL), 56_644_662); + vm.selectFork(_forkId); + calculator = new IdentityEarningPowerCalculator(); + zkStaker = new ZkStaker( + IERC20(ZK_TOKEN_ADDRESS), + IERC20Staking(ZK_TOKEN_ADDRESS), + calculator, + 1e18, + 1e24, + address(this), + address(this), + "ZkStaker", + 1e18, + true + ); + } + + function _dealStakingToken(address _recipient, uint96 _amount) internal returns (uint96) { + // Bound amount to reasonable values + _amount = uint96(bound(_amount, 0.1e18, 250_000_000e18)); + deal(address(zkStaker.STAKE_TOKEN()), _recipient, _amount); + return _amount; + } + + function _jumpAheadByPercentOfRewardDuration(uint256 _percent) internal { + _percent = bound(_percent, 0, 100); + vm.warp(block.timestamp + (REWARD_DURATION * _percent) / 100); + } + + function _boundToRealisticReward(uint256 _rewardAmount) internal pure returns (uint256) { + // Use much more conservative bounds to prevent overflow + return bound(_rewardAmount, 1e18, 1_000_000e18); // Max 1M tokens + } + + function _mintTransferAndNotifyReward(uint256 _rewardAmount) internal { + // Bound the reward amount to realistic values + _rewardAmount = _boundToRealisticReward(_rewardAmount); + + // Get the admin from the deployment script + address admin = zkStaker.admin(); + address rewardNotifier = makeAddr("rewardNotifier"); + + // Set up the reward notifier + vm.prank(admin); + zkStaker.setRewardNotifier(rewardNotifier, true); + + // Use deal with the bounded amount + deal(address(zkStaker.REWARD_TOKEN()), rewardNotifier, _rewardAmount); + + // Transfer tokens to the staking contract and notify + vm.startPrank(rewardNotifier); + IERC20(address(zkStaker.REWARD_TOKEN())).transfer(address(zkStaker), _rewardAmount); + zkStaker.notifyRewardAmount(_rewardAmount); + vm.stopPrank(); + } + + function _boundEligibilityScore(uint256 _score) internal pure returns (uint256) { + return bound(_score, 50, 100); + } +} + +contract Stake is IntegrationTest, PercentAssertions { + function testForkFuzz_CorrectlyStakeAndEarnRewardsAfterDuration( + address _depositor, + uint96 _amount, + address _delegatee, + uint256 _rewardAmount, + uint256 _percentDuration, + uint256 _eligibilityScore + ) public { + vm.assume(_depositor != address(0) && _delegatee != address(0)); + vm.assume(_depositor != address(zkStaker)); + _amount = _dealStakingToken(_depositor, _amount); + zkStaker.setTotalStakeCap(zkStaker.totalStakeCap() + _amount); + _rewardAmount = _boundToRealisticReward(_rewardAmount); + _percentDuration = bound(_percentDuration, 0, 100); + _eligibilityScore = _boundEligibilityScore(_eligibilityScore); + + vm.startPrank(_depositor); + IERC20(address(zkStaker.STAKE_TOKEN())).approve(address(zkStaker), _amount); + ZkStaker.DepositIdentifier _depositId = + zkStaker.stake(_amount, _delegatee, address(0x1), address(0x2)); + vm.stopPrank(); + + _mintTransferAndNotifyReward(_rewardAmount); + _jumpAheadByPercentOfRewardDuration(_percentDuration); + + // Calculate expected rewards based on percentage of duration + uint256 expectedRewards = (_rewardAmount * _percentDuration) / 100; + assertLteWithinOnePercent(zkStaker.unclaimedReward(_depositId), expectedRewards); + // assertEq(zkStaker.); + } + + function testForkFuzz_CorrectlyStakeMoreAndEarnRewardsAfterDuration( + address _depositor, + uint96 _initialAmount, + uint96 _additionalAmount, + address _delegatee, + uint256 _rewardAmount, + uint256 _percentDuration, + uint256 _eligibilityScore + ) public { + vm.assume(_depositor != address(0) && _delegatee != address(0)); + vm.assume(_depositor != address(zkStaker)); + _rewardAmount = _boundToRealisticReward(_rewardAmount); + _percentDuration = bound(_percentDuration, 0, 100); + _eligibilityScore = _boundEligibilityScore(_eligibilityScore); + + // Only deal the initial amount first + _initialAmount = _dealStakingToken(_depositor, _initialAmount); + zkStaker.setTotalStakeCap(zkStaker.totalStakeCap() + _initialAmount); + + // Approve and stake initial amount + vm.startPrank(_depositor); + IERC20(address(zkStaker.STAKE_TOKEN())).approve(address(zkStaker), _initialAmount); + ZkStaker.DepositIdentifier _depositId = zkStaker.stake(_initialAmount, _delegatee); + vm.stopPrank(); + + _mintTransferAndNotifyReward(_rewardAmount); + _percentDuration = bound(_percentDuration, 0, 100); + _jumpAheadByPercentOfRewardDuration(_percentDuration); + + // Deal the additional tokens just before staking more + _additionalAmount = _dealStakingToken(_depositor, _additionalAmount); + zkStaker.setTotalStakeCap(zkStaker.totalStakeCap() + _additionalAmount); + + // Approve and stake additional amount + vm.startPrank(_depositor); + IERC20(address(zkStaker.STAKE_TOKEN())).approve(address(zkStaker), _additionalAmount); + zkStaker.stakeMore(_depositId, _additionalAmount); + vm.stopPrank(); + + // Jump ahead to complete the reward duration + _jumpAheadByPercentOfRewardDuration(100 - _percentDuration); + + // Calculate expected rewards: + // 1. Rewards earned with initial amount during first period + uint256 expectedRewardsPeriod1 = + (_rewardAmount * _percentDuration * _initialAmount) / (100 * (_initialAmount)); + // 2. Rewards earned with combined amount during second period + uint256 expectedRewardsPeriod2 = (_rewardAmount * (100 - _percentDuration)) / 100; + uint256 totalExpectedRewards = expectedRewardsPeriod1 + expectedRewardsPeriod2; + + // Assert that the unclaimed rewards are within one percent of the expected amount + assertLteWithinOnePercent(zkStaker.unclaimedReward(_depositId), totalExpectedRewards); + } +} + +contract Unstake is IntegrationTest, PercentAssertions { + function testForkFuzz_CorrectlyUnstakeAfterDuration( + address _depositor, + uint96 _amount, + address _delegatee, + uint256 _rewardAmount, + uint256 _withdrawAmount, + uint256 _percentDuration, + uint256 _eligibilityScore + ) public { + vm.assume(_depositor != address(0) && _delegatee != address(0)); + vm.assume(_depositor != address(zkStaker)); + _amount = _dealStakingToken(_depositor, _amount); + zkStaker.setTotalStakeCap(zkStaker.totalStakeCap() + _amount); + _rewardAmount = _boundToRealisticReward(_rewardAmount); + _withdrawAmount = bound(_withdrawAmount, 1e17, _amount); + _percentDuration = bound(_percentDuration, 0, 100); + _eligibilityScore = _boundEligibilityScore(_eligibilityScore); + + vm.startPrank(_depositor); + IERC20(address(zkStaker.STAKE_TOKEN())).approve(address(zkStaker), _amount); + ZkStaker.DepositIdentifier _depositId = zkStaker.stake(_amount, _delegatee); + vm.stopPrank(); + + _mintTransferAndNotifyReward(_rewardAmount); + _jumpAheadByPercentOfRewardDuration(_percentDuration); + + uint256 oldBalance = IERC20(address(zkStaker.STAKE_TOKEN())).balanceOf(_depositor); + + vm.prank(_depositor); + zkStaker.withdraw(_depositId, _withdrawAmount); + + uint256 newBalance = IERC20(address(zkStaker.STAKE_TOKEN())).balanceOf(_depositor); + assertEq(newBalance - oldBalance, _withdrawAmount); + } +} + +contract ClaimRewards is IntegrationTest, PercentAssertions { + function testForkFuzz_CorrectlyStakeAndClaimRewardsAfterDuration( + address _depositor, + uint96 _amount, + address _delegatee, + uint256 _rewardAmount, + uint256 _percentDuration, + uint256 _eligibilityScore + ) public { + vm.assume(_depositor != address(0) && _delegatee != address(0)); + vm.assume(_depositor != address(zkStaker)); + _amount = _dealStakingToken(_depositor, _amount); + zkStaker.setTotalStakeCap(zkStaker.totalStakeCap() + _amount); + _rewardAmount = _boundToRealisticReward(_rewardAmount); + _percentDuration = bound(_percentDuration, 0, 100); + _eligibilityScore = _boundEligibilityScore(_eligibilityScore); + + vm.startPrank(_depositor); + IERC20(address(zkStaker.STAKE_TOKEN())).approve(address(zkStaker), _amount); + ZkStaker.DepositIdentifier _depositId = zkStaker.stake(_amount, _delegatee); + vm.stopPrank(); + + _mintTransferAndNotifyReward(_rewardAmount); + _jumpAheadByPercentOfRewardDuration(_percentDuration); + + uint256 oldBalance = IERC20(address(zkStaker.REWARD_TOKEN())).balanceOf(_depositor); + + vm.prank(_depositor); + zkStaker.claimReward(_depositId); + + uint256 newBalance = IERC20(address(zkStaker.REWARD_TOKEN())).balanceOf(_depositor); + + // Calculate expected rewards based on percentage of duration + uint256 expectedRewards = (_rewardAmount * _percentDuration) / 100; + assertLteWithinOnePercent(newBalance - oldBalance, expectedRewards); + assertEq(zkStaker.unclaimedReward(_depositId), 0); + } + + // TODO: This test is being skipped right now + function testForkFuzz_CorrectlyUnstakeAndClaimRewardsAfterDuration( + address _depositor, + uint96 _amount, + address _delegatee, + uint256 _rewardAmount, + uint256 _withdrawAmount, + uint256 _percentDuration, + uint256 _eligibilityScore + ) public { + vm.skip(true); + vm.assume(_depositor != address(0) && _delegatee != address(0)); + vm.assume(_depositor != address(zkStaker)); + _amount = _dealStakingToken(_depositor, _amount); + zkStaker.setTotalStakeCap(zkStaker.totalStakeCap() + _amount); + _rewardAmount = _boundToRealisticReward(_rewardAmount); + _withdrawAmount = bound(_withdrawAmount, 1e17, _amount); + _percentDuration = bound(_percentDuration, 0, 100); + _eligibilityScore = _boundEligibilityScore(_eligibilityScore); + + vm.startPrank(_depositor); + IERC20(address(zkStaker.STAKE_TOKEN())).approve(address(zkStaker), _amount); + ZkStaker.DepositIdentifier _depositId = zkStaker.stake(_amount, _delegatee); + vm.stopPrank(); + + _mintTransferAndNotifyReward(_rewardAmount); + _jumpAheadByPercentOfRewardDuration(_percentDuration); + + uint256 oldStakeBalance = IERC20(address(zkStaker.STAKE_TOKEN())).balanceOf(_depositor); + uint256 oldRewardBalance = IERC20(address(zkStaker.REWARD_TOKEN())).balanceOf(_depositor); + + vm.startPrank(_depositor); + zkStaker.withdraw(_depositId, _withdrawAmount); + zkStaker.claimReward(_depositId); + vm.stopPrank(); + + uint256 newStakeBalance = IERC20(address(zkStaker.STAKE_TOKEN())).balanceOf(_depositor); + uint256 newRewardBalance = IERC20(address(zkStaker.REWARD_TOKEN())).balanceOf(_depositor); + + assertEq(newStakeBalance - oldStakeBalance, _withdrawAmount); + + uint256 expectedRewards = (_rewardAmount * _percentDuration) / 100; + assertLteWithinOnePercent(newRewardBalance - oldRewardBalance, expectedRewards); + assertEq(zkStaker.unclaimedReward(_depositId), 0); + } +} diff --git a/test/ZkStaker.t.sol b/test/ZkStaker.t.sol index e9d141c..790046f 100644 --- a/test/ZkStaker.t.sol +++ b/test/ZkStaker.t.sol @@ -1,32 +1,85 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.28; -import {Test} from "forge-std/Test.sol"; -import {ZkStaker, IERC20, IEarningPowerCalculator} from "src/ZkStaker.sol"; +import {Test, Vm, stdStorage, StdStorage} from "forge-std/Test.sol"; +import {ZkStaker, Staker, IERC20, IEarningPowerCalculator} from "src/ZkStaker.sol"; +import {StakerOnBehalf} from "staker/extensions/StakerOnBehalf.sol"; import {IERC20Staking} from "staker/interfaces/IERC20Staking.sol"; import {ERC20Fake} from "staker-test/fakes/ERC20Fake.sol"; import {ERC20VotesMock} from "staker-test/mocks/MockERC20Votes.sol"; -import {MockFullEarningPowerCalculator} from "staker-test/mocks/MockFullEarningPowerCalculator.sol"; +import {MockFullEarningPowerCalculatorExtended} from + "test/mocks/MockFullEarningPowerCalculatorExtended.sol"; +import { + IConsensusRegistryExtended, + IConsensusRegistry +} from "src/interfaces/IConsensusRegistryExtended.sol"; +import {ConsensusRegistryMock} from "test/mocks/ConsensusRegistryMock.sol"; contract ZkStakerTestBase is Test { ERC20Fake rewardToken; ERC20VotesMock govToken; - MockFullEarningPowerCalculator earningPowerCalculator; + MockFullEarningPowerCalculatorExtended earningPowerCalculator; ZkStaker zkStaker; address admin; + address validatorStakeAuthority; uint256 maxBumpTip; uint256 initialTotalStakeCap; string name; + uint256 initialValidatorWeightThreshold; + bool initialIsLeaderDefault; function setUp() public virtual { rewardToken = new ERC20Fake(); govToken = new ERC20VotesMock(); - earningPowerCalculator = new MockFullEarningPowerCalculator(); - admin = makeAddr("admin"); + earningPowerCalculator = new MockFullEarningPowerCalculatorExtended(); maxBumpTip = 1e18; initialTotalStakeCap = 1e24; + admin = makeAddr("admin"); + validatorStakeAuthority = makeAddr("validatorStakeAuthority"); name = "ZkStaker"; + initialValidatorWeightThreshold = 1e18; + initialIsLeaderDefault = true; + + zkStaker = new ZkStaker( + IERC20(address(rewardToken)), + IERC20Staking(address(govToken)), + IEarningPowerCalculator(address(earningPowerCalculator)), + maxBumpTip, + initialTotalStakeCap, + admin, + validatorStakeAuthority, + name, + initialValidatorWeightThreshold, + initialIsLeaderDefault + ); + } + + function assertEq( + IConsensusRegistry.BLS12_381PublicKey memory _pubKey, + IConsensusRegistry.BLS12_381PublicKey memory _expectedPubKey + ) internal pure { + assertEq(_pubKey.a, _expectedPubKey.a); + assertEq(_pubKey.b, _expectedPubKey.b); + assertEq(_pubKey.c, _expectedPubKey.c); + } + + function assertEq( + IConsensusRegistry.BLS12_381Signature memory _pop, + IConsensusRegistry.BLS12_381Signature memory _expectedPop + ) internal pure { + assertEq(_pop.a, _expectedPop.a); + assertEq(_pop.b, _expectedPop.b); + } + + /// @dev Helper function to assert that a validator is removed or, if above threshold, has a + /// specific weight. + function assertValidatorRemovedOrWeightIfAboveThreshold( + IConsensusRegistry.ValidatorAttr memory _validator, + uint256 _weight + ) internal view { + if (_weight < zkStaker.validatorWeightThreshold()) assertEq(_validator.removed, true); + else assertEq(_validator.weight, _weight); } /// @dev Helper function to validate addresses for fuzz tests @@ -47,6 +100,176 @@ contract ZkStakerTestBase is Test { vm.assume(_rewardToken != _earningPowerCalculator); vm.assume(_stakeToken != _earningPowerCalculator); } + + function _boundAndMintGovToken(address _to, uint256 _amount) internal returns (uint256) { + vm.assume(_to != address(0)); + _amount = bound(_amount, 0, zkStaker.totalStakeCap() - zkStaker.totalStaked()); + govToken.mint(_to, _amount); + return _amount; + } + + function _mintGovToken(address _to, uint256 _amount) internal { + vm.assume(_to != address(0)); + govToken.mint(_to, _amount); + } + + function _boundMintAndStake( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator + ) internal returns (uint256 _boundedAmount, ZkStaker.DepositIdentifier _depositId) { + _boundedAmount = _boundAndMintGovToken(_depositor, _amount); + + vm.startPrank(_depositor); + govToken.approve(address(zkStaker), _boundedAmount); + _depositId = zkStaker.stake(_boundedAmount, _delegatee, _claimer, _validator); + vm.stopPrank(); + } + + function _fetchDeposit(Staker.DepositIdentifier _depositId) + internal + view + returns (Staker.Deposit memory) + { + ( + uint96 _balance, + address _owner, + uint96 _earningPower, + address _delegatee, + address _claimer, + uint256 _rewardPerTokenCheckpoint, + uint256 _scaledUnclaimedRewardCheckpoint + ) = zkStaker.deposits(_depositId); + return Staker.Deposit({ + balance: _balance, + owner: _owner, + delegatee: _delegatee, + claimer: _claimer, + earningPower: _earningPower, + rewardPerTokenCheckpoint: _rewardPerTokenCheckpoint, + scaledUnclaimedRewardCheckpoint: _scaledUnclaimedRewardCheckpoint + }); + } + + function _assumeValidKeys( + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) internal pure { + vm.assume( + _validatorPubKey.a != bytes32(0) && _validatorPubKey.b != bytes32(0) + && _validatorPubKey.c != bytes32(0) + ); + vm.assume(_validatorPoP.a != bytes32(0) && _validatorPoP.b != bytes16(0)); + } + + function _assumeValidDelegateeAndClaimer(address _delegatee, address _claimer) internal pure { + vm.assume(_delegatee != address(0)); + vm.assume(_claimer != address(0)); + } + + function _setMockRegistry() internal { + ConsensusRegistryMock mockRegistry = new ConsensusRegistryMock(); + vm.prank(admin); + zkStaker.setRegistry(IConsensusRegistryExtended(address(mockRegistry))); + } + + function _registerValidator( + address _validator, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) internal { + _assumeValidKeys(_validatorPubKey, _validatorPoP); + vm.prank(_validator); + zkStaker.changeValidatorKey(_validator, _validatorPubKey, _validatorPoP); + } + + function _setRegistryAndRegisterValidatorWithBonusWeightAboveThreshold( + address _validator, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP, + uint256 _bonusWeightAboveThreshold + ) internal returns (uint256 boundedBonusWeightAboveThreshold) { + _assumeValidKeys(_validatorPubKey, _validatorPoP); + boundedBonusWeightAboveThreshold = + _boundAndSetBonusWeightAboveThreshold(_validator, _bonusWeightAboveThreshold); + _setMockRegistry(); + _registerValidator(_validator, _validatorPubKey, _validatorPoP); + } + + function _boundAndSetBonusWeightAboveThreshold( + address _validatorOwner, + uint256 _bonusWeightAboveThreshold + ) internal returns (uint256) { + _bonusWeightAboveThreshold = bound( + _bonusWeightAboveThreshold, + initialValidatorWeightThreshold, + zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + vm.prank(validatorStakeAuthority); + zkStaker.setBonusWeight(_validatorOwner, _bonusWeightAboveThreshold); + return _bonusWeightAboveThreshold; + } + + function _boundAndSetBonusWeightBelowThreshold( + address _validatorOwner, + uint256 _bonusWeightBelowThreshold + ) internal returns (uint256) { + _bonusWeightBelowThreshold = + bound(_bonusWeightBelowThreshold, 0, initialValidatorWeightThreshold - 1); + vm.prank(validatorStakeAuthority); + zkStaker.setBonusWeight(_validatorOwner, _bonusWeightBelowThreshold); + return _bonusWeightBelowThreshold; + } + + /// @notice Checks if a BLS12-381 public key is empty. + /// @param _pubKey The BLS12-381 public key to check. + /// @return True if the public key is empty, false otherwise. + function _isEmptyBLS12_381PublicKey(IConsensusRegistry.BLS12_381PublicKey memory _pubKey) + internal + pure + returns (bool) + { + return _pubKey.a == bytes32(0) && _pubKey.b == bytes32(0) && _pubKey.c == bytes32(0); + } + + /// @notice Checks if a BLS12-381 signature is empty. + /// @param _pop The BLS12-381 proof-of-possession signature to check. + /// @return True if the signature is empty, false otherwise. + function _isEmptyBLS12_381Signature(IConsensusRegistry.BLS12_381Signature memory _pop) + internal + pure + returns (bool) + { + return _pop.a == bytes32(0) && _pop.b == bytes16(0); + } + + function _sign(uint256 _privateKey, bytes32 _messageHash) internal pure returns (bytes memory) { + (uint8 _v, bytes32 _r, bytes32 _s) = vm.sign(_privateKey, _messageHash); + return abi.encodePacked(_r, _s, _v); + } + + function _modifyMessage(bytes32 _message, uint256 _index) internal pure returns (bytes32) { + _index = bound(_index, 0, 31); + bytes memory _messageBytes = abi.encodePacked(_message); + // zero out the byte at the given index, or set it to 1 if it's already zero + if (_messageBytes[_index] == 0) _messageBytes[_index] = bytes1(uint8(1)); + else _messageBytes[_index] = bytes1(uint8(0)); + return bytes32(_messageBytes); + } + + function _modifySignature(bytes memory _signature, uint256 _index) + internal + pure + returns (bytes memory) + { + _index = bound(_index, 0, _signature.length - 1); + // zero out the byte at the given index, or set it to 1 if it's already zero + if (_signature[_index] == 0) _signature[_index] = bytes1(uint8(1)); + else _signature[_index] = bytes1(uint8(0)); + return _signature; + } } contract Constructor is ZkStakerTestBase { @@ -58,7 +281,10 @@ contract Constructor is ZkStakerTestBase { maxBumpTip, initialTotalStakeCap, admin, - name + validatorStakeAuthority, + name, + initialValidatorWeightThreshold, + initialIsLeaderDefault ); assertEq(address(zkStaker.REWARD_TOKEN()), address(rewardToken)); @@ -66,6 +292,59 @@ contract Constructor is ZkStakerTestBase { assertEq(address(zkStaker.earningPowerCalculator()), address(earningPowerCalculator)); assertEq(zkStaker.maxBumpTip(), maxBumpTip); assertEq(zkStaker.admin(), admin); + assertEq(zkStaker.validatorStakeAuthority(), validatorStakeAuthority); + assertEq(zkStaker.validatorWeightThreshold(), initialValidatorWeightThreshold); + } + + function test_EmitsValidatorStakeAuthoritySetEvent() public { + vm.expectEmit(); + emit ZkStaker.ValidatorStakeAuthoritySet(address(0), validatorStakeAuthority); + zkStaker = new ZkStaker( + IERC20(address(rewardToken)), + IERC20Staking(address(govToken)), + IEarningPowerCalculator(address(earningPowerCalculator)), + maxBumpTip, + initialTotalStakeCap, + admin, + validatorStakeAuthority, + name, + initialValidatorWeightThreshold, + initialIsLeaderDefault + ); + } + + function test_EmitsIsLeaderDefaultSetEvent() public { + vm.expectEmit(); + emit ZkStaker.IsLeaderDefaultSet(false, initialIsLeaderDefault); + zkStaker = new ZkStaker( + IERC20(address(rewardToken)), + IERC20Staking(address(govToken)), + IEarningPowerCalculator(address(earningPowerCalculator)), + maxBumpTip, + initialTotalStakeCap, + admin, + validatorStakeAuthority, + name, + initialValidatorWeightThreshold, + initialIsLeaderDefault + ); + } + + function test_EmitsValidatorWeightThresholdSetEvent() public { + vm.expectEmit(); + emit ZkStaker.ValidatorWeightThresholdSet(0, initialValidatorWeightThreshold); + zkStaker = new ZkStaker( + IERC20(address(rewardToken)), + IERC20Staking(address(govToken)), + IEarningPowerCalculator(address(earningPowerCalculator)), + maxBumpTip, + initialTotalStakeCap, + admin, + validatorStakeAuthority, + name, + initialValidatorWeightThreshold, + initialIsLeaderDefault + ); } function testFuzz_SetsTheRewardTokenStakeTokenAndOwnerToArbitraryAddresses( @@ -75,7 +354,10 @@ contract Constructor is ZkStakerTestBase { uint256 _maxBumpTip, uint256 _initialTotalStakeCap, address _admin, - string memory _name + address _validatorStakeAuthority, + string memory _name, + uint256 _initialValidatorWeightThreshold, + bool _initialIsLeaderDefault ) public { _validateAddresses(_rewardToken, _stakeToken, _earningPowerCalculator, _admin); @@ -86,7 +368,10 @@ contract Constructor is ZkStakerTestBase { _maxBumpTip, _initialTotalStakeCap, _admin, - _name + _validatorStakeAuthority, + _name, + _initialValidatorWeightThreshold, + _initialIsLeaderDefault ); assertEq(address(zkStaker.REWARD_TOKEN()), _rewardToken); @@ -95,6 +380,8 @@ contract Constructor is ZkStakerTestBase { assertEq(zkStaker.maxBumpTip(), _maxBumpTip); assertEq(zkStaker.totalStakeCap(), _initialTotalStakeCap); assertEq(zkStaker.admin(), _admin); + assertEq(zkStaker.validatorStakeAuthority(), _validatorStakeAuthority); + assertEq(zkStaker.validatorWeightThreshold(), _initialValidatorWeightThreshold); } function testFuzz_SetsClaimFeeParameters( @@ -104,7 +391,10 @@ contract Constructor is ZkStakerTestBase { uint256 _maxBumpTip, uint256 _initialTotalStakeCap, address _admin, - string memory _name + address _validatorStakeAuthority, + string memory _name, + uint256 _initialValidatorWeightThreshold, + bool _initialIsLeaderDefault ) public { _validateAddresses(_rewardToken, _stakeToken, _earningPowerCalculator, _admin); @@ -115,7 +405,10 @@ contract Constructor is ZkStakerTestBase { _maxBumpTip, _initialTotalStakeCap, _admin, - _name + _validatorStakeAuthority, + _name, + _initialValidatorWeightThreshold, + _initialIsLeaderDefault ); assertEq(zkStaker.MAX_CLAIM_FEE(), 1e18); @@ -124,3 +417,1957 @@ contract Constructor is ZkStakerTestBase { assertEq(feeCollector, address(0)); } } + +contract Stake is ZkStakerTestBase { + function testFuzz_StakesTokensAndSetsValidatorAndValidatorStakeWeight( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + + _amount = _boundAndMintGovToken(_depositor, _amount); + + vm.startPrank(_depositor); + govToken.approve(address(zkStaker), _amount); + ZkStaker.DepositIdentifier _depositId = + zkStaker.stake(_amount, _delegatee, _claimer, _validator); + vm.stopPrank(); + + assertEq(zkStaker.validatorForDeposit(_depositId), _validator); + assertEq(zkStaker.validatorStakeWeight(_validator), _amount); + } + + function testFuzz_EmitsValidatorTotalWeightUpdatedEvent( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator + ) public { + vm.assume(_delegatee != address(0)); + vm.assume(_claimer != address(0)); + + _amount = _boundAndMintGovToken(_depositor, _amount); + + vm.startPrank(_depositor); + govToken.approve(address(zkStaker), _amount); + vm.expectEmit(); + emit ZkStaker.ValidatorTotalWeightUpdated(_validator, _amount); + zkStaker.stake(_amount, _delegatee, _claimer, _validator); + vm.stopPrank(); + } + + function testFuzz_AddsValidatorToRegistryWhenValidatorWeightIsAboveThreshold( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _amount = bound( + _amount, initialValidatorWeightThreshold, zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + _mintGovToken(_depositor, _amount); + _setMockRegistry(); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + + vm.startPrank(_depositor); + govToken.approve(address(zkStaker), _amount); + zkStaker.stake(_amount, _delegatee, _claimer, _validatorOwner); + vm.stopPrank(); + + IConsensusRegistry.Validator memory _validator = zkStaker.registry().validators(_validatorOwner); + IConsensusRegistry.BLS12_381PublicKey memory _pubKey = _validator.latest.pubKey; + IConsensusRegistry.BLS12_381Signature memory _pop = _validator.latest.proofOfPossession; + assertEq(_pubKey.a, _validatorPubKey.a); + assertEq(_pubKey.b, _validatorPubKey.b); + assertEq(_pubKey.c, _validatorPubKey.c); + assertEq(_pop.a, _validatorPoP.a); + assertEq(_pop.b, _validatorPoP.b); + } + + function testFuzz_UpdatesValidatorWeightOnRegistryWhenValidatorIsAlreadyRegistered( + address _depositor, + uint256 _bonusWeightAboveThreshold, + uint256 _bonusWeightBelowThreshold, + uint256 _amount, + address _delegatee, + address _claimer, + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _amount = bound( + _amount, initialValidatorWeightThreshold, zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + _mintGovToken(_depositor, _amount); + _bonusWeightAboveThreshold = _setRegistryAndRegisterValidatorWithBonusWeightAboveThreshold( + _validatorOwner, _validatorPubKey, _validatorPoP, _bonusWeightAboveThreshold + ); + _bonusWeightBelowThreshold = + _boundAndSetBonusWeightBelowThreshold(_validatorOwner, _bonusWeightBelowThreshold); + + vm.startPrank(_depositor); + govToken.approve(address(zkStaker), _amount); + zkStaker.stake(_amount, _delegatee, _claimer, _validatorOwner); + vm.stopPrank(); + + IConsensusRegistry.Validator memory _validator = zkStaker.registry().validators(_validatorOwner); + assertValidatorRemovedOrWeightIfAboveThreshold( + _validator.latest, _bonusWeightBelowThreshold + _amount + ); + } + + function testFuzz_ValidatorForAtomicEarningPowerCalculationIsSet( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator + ) public { + vm.assume(_delegatee != address(0)); + vm.assume(_claimer != address(0)); + + _amount = _boundAndMintGovToken(_depositor, _amount); + earningPowerCalculator.__setZkStakerAndTestValidatorExpectedForAtomicEarningPowerCalculation( + zkStaker, _validator + ); + + vm.startPrank(_depositor); + govToken.approve(address(zkStaker), _amount); + zkStaker.stake(_amount, _delegatee, _claimer, _validator); + vm.stopPrank(); + } + + function testFuzz_DoesNotAddValidatorToRegistryWhenValidatorWeightIsBelowThreshold( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _amount = bound(_amount, 0, initialValidatorWeightThreshold - 1); + _mintGovToken(_depositor, _amount); + _setMockRegistry(); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + + vm.startPrank(_depositor); + govToken.approve(address(zkStaker), _amount); + zkStaker.stake(_amount, _delegatee, _claimer, _validatorOwner); + vm.stopPrank(); + + IConsensusRegistry.Validator memory _validator = zkStaker.registry().validators(_validatorOwner); + assertEq(_isEmptyBLS12_381PublicKey(_validator.latest.pubKey), true); + assertEq(_isEmptyBLS12_381Signature(_validator.latest.proofOfPossession), true); + } +} + +contract StakeOnBehalf is ZkStakerTestBase { + using stdStorage for StdStorage; + + function testFuzz_CanStakeOnBehalfOfAnotherAccount( + uint256 _depositorPrivateKey, + address _sender, + uint256 _depositAmount, + address _delegatee, + address _claimer, + address _validator, + uint256 _currentNonce, + uint256 _deadline + ) public { + vm.assume(_delegatee != address(0) && _claimer != address(0) && _sender != address(0)); + _deadline = bound(_deadline, block.timestamp, type(uint256).max); + _depositorPrivateKey = bound(_depositorPrivateKey, 1, 100e18); + address _depositor = vm.addr(_depositorPrivateKey); + _depositAmount = _boundAndMintGovToken(_depositor, _depositAmount); + + stdstore.target(address(zkStaker)).sig("nonces(address)").with_key(_depositor).checked_write( + _currentNonce + ); + + vm.prank(_depositor); + govToken.approve(address(zkStaker), _depositAmount); + + bytes32 _message = keccak256( + abi.encode( + zkStaker.STAKE_WITH_VALIDATOR_TYPEHASH(), + _depositAmount, + _delegatee, + _claimer, + _validator, + _depositor, + _currentNonce, + _deadline + ) + ); + + bytes32 _messageHash = + keccak256(abi.encodePacked("\x19\x01", zkStaker.DOMAIN_SEPARATOR(), _message)); + bytes memory _signature = _sign(_depositorPrivateKey, _messageHash); + + vm.prank(_sender); + Staker.DepositIdentifier _depositId = zkStaker.stakeOnBehalf( + _depositAmount, _delegatee, _claimer, _validator, _depositor, _deadline, _signature + ); + + Staker.Deposit memory _deposit = _fetchDeposit(_depositId); + + assertEq(_deposit.balance, _depositAmount); + assertEq(_deposit.owner, _depositor); + assertEq(_deposit.delegatee, _delegatee); + assertEq(_deposit.claimer, _claimer); + } + + function testFuzz_RevertIf_WrongNonceIsUsed( + uint256 _depositorPrivateKey, + address _sender, + uint256 _depositAmount, + address _delegatee, + address _claimer, + address _validator, + uint256 _currentNonce, + uint256 _suppliedNonce, + uint256 _deadline + ) public { + vm.assume(_currentNonce != _suppliedNonce); + vm.assume(_delegatee != address(0) && _claimer != address(0) && _sender != address(0)); + _deadline = bound(_deadline, block.timestamp, type(uint256).max); + _depositorPrivateKey = bound(_depositorPrivateKey, 1, 100e18); + address _depositor = vm.addr(_depositorPrivateKey); + _depositAmount = _boundAndMintGovToken(_depositor, _depositAmount); + + stdstore.target(address(zkStaker)).sig("nonces(address)").with_key(_depositor).checked_write( + _currentNonce + ); + + vm.prank(_depositor); + govToken.approve(address(zkStaker), _depositAmount); + + bytes32 _message = keccak256( + abi.encode( + zkStaker.STAKE_WITH_VALIDATOR_TYPEHASH(), + _depositAmount, + _delegatee, + _claimer, + _validator, + _depositor, + _suppliedNonce, + _deadline + ) + ); + + bytes32 _messageHash = + keccak256(abi.encodePacked("\x19\x01", zkStaker.DOMAIN_SEPARATOR(), _message)); + bytes memory _signature = _sign(_depositorPrivateKey, _messageHash); + + vm.expectRevert(StakerOnBehalf.StakerOnBehalf__InvalidSignature.selector); + vm.prank(_sender); + zkStaker.stakeOnBehalf( + _depositAmount, _delegatee, _claimer, _validator, _depositor, _deadline, _signature + ); + } + + function testFuzz_RevertIf_DeadlineExpired( + uint256 _depositorPrivateKey, + address _sender, + uint256 _depositAmount, + address _delegatee, + address _claimer, + address _validator, + uint256 _currentNonce, + uint256 _deadline + ) public { + vm.assume(_delegatee != address(0) && _claimer != address(0) && _sender != address(0)); + _deadline = bound(_deadline, 0, block.timestamp - 1); + _depositorPrivateKey = bound(_depositorPrivateKey, 1, 100e18); + address _depositor = vm.addr(_depositorPrivateKey); + _depositAmount = _boundAndMintGovToken(_depositor, _depositAmount); + + stdstore.target(address(zkStaker)).sig("nonces(address)").with_key(_depositor).checked_write( + _currentNonce + ); + + vm.prank(_depositor); + govToken.approve(address(zkStaker), _depositAmount); + + bytes32 _message = keccak256( + abi.encode( + zkStaker.STAKE_WITH_VALIDATOR_TYPEHASH(), + _depositAmount, + _delegatee, + _claimer, + _validator, + _depositor, + _currentNonce, + _deadline + ) + ); + + bytes32 _messageHash = + keccak256(abi.encodePacked("\x19\x01", zkStaker.DOMAIN_SEPARATOR(), _message)); + bytes memory _signature = _sign(_depositorPrivateKey, _messageHash); + + vm.prank(_sender); + vm.expectRevert(StakerOnBehalf.StakerOnBehalf__ExpiredDeadline.selector); + zkStaker.stakeOnBehalf( + _depositAmount, _delegatee, _claimer, _validator, _depositor, _deadline, _signature + ); + } + + function testFuzz_RevertIf_InvalidSignatureIsPassed( + uint256 _depositorPrivateKey, + address _sender, + uint256 _depositAmount, + address _delegatee, + address _claimer, + address _validator, + uint256 _currentNonce, + uint256 _randomSeed, + uint256 _deadline + ) public { + vm.assume(_delegatee != address(0) && _claimer != address(0)); + _deadline = bound(_deadline, block.timestamp, type(uint256).max); + _depositorPrivateKey = bound(_depositorPrivateKey, 1, 100e18); + address _depositor = vm.addr(_depositorPrivateKey); + _depositAmount = _boundAndMintGovToken(_depositor, _depositAmount); + + stdstore.target(address(zkStaker)).sig("nonces(address)").with_key(_depositor).checked_write( + _currentNonce + ); + + vm.prank(_depositor); + govToken.approve(address(zkStaker), _depositAmount); + + bytes32 _message = keccak256( + abi.encode( + zkStaker.STAKE_TYPEHASH(), + _depositAmount, + _validator, + _delegatee, + _claimer, + _depositor, + zkStaker.nonces(_depositor), + _deadline + ) + ); + + bytes32 _messageHash = + keccak256(abi.encodePacked("\x19\x01", zkStaker.DOMAIN_SEPARATOR(), _message)); + + // Here we use `_randomSeed` as an arbitrary source of randomness to replace a legit parameter + // with an attack-like one. + if (_randomSeed % 6 == 0) { + _depositAmount = uint256(keccak256(abi.encode(_depositAmount))); + } else if (_randomSeed % 6 == 1) { + _delegatee = address(uint160(uint256(keccak256(abi.encode(_delegatee))))); + } else if (_randomSeed % 6 == 2) { + _depositor = address(uint160(uint256(keccak256(abi.encode(_depositor))))); + } else if (_randomSeed % 6 == 3) { + _messageHash = _modifyMessage(_messageHash, uint256(keccak256(abi.encode(_randomSeed)))); + } else if (_randomSeed % 6 == 4) { + _deadline = uint256(keccak256(abi.encode(_deadline))); + } + bytes memory _signature = _sign(_depositorPrivateKey, _messageHash); + if (_randomSeed % 6 == 5) _signature = _modifySignature(_signature, _randomSeed); + + vm.prank(_sender); + vm.expectRevert(StakerOnBehalf.StakerOnBehalf__InvalidSignature.selector); + zkStaker.stakeOnBehalf( + _depositAmount, _delegatee, _claimer, _validator, _depositor, _deadline, _signature + ); + } +} + +contract StakeMore is ZkStakerTestBase { + function testFuzz_StakesMoreTokensAndUpdatesValidatorStakeWeight( + address _depositor, + uint256 _initialAmount, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + + ZkStaker.DepositIdentifier _depositId; + (_initialAmount, _depositId) = + _boundMintAndStake(_depositor, _initialAmount, _delegatee, _claimer, _validator); + + _amount = _boundAndMintGovToken(_depositor, _amount); + vm.startPrank(_depositor); + govToken.approve(address(zkStaker), _amount); + zkStaker.stakeMore(_depositId, _amount); + vm.stopPrank(); + + assertEq(zkStaker.validatorForDeposit(_depositId), _validator); + assertEq(zkStaker.validatorStakeWeight(_validator), _initialAmount + _amount); + } + + function testFuzz_EmitsValidatorTotalWeightUpdatedEvent( + address _depositor, + uint256 _initialAmount, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator + ) public { + vm.assume(_delegatee != address(0)); + vm.assume(_claimer != address(0)); + + ZkStaker.DepositIdentifier _depositId; + (_initialAmount, _depositId) = + _boundMintAndStake(_depositor, _initialAmount, _delegatee, _claimer, _validator); + _amount = _boundAndMintGovToken(_depositor, _amount); + + vm.startPrank(_depositor); + govToken.approve(address(zkStaker), _amount); + vm.expectEmit(); + emit ZkStaker.ValidatorTotalWeightUpdated(_validator, _initialAmount + _amount); + zkStaker.stakeMore(_depositId, _amount); + vm.stopPrank(); + } + + function testFuzz_AddsValidatorToRegistryWhenValidatorWeightIsAboveThreshold( + address _depositor, + uint256 _amount, + uint256 _stakeMoreAmountAboveThreshold, + address _delegatee, + address _claimer, + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _amount = _boundAndMintGovToken(_depositor, _amount); + _setMockRegistry(); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + ZkStaker.DepositIdentifier _depositId; + _amount = bound(_amount, 0, initialValidatorWeightThreshold - 1); + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validatorOwner); + + _stakeMoreAmountAboveThreshold = bound( + _stakeMoreAmountAboveThreshold, + initialValidatorWeightThreshold, + zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + _mintGovToken(_depositor, _stakeMoreAmountAboveThreshold); + vm.startPrank(_depositor); + govToken.approve(address(zkStaker), _stakeMoreAmountAboveThreshold); + zkStaker.stakeMore(_depositId, _stakeMoreAmountAboveThreshold); + vm.stopPrank(); + + IConsensusRegistry.Validator memory _validator = zkStaker.registry().validators(_validatorOwner); + IConsensusRegistry.BLS12_381PublicKey memory _pubKey = _validator.latest.pubKey; + IConsensusRegistry.BLS12_381Signature memory _pop = _validator.latest.proofOfPossession; + assertEq(_pubKey.a, _validatorPubKey.a); + assertEq(_pubKey.b, _validatorPubKey.b); + assertEq(_pubKey.c, _validatorPubKey.c); + assertEq(_pop.a, _validatorPoP.a); + assertEq(_pop.b, _validatorPoP.b); + assertEq(_validator.latest.weight, _amount + _stakeMoreAmountAboveThreshold); + } + + function testFuzz_UpdatesValidatorWeightOnRegistryWhenValidatorIsAlreadyRegistered( + address _depositor, + uint256 _amount, + uint256 _stakeMoreAmountAboveThreshold, + address _delegatee, + address _claimer, + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _stakeMoreAmountAboveThreshold = bound( + _stakeMoreAmountAboveThreshold, + initialValidatorWeightThreshold, + zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + _setMockRegistry(); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + ZkStaker.DepositIdentifier _depositId; + (_stakeMoreAmountAboveThreshold, _depositId) = _boundMintAndStake( + _depositor, _stakeMoreAmountAboveThreshold, _delegatee, _claimer, _validatorOwner + ); + + _amount = _boundAndMintGovToken(_depositor, _amount); + _mintGovToken(_depositor, _amount); + vm.startPrank(_depositor); + govToken.approve(address(zkStaker), _amount); + zkStaker.stakeMore(_depositId, _amount); + vm.stopPrank(); + + IConsensusRegistry.Validator memory _validator = zkStaker.registry().validators(_validatorOwner); + assertValidatorRemovedOrWeightIfAboveThreshold( + _validator.latest, _stakeMoreAmountAboveThreshold + _amount + ); + } + + function testFuzz_DoesNotAddValidatorToRegistryWhenValidatorWeightIsBelowThreshold( + address _depositor, + uint256 _amount, + uint256 _stakeMoreAmountAboveThreshold, + address _delegatee, + address _claimer, + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _amount = _boundAndMintGovToken(_depositor, _amount); + _setMockRegistry(); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + ZkStaker.DepositIdentifier _depositId; + _amount = bound(_amount, 0, initialValidatorWeightThreshold - 1); + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validatorOwner); + + _stakeMoreAmountAboveThreshold = + bound(_stakeMoreAmountAboveThreshold, 0, initialValidatorWeightThreshold - _amount - 1); + _mintGovToken(_depositor, _stakeMoreAmountAboveThreshold); + vm.startPrank(_depositor); + govToken.approve(address(zkStaker), _stakeMoreAmountAboveThreshold); + zkStaker.stakeMore(_depositId, _stakeMoreAmountAboveThreshold); + vm.stopPrank(); + + IConsensusRegistry.Validator memory _validator = zkStaker.registry().validators(_validatorOwner); + IConsensusRegistry.BLS12_381PublicKey memory _pubKey = _validator.latest.pubKey; + IConsensusRegistry.BLS12_381Signature memory _pop = _validator.latest.proofOfPossession; + assertEq(_isEmptyBLS12_381PublicKey(_pubKey), true); + assertEq(_isEmptyBLS12_381Signature(_pop), true); + } + + function testFuzz_ValidatorForAtomicEarningPowerCalculationIsSet( + address _depositor, + uint256 _initialAmount, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator + ) public { + vm.assume(_delegatee != address(0)); + vm.assume(_claimer != address(0)); + + ZkStaker.DepositIdentifier _depositId; + (_initialAmount, _depositId) = + _boundMintAndStake(_depositor, _initialAmount, _delegatee, _claimer, _validator); + + earningPowerCalculator.__setZkStakerAndTestValidatorExpectedForAtomicEarningPowerCalculation( + zkStaker, _validator + ); + + _amount = _boundAndMintGovToken(_depositor, _amount); + vm.startPrank(_depositor); + govToken.approve(address(zkStaker), _amount); + zkStaker.stakeMore(_depositId, _amount); + vm.stopPrank(); + } +} + +contract Withdraw is ZkStakerTestBase { + function testFuzz_DecreasesValidatorStakeWeight( + address _depositor, + uint256 _amount, + uint256 _withdrawAmount, + address _delegatee, + address _claimer, + address _validator + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + vm.assume(_validator != address(0)); + + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + _withdrawAmount = bound(_withdrawAmount, 0, _amount); + + vm.prank(_depositor); + zkStaker.withdraw(_depositId, _withdrawAmount); + + assertEq(zkStaker.validatorStakeWeight(_validator), _amount - _withdrawAmount); + } + + function testFuzz_EmitsValidatorTotalWeightUpdatedEvent( + address _depositor, + uint256 _amount, + uint256 _withdrawAmount, + address _delegatee, + address _claimer, + address _validator + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + vm.assume(_validator != address(0)); + + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + _withdrawAmount = bound(_withdrawAmount, 0, _amount); + + vm.expectEmit(); + emit ZkStaker.ValidatorTotalWeightUpdated(_validator, _amount - _withdrawAmount); + vm.prank(_depositor); + zkStaker.withdraw(_depositId, _withdrawAmount); + } + + function testFuzz_UpdatesValidatorWeightOnRegistryWhenValidatorIsAlreadyRegistered( + address _depositor, + uint256 _stakeAmount, + uint256 _withdrawAmount, + address _delegatee, + address _claimer, + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + vm.assume(_validatorOwner != address(0)); + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _setMockRegistry(); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + _stakeAmount = bound( + _stakeAmount, + initialValidatorWeightThreshold, + zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + ZkStaker.DepositIdentifier _depositId; + (_stakeAmount, _depositId) = + _boundMintAndStake(_depositor, _stakeAmount, _delegatee, _claimer, _validatorOwner); + _withdrawAmount = bound(_withdrawAmount, 0, _stakeAmount); + + vm.prank(_depositor); + zkStaker.withdraw(_depositId, _withdrawAmount); + + IConsensusRegistry.Validator memory _validator = zkStaker.registry().validators(_validatorOwner); + assertValidatorRemovedOrWeightIfAboveThreshold( + _validator.latest, _stakeAmount - _withdrawAmount + ); + } + + function testFuzz_RemovesValidatorFromRegistryWhenValidatorIsAlreadyRegisteredButBelowThreshold( + address _depositor, + uint256 _stakeAmount, + uint256 _withdrawAmount, + address _delegatee, + address _claimer, + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + vm.assume(_validatorOwner != address(0)); + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _setMockRegistry(); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + _stakeAmount = bound( + _stakeAmount, + initialValidatorWeightThreshold, + zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + ZkStaker.DepositIdentifier _depositId; + (_stakeAmount, _depositId) = + _boundMintAndStake(_depositor, _stakeAmount, _delegatee, _claimer, _validatorOwner); + _withdrawAmount = + bound(_withdrawAmount, _stakeAmount - initialValidatorWeightThreshold + 1, _stakeAmount); + + vm.prank(_depositor); + zkStaker.withdraw(_depositId, _withdrawAmount); + + IConsensusRegistry.Validator memory _validator = zkStaker.registry().validators(_validatorOwner); + assertEq(_validator.latest.removed, true); + } + + function testFuzz_ValidatorForAtomicEarningPowerCalculationIsSet( + address _depositor, + uint256 _amount, + uint256 _withdrawAmount, + address _delegatee, + address _claimer, + address _validator + ) public { + vm.assume(_delegatee != address(0)); + vm.assume(_claimer != address(0)); + vm.assume(_validator != address(0)); + + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + _withdrawAmount = bound(_withdrawAmount, 0, _amount); + + earningPowerCalculator.__setZkStakerAndTestValidatorExpectedForAtomicEarningPowerCalculation( + zkStaker, _validator + ); + + vm.prank(_depositor); + zkStaker.withdraw(_depositId, _withdrawAmount); + } +} + +contract AlterValidator is ZkStakerTestBase { + function testFuzz_ChangesTheValidatorOfTheAssociatedDeposit( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator, + address _newValidator + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + + vm.prank(_depositor); + zkStaker.alterValidator(_depositId, _newValidator); + + assertEq(zkStaker.validatorForDeposit(_depositId), _newValidator); + } + + function testFuzz_EmitsValidatorAlteredEvent( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator, + address _newValidator + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + vm.assume(_validator != _newValidator); + + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + + vm.expectEmit(); + emit ZkStaker.ValidatorAltered(_depositId, _validator, _newValidator, _amount); + vm.prank(_depositor); + zkStaker.alterValidator(_depositId, _newValidator); + } + + function testFuzz_ChangesTheStakeWeightOfTheOldAndNewValidator( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator, + address _newValidator + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + vm.assume(_validator != _newValidator); + + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + uint256 _previousValidatorStakeWeight = zkStaker.validatorStakeWeight(_validator); + vm.prank(_depositor); + zkStaker.alterValidator(_depositId, _newValidator); + assertEq(zkStaker.validatorStakeWeight(_validator), _previousValidatorStakeWeight - _amount); + assertEq(zkStaker.validatorStakeWeight(_newValidator), _amount); + } + + function testFuzz_EmitsValidatorTotalWeightUpdatedEvent( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator, + address _newValidator + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + uint256 _previousValidatorStakeWeight = zkStaker.validatorStakeWeight(_validator); + + vm.prank(_depositor); + vm.expectEmit(); + emit ZkStaker.ValidatorTotalWeightUpdated(_validator, _previousValidatorStakeWeight - _amount); + vm.expectEmit(); + emit ZkStaker.ValidatorTotalWeightUpdated(_newValidator, _amount); + zkStaker.alterValidator(_depositId, _newValidator); + } + + function testFuzz_AllowsTheDepositorToReiterateTheirExistingValidator( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + uint256 _previousValidatorStakeWeight = zkStaker.validatorStakeWeight(_validator); + + vm.prank(_depositor); + zkStaker.alterValidator(_depositId, _validator); + + assertEq(_previousValidatorStakeWeight, _amount); + assertEq(zkStaker.validatorStakeWeight(_validator), _amount); + } + + function testFuzz_AddsValidatorToRegistryWhenValidatorIsNotRegisteredAndAboveThreshold( + address _depositor, + uint256 _stakeAmountAboveThreshold, + address _delegatee, + address _claimer, + address _validator, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _setMockRegistry(); + _registerValidator(_validator, _validatorPubKey, _validatorPoP); + _stakeAmountAboveThreshold = bound( + _stakeAmountAboveThreshold, + initialValidatorWeightThreshold, + zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + ZkStaker.DepositIdentifier _depositId; + (, _depositId) = + _boundMintAndStake(_depositor, _stakeAmountAboveThreshold, _delegatee, _claimer, _validator); + + vm.prank(_depositor); + zkStaker.alterValidator(_depositId, _validator); + + IConsensusRegistry.Validator memory _currentValidator = + zkStaker.registry().validators(_validator); + assertEq(_currentValidator.latest.weight, _stakeAmountAboveThreshold); + } + + function testFuzz_ChangesValidatorWeightOnRegistryWhenValidatorIsAlreadyRegistered( + address _depositor, + uint256 _amount, + uint256 _bonusWeightAboveThreshold, + address _delegatee, + address _claimer, + address _validator, + address _newValidator, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP, + IConsensusRegistry.BLS12_381PublicKey calldata _newValidatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _newValidatorPoP + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + vm.assume(_validator != _newValidator); + _amount = bound( + _amount, initialValidatorWeightThreshold, zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + _setMockRegistry(); + _registerValidator(_validator, _validatorPubKey, _validatorPoP); + _bonusWeightAboveThreshold = _setRegistryAndRegisterValidatorWithBonusWeightAboveThreshold( + _newValidator, _newValidatorPubKey, _newValidatorPoP, _bonusWeightAboveThreshold + ); + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + + vm.prank(_depositor); + zkStaker.alterValidator(_depositId, _newValidator); + + IConsensusRegistry.Validator memory _previousValidator = + zkStaker.registry().validators(_validator); + IConsensusRegistry.Validator memory _currentValidator = + zkStaker.registry().validators(_newValidator); + assertValidatorRemovedOrWeightIfAboveThreshold(_previousValidator.latest, 0); + assertEq(_currentValidator.latest.weight, _amount + _bonusWeightAboveThreshold); + } + + function testFuzz_RemovesValidatorFromRegistryWhenValidatorRegisteredButBelowThreshold( + address _depositor, + uint256 _amount, + uint256 _bonusWeightAboveThreshold, + address _delegatee, + address _claimer, + address _validator, + address _newValidator, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP, + IConsensusRegistry.BLS12_381PublicKey calldata _newValidatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _newValidatorPoP + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + vm.assume(_validator != _newValidator); + _amount = bound( + _amount, initialValidatorWeightThreshold, zkStaker.totalStakeCap() - zkStaker.totalStaked() + ); + _setMockRegistry(); + _registerValidator(_validator, _validatorPubKey, _validatorPoP); + _bonusWeightAboveThreshold = _setRegistryAndRegisterValidatorWithBonusWeightAboveThreshold( + _newValidator, _newValidatorPubKey, _newValidatorPoP, _bonusWeightAboveThreshold + ); + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + + vm.prank(_depositor); + zkStaker.alterValidator(_depositId, _newValidator); + + IConsensusRegistry.Validator memory _previousValidator = + zkStaker.registry().validators(_validator); + assertEq(_previousValidator.latest.removed, true); + } + + function testFuzz_UpdatesDepositEarningPower( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator, + address _newValidator, + uint96 _newEarningPower + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + earningPowerCalculator.__setEarningPowerForDelegatee(_delegatee, _newEarningPower); + + vm.prank(_depositor); + zkStaker.alterValidator(_depositId, _newValidator); + + Staker.Deposit memory _deposit = _fetchDeposit(_depositId); + assertEq(_deposit.earningPower, _newEarningPower); + } + + function testFuzz_UpdatesGlobalTotalEarningPower( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator, + address _newValidator, + uint96 _newEarningPower + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + earningPowerCalculator.__setEarningPowerForDelegatee(_delegatee, _newEarningPower); + + vm.prank(_depositor); + zkStaker.alterValidator(_depositId, _newValidator); + + assertEq(zkStaker.totalEarningPower(), _newEarningPower); + } + + function testFuzz_UpdatesDepositorTotalEarningPower( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator, + address _newValidator, + uint96 _newEarningPower + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + earningPowerCalculator.__setEarningPowerForDelegatee(_delegatee, _newEarningPower); + + vm.prank(_depositor); + zkStaker.alterValidator(_depositId, _newValidator); + + assertEq(zkStaker.depositorTotalEarningPower(_depositor), _newEarningPower); + } + + function testFuzz_ValidatorForAtomicEarningPowerCalculationIsSet( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator, + address _newValidator + ) public { + vm.assume(_delegatee != address(0)); + vm.assume(_claimer != address(0)); + + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + + earningPowerCalculator.__setZkStakerAndTestValidatorExpectedForAtomicEarningPowerCalculation( + zkStaker, _newValidator + ); + + vm.prank(_depositor); + zkStaker.alterValidator(_depositId, _newValidator); + } + + function testFuzz_RevertIf_NotDepositOwner( + address _depositor, + address _notDepositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator, + address _newValidator + ) public { + vm.assume(_notDepositor != _depositor); + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + + vm.expectRevert( + abi.encodeWithSelector( + Staker.Staker__Unauthorized.selector, bytes32("not owner"), _notDepositor + ) + ); + vm.prank(_notDepositor); + zkStaker.alterValidator(_depositId, _newValidator); + } + + function testFuzz_RevertIf_TheDepositIdentifierIsInvalid( + address _depositor, + Staker.DepositIdentifier _invalidDepositId, + address _newValidator + ) public { + vm.assume(_depositor != address(0)); + + vm.expectRevert( + abi.encodeWithSelector(Staker.Staker__Unauthorized.selector, bytes32("not owner"), _depositor) + ); + vm.prank(_depositor); + zkStaker.alterValidator(_invalidDepositId, _newValidator); + } + + function testFuzz_SetsScaledEarningPowerWhenCalculatorScalesStakeAmount( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator, + address _newValidator, + uint256 _multiplierBips + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _multiplierBips = bound(_multiplierBips, 0, 20_000); + earningPowerCalculator.__setMultiplierBips(_multiplierBips); + + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + + vm.prank(_depositor); + zkStaker.alterValidator(_depositId, _newValidator); + + uint256 _expectedEarningPower = (_amount * _multiplierBips) / 10_000; + Staker.Deposit memory _deposit = _fetchDeposit(_depositId); + assertEq(_deposit.earningPower, _expectedEarningPower); + assertEq(zkStaker.totalEarningPower(), _expectedEarningPower); + assertEq(zkStaker.depositorTotalEarningPower(_depositor), _expectedEarningPower); + } + + function testFuzz_SetsFixedEarningPowerWhenCalculatorReturnsConstantAmount( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator, + address _newValidator, + uint256 _fixedEarningPower + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _fixedEarningPower = bound(_fixedEarningPower, 0.1e18, 25_000_000e18); + + earningPowerCalculator.__setFixedReturn(_fixedEarningPower); + + ZkStaker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + + vm.prank(_depositor); + zkStaker.alterValidator(_depositId, _newValidator); + + Staker.Deposit memory _deposit = _fetchDeposit(_depositId); + assertEq(_deposit.earningPower, _fixedEarningPower); + assertEq(zkStaker.totalEarningPower(), _fixedEarningPower); + assertEq(zkStaker.depositorTotalEarningPower(_depositor), _fixedEarningPower); + } +} + +contract AlterValidatorOnBehalf is ZkStakerTestBase { + using stdStorage for StdStorage; + + function testFuzz_CanAlterValidatorBehalfOfAnotherAccount( + uint256 _depositorPrivateKey, + uint256 _amount, + address _sender, + address _delegatee, + address _claimer, + address _validator, + address _newValidator, + uint256 _currentNonce, + uint256 _deadline + ) public { + vm.assume(_delegatee != address(0) && _claimer != address(0) && _sender != address(0)); + _deadline = bound(_deadline, block.timestamp, type(uint256).max); + _depositorPrivateKey = bound(_depositorPrivateKey, 1, 100e18); + address _depositor = vm.addr(_depositorPrivateKey); + (, ZkStaker.DepositIdentifier _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + + assertEq(zkStaker.validatorForDeposit(_depositId), _validator); + stdstore.target(address(zkStaker)).sig("nonces(address)").with_key(_depositor).checked_write( + _currentNonce + ); + + bytes32 _message = keccak256( + abi.encode( + zkStaker.ALTER_VALIDATOR_TYPEHASH(), + _depositId, + _newValidator, + _depositor, + _currentNonce, + _deadline + ) + ); + + bytes32 _messageHash = + keccak256(abi.encodePacked("\x19\x01", zkStaker.DOMAIN_SEPARATOR(), _message)); + bytes memory _signature = _sign(_depositorPrivateKey, _messageHash); + + vm.prank(_sender); + zkStaker.alterValidatorOnBehalf(_depositId, _newValidator, _depositor, _deadline, _signature); + + assertEq(zkStaker.validatorForDeposit(_depositId), _newValidator); + } + + function testFuzz_RevertIf_WrongNonceIsUsed( + uint256 _depositorPrivateKey, + uint256 _amount, + address _sender, + address _delegatee, + address _claimer, + address _validator, + address _newValidator, + uint256 _currentNonce, + uint256 _suppliedNonce, + uint256 _deadline + ) public { + vm.assume(_currentNonce != _suppliedNonce); + vm.assume(_delegatee != address(0) && _claimer != address(0) && _sender != address(0)); + _deadline = bound(_deadline, block.timestamp, type(uint256).max); + _depositorPrivateKey = bound(_depositorPrivateKey, 1, 100e18); + address _depositor = vm.addr(_depositorPrivateKey); + (, ZkStaker.DepositIdentifier _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + + assertEq(zkStaker.validatorForDeposit(_depositId), _validator); + stdstore.target(address(zkStaker)).sig("nonces(address)").with_key(_depositor).checked_write( + _currentNonce + ); + + bytes32 _message = keccak256( + abi.encode( + zkStaker.ALTER_VALIDATOR_TYPEHASH(), + _depositId, + _newValidator, + _depositor, + _suppliedNonce, + _deadline + ) + ); + + bytes32 _messageHash = + keccak256(abi.encodePacked("\x19\x01", zkStaker.DOMAIN_SEPARATOR(), _message)); + bytes memory _signature = _sign(_depositorPrivateKey, _messageHash); + + vm.prank(_sender); + vm.expectRevert(StakerOnBehalf.StakerOnBehalf__InvalidSignature.selector); + zkStaker.alterValidatorOnBehalf(_depositId, _newValidator, _depositor, _deadline, _signature); + } + + function testFuzz_RevertIf_DeadlineExpired( + uint256 _depositorPrivateKey, + uint256 _amount, + address _sender, + address _delegatee, + address _claimer, + address _validator, + address _newValidator, + uint256 _currentNonce, + uint256 _deadline + ) public { + vm.assume(_delegatee != address(0) && _claimer != address(0) && _sender != address(0)); + _deadline = bound(_deadline, 0, block.timestamp - 1); + _depositorPrivateKey = bound(_depositorPrivateKey, 1, 100e18); + address _depositor = vm.addr(_depositorPrivateKey); + (, ZkStaker.DepositIdentifier _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + + assertEq(zkStaker.validatorForDeposit(_depositId), _validator); + stdstore.target(address(zkStaker)).sig("nonces(address)").with_key(_depositor).checked_write( + _currentNonce + ); + + bytes32 _message = keccak256( + abi.encode( + zkStaker.ALTER_VALIDATOR_TYPEHASH(), + _depositId, + _newValidator, + _depositor, + _currentNonce, + _deadline + ) + ); + + bytes32 _messageHash = + keccak256(abi.encodePacked("\x19\x01", zkStaker.DOMAIN_SEPARATOR(), _message)); + bytes memory _signature = _sign(_depositorPrivateKey, _messageHash); + + vm.prank(_sender); + vm.expectRevert(StakerOnBehalf.StakerOnBehalf__ExpiredDeadline.selector); + zkStaker.alterValidatorOnBehalf(_depositId, _newValidator, _depositor, _deadline, _signature); + } + + function testFuzz_RevertIf_InvalidSignatureIsPassed( + uint256 _depositorPrivateKey, + address _sender, + uint256 _depositAmount, + address _delegatee, + address _claimer, + address _validator, + address _newValidator, + uint256 _currentNonce, + uint256 _randomSeed, + uint256 _deadline + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + _deadline = bound(_deadline, block.timestamp, type(uint256).max); + _depositorPrivateKey = bound(_depositorPrivateKey, 1, 100e18); + address _depositor = vm.addr(_depositorPrivateKey); + (, ZkStaker.DepositIdentifier _depositId) = + _boundMintAndStake(_depositor, _depositAmount, _delegatee, _claimer, _validator); + + stdstore.target(address(zkStaker)).sig("nonces(address)").with_key(_depositor).checked_write( + _currentNonce + ); + + bytes32 _message = keccak256( + abi.encode( + zkStaker.ALTER_VALIDATOR_TYPEHASH(), + _depositId, + _newValidator, + _depositor, + _currentNonce, + _deadline + ) + ); + + bytes32 _messageHash = + keccak256(abi.encodePacked("\x19\x01", zkStaker.DOMAIN_SEPARATOR(), _message)); + + // Here we use `_randomSeed` as an arbitrary source of randomness to replace a legit parameter + // with an attack-like one. + if (_randomSeed % 5 == 0) { + _newValidator = address(uint160(uint256(keccak256(abi.encode(_newValidator))))); + } else if (_randomSeed % 5 == 1) { + _depositor = address(uint160(uint256(keccak256(abi.encode(_depositor))))); + } else if (_randomSeed % 5 == 2) { + _messageHash = _modifyMessage(_messageHash, uint256(keccak256(abi.encode(_randomSeed)))); + } else if (_randomSeed % 5 == 3) { + _deadline = uint256(keccak256(abi.encode(_deadline))); + } + bytes memory _signature = _sign(_depositorPrivateKey, _messageHash); + if (_randomSeed % 5 == 4) _signature = _modifySignature(_signature, _randomSeed); + + vm.expectRevert(StakerOnBehalf.StakerOnBehalf__InvalidSignature.selector); + vm.prank(_sender); + zkStaker.alterValidatorOnBehalf(_depositId, _newValidator, _depositor, _deadline, _signature); + } +} + +contract AlterClaimer is ZkStakerTestBase { + function testFuzz_SetsValidatorForAtomicEarningPowerCalculation( + address _depositor, + uint256 _depositAmount, + address _delegatee, + address _firstClaimer, + address _newClaimer, + address _validator + ) public { + vm.assume(_delegatee != address(0)); + vm.assume(_firstClaimer != address(0)); + vm.assume(_newClaimer != address(0) && _newClaimer != _firstClaimer); + + Staker.DepositIdentifier _depositId; + (_depositAmount, _depositId) = + _boundMintAndStake(_depositor, _depositAmount, _delegatee, _firstClaimer, _validator); + earningPowerCalculator.__setZkStakerAndTestValidatorExpectedForAtomicEarningPowerCalculation( + zkStaker, _validator + ); + + vm.prank(_depositor); + zkStaker.alterClaimer(_depositId, _newClaimer); + } +} + +contract ClaimReward is ZkStakerTestBase { + function testFuzz_DepositorReceivesRewardsWhenClaiming( + address _depositor, + uint256 _amount, + address _delegatee, + address _claimer, + address _validator + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + + Staker.DepositIdentifier _depositId; + (_amount, _depositId) = + _boundMintAndStake(_depositor, _amount, _delegatee, _claimer, _validator); + + earningPowerCalculator.__setZkStakerAndTestValidatorExpectedForAtomicEarningPowerCalculation( + zkStaker, _validator + ); + + vm.prank(_depositor); + zkStaker.claimReward(_depositId); + } +} + +contract SetValidatorStakeAuthority is ZkStakerTestBase { + function testFuzz_SetsValidatorStakeAuthority(address _newAuthority) public { + vm.prank(admin); + zkStaker.setValidatorStakeAuthority(_newAuthority); + assertEq(zkStaker.validatorStakeAuthority(), _newAuthority); + } + + function testFuzz_EmitsValidatorStakeAuthoritySetEvent(address _newAuthority) public { + vm.expectEmit(); + emit ZkStaker.ValidatorStakeAuthoritySet(validatorStakeAuthority, _newAuthority); + vm.prank(admin); + zkStaker.setValidatorStakeAuthority(_newAuthority); + } + + function testFuzz_RevertIf_NotAdmin(address _caller, address _newAuthority) public { + vm.assume(_caller != admin); + vm.expectRevert( + abi.encodeWithSelector(Staker.Staker__Unauthorized.selector, bytes32("not admin"), _caller) + ); + vm.prank(_caller); + zkStaker.setValidatorStakeAuthority(_newAuthority); + } +} + +contract SetBonusWeight is ZkStakerTestBase { + function testFuzz_SetsBonusWeight(address _validator, uint256 _newBonusWeight) public { + vm.prank(validatorStakeAuthority); + zkStaker.setBonusWeight(_validator, _newBonusWeight); + assertEq(zkStaker.validatorBonusWeight(_validator), _newBonusWeight); + } + + function testFuzz_EmitsValidatorBonusWeightSetEvent(address _validator, uint256 _newBonusWeight) + public + { + vm.expectEmit(); + emit ZkStaker.ValidatorBonusWeightSet(_validator, _newBonusWeight); + vm.prank(validatorStakeAuthority); + zkStaker.setBonusWeight(_validator, _newBonusWeight); + } + + function testFuzz_EmitsValidatorTotalWeightUpdatedEvent( + address _validator, + uint256 _newBonusWeight + ) public { + vm.expectEmit(); + emit ZkStaker.ValidatorTotalWeightUpdated(_validator, _newBonusWeight); + vm.prank(validatorStakeAuthority); + zkStaker.setBonusWeight(_validator, _newBonusWeight); + } + + function testFuzz_AddsValidatorToRegistryWhenBonusWeightIsAboveThreshold( + address _validatorOwner, + uint256 _bonusWeightAboveThreshold, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _setMockRegistry(); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + _bonusWeightAboveThreshold = + _boundAndSetBonusWeightAboveThreshold(_validatorOwner, _bonusWeightAboveThreshold); + + IConsensusRegistry.Validator memory _validator = zkStaker.registry().validators(_validatorOwner); + assertEq(_validator.latest.weight, _bonusWeightAboveThreshold); + } + + function testFuzz_ChangesValidatorWeightOnRegistryWhenItIsAlreadyRegistered( + address _validatorOwner, + uint256 _bonusWeightAboveThreshold, + uint256 _newBonusWeight, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _setRegistryAndRegisterValidatorWithBonusWeightAboveThreshold( + _validatorOwner, _validatorPubKey, _validatorPoP, _bonusWeightAboveThreshold + ); + + vm.prank(validatorStakeAuthority); + zkStaker.setBonusWeight(_validatorOwner, _newBonusWeight); + + IConsensusRegistry.Validator memory _validator = zkStaker.registry().validators(_validatorOwner); + assertValidatorRemovedOrWeightIfAboveThreshold(_validator.latest, _newBonusWeight); + } + + function testFuzz_RemovesValidatorFromRegistryWhenBonusWeightIsBelowThreshold( + address _validatorOwner, + uint256 _bonusWeightAboveThreshold, + uint256 _bonusWeightBelowThreshold, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _setRegistryAndRegisterValidatorWithBonusWeightAboveThreshold( + _validatorOwner, _validatorPubKey, _validatorPoP, _bonusWeightAboveThreshold + ); + _boundAndSetBonusWeightBelowThreshold(_validatorOwner, _bonusWeightBelowThreshold); + + IConsensusRegistry.Validator memory _validator = zkStaker.registry().validators(_validatorOwner); + assertEq(_validator.latest.removed, true); + } + + function testFuzz_RevertIf_NotValidatorStakeAuthority( + address _caller, + address _validator, + uint256 _newBonusWeight + ) public { + vm.assume(_caller != validatorStakeAuthority); + vm.expectRevert( + abi.encodeWithSelector( + Staker.Staker__Unauthorized.selector, bytes32("not validator stake authority"), _caller + ) + ); + vm.prank(_caller); + zkStaker.setBonusWeight(_validator, _newBonusWeight); + } +} + +contract SetIsLeaderDefault is ZkStakerTestBase { + function testFuzz_SetsIsLeaderDefault(bool _isLeaderDefault) public { + vm.prank(validatorStakeAuthority); + zkStaker.setIsLeaderDefault(_isLeaderDefault); + assertEq(zkStaker.isLeaderDefault(), _isLeaderDefault); + } + + function testFuzz_EmitsIsLeaderDefaultSetEvent(bool _isLeaderDefault) public { + vm.expectEmit(); + emit ZkStaker.IsLeaderDefaultSet(zkStaker.isLeaderDefault(), _isLeaderDefault); + vm.prank(validatorStakeAuthority); + zkStaker.setIsLeaderDefault(_isLeaderDefault); + } + + function testFuzz_RevertIf_NotValidatorStakeAuthority(address _caller, bool _isLeaderDefault) + public + { + vm.assume(_caller != validatorStakeAuthority); + vm.expectRevert( + abi.encodeWithSelector( + Staker.Staker__Unauthorized.selector, bytes32("not validator stake authority"), _caller + ) + ); + vm.prank(_caller); + zkStaker.setIsLeaderDefault(_isLeaderDefault); + } +} + +contract SetValidatorWeightThreshold is ZkStakerTestBase { + function testFuzz_SetsValidatorWeightThreshold(uint256 _newValidatorWeightThreshold) public { + vm.prank(admin); + zkStaker.setValidatorWeightThreshold(_newValidatorWeightThreshold); + assertEq(zkStaker.validatorWeightThreshold(), _newValidatorWeightThreshold); + } + + function testFuzz_EmitsValidatorWeightThresholdSetEvent(uint256 _newValidatorWeightThreshold) + public + { + vm.expectEmit(); + emit ZkStaker.ValidatorWeightThresholdSet( + zkStaker.validatorWeightThreshold(), _newValidatorWeightThreshold + ); + vm.prank(admin); + zkStaker.setValidatorWeightThreshold(_newValidatorWeightThreshold); + } + + function testFuzz_RevertIf_NotAdmin(address _caller, uint256 _newValidatorWeightThreshold) public { + vm.assume(_caller != admin); + vm.expectRevert( + abi.encodeWithSelector(Staker.Staker__Unauthorized.selector, bytes32("not admin"), _caller) + ); + vm.prank(_caller); + zkStaker.setValidatorWeightThreshold(_newValidatorWeightThreshold); + } +} + +contract ValidatorTotalWeight is ZkStakerTestBase { + function testFuzz_ReturnsTheSumOfValidatorStakeWeightAndBonusWeight( + address _depositor, + address _validator, + address _delegatee, + address _claimer, + uint256 _stakeWeight, + uint256 _bonusWeight + ) public { + _assumeValidDelegateeAndClaimer(_delegatee, _claimer); + (uint256 boundedStakeWeight,) = + _boundMintAndStake(_depositor, _stakeWeight, _delegatee, _claimer, _validator); + _bonusWeight = bound(_bonusWeight, 0, type(uint256).max - boundedStakeWeight); + vm.prank(validatorStakeAuthority); + zkStaker.setBonusWeight(_validator, _bonusWeight); + + uint256 expectedTotalWeight = boundedStakeWeight + _bonusWeight; + assertEq(zkStaker.validatorTotalWeight(_validator), expectedTotalWeight); + } + + function testFuzz_ReturnsCorrectTotalWeightWhenChangingBonusWeightAndAddingStake( + address _depositor, + address _validator, + address _delegatee, + address _claimer, + uint256 _initialStakeWeight, + uint256 _additionalStakeWeight, + uint256 _initialBonusWeight, + uint256 _newBonusWeight + ) public { + vm.assume(_delegatee != address(0)); + vm.assume(_claimer != address(0)); + (uint256 boundedInitialStakeWeight,) = + _boundMintAndStake(_depositor, _initialStakeWeight, _delegatee, _claimer, _validator); + _initialBonusWeight = + bound(_initialBonusWeight, 0, type(uint248).max - boundedInitialStakeWeight); + vm.prank(validatorStakeAuthority); + zkStaker.setBonusWeight(_validator, _initialBonusWeight); + + (uint256 boundedAdditionalStakeWeight,) = + _boundMintAndStake(_depositor, _additionalStakeWeight, _delegatee, _claimer, _validator); + _newBonusWeight = bound( + _newBonusWeight, + 0, + type(uint256).max - (boundedInitialStakeWeight + boundedAdditionalStakeWeight) + ); + vm.prank(validatorStakeAuthority); + zkStaker.setBonusWeight(_validator, _newBonusWeight); + + uint256 expectedTotalWeight = + boundedInitialStakeWeight + boundedAdditionalStakeWeight + _newBonusWeight; + assertEq(zkStaker.validatorTotalWeight(_validator), expectedTotalWeight); + } +} + +contract SetRegistry is ZkStakerTestBase { + function testFuzz_AdminSetsRegistry(IConsensusRegistryExtended _newRegistry) public { + vm.prank(admin); + zkStaker.setRegistry(_newRegistry); + assertEq(address(zkStaker.registry()), address(_newRegistry)); + } + + function testFuzz_EmitsRegistrySetEvent(IConsensusRegistryExtended _newRegistry) public { + vm.expectEmit(); + emit ZkStaker.RegistrySet(address(zkStaker.registry()), address(_newRegistry)); + vm.prank(admin); + zkStaker.setRegistry(_newRegistry); + } + + function testFuzz_RevertIf_NotAdmin(address _caller, IConsensusRegistryExtended _newRegistry) + public + { + vm.assume(_caller != admin); + vm.expectRevert( + abi.encodeWithSelector(Staker.Staker__Unauthorized.selector, bytes32("not admin"), _caller) + ); + vm.prank(_caller); + zkStaker.setRegistry(_newRegistry); + } +} + +contract ChangeValidatorKey is ZkStakerTestBase { + function testFuzz_RegistersValidatorAsOwner( + address _validator, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + vm.prank(_validator); + _assumeValidKeys(_validatorPubKey, _validatorPoP); + + zkStaker.changeValidatorKey(_validator, _validatorPubKey, _validatorPoP); + + ( + IConsensusRegistry.BLS12_381PublicKey memory _pubKey, + IConsensusRegistry.BLS12_381Signature memory _pop + ) = zkStaker.registeredValidators(_validator); + assertEq(_pubKey, _validatorPubKey); + assertEq(_pop, _validatorPoP); + } + + function testFuzz_RegistersValidatorAsStakeAuthority( + address _validator, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + vm.assume(_validator != validatorStakeAuthority); + _assumeValidKeys(_validatorPubKey, _validatorPoP); + + vm.prank(validatorStakeAuthority); + zkStaker.changeValidatorKey(_validator, _validatorPubKey, _validatorPoP); + + ( + IConsensusRegistry.BLS12_381PublicKey memory _pubKey, + IConsensusRegistry.BLS12_381Signature memory _pop + ) = zkStaker.registeredValidators(_validator); + assertEq(_pubKey, _validatorPubKey); + assertEq(_pop, _validatorPoP); + } + + function testFuzz_RegistersValidatorAsOwnerOnTheRegistryWhenAboveThreshold( + address _validatorOwner, + uint256 _bonusWeightAboveThreshold, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _boundAndSetBonusWeightAboveThreshold(_validatorOwner, _bonusWeightAboveThreshold); + _setMockRegistry(); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + + vm.prank(_validatorOwner); + zkStaker.changeValidatorKey(_validatorOwner, _validatorPubKey, _validatorPoP); + + IConsensusRegistry.Validator memory _validator = zkStaker.registry().validators(_validatorOwner); + IConsensusRegistry.BLS12_381PublicKey memory _pubKey = _validator.latest.pubKey; + IConsensusRegistry.BLS12_381Signature memory _pop = _validator.latest.proofOfPossession; + assertEq(_pubKey, _validatorPubKey); + assertEq(_pop, _validatorPoP); + } + + function testFuzz_RegistersValidatorAsValidatorStakeAuthorityOnTheRegistryWhenAboveThreshold( + address _validatorOwner, + uint256 _bonusWeightAboveThreshold, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _boundAndSetBonusWeightAboveThreshold(_validatorOwner, _bonusWeightAboveThreshold); + _setMockRegistry(); + _registerValidator(_validatorOwner, _validatorPubKey, _validatorPoP); + + vm.prank(validatorStakeAuthority); + zkStaker.changeValidatorKey(_validatorOwner, _validatorPubKey, _validatorPoP); + + IConsensusRegistry.Validator memory _validator = zkStaker.registry().validators(_validatorOwner); + IConsensusRegistry.BLS12_381PublicKey memory _pubKey = _validator.latest.pubKey; + IConsensusRegistry.BLS12_381Signature memory _pop = _validator.latest.proofOfPossession; + assertEq(_pubKey, _validatorPubKey); + assertEq(_pop, _validatorPoP); + } + + function testFuzz_EmitsValidatorKeysSetEvent( + address _validator, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + _assumeValidKeys(_validatorPubKey, _validatorPoP); + + vm.expectEmit(); + emit ZkStaker.ValidatorKeysSet(_validator, _validatorPubKey, _validatorPoP); + vm.prank(_validator); + zkStaker.changeValidatorKey(_validator, _validatorPubKey, _validatorPoP); + } + + function testFuzz_ChangesValidatorKeysAsOwner( + address _validator, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP, + IConsensusRegistry.BLS12_381PublicKey calldata _newValidatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _newValidatorPoP + ) public { + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _assumeValidKeys(_newValidatorPubKey, _newValidatorPoP); + vm.prank(_validator); + zkStaker.changeValidatorKey(_validator, _validatorPubKey, _validatorPoP); + + vm.prank(_validator); + zkStaker.changeValidatorKey(_validator, _newValidatorPubKey, _newValidatorPoP); + + ( + IConsensusRegistry.BLS12_381PublicKey memory _pubKey, + IConsensusRegistry.BLS12_381Signature memory _pop + ) = zkStaker.registeredValidators(_validator); + assertEq(_pubKey, _newValidatorPubKey); + assertEq(_pop, _newValidatorPoP); + } + + function testFuzz_ChangesValidatorKeysAsOwnerOnTheRegistryWhenAboveThreshold( + address _validatorOwner, + uint256 _bonusWeightAboveThreshold, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP, + IConsensusRegistry.BLS12_381PublicKey calldata _newValidatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _newValidatorPoP + ) public { + _boundAndSetBonusWeightAboveThreshold(_validatorOwner, _bonusWeightAboveThreshold); + _setMockRegistry(); + + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _assumeValidKeys(_newValidatorPubKey, _newValidatorPoP); + vm.prank(_validatorOwner); + zkStaker.changeValidatorKey(_validatorOwner, _validatorPubKey, _validatorPoP); + + vm.prank(_validatorOwner); + zkStaker.changeValidatorKey(_validatorOwner, _newValidatorPubKey, _newValidatorPoP); + + IConsensusRegistry.Validator memory _validator = zkStaker.registry().validators(_validatorOwner); + IConsensusRegistry.BLS12_381PublicKey memory _pubKey = _validator.latest.pubKey; + IConsensusRegistry.BLS12_381Signature memory _pop = _validator.latest.proofOfPossession; + assertEq(_pubKey, _newValidatorPubKey); + assertEq(_pop, _newValidatorPoP); + } + + function testFuzz_ChangesValidatorKeysAsStakeAuthority( + address _validator, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP, + IConsensusRegistry.BLS12_381PublicKey calldata _newValidatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _newValidatorPoP + ) public { + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _assumeValidKeys(_newValidatorPubKey, _newValidatorPoP); + vm.prank(_validator); + zkStaker.changeValidatorKey(_validator, _validatorPubKey, _validatorPoP); + + vm.prank(validatorStakeAuthority); + zkStaker.changeValidatorKey(_validator, _newValidatorPubKey, _newValidatorPoP); + + ( + IConsensusRegistry.BLS12_381PublicKey memory _pubKey, + IConsensusRegistry.BLS12_381Signature memory _pop + ) = zkStaker.registeredValidators(_validator); + assertEq(_pubKey, _newValidatorPubKey); + assertEq(_pop, _newValidatorPoP); + } + + function testFuzz_ChangesValidatorKeysAsStakeAuthorityOnTheRegistryWhenAboveThreshold( + address _validatorOwner, + uint256 _bonusWeightAboveThreshold, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP, + IConsensusRegistry.BLS12_381PublicKey calldata _newValidatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _newValidatorPoP + ) public { + _bonusWeightAboveThreshold = + bound(_bonusWeightAboveThreshold, initialValidatorWeightThreshold, type(uint256).max); + + vm.prank(validatorStakeAuthority); + zkStaker.setBonusWeight(_validatorOwner, _bonusWeightAboveThreshold); + _setMockRegistry(); + + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _assumeValidKeys(_newValidatorPubKey, _newValidatorPoP); + vm.prank(_validatorOwner); + zkStaker.changeValidatorKey(_validatorOwner, _validatorPubKey, _validatorPoP); + + vm.prank(validatorStakeAuthority); + zkStaker.changeValidatorKey(_validatorOwner, _newValidatorPubKey, _newValidatorPoP); + + IConsensusRegistry.Validator memory _validator = zkStaker.registry().validators(_validatorOwner); + IConsensusRegistry.BLS12_381PublicKey memory _pubKey = _validator.latest.pubKey; + IConsensusRegistry.BLS12_381Signature memory _pop = _validator.latest.proofOfPossession; + assertEq(_pubKey, _newValidatorPubKey); + assertEq(_pop, _newValidatorPoP); + } + + function testFuzz_RemovesValidatorFromRegistryWhenValidatorIsAlreadyRegisteredButBelowThreshold( + uint256 _bonusWeightAboveThreshold, + uint256 _bonusWeightBelowThreshold, + address _delegatee, + address _claimer, + address _validatorOwner, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + vm.assume(_delegatee != address(0)); + vm.assume(_claimer != address(0)); + _assumeValidKeys(_validatorPubKey, _validatorPoP); + _setRegistryAndRegisterValidatorWithBonusWeightAboveThreshold( + _validatorOwner, _validatorPubKey, _validatorPoP, _bonusWeightAboveThreshold + ); + _bonusWeightBelowThreshold = + _boundAndSetBonusWeightBelowThreshold(_validatorOwner, _bonusWeightBelowThreshold); + + vm.prank(_validatorOwner); + zkStaker.changeValidatorKey(_validatorOwner, _validatorPubKey, _validatorPoP); + + IConsensusRegistry.Validator memory _validator = zkStaker.registry().validators(_validatorOwner); + assertEq(_validator.latest.removed, true); + } + + function testFuzz_RevertIf_NotOwnerAndNotValidatorStakeAuthority( + address _caller, + address _validator, + IConsensusRegistry.BLS12_381PublicKey calldata _validatorPubKey, + IConsensusRegistry.BLS12_381Signature calldata _validatorPoP + ) public { + vm.assume(_caller != _validator && _caller != validatorStakeAuthority); + + vm.prank(_caller); + vm.expectRevert( + abi.encodeWithSelector( + Staker.Staker__Unauthorized.selector, bytes32("not validator stake authority"), _caller + ) + ); + zkStaker.changeValidatorKey(_validator, _validatorPubKey, _validatorPoP); + } + + function testFuzz_RevertIf_InvalidKeys( + uint256 _arbitraryNumber, + address _validator, + IConsensusRegistry.BLS12_381PublicKey memory _validatorPubKey, + IConsensusRegistry.BLS12_381Signature memory _validatorPoP + ) public { + if (_arbitraryNumber % 2 == 0) { + _validatorPubKey = + IConsensusRegistry.BLS12_381PublicKey({a: bytes32(0), b: bytes32(0), c: bytes32(0)}); + } else { + _validatorPoP = IConsensusRegistry.BLS12_381Signature({a: bytes32(0), b: bytes16(0)}); + } + + vm.prank(_validator); + vm.expectRevert(abi.encodeWithSelector(ZkStaker.InvalidValidatorKeys.selector)); + zkStaker.changeValidatorKey(_validator, _validatorPubKey, _validatorPoP); + } +} + +contract ChangeValidatorLeader is ZkStakerTestBase { + function setUp() public override { + super.setUp(); + _setMockRegistry(); + } + + function testFuzz_ChangesValidatorLeader(address _validator) public { + vm.assume(_validator != address(this)); + vm.prank(validatorStakeAuthority); + zkStaker.changeValidatorLeader(_validator, true); + + assertEq(zkStaker.registry().validators(_validator).latest.leader, true); + } + + function testFuzz_RevertIf_NotValidatorStakeAuthority(address _caller, address _validator) public { + vm.assume(_caller != validatorStakeAuthority); + + vm.prank(_caller); + vm.expectRevert( + abi.encodeWithSelector( + Staker.Staker__Unauthorized.selector, bytes32("not validator stake authority"), _caller + ) + ); + zkStaker.changeValidatorLeader(_validator, true); + } +} + +contract CommitValidatorCommittee is ZkStakerTestBase { + function setUp() public override { + super.setUp(); + _setMockRegistry(); + } + + function testFuzz_CommitsValidatorCommittee() public { + vm.prank(validatorStakeAuthority); + zkStaker.commitValidatorCommittee(); + + uint64 _validatorCommit = zkStaker.registry().validatorsCommit(); + assertEq(_validatorCommit, 1); + } + + function testFuzz_RevertIf_NotValidatorStakeAuthority(address _caller) public { + vm.assume(_caller != validatorStakeAuthority); + + vm.prank(_caller); + vm.expectRevert( + abi.encodeWithSelector( + Staker.Staker__Unauthorized.selector, bytes32("not validator stake authority"), _caller + ) + ); + zkStaker.commitValidatorCommittee(); + } +} + +contract SetCommitteeActivationDelay is ZkStakerTestBase { + function setUp() public override { + super.setUp(); + _setMockRegistry(); + } + + function testFuzz_SetsCommitteeActivationDelay(uint256 _delay) public { + vm.prank(validatorStakeAuthority); + zkStaker.setCommitteeActivationDelay(_delay); + + assertEq(zkStaker.registry().committeeActivationDelay(), _delay); + } + + function testFuzz_RevertIf_NotValidatorStakeAuthority(address _caller, uint256 _delay) public { + vm.assume(_caller != validatorStakeAuthority); + + vm.prank(_caller); + vm.expectRevert( + abi.encodeWithSelector( + Staker.Staker__Unauthorized.selector, bytes32("not validator stake authority"), _caller + ) + ); + zkStaker.setCommitteeActivationDelay(_delay); + } +} + +contract UpdateLeaderSelection is ZkStakerTestBase { + function setUp() public override { + super.setUp(); + _setMockRegistry(); + } + + function testFuzz_UpdatesLeaderSelection(uint64 _frequency, bool _weighted) public { + vm.prank(validatorStakeAuthority); + zkStaker.updateLeaderSelection(_frequency, _weighted); + + assertEq(zkStaker.registry().leaderSelection().latest.frequency, _frequency); + assertEq(zkStaker.registry().leaderSelection().latest.weighted, _weighted); + } + + function testFuzz_RevertIf_NotValidatorStakeAuthority( + address _caller, + uint64 _frequency, + bool _weighted + ) public { + vm.assume(_caller != validatorStakeAuthority); + + vm.prank(_caller); + vm.expectRevert( + abi.encodeWithSelector( + Staker.Staker__Unauthorized.selector, bytes32("not validator stake authority"), _caller + ) + ); + zkStaker.updateLeaderSelection(_frequency, _weighted); + } +} diff --git a/test/helpers/IntegrationTest.sol b/test/helpers/IntegrationTest.sol deleted file mode 100644 index 6ca1ced..0000000 --- a/test/helpers/IntegrationTest.sol +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity ^0.8.23; - -import {Test, console2} from "forge-std/Test.sol"; -import {ZkStaker, IERC20} from "src/ZkStaker.sol"; -import {IERC20Staking} from "staker/interfaces/IERC20Staking.sol"; -import {IdentityEarningPowerCalculator} from "staker/calculators/IdentityEarningPowerCalculator.sol"; - -contract IntegrationTest is Test { - address constant ZK_TOKEN_ADDRESS = 0x5A7d6b2F92C77FAD6CCaBd7EE0624E64907Eaf3E; - string constant ZKSYNC_RPC_URL = "https://mainnet.era.zksync.io"; - ZkStaker zkStaker; - IdentityEarningPowerCalculator calculator; - // ArbitrumDeploy deployScript; - uint256 constant REWARD_DURATION = 30 days; - uint256 constant SCALE_FACTOR = 1e36; - - function setUp() public virtual { - uint256 _forkId = vm.createFork(vm.rpcUrl(ZKSYNC_RPC_URL), 56_644_662); - vm.selectFork(_forkId); - calculator = new IdentityEarningPowerCalculator(); - zkStaker = new ZkStaker( - IERC20(ZK_TOKEN_ADDRESS), - IERC20Staking(ZK_TOKEN_ADDRESS), - calculator, - 1e18, - 1e24, - address(this), - "ZkStaker" - ); - } - - function _dealStakingToken(address _recipient, uint96 _amount) internal returns (uint96) { - // Bound amount to reasonable values - _amount = uint96(bound(_amount, 0.1e18, 250_000_000e18)); - deal(address(zkStaker.STAKE_TOKEN()), _recipient, _amount); - return _amount; - } - - function _jumpAheadByPercentOfRewardDuration(uint256 _percent) internal { - _percent = bound(_percent, 0, 100); - vm.warp(block.timestamp + (REWARD_DURATION * _percent) / 100); - } - - function _boundToRealisticReward(uint256 _rewardAmount) internal pure returns (uint256) { - // Use much more conservative bounds to prevent overflow - return bound(_rewardAmount, 1e18, 1_000_000e18); // Max 1M tokens - } - - function _mintTransferAndNotifyReward(uint256 _rewardAmount) internal { - // Bound the reward amount to realistic values - _rewardAmount = _boundToRealisticReward(_rewardAmount); - - // Get the admin from the deployment script - address admin = zkStaker.admin(); - address rewardNotifier = makeAddr("rewardNotifier"); - - // Set up the reward notifier - vm.prank(admin); - zkStaker.setRewardNotifier(rewardNotifier, true); - - // Use deal with the bounded amount - deal(address(zkStaker.REWARD_TOKEN()), rewardNotifier, _rewardAmount); - - // Transfer tokens to the staking contract and notify - vm.startPrank(rewardNotifier); - IERC20(address(zkStaker.REWARD_TOKEN())).transfer(address(zkStaker), _rewardAmount); - zkStaker.notifyRewardAmount(_rewardAmount); - vm.stopPrank(); - } - - function _boundEligibilityScore(uint256 _score) internal pure returns (uint256) { - return bound(_score, 50, 100); - } -} diff --git a/test/mocks/ConsensusRegistryMock.sol b/test/mocks/ConsensusRegistryMock.sol new file mode 100644 index 0000000..a1c7c0b --- /dev/null +++ b/test/mocks/ConsensusRegistryMock.sol @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity ^0.8.28; + +import { + IConsensusRegistryExtended, + IConsensusRegistry +} from "src/interfaces/IConsensusRegistryExtended.sol"; + +contract ConsensusRegistryMock is IConsensusRegistryExtended { + /// @dev A mapping of validator owners => validators. + mapping(address => Validator) private _validators; + + uint64 private _validatorsCommit; + + uint256 private _committeeActivationDelay; + + LeaderSelection private _leaderSelection; + + function validators(address _validatorOwner) external view returns (Validator memory _validator) { + return _validators[_validatorOwner]; + } + + function validatorsCommit() external view returns (uint64) { + return _validatorsCommit; + } + + function committeeActivationDelay() external view returns (uint256) { + return _committeeActivationDelay; + } + + function leaderSelection() external view returns (LeaderSelection memory) { + return _leaderSelection; + } + + function add( + address _validatorOwner, + bool _validatorIsLeader, + bool _validatorIsActive, + uint256 _validatorWeight, + BLS12_381PublicKey calldata _validatorPubKey, + BLS12_381Signature calldata _validatorPoP + ) external { + _validators[_validatorOwner] = Validator({ + ownerIdx: 0, // Assuming a default value for ownerIdx + latest: ValidatorAttr({ + active: _validatorIsActive, + removed: false, + leader: _validatorIsLeader, + weight: _validatorWeight, + pubKey: _validatorPubKey, + proofOfPossession: _validatorPoP + }), + snapshot: ValidatorAttr({ + active: false, + removed: false, + leader: false, + weight: 0, + pubKey: BLS12_381PublicKey({a: bytes32(0), b: bytes32(0), c: bytes32(0)}), + proofOfPossession: BLS12_381Signature({a: bytes32(0), b: bytes16(0)}) + }), + snapshotCommit: 0, + previousSnapshot: ValidatorAttr({ + active: false, + removed: false, + leader: false, + weight: 0, + pubKey: BLS12_381PublicKey({a: bytes32(0), b: bytes32(0), c: bytes32(0)}), + proofOfPossession: BLS12_381Signature({a: bytes32(0), b: bytes16(0)}) + }), + previousSnapshotCommit: 0 + }); + } + + function changeValidatorKey( + address _validatorOwner, + BLS12_381PublicKey calldata _pubKey, + BLS12_381Signature calldata _pop + ) external { + _validators[_validatorOwner].latest.pubKey = _pubKey; + _validators[_validatorOwner].latest.proofOfPossession = _pop; + } + + function changeValidatorWeight(address _validatorOwner, uint256 _weight) external { + _validators[_validatorOwner].latest.weight = _weight; + } + + function remove(address _validatorOwner) external { + _validators[_validatorOwner].latest.removed = true; + } + + function changeValidatorActive(address _validatorOwner, bool _isActive) external {} + + function changeValidatorLeader(address _validatorOwner, bool _isLeader) external { + _validators[_validatorOwner].latest.leader = _isLeader; + } + + function commitValidatorCommittee() external { + _validatorsCommit++; + } + + function getValidatorCommittee() + external + view + returns (CommitteeValidator[] memory, LeaderSelectionAttr memory) + {} + + function getNextValidatorCommittee() + external + view + returns (CommitteeValidator[] memory, LeaderSelectionAttr memory) + {} + + function setCommitteeActivationDelay(uint256 _delay) external { + _committeeActivationDelay = _delay; + } + + function updateLeaderSelection(uint64 _frequency, bool _weighted) external { + _leaderSelection.latest = LeaderSelectionAttr({frequency: _frequency, weighted: _weighted}); + } +} diff --git a/test/mocks/MockFullEarningPowerCalculatorExtended.sol b/test/mocks/MockFullEarningPowerCalculatorExtended.sol new file mode 100644 index 0000000..560ae3a --- /dev/null +++ b/test/mocks/MockFullEarningPowerCalculatorExtended.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity ^0.8.23; + +import {MockFullEarningPowerCalculator} from "staker-test/mocks/MockFullEarningPowerCalculator.sol"; +import {ZkStaker} from "src/ZkStaker.sol"; + +contract MockFullEarningPowerCalculatorExtended is MockFullEarningPowerCalculator { + address validatorForAtomicEarningPowerCalculation; + bool isTestingValidatorForAtomicEarningPowerCalculation; + ZkStaker zkStaker; + + error ValidatorForAtomicEarningPowerCalculationMismatch(address _expected, address _actual); + + function getNewEarningPower(uint256 _amountStaked, address _delegatee) + external + view + returns (uint256 _newEarningPower, bool _isQualifiedForBump) + { + if (isTestingValidatorForAtomicEarningPowerCalculation) { + if ( + validatorForAtomicEarningPowerCalculation + != zkStaker.validatorForAtomicEarningPowerCalculation() + ) { + revert ValidatorForAtomicEarningPowerCalculationMismatch( + validatorForAtomicEarningPowerCalculation, + zkStaker.validatorForAtomicEarningPowerCalculation() + ); + } + } + (_newEarningPower, _isQualifiedForBump) = __getEarningPower(_amountStaked, _delegatee); + } + + function __setZkStakerAndTestValidatorExpectedForAtomicEarningPowerCalculation( + ZkStaker _zkStaker, + address _validator + ) public { + zkStaker = _zkStaker; + isTestingValidatorForAtomicEarningPowerCalculation = true; + validatorForAtomicEarningPowerCalculation = _validator; + } +}