diff --git a/examples/CRISP/enclave.config.yaml b/examples/CRISP/enclave.config.yaml index 72784717b8..04dc00d664 100644 --- a/examples/CRISP/enclave.config.yaml +++ b/examples/CRISP/enclave.config.yaml @@ -1,25 +1,25 @@ chains: - - name: "localhost" - rpc_url: "ws://localhost:8545" + - name: localhost + rpc_url: ws://localhost:8545 contracts: e3_program: - address: "0x5eb3Bc0a489C5A8288765d2336659EbCA68FCd00" - deploy_block: 30 + address: "0x36C02dA8a0983159322a80FFE9F24b1acfF8B570" + deploy_block: 33 enclave: address: "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e" - deploy_block: 12 + deploy_block: 15 ciphernode_registry: address: "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853" - deploy_block: 8 + deploy_block: 11 bonding_registry: address: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318" - deploy_block: 9 + deploy_block: 12 slashing_manager: address: "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" - deploy_block: 7 + deploy_block: 10 fee_token: address: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" - deploy_block: 3 + deploy_block: 6 program: dev: true # risc0: @@ -32,37 +32,37 @@ program: # onchain: true # true = onchain requests, false = offchain nodes: cn1: - address: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" + address: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8' quic_port: 9201 ctrl_port: 50501 autonetkey: true autopassword: true cn2: - address: "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" + address: '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC' quic_port: 9202 ctrl_port: 50502 autonetkey: true autopassword: true cn3: - address: "0x90F79bf6EB2c4f870365E785982E1f101E93b906" + address: '0x90F79bf6EB2c4f870365E785982E1f101E93b906' quic_port: 9203 ctrl_port: 50503 autonetkey: true autopassword: true cn4: - address: "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65" + address: '0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65' quic_port: 9204 ctrl_port: 50504 autonetkey: true autopassword: true cn5: - address: "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc" + address: '0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc' quic_port: 9205 ctrl_port: 50505 autonetkey: true autopassword: true ag: - address: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + address: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266' quic_port: 9206 ctrl_port: 50506 autonetkey: true diff --git a/examples/CRISP/packages/crisp-contracts/deployed_contracts.json b/examples/CRISP/packages/crisp-contracts/deployed_contracts.json index 0335eac42e..998491cfd6 100644 --- a/examples/CRISP/packages/crisp-contracts/deployed_contracts.json +++ b/examples/CRISP/packages/crisp-contracts/deployed_contracts.json @@ -151,21 +151,21 @@ }, "localhost": { "PoseidonT3": { - "blockNumber": 2, + "blockNumber": 5, "address": "0x3333333C0A88F9BE4fd23ed0536F9B6c427e3B93" }, "MockUSDC": { "constructorArgs": { "initialSupply": "1000000" }, - "blockNumber": 3, + "blockNumber": 6, "address": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" }, "EnclaveToken": { "constructorArgs": { "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" }, - "blockNumber": 4, + "blockNumber": 7, "address": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" }, "EnclaveTicketToken": { @@ -174,14 +174,14 @@ "registry": "0x0000000000000000000000000000000000000001", "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" }, - "blockNumber": 6, + "blockNumber": 9, "address": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9" }, "SlashingManager": { "constructorArgs": { "admin": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" }, - "blockNumber": 7, + "blockNumber": 10, "address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" }, "CiphernodeRegistryOwnable": { @@ -196,7 +196,7 @@ "proxyAdminAddress": "0x9bd03768a7DCc129555dE410FF8E85528A4F88b5", "implementationAddress": "0x0165878A594ca255338adfa4d48449f69242Eb8F" }, - "blockNumber": 8, + "blockNumber": 11, "address": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853" }, "BondingRegistry": { @@ -218,7 +218,7 @@ "proxyAdminAddress": "0x8aCd85898458400f7Db866d53FCFF6f0D49741FF", "implementationAddress": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6" }, - "blockNumber": 9, + "blockNumber": 12, "address": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318" }, "Enclave": { @@ -241,7 +241,7 @@ "proxyAdminAddress": "0x8dAF17A20c9DBA35f005b6324F493785D239719d", "implementationAddress": "0x610178dA211FEF7D417bC0e6FeD39F05609AD788" }, - "blockNumber": 12, + "blockNumber": 15, "address": "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e" }, "E3RefundManager": { @@ -257,70 +257,70 @@ "proxyAdminAddress": "0x32467b43BFa67273FC7dDda0999Ee9A12F2AaA08", "implementationAddress": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0" }, - "blockNumber": 14, + "blockNumber": 17, "address": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82" }, "MockComputeProvider": { - "blockNumber": 16, - "address": "0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E" + "blockNumber": 19, + "address": "0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690" }, "MockDecryptionVerifier": { - "blockNumber": 17, - "address": "0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690" + "blockNumber": 20, + "address": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB" }, "MockPkVerifier": { - "blockNumber": 18, - "address": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB" + "blockNumber": 21, + "address": "0x9E545E3C0baAB3E08CdfD552C960A1050f373042" }, "MockE3Program": { - "blockNumber": 19, - "address": "0x9E545E3C0baAB3E08CdfD552C960A1050f373042" + "blockNumber": 22, + "address": "0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9" }, "ZKTranscriptLib": { - "blockNumber": 21, - "address": "0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8" + "blockNumber": 24, + "address": "0x851356ae760d987E095750cCeb3bC6014560891C" }, "RecursiveAggregationFoldVerifier": { - "blockNumber": 22, - "address": "0x851356ae760d987E095750cCeb3bC6014560891C" + "blockNumber": 25, + "address": "0xf5059a5D33d5853360D16C683c16e67980206f36" }, "ThresholdDecryptedSharesAggregationVerifier": { - "blockNumber": 23, - "address": "0xf5059a5D33d5853360D16C683c16e67980206f36" + "blockNumber": 26, + "address": "0x95401dc811bb5740090279Ba06cfA8fcF6113778" }, "ThresholdPkAggregationVerifier": { - "blockNumber": 24, - "address": "0x95401dc811bb5740090279Ba06cfA8fcF6113778" + "blockNumber": 27, + "address": "0x998abeb3E57409262aE5b751f60747921B33613E" }, "BfvDecryptionVerifier": { - "blockNumber": 25, - "address": "0x998abeb3E57409262aE5b751f60747921B33613E" + "blockNumber": 28, + "address": "0x70e0bA845a1A0F2DA3359C97E0285013525FFC49" }, "BfvPkVerifier": { - "blockNumber": 27, - "address": "0x4826533B4897376654Bb4d4AD88B7faFD0C98528" + "blockNumber": 30, + "address": "0x99bbA657f2BbC93c02D617f8bA121cB8Fc104Acf" }, "MockRISC0Verifier": { - "address": "0x0E801D84Fa97b50751Dbf25036d067dCf18858bF", - "blockNumber": 29 + "address": "0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf", + "blockNumber": 32 }, "HonkVerifier": { - "address": "0x9d4454B023096f34B160D6B654540c56A1F81688", - "blockNumber": 30 + "address": "0x5eb3Bc0a489C5A8288765d2336659EbCA68FCd00", + "blockNumber": 33 }, "CRISPProgram": { - "address": "0x5eb3Bc0a489C5A8288765d2336659EbCA68FCd00", - "blockNumber": 30, + "address": "0x36C02dA8a0983159322a80FFE9F24b1acfF8B570", + "blockNumber": 33, "constructorArgs": { "enclave": "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e", - "verifierAddress": "0x0E801D84Fa97b50751Dbf25036d067dCf18858bF", - "honkVerifierAddress": "0x9d4454B023096f34B160D6B654540c56A1F81688", + "verifierAddress": "0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf", + "honkVerifierAddress": "0x5eb3Bc0a489C5A8288765d2336659EbCA68FCd00", "imageId": "0x23734b77b0f76e85623a88d7a82f24c34c94834f2501964ea123b7a2027013a2" } }, "MockVotingToken": { - "address": "0x809d550fca64d94Bd9F66E60752A544199cfAC3D", - "blockNumber": 32 + "address": "0x4c5859f0F772848b2D91F1D83E2Fe57935348029", + "blockNumber": 35 } } } \ No newline at end of file diff --git a/examples/CRISP/server/.env.example b/examples/CRISP/server/.env.example index 652915fdd5..af56812859 100644 --- a/examples/CRISP/server/.env.example +++ b/examples/CRISP/server/.env.example @@ -15,7 +15,7 @@ CRON_API_KEY=1234567890 # Based on Default Anvil Deployments (Only for testing) ENCLAVE_ADDRESS="0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e" CIPHERNODE_REGISTRY_ADDRESS="0xa513E6E4b8f2a923D98304ec87F64353C4D5C853" -E3_PROGRAM_ADDRESS="0x5eb3Bc0a489C5A8288765d2336659EbCA68FCd00" +E3_PROGRAM_ADDRESS="0x36C02dA8a0983159322a80FFE9F24b1acfF8B570" FEE_TOKEN_ADDRESS="0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" # E3 Config diff --git a/packages/enclave-contracts/artifacts/contracts/Enclave.sol/Enclave.json b/packages/enclave-contracts/artifacts/contracts/Enclave.sol/Enclave.json index b70940cb23..9ea44ab9b2 100644 --- a/packages/enclave-contracts/artifacts/contracts/Enclave.sol/Enclave.json +++ b/packages/enclave-contracts/artifacts/contracts/Enclave.sol/Enclave.json @@ -8,6 +8,49 @@ "stateMutability": "nonpayable", "type": "constructor" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "size", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minimum", + "type": "uint256" + } + ], + "name": "BelowMinCommitteeSize", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "threshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minimum", + "type": "uint256" + } + ], + "name": "BelowMinThreshold", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "BpsExceedsMax", + "type": "error" + }, { "inputs": [ { @@ -62,6 +105,17 @@ "name": "CommitteeSizeNotConfigured", "type": "error" }, + { + "inputs": [ + { + "internalType": "enum IEnclave.CommitteeSize", + "name": "committeeSize", + "type": "uint8" + } + ], + "name": "CommitteeSizeTooSmall", + "type": "error" + }, { "inputs": [ { @@ -95,6 +149,17 @@ "name": "E3DoesNotExist", "type": "error" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "E3NotFailed", + "type": "error" + }, { "inputs": [ { @@ -258,6 +323,21 @@ "name": "InvalidStage", "type": "error" }, + { + "inputs": [], + "name": "InvalidThresholdValues", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTimeoutWindow", + "type": "error" + }, + { + "inputs": [], + "name": "MinSizeBelowMinThreshold", + "type": "error" + }, { "inputs": [ { @@ -280,11 +360,37 @@ "name": "ModuleNotEnabled", "type": "error" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "NoPaymentToRefund", + "type": "error" + }, { "inputs": [], "name": "NotInitializing", "type": "error" }, + { + "inputs": [], + "name": "OnlyCiphernodeRegistry", + "type": "error" + }, + { + "inputs": [], + "name": "OnlyCiphernodeRegistryOrSlashingManager", + "type": "error" + }, + { + "inputs": [], + "name": "OnlySlashingManager", + "type": "error" + }, { "inputs": [ { @@ -340,6 +446,33 @@ "name": "SafeERC20FailedOperation", "type": "error" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "threshold", + "type": "uint256" + } + ], + "name": "ThresholdTooSmall", + "type": "error" + }, + { + "inputs": [], + "name": "TreasuryRequired", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "UtilizationBpsExceedsMax", + "type": "error" + }, { "anonymous": false, "inputs": [ @@ -812,6 +945,96 @@ "name": "PlaintextOutputPublished", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "keyGenFixedPerNode", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "keyGenPerEncryptionProof", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "coordinationPerPair", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "availabilityPerNodePerSec", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decryptionPerNode", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "publicationBase", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "verificationPerProof", + "type": "uint256" + }, + { + "internalType": "address", + "name": "protocolTreasury", + "type": "address" + }, + { + "internalType": "uint16", + "name": "marginBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "protocolShareBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "dkgUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "computeUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "decryptUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint32", + "name": "minCommitteeSize", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "minThreshold", + "type": "uint32" + } + ], + "indexed": false, + "internalType": "struct IEnclave.PricingConfig", + "name": "config", + "type": "tuple" + } + ], + "name": "PricingConfigUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -1408,7 +1631,7 @@ } ], "internalType": "struct IEnclave.E3RequestParams", - "name": "", + "name": "requestParams", "type": "tuple" } ], @@ -1420,7 +1643,7 @@ "type": "uint256" } ], - "stateMutability": "pure", + "stateMutability": "view", "type": "function" }, { @@ -1480,6 +1703,96 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "getPricingConfig", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "keyGenFixedPerNode", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "keyGenPerEncryptionProof", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "coordinationPerPair", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "availabilityPerNodePerSec", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decryptionPerNode", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "publicationBase", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "verificationPerProof", + "type": "uint256" + }, + { + "internalType": "address", + "name": "protocolTreasury", + "type": "address" + }, + { + "internalType": "uint16", + "name": "marginBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "protocolShareBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "dkgUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "computeUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "decryptUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint32", + "name": "minCommitteeSize", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "minThreshold", + "type": "uint32" + } + ], + "internalType": "struct IEnclave.PricingConfig", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -2086,6 +2399,96 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "keyGenFixedPerNode", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "keyGenPerEncryptionProof", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "coordinationPerPair", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "availabilityPerNodePerSec", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decryptionPerNode", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "publicationBase", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "verificationPerProof", + "type": "uint256" + }, + { + "internalType": "address", + "name": "protocolTreasury", + "type": "address" + }, + { + "internalType": "uint16", + "name": "marginBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "protocolShareBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "dkgUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "computeUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "decryptUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint32", + "name": "minCommitteeSize", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "minThreshold", + "type": "uint32" + } + ], + "internalType": "struct IEnclave.PricingConfig", + "name": "config", + "type": "tuple" + } + ], + "name": "setPricingConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -2156,11 +2559,11 @@ "type": "function" } ], - "bytecode": "0x6080604052348015600e575f5ffd5b5060156019565b60c9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff161560685760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b039081161460c65780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b614a48806100d65f395ff3fe608060405234801561000f575f5ffd5b50600436106102c3575f3560e01c806390173a4111610177578063cb649617116100d5578063ea71aa571161008f578063ea71aa5714610745578063f0691cba14610758578063f2fde38b1461076b578063f81b8ef61461077e578063fad8e11114610791578063fbdb3237146107a4578063fd2f3d01146107cc575f5ffd5b8063cb649617146106c1578063cbd16872146106ca578063cf0f34c4146106dd578063cfbdc98d146106f0578063da16fb2f1461071f578063e59e469514610732575f5ffd5b8063ac3d2f4211610131578063ac3d2f4214610618578063b27392d514610640578063b68fd1be14610653578063bb2d1b8214610666578063bff232c114610679578063c1ab0f1f1461068c578063c4ccafa21461069f575f5ffd5b806390173a41146105815780639117173c1461059657806392312386146105a9578063929a8faf146105bc57806399c6679d146105dd5780639c8570c814610605575f5ffd5b80634fc77264116102245780637c8c3b4d116101de5780637c8c3b4d146105085780637cfa9d741461051b57806381476ec21461052e57806385814243146105415780638da5cb5b146105545780638dcdd86b1461055c5780638e5ce3ad1461056e575f5ffd5b80634fc772641461049d57806364226409146104b0578063647846a5146104d15780636db5c8fd146104e4578063715018a6146104ed57806377868ae4146104f5575f5ffd5b80631ba72945116102805780631ba729451461039057806336c5d38a146103a35780634017daf0146103d2578063406ed35c146103ff5780634147a3601461041f578063459d92941461044c5780634e92ec631461048a575f5ffd5b806301d12f1c146102c757806302a3a9c9146102dc5780630ef81b2f146102ef57806310bc62811461032d57806311bd61d91461035557806315cce2241461037d575b5f5ffd5b6102da6102d5366004613b3b565b6107df565b005b6102da6102ea366004613beb565b610945565b6103176102fd366004613c06565b5f908152600960205260409020546001600160a01b031690565b6040516103249190613c2a565b60405180910390f35b61031761033b366004613c06565b60096020525f90815260409020546001600160a01b031681565b610368610363366004613c51565b6109f1565b60405163ffffffff9091168152602001610324565b6102da61038b366004613beb565b610a2d565b6102da61039e366004613c79565b610ad2565b6103c56103b1366004613c06565b5f908152600f602052604090205460ff1690565b6040516103249190613cbb565b6103e56103e0366004613c06565b610ae6565b6040516103249e9d9c9b9a99989796959493929190613d07565b61041261040d366004613c06565b610d10565b6040516103249190613ef7565b61043e61042d366004613c06565b600c6020525f908152604090205481565b604051908152602001610324565b61047a61045a366004613f09565b8051602081830181018051600b8252928201919093012091525460ff1681565b6040519015158152602001610324565b6102da610498366004613c06565b61100d565b6102da6104ab366004613beb565b61109c565b6104c36104be366004613f42565b61112f565b604051610324929190613f79565b600454610317906001600160a01b031681565b61043e60055481565b6102da61193b565b6102da610503366004613f91565b61194e565b6102da610516366004613fc2565b6119e6565b6102da610529366004613c06565b611a6f565b6102da61053c366004613ff0565b611b6d565b600154610317906001600160a01b031681565b610317611c60565b5f54610317906001600160a01b031681565b600354610317906001600160a01b031681565b610589611c8e565b6040516103249190614010565b6102da6105a4366004613c06565b611cd4565b6105896105b7366004613c06565b611e7c565b6105cf6105ca366004613c06565b611ed5565b604051610324929190614031565b6103176105eb366004613c06565b5f908152601060205260409020546001600160a01b031690565b61047a610613366004614084565b611efc565b610317610626366004613c06565b5f908152600a60205260409020546001600160a01b031690565b61047a61064e3660046140fb565b612194565b6102da610661366004613f91565b6123c4565b6102da6106743660046141a0565b61245b565b6102da610687366004613beb565b612546565b6102da61069a366004613ff0565b6125ed565b61047a6106ad366004613beb565b60076020525f908152604090205460ff1681565b61043e60065481565b6102da6106d8366004613fc2565b6126d0565b6102da6106eb366004613c06565b612783565b6107126106fe366004613c06565b5f908152600d602052604090205460ff1690565b60405161032491906141d8565b61043e61072d366004613f42565b6127c0565b6102da610740366004613beb565b6127ca565b6102da6107533660046141e6565b612864565b600254610317906001600160a01b031681565b6102da610779366004613beb565b612977565b6103c561078c366004613c06565b6129b1565b6102da61079f366004613beb565b612b4b565b6103176107b2366004613c06565b600a6020525f90815260409020546001600160a01b031681565b6102da6107da366004613beb565b612be3565b5f6107e8612c72565b805490915060ff600160401b82041615906001600160401b03165f8115801561080e5750825b90505f826001600160401b031660011480156108295750303b155b905081158015610837575080155b156108555760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561087f57845460ff60401b1916600160401b1785555b61088833612c9c565b61089188612783565b61089a8c612b4b565b6108a38b6127ca565b6108ac8a610945565b6108b589610a2d565b6108be87612cad565b6108c7866123c4565b6108cf611c60565b6001600160a01b03168d6001600160a01b0316146108f0576108f08d612977565b831561093657845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050505050565b61094d612de1565b6001600160a01b0381166109a85760405162461bcd60e51b815260206004820152601f60248201527f496e76616c6964204533526566756e644d616e6167657220616464726573730060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040517f9557d04c1c0b16f93f13b69aed23b3b6ab935bff3c53ac81d17896d3583542ed905f90a250565b6012602052815f5260405f208160028110610a0a575f80fd5b60089182820401919006600402915091509054906101000a900463ffffffff1681565b610a35612de1565b6001600160a01b03811615801590610a5b57506004546001600160a01b03828116911614155b8190610a7b5760405163eddf07f560e01b815260040161099f9190613c2a565b50600480546001600160a01b0319166001600160a01b0383161790556040517f722ff84c1234b2482061def5c82c6b5080c117b3cbb69d686844a051e4b8e7f390610ac7908390613c2a565b60405180910390a150565b610ada612de1565b610ae381612cad565b50565b60086020525f9081526040902080546001820154600283015460058401546006850154600786018054959660ff90951695939492936001600160a01b039092169291610b319061421d565b80601f0160208091040260200160405190810160405280929190818152602001828054610b5d9061421d565b8015610ba85780601f10610b7f57610100808354040283529160200191610ba8565b820191905f5260205f20905b815481529060010190602001808311610b8b57829003601f168201915b505050505090806008018054610bbd9061421d565b80601f0160208091040260200160405190810160405280929190818152602001828054610be99061421d565b8015610c345780601f10610c0b57610100808354040283529160200191610c34565b820191905f5260205f20905b815481529060010190602001808311610c1757829003601f168201915b5050506009840154600a850154600b860154600c870154600d8801805497986001600160a01b03958616989490951696509194509291610c739061421d565b80601f0160208091040260200160405190810160405280929190818152602001828054610c9f9061421d565b8015610cea5780601f10610cc157610100808354040283529160200191610cea565b820191905f5260205f20905b815481529060010190602001808311610ccd57829003601f168201915b505050600e90930154919250506001600160a01b0381169060ff600160a01b909104168e565b610d18613830565b5f8281526008602090815260409182902082516101e08101909352805483526001810154909183019060ff166003811115610d5557610d55613c93565b6003811115610d6657610d66613c93565b8152600282810154602083015260408051808201808352919093019291600385019182845b815481526020019060010190808311610d8b5750505091835250506005820154602082015260068201546001600160a01b03166040820152600782018054606090920191610dd89061421d565b80601f0160208091040260200160405190810160405280929190818152602001828054610e049061421d565b8015610e4f5780601f10610e2657610100808354040283529160200191610e4f565b820191905f5260205f20905b815481529060010190602001808311610e3257829003601f168201915b50505050508152602001600882018054610e689061421d565b80601f0160208091040260200160405190810160405280929190818152602001828054610e949061421d565b8015610edf5780601f10610eb657610100808354040283529160200191610edf565b820191905f5260205f20905b815481529060010190602001808311610ec257829003601f168201915b505050918352505060098201546001600160a01b039081166020830152600a830154166040820152600b8201546060820152600c8201546080820152600d8201805460a090920191610f309061421d565b80601f0160208091040260200160405190810160405280929190818152602001828054610f5c9061421d565b8015610fa75780601f10610f7e57610100808354040283529160200191610fa7565b820191905f5260205f20905b815481529060010190602001808311610f8a57829003601f168201915b5050509183525050600e91909101546001600160a01b038082166020840152600160a01b90910460ff16151560409092019190915260a08201519192508391166110075760405163cd6f4a4f60e01b815260040161099f91815260200190565b50919050565b611015612de1565b5f8181526009602052604090205481906001600160a01b031661104e576040516381c4951960e01b815260040161099f91815260200190565b505f818152600960205260409081902080546001600160a01b0319169055517f104eb329a192aef26eddea07c2af5ad2587792e62b37ed4045b6ba59bc5540fc90610ac79083815260200190565b6110a4612de1565b6001600160a01b0381165f90815260076020526040902054819060ff166110df576040516321ac7c5f60e01b815260040161099f9190613c2a565b506001600160a01b0381165f9081526007602052604090819020805460ff19169055517f56070b80bd617fcd2f7a284861edb488830a38f9dedcd77b2cb2f4eac17743e790610ac7908390613c2a565b5f611138613830565b5f601281611149602087018761424f565b600381111561115a5761115a613c93565b600381111561116b5761116b613c93565b8152602081019190915260409081015f20815180830190925260028282826020028201915f905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411611192579050505050505090505f816001600281106111e9576111e9614268565b602002015163ffffffff1611845f016020810190611207919061424f565b906112265760405163286c068d60e11b815260040161099f919061427c565b5060208401354281101561125057604051630b99e87960e01b815260040161099f91815260200190565b506040840135602085013581101561127e5760405163174b5a0760e21b815260040161099f91815260200190565b506015546014545f919061129642604089013561429e565b6112a091906142b1565b6112aa91906142b1565b9050600554811081906112d3576040516313b783af60e21b815260040161099f91815260200190565b5060075f6112e76080880160608901613beb565b6001600160a01b0316815260208101919091526040015f205460ff166113136080870160608801613beb565b906113325760405163295a6a6f60e11b815260040161099f9190613c2a565b505f61133d866127c0565b60068054965090915085905f611352836142c4565b9091555050604080514460208201529081018690525f9060600160408051808303601f1901815291815281516020928301205f898152600c84528281208690556004546011855283822080546001600160a01b039092166001600160a01b0319928316179055600d8552838220805460ff1916600117905560109094528290208054339416939093179092556014549192506113f191908901356142b1565b5f878152600e60209081526040909120600101919091558186526114179088018861424f565b8560200190600381111561142d5761142d613c93565b9081600381111561144057611440613c93565b905250436040808701919091528051808201825290602089019060029083908390808284375f9201919091525050506060808701919091526114889060808901908901613beb565b6001600160a01b031660a08601526114a360808801886142dc565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050505060c0808701919091526114eb908801886142dc565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050505060e08087019190915261153890610100890190890161432b565b15156101c08601525f610140860181905261016086018190526040805160208101909152908152610180860152336101a08601819052600454611588916001600160a01b03909116903085612e13565b5f6115996080890160608a01613beb565b6001600160a01b031663fefd9a8b88846115b660808d018d6142dc565b6115c360a08f018f6142dc565b8f8060c001906115d391906142dc565b6040518963ffffffff1660e01b81526004016115f698979695949392919061436e565b6020604051808303815f875af1158015611612573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061163691906143c4565b5f818152600960205260409020549091506001600160a01b03168181611672576040516381c4951960e01b815260040161099f91815260200190565b505f828152600a60205260409020546001600160a01b031682816116ac576040516381c4951960e01b815260040161099f91815260200190565b50608088018390526001600160a01b038083166101008a015281166101208901525f8981526008602090815260409091208951815590890151600180830180548c94939260ff19919091169083600381111561170a5761170a613c93565b0217905550604082015181600201556060820151816003019060026117309291906138ad565b506080820151600582015560a08201516006820180546001600160a01b0319166001600160a01b0390921691909117905560c08201516007820190611775908261443a565b5060e0820151600882019061178a908261443a565b506101008201516009820180546001600160a01b039283166001600160a01b031991821617909155610120840151600a84018054919093169116179055610140820151600b820155610160820151600c820155610180820151600d8201906117f2908261443a565b506101a0820151600e90910180546101c0909301511515600160a01b026001600160a81b03199093166001600160a01b0392831617929092179091555f5460405163291a691b60e01b815291169063291a691b90611858908c9088908c906004016144ef565b6020604051808303815f875af1158015611874573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118989190614534565b6118b557604051630d8dbe2560e01b815260040160405180910390fd5b6118c560808b0160608c01613beb565b6001600160a01b03167f5904e83d57e704fba4d92c5617f6b50ae993cd42d78babfcb239d0a6775f30708a8a6040516118ff929190613f79565b60405180910390a2885f516020614a1c5f395f51905f525f600160405161192792919061454f565b60405180910390a250505050505050915091565b611943612de1565b61194c5f612e80565b565b611956612de1565b80515f5b818110156119aa57600b83828151811061197657611976614268565b602002602001015160405161198b919061456a565b908152604051908190036020019020805460ff1916905560010161195a565b507fd1b46e030b48add7bc03225cc5a6f403970976b36983f99ec31d535d627fc7db826040516119da9190614580565b60405180910390a15050565b6119ee612de1565b6001600160a01b03811615801590611a1f57505f828152600a60205260409020546001600160a01b03828116911614155b8290611a41576040516381c4951960e01b815260040161099f91815260200190565b505f918252600a602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b5f546001600160a01b03163314611a985760405162461bcd60e51b815260040161099f906145e3565b5f818152600d602052604090205460ff166001816006811115611abd57611abd613c93565b14611ae257816001826040516337e1404160e01b815260040161099f93929190614614565b5f828152600d60205260409020805460ff19166002179055601354611b0790426142b1565b5f838152600e602052604080822092909255905183917fc44405af9078047712501f519e1fb900c2896c62b488336f84529c72ae16e6f191a2815f516020614a1c5f395f51905f5260016002604051611b6192919061454f565b60405180910390a25050565b5f546001600160a01b03163314611b965760405162461bcd60e51b815260040161099f906145e3565b5f828152600860209081526040808320600d9092529091205460ff166002816006811115611bc657611bc6613c93565b14611beb57836002826040516337e1404160e01b815260040161099f93929190614614565b5f848152600d6020526040808220805460ff19166003179055600b84018590555185917f11df18edb9bc9cd90a79068e0e208b630202148643d797d6150e7bacb733e63c91a2835f516020614a1c5f395f51905f5260026003604051611c5292919061454f565b60405180910390a250505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b611caf60405180606001604052805f81526020015f81526020015f81525090565b5060408051606081018252601354815260145460208201526015549181019190915290565b5f818152600d602052604090205460ff166006816006811115611cf957611cf9613c93565b14611d365760405162461bcd60e51b815260206004820152600d60248201526c114cc81b9bdd0819985a5b1959609a1b604482015260640161099f565b5f828152600c602052604090205480611d885760405162461bcd60e51b8152602060048201526014602482015273139bc81c185e5b595b9d081d1bc81c99599d5b9960621b604482015260640161099f565b5f838152600c60205260408120819055611da184612ef0565b5f858152601160205260409020546002549192506001600160a01b0390811691611dce9183911685612fe4565b60025460405163da19b69760e01b81526001600160a01b039091169063da19b69790611e04908890879087908790600401614678565b5f604051808303815f87803b158015611e1b575f5ffd5b505af1158015611e2d573d5f5f3e3d5ffd5b50505050847f5297818f48a66292b8b3e2caab83eec531b669bb20807fd38cf006adb2a07317848451604051611e6d929190918252602082015260400190565b60405180910390a25050505050565b611e9d60405180606001604052805f81526020015f81526020015f81525090565b505f908152600e6020908152604091829020825160608101845281548152600182015492810192909252600201549181019190915290565b5f818152600d6020526040812054819060ff16611ef2848261300f565b9250925050915091565b5f5f611f0787610d10565b5f888152600d602052604090205490915060ff166003816006811115611f2f57611f2f613c93565b1488600383909192611f57576040516337e1404160e01b815260040161099f93929190614614565b5050505f888152600e6020908152604091829020825160608101845281548152600182015492810183905260029091015492810192909252899042811015611fbb576040516308f3034360e31b81526004810192909252602482015260440161099f565b5050606083015160200151899042811115611ff25760405163017e35e560e71b81526004810192909252602482015260440161099f565b505061016083015189901561201d57604051637eb9cea960e11b815260040161099f91815260200190565b505f888860405161202f9291906146af565b60408051918290039091205f8c815260086020908152838220600c01839055600d905291909120805460ff1916600417905560155490915061207190426142b1565b5f8b8152600e6020526040908190206002019190915560a08501519051632f0e1bbf60e01b81526001600160a01b0390911690632f0e1bbf906120be908d9085908c908c906004016146be565b6020604051808303815f875af11580156120da573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120fe9190614534565b945088888661212257604051632f9f8ab960e01b815260040161099f9291906146dd565b5050897f7cc27e4a5626cbc4f8ba1a927b0448de55e6a114bc87660331270c5109ade0718a8a6040516121569291906146dd565b60405180910390a2895f516020614a1c5f395f51905f526003600460405161217f92919061454f565b60405180910390a25050505095945050505050565b5f5f61219f89610d10565b5f8a8152600d602052604090205490915060ff1660048160068111156121c7576121c7613c93565b148a6004839091926121ef576040516337e1404160e01b815260040161099f93929190614614565b5050505f8a8152600e602090815260409182902082516060810184528154815260018201549281019290925260020154918101829052908b9042811015612252576040516308f3034360e31b81526004810192909252602482015260440161099f565b50505f8b8152600860205260409020600d0161226f8a8c836146f0565b505f8b8152600d6020526040902080546005919060ff191660018302179055508261010001516001600160a01b0316635bf48e3a8b8b6040516122b39291906146af565b6040519081900381206001600160e01b031960e084901b1682526122e1918c908c908c908c906004016147a4565b602060405180830381865afa1580156122fc573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123209190614534565b935089898561234457604051632f9f8ab960e01b815260040161099f9291906146dd565b505061234f8b613197565b8a7f3a140076c461ebc41d74833ae0ee8bbc8079a135a63392098cd381e84350b69b8b8b8b8b60405161238594939291906147dc565b60405180910390a28a5f516020614a1c5f395f51905f52600460056040516123ae92919061454f565b60405180910390a2505050979650505050505050565b6123cc612de1565b80515f5b8181101561242b576001600b8483815181106123ee576123ee614268565b6020026020010151604051612403919061456a565b908152604051908190036020019020805491151560ff199092169190911790556001016123d0565b507f027b83cad653f54850fef6faa8c705f73a53e7f8de50a3a33ac1e0e3a5c0be81826040516119da9190614580565b5f546001600160a01b031633148061247d57506003546001600160a01b031633145b6124c95760405162461bcd60e51b815260206004820152601c60248201527f4f6e6c79205265676973747279206f7220536c617368696e674d677200000000604482015260640161099f565b5f8160ff161180156124df5750600d60ff821611155b6125245760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b2103330b4b63ab932903932b0b9b7b760511b604482015260640161099f565b612542828260ff16600d81111561253d5761253d613c93565b613546565b5050565b61254e612de1565b6001600160a01b0381166125a45760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420536c617368696e674d616e61676572206164647265737300604482015260640161099f565b600380546001600160a01b0319166001600160a01b0383169081179091556040517f4ccc8ed483c7c44c3602c3c38afc2c014a8f1d2dc210dfe58ebeeeead230f8e0905f90a250565b6003546001600160a01b0316331461263e5760405162461bcd60e51b815260206004820152601460248201527327b7363c9029b630b9b434b733a6b0b730b3b2b960611b604482015260640161099f565b60025460405163c1ab0f1f60e01b815260048101849052602481018390526001600160a01b039091169063c1ab0f1f906044015f604051808303815f87803b158015612688575f5ffd5b505af115801561269a573d5f5f3e3d5ffd5b50505050817f4f41a3b0a032ebcae925f2ace77d507435840ca4b2dbaffdd7723fa8d72ee54282604051611b6191815260200190565b6126d8612de1565b6001600160a01b0381161580159061270957505f828152600960205260409020546001600160a01b03828116911614155b829061272b576040516381c4951960e01b815260040161099f91815260200190565b505f8281526009602090815260409182902080546001600160a01b0319166001600160a01b03851617905590518381527ff4041a3f914dac3bc9bf5f003ba41f28dbb84abe42f4e07c76266f5c8ceecb6991016119da565b61278b612de1565b60058190556040518181527fba0716ba1ee2ea8ecc4c64119b4537cdb42a99d82acf92af5b87607b8b52355290602001610ac7565b620f424080611007565b6127d2612de1565b6001600160a01b038116158015906127f857506001546001600160a01b03828116911614155b8190612818576040516320252f0b60e01b815260040161099f9190613c2a565b50600180546001600160a01b0319166001600160a01b0383161790556040517fad4055f18cdad6f4bdd71afe3a72cbeee964217943e1bde38f138289e981a9a790610ac7908390613c2a565b61286c612de1565b6128796020820182614820565b63ffffffff1661288f6040830160208401614820565b63ffffffff16101580156128b457505f6128ac6020830183614820565b63ffffffff16115b6128f45760405162461bcd60e51b8152602060048201526011602482015270125b9d985b1a59081d1a1c995cda1bdb19607a1b604482015260640161099f565b8060125f84600381111561290a5761290a613c93565b600381111561291b5761291b613c93565b815260208101919091526040015f206129359160026138eb565b5081600381111561294857612948613c93565b7f8b56fae526eee054f0849759a99fc7d4ff3823824ebf097a56f7d78adb6b34fa82604051611b619190614839565b61297f612de1565b6001600160a01b0381166129a8575f604051631e4fbdf760e01b815260040161099f9190613c2a565b610ae381612e80565b5f818152600d602052604081205460ff16818160068111156129d5576129d5613c93565b036129fa57826001826040516337e1404160e01b815260040161099f93929190614614565b6005816006811115612a0e57612a0e613c93565b03612a2f5760405163462c7bed60e01b81526004810184905260240161099f565b6006816006811115612a4357612a43613c93565b03612a6457604051633de16e3560e11b81526004810184905260240161099f565b5f612a6f848361300f565b9350905080612a9457604051639f65d93560e01b81526004810185905260240161099f565b5f848152600d6020526040902080546006919060ff191660018302179055505f848152600f60205260409020805484919060ff1916600183600d811115612add57612add613c93565b0217905550835f516020614a1c5f395f51905f52836006604051612b0292919061454f565b60405180910390a2837fe20209be7caae6e76291267cfa711353981274bf127e94f16eb9ec44b68582bb8385604051612b3c929190614877565b60405180910390a25050919050565b612b53612de1565b6001600160a01b03811615801590612b7857505f546001600160a01b03828116911614155b8190612b98576040516375ac4eb760e11b815260040161099f9190613c2a565b505f80546001600160a01b0319166001600160a01b0383161790556040517f80052b810d39120cf6c976cca504a21703f585521dc7a41c6d241090e6c579b690610ac7908390613c2a565b6001600160a01b0381165f90815260076020526040902054819060ff1615612c1f5760405163b29d459560e01b815260040161099f9190613c2a565b506001600160a01b0381165f9081526007602052604090819020805460ff19166001179055517fb8d368517268f297fff00825d67d098763117d061360d31027be5b2e1a59d46790610ac7908390613c2a565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005b92915050565b612ca46136ae565b610ae3816136d3565b8035612cf05760405162461bcd60e51b8152602060048201526012602482015271496e76616c696420444b472077696e646f7760701b604482015260640161099f565b5f816020013511612d3c5760405162461bcd60e51b8152602060048201526016602482015275496e76616c696420636f6d707574652077696e646f7760501b604482015260640161099f565b5f816040013511612d8b5760405162461bcd60e51b8152602060048201526019602482015278496e76616c69642064656372797074696f6e2077696e646f7760381b604482015260640161099f565b80356013819055602080830135601481905560408085013560158190558151948552928401919091528201527f7e86ba16b805e2835af5c5b7aa5a942ced8bcc1fb95a05fbe42dae3862350a1690606001610ac7565b33612dea611c60565b6001600160a01b03161461194c573360405163118cdaa760e01b815260040161099f9190613c2a565b6040516001600160a01b038481166024830152838116604483015260648201839052612e7a9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506136db565b50505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b5f818152600f602052604090205460609060ff16600181600d811115612f1857612f18613c93565b1480612f355750600281600d811115612f3357612f33613c93565b145b15612f6d575f5b604051908082528060200260200182016040528015612f65578160200160208202803683370190505b509392505050565b5f5460405162beb08960e51b8152600481018590526001600160a01b03909116906317d61120906024015f60405180830381865afa925050508015612fd357506040513d5f823e601f3d908101601f19168201604052612fd09190810190614892565b60015b612fdd575f612f3c565b9392505050565b61300a83846001600160a01b031663a9059cbb8585604051602401612e48929190614921565b505050565b5f828152600e60209081526040808320815160608101835281548152600182015493810193909352600201548282015282549051632800d82960e01b81526004810186905283929183916001600160a01b0390911690632800d82990602401602060405180830381865afa158015613089573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130ad91906143c4565b905060018560068111156130c3576130c3613c93565b1480156130cf57508042115b156130e257600180935093505050613190565b60028560068111156130f6576130f6613c93565b1480156131035750815142115b156131175760016003935093505050613190565b600385600681111561312b5761312b613c93565b14801561313b5750816020015142115b1561314f5760016006935093505050613190565b600485600681111561316357613163613c93565b1480156131735750816040015142115b15613187576001600a935093505050613190565b5f5f9350935050505b9250929050565b5f805460405162beb08960e51b8152600481018490526001600160a01b03909116906317d61120906024015f60405180830381865afa1580156131dc573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526132039190810190614892565b80515f848152600c60209081526040808320805490849055601190925282205493945091926001600160a01b0316908290036132a1576002546040516341489f1560e01b81526001600160a01b03909116906341489f159061326d9088908890869060040161493a565b5f604051808303815f87803b158015613284575f5ffd5b505af1158015613296573d5f5f3e3d5ffd5b505050505050505050565b825f03613342575f858152601060205260409020546001600160a01b031680156132d9576132d96001600160a01b0383168285612fe4565b6002546040516341489f1560e01b81526001600160a01b03909116906341489f159061330d9089908990879060040161493a565b5f604051808303815f87803b158015613324575f5ffd5b505af1158015613336573d5f5f3e3d5ffd5b50505050505050505050565b5f836001600160401b0381111561335b5761335b6139dd565b604051908082528060200260200182016040528015613384578160200160208202803683370190505b5090505f613392858561496a565b90505f805b868110156133d157828482815181106133b2576133b2614268565b60209081029190910101526133c783836142b1565b9150600101613397565b505f6133dd828761429e565b9050801561341a5780846133f260018a61429e565b8151811061340257613402614268565b6020026020010181815161341691906142b1565b9052505b600154613434906001600160a01b0387811691168861373e565b600154604051636ec640c760e11b81526001600160a01b039091169063dd8c818e906134689088908c9089906004016149b9565b5f604051808303815f87803b15801561347f575f5ffd5b505af1158015613491573d5f5f3e3d5ffd5b50506001546134af92506001600160a01b038881169250165f61373e565b887fac9fe8ad7f55eac03284399116ecafc104f10459773f4cdf47063c46e5be335a89866040516134e19291906149ee565b60405180910390a26002546040516341489f1560e01b81526001600160a01b03909116906341489f159061351d908c908c908a9060040161493a565b5f604051808303815f87803b158015613534575f5ffd5b505af1158015610936573d5f5f3e3d5ffd5b5f828152600d602052604081205460ff169081600681111561356a5761356a613c93565b0361358f57826001826040516337e1404160e01b815260040161099f93929190614614565b60058160068111156135a3576135a3613c93565b036135c45760405163462c7bed60e01b81526004810184905260240161099f565b60068160068111156135d8576135d8613c93565b036135f957604051633de16e3560e11b81526004810184905260240161099f565b5f838152600d6020526040902080546006919060ff191660018302179055505f838152600f60205260409020805483919060ff1916600183600d81111561364257613642613c93565b0217905550825f516020614a1c5f395f51905f5282600660405161366792919061454f565b60405180910390a2827fe20209be7caae6e76291267cfa711353981274bf127e94f16eb9ec44b68582bb82846040516136a1929190614877565b60405180910390a2505050565b6136b66137ce565b61194c57604051631afcd79f60e31b815260040160405180910390fd5b61297f6136ae565b5f5f60205f8451602086015f885af1806136fa576040513d5f823e3d81fd5b50505f513d9150811561371157806001141561371e565b6001600160a01b0384163b155b15612e7a5783604051635274afe760e01b815260040161099f9190613c2a565b5f836001600160a01b031663095ea7b38484604051602401613761929190614921565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050905061379a84826137e7565b612e7a576137c484856001600160a01b031663095ea7b3865f604051602401612e48929190614921565b612e7a84826136db565b5f6137d7612c72565b54600160401b900460ff16919050565b5f5f5f5f60205f8651602088015f8a5af192503d91505f519050828015613826575081156138185780600114613826565b5f866001600160a01b03163b115b9695505050505050565b604080516101e081019091525f808252602082019081526020015f8152602001613858613987565b81525f602082018190526040820181905260608083018190526080830181905260a0830182905260c0830182905260e08301829052610100830182905261012083015261014082018190526101609091015290565b82600281019282156138db579160200282015b828111156138db5782518255916020019190600101906138c0565b506138e79291506139a5565b5090565b6001830191839082156138db579160200282015f5b8382111561394a57833563ffffffff1683826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302613900565b801561397a5782816101000a81549063ffffffff021916905560040160208160030104928301926001030261394a565b50506138e79291506139a5565b60405180604001604052806002906020820280368337509192915050565b5b808211156138e7575f81556001016139a6565b6001600160a01b0381168114610ae3575f5ffd5b5f60608284031215611007575f5ffd5b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b0381118282101715613a1957613a196139dd565b604052919050565b5f6001600160401b03821115613a3957613a396139dd565b5060051b60200190565b5f82601f830112613a52575f5ffd5b81356001600160401b03811115613a6b57613a6b6139dd565b613a7e601f8201601f19166020016139f1565b818152846020838601011115613a92575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f82601f830112613abd575f5ffd5b8135613ad0613acb82613a21565b6139f1565b8082825260208201915060208360051b860101925085831115613af1575f5ffd5b602085015b83811015613b315780356001600160401b03811115613b13575f5ffd5b613b22886020838a0101613a43565b84525060209283019201613af6565b5095945050505050565b5f5f5f5f5f5f5f5f610140898b031215613b53575f5ffd5b8835613b5e816139b9565b97506020890135613b6e816139b9565b96506040890135613b7e816139b9565b95506060890135613b8e816139b9565b94506080890135613b9e816139b9565b935060a08901359250613bb48a60c08b016139cd565b91506101208901356001600160401b03811115613bcf575f5ffd5b613bdb8b828c01613aae565b9150509295985092959890939650565b5f60208284031215613bfb575f5ffd5b8135612fdd816139b9565b5f60208284031215613c16575f5ffd5b5035919050565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b803560048110613c4c575f5ffd5b919050565b5f5f60408385031215613c62575f5ffd5b613c6b83613c3e565b946020939093013593505050565b5f60608284031215613c89575f5ffd5b612fdd83836139cd565b634e487b7160e01b5f52602160045260245ffd5b600e8110613cb757613cb7613c93565b9052565b60208101612c968284613ca7565b60048110613cb757613cb7613c93565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b8e8152613d17602082018f613cc9565b8c60408201528b6060820152613d30608082018c613c1d565b6101c060a08201525f613d476101c083018c613cd9565b82810360c0840152613d59818c613cd9565b9050613d6860e084018b613c1d565b613d7661010084018a613c1d565b8761012084015286610140840152828103610160840152613d978187613cd9565b915050613da8610180830185613c1d565b8215156101a08301529f9e505050505050505050505050505050565b805f5b6002811015612e7a578151845260209384019390910190600101613dc7565b805182525f6020820151613dfd6020850182613cc9565b50604082015160408401526060820151613e1a6060850182613dc4565b50608082015160a084015260a0820151613e3760c0850182613c1d565b5060c082015161020060e0850152613e53610200850182613cd9565b905060e0830151848203610100860152613e6d8282613cd9565b915050610100830151613e84610120860182613c1d565b50610120830151613e99610140860182613c1d565b506101408301516101608501526101608301516101808501526101808301518482036101a0860152613ecb8282613cd9565b9150506101a0830151613ee26101c0860182613c1d565b506101c08301518015156101e0860152612f65565b602081525f612fdd6020830184613de6565b5f60208284031215613f19575f5ffd5b81356001600160401b03811115613f2e575f5ffd5b613f3a84828501613a43565b949350505050565b5f60208284031215613f52575f5ffd5b81356001600160401b03811115613f67575f5ffd5b82016101008185031215612fdd575f5ffd5b828152604060208201525f613f3a6040830184613de6565b5f60208284031215613fa1575f5ffd5b81356001600160401b03811115613fb6575f5ffd5b613f3a84828501613aae565b5f5f60408385031215613fd3575f5ffd5b823591506020830135613fe5816139b9565b809150509250929050565b5f5f60408385031215614001575f5ffd5b50508035926020909101359150565b81518152602080830151908201526040808301519082015260608101612c96565b821515815260408101612fdd6020830184613ca7565b5f5f83601f840112614057575f5ffd5b5081356001600160401b0381111561406d575f5ffd5b602083019150836020828501011115613190575f5ffd5b5f5f5f5f5f60608688031215614098575f5ffd5b8535945060208601356001600160401b038111156140b4575f5ffd5b6140c088828901614047565b90955093505060408601356001600160401b038111156140de575f5ffd5b6140ea88828901614047565b969995985093965092949392505050565b5f5f5f5f5f5f5f6080888a031215614111575f5ffd5b8735965060208801356001600160401b0381111561412d575f5ffd5b6141398a828b01614047565b90975095505060408801356001600160401b03811115614157575f5ffd5b6141638a828b01614047565b90955093505060608801356001600160401b03811115614181575f5ffd5b61418d8a828b01614047565b989b979a50959850939692959293505050565b5f5f604083850312156141b1575f5ffd5b82359150602083013560ff81168114613fe5575f5ffd5b60078110613cb757613cb7613c93565b60208101612c9682846141c8565b5f5f606083850312156141f7575f5ffd5b61420083613c3e565b915083606084011115614211575f5ffd5b50926020919091019150565b600181811c9082168061423157607f821691505b60208210810361100757634e487b7160e01b5f52602260045260245ffd5b5f6020828403121561425f575f5ffd5b612fdd82613c3e565b634e487b7160e01b5f52603260045260245ffd5b60208101612c968284613cc9565b634e487b7160e01b5f52601160045260245ffd5b81810381811115612c9657612c9661428a565b80820180821115612c9657612c9661428a565b5f600182016142d5576142d561428a565b5060010190565b5f5f8335601e198436030181126142f1575f5ffd5b8301803591506001600160401b0382111561430a575f5ffd5b602001915036819003821315613190575f5ffd5b8015158114610ae3575f5ffd5b5f6020828403121561433b575f5ffd5b8135612fdd8161431e565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b88815287602082015260a060408201525f61438d60a08301888a614346565b82810360608401526143a0818789614346565b905082810360808401526143b5818587614346565b9b9a5050505050505050505050565b5f602082840312156143d4575f5ffd5b5051919050565b601f82111561300a57805f5260205f20601f840160051c810160208510156144005750805b601f840160051c820191505b8181101561441f575f815560010161440c565b5050505050565b5f19600383901b1c191660019190911b1790565b81516001600160401b03811115614453576144536139dd565b61446781614461845461421d565b846143db565b6020601f821160018114614494575f83156144825750848201515b61448c8482614426565b85555061441f565b5f84815260208120601f198516915b828110156144c357878501518255602094850194600190920191016144a3565b50848210156144e057868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b838152602081018390526080810160408201835f5b600281101561452957815163ffffffff16835260209283019290910190600101614504565b505050949350505050565b5f60208284031215614544575f5ffd5b8151612fdd8161431e565b6040810161455d82856141c8565b612fdd60208301846141c8565b5f82518060208501845e5f920191825250919050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b828110156145d757603f198786030184526145c2858351613cd9565b945060209384019391909101906001016145a6565b50929695505050505050565b6020808252601790820152764f6e6c79204369706865726e6f6465526567697374727960481b604082015260600190565b8381526060810161462860208301856141c8565b613f3a60408301846141c8565b5f8151808452602084019350602083015f5b8281101561466e5781516001600160a01b0316865260209586019590910190600101614647565b5093949350505050565b848152836020820152608060408201525f6146966080830185614635565b905060018060a01b038316606083015295945050505050565b818382375f9101908152919050565b848152836020820152606060408201525f613826606083018486614346565b602081525f613f3a602083018486614346565b6001600160401b03831115614707576147076139dd565b61471b83614715835461421d565b836143db565b5f601f841160018114614747575f85156147355750838201355b61473f8682614426565b84555061441f565b5f83815260208120601f198716915b828110156147765786850135825560209485019460019092019101614756565b5086821015614792575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b858152606060208201525f6147bd606083018688614346565b82810360408401526147d0818587614346565b98975050505050505050565b604081525f6147ef604083018688614346565b8281036020840152614802818587614346565b979650505050505050565b803563ffffffff81168114613c4c575f5ffd5b5f60208284031215614830575f5ffd5b612fdd8261480d565b6040810181835f5b600281101561486e5763ffffffff6148588361480d565b1683526020928301929190910190600101614841565b50505092915050565b6040810161488582856141c8565b612fdd6020830184613ca7565b5f602082840312156148a2575f5ffd5b81516001600160401b038111156148b7575f5ffd5b8201601f810184136148c7575f5ffd5b80516148d5613acb82613a21565b8082825260208201915060208360051b8501019250868311156148f6575f5ffd5b6020840193505b82841015613826578351614910816139b9565b8252602093840193909101906148fd565b6001600160a01b03929092168252602082015260400190565b838152606060208201525f6149526060830185614635565b905060018060a01b0383166040830152949350505050565b5f8261498457634e487b7160e01b5f52601260045260245ffd5b500490565b5f8151808452602084019350602083015f5b8281101561466e57815186526020958601959091019060010161499b565b6001600160a01b03841681526060602082018190525f906149dc90830185614635565b82810360408401526138268185614989565b604081525f614a006040830185614635565b8281036020840152614a128185614989565b9594505050505056fe1b418a230a21d37a078bf8f16decbde8ccceacd77159371f62f0d4ea00d19967a164736f6c634300081c000a", - "deployedBytecode": "0x608060405234801561000f575f5ffd5b50600436106102c3575f3560e01c806390173a4111610177578063cb649617116100d5578063ea71aa571161008f578063ea71aa5714610745578063f0691cba14610758578063f2fde38b1461076b578063f81b8ef61461077e578063fad8e11114610791578063fbdb3237146107a4578063fd2f3d01146107cc575f5ffd5b8063cb649617146106c1578063cbd16872146106ca578063cf0f34c4146106dd578063cfbdc98d146106f0578063da16fb2f1461071f578063e59e469514610732575f5ffd5b8063ac3d2f4211610131578063ac3d2f4214610618578063b27392d514610640578063b68fd1be14610653578063bb2d1b8214610666578063bff232c114610679578063c1ab0f1f1461068c578063c4ccafa21461069f575f5ffd5b806390173a41146105815780639117173c1461059657806392312386146105a9578063929a8faf146105bc57806399c6679d146105dd5780639c8570c814610605575f5ffd5b80634fc77264116102245780637c8c3b4d116101de5780637c8c3b4d146105085780637cfa9d741461051b57806381476ec21461052e57806385814243146105415780638da5cb5b146105545780638dcdd86b1461055c5780638e5ce3ad1461056e575f5ffd5b80634fc772641461049d57806364226409146104b0578063647846a5146104d15780636db5c8fd146104e4578063715018a6146104ed57806377868ae4146104f5575f5ffd5b80631ba72945116102805780631ba729451461039057806336c5d38a146103a35780634017daf0146103d2578063406ed35c146103ff5780634147a3601461041f578063459d92941461044c5780634e92ec631461048a575f5ffd5b806301d12f1c146102c757806302a3a9c9146102dc5780630ef81b2f146102ef57806310bc62811461032d57806311bd61d91461035557806315cce2241461037d575b5f5ffd5b6102da6102d5366004613b3b565b6107df565b005b6102da6102ea366004613beb565b610945565b6103176102fd366004613c06565b5f908152600960205260409020546001600160a01b031690565b6040516103249190613c2a565b60405180910390f35b61031761033b366004613c06565b60096020525f90815260409020546001600160a01b031681565b610368610363366004613c51565b6109f1565b60405163ffffffff9091168152602001610324565b6102da61038b366004613beb565b610a2d565b6102da61039e366004613c79565b610ad2565b6103c56103b1366004613c06565b5f908152600f602052604090205460ff1690565b6040516103249190613cbb565b6103e56103e0366004613c06565b610ae6565b6040516103249e9d9c9b9a99989796959493929190613d07565b61041261040d366004613c06565b610d10565b6040516103249190613ef7565b61043e61042d366004613c06565b600c6020525f908152604090205481565b604051908152602001610324565b61047a61045a366004613f09565b8051602081830181018051600b8252928201919093012091525460ff1681565b6040519015158152602001610324565b6102da610498366004613c06565b61100d565b6102da6104ab366004613beb565b61109c565b6104c36104be366004613f42565b61112f565b604051610324929190613f79565b600454610317906001600160a01b031681565b61043e60055481565b6102da61193b565b6102da610503366004613f91565b61194e565b6102da610516366004613fc2565b6119e6565b6102da610529366004613c06565b611a6f565b6102da61053c366004613ff0565b611b6d565b600154610317906001600160a01b031681565b610317611c60565b5f54610317906001600160a01b031681565b600354610317906001600160a01b031681565b610589611c8e565b6040516103249190614010565b6102da6105a4366004613c06565b611cd4565b6105896105b7366004613c06565b611e7c565b6105cf6105ca366004613c06565b611ed5565b604051610324929190614031565b6103176105eb366004613c06565b5f908152601060205260409020546001600160a01b031690565b61047a610613366004614084565b611efc565b610317610626366004613c06565b5f908152600a60205260409020546001600160a01b031690565b61047a61064e3660046140fb565b612194565b6102da610661366004613f91565b6123c4565b6102da6106743660046141a0565b61245b565b6102da610687366004613beb565b612546565b6102da61069a366004613ff0565b6125ed565b61047a6106ad366004613beb565b60076020525f908152604090205460ff1681565b61043e60065481565b6102da6106d8366004613fc2565b6126d0565b6102da6106eb366004613c06565b612783565b6107126106fe366004613c06565b5f908152600d602052604090205460ff1690565b60405161032491906141d8565b61043e61072d366004613f42565b6127c0565b6102da610740366004613beb565b6127ca565b6102da6107533660046141e6565b612864565b600254610317906001600160a01b031681565b6102da610779366004613beb565b612977565b6103c561078c366004613c06565b6129b1565b6102da61079f366004613beb565b612b4b565b6103176107b2366004613c06565b600a6020525f90815260409020546001600160a01b031681565b6102da6107da366004613beb565b612be3565b5f6107e8612c72565b805490915060ff600160401b82041615906001600160401b03165f8115801561080e5750825b90505f826001600160401b031660011480156108295750303b155b905081158015610837575080155b156108555760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561087f57845460ff60401b1916600160401b1785555b61088833612c9c565b61089188612783565b61089a8c612b4b565b6108a38b6127ca565b6108ac8a610945565b6108b589610a2d565b6108be87612cad565b6108c7866123c4565b6108cf611c60565b6001600160a01b03168d6001600160a01b0316146108f0576108f08d612977565b831561093657845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050505050565b61094d612de1565b6001600160a01b0381166109a85760405162461bcd60e51b815260206004820152601f60248201527f496e76616c6964204533526566756e644d616e6167657220616464726573730060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040517f9557d04c1c0b16f93f13b69aed23b3b6ab935bff3c53ac81d17896d3583542ed905f90a250565b6012602052815f5260405f208160028110610a0a575f80fd5b60089182820401919006600402915091509054906101000a900463ffffffff1681565b610a35612de1565b6001600160a01b03811615801590610a5b57506004546001600160a01b03828116911614155b8190610a7b5760405163eddf07f560e01b815260040161099f9190613c2a565b50600480546001600160a01b0319166001600160a01b0383161790556040517f722ff84c1234b2482061def5c82c6b5080c117b3cbb69d686844a051e4b8e7f390610ac7908390613c2a565b60405180910390a150565b610ada612de1565b610ae381612cad565b50565b60086020525f9081526040902080546001820154600283015460058401546006850154600786018054959660ff90951695939492936001600160a01b039092169291610b319061421d565b80601f0160208091040260200160405190810160405280929190818152602001828054610b5d9061421d565b8015610ba85780601f10610b7f57610100808354040283529160200191610ba8565b820191905f5260205f20905b815481529060010190602001808311610b8b57829003601f168201915b505050505090806008018054610bbd9061421d565b80601f0160208091040260200160405190810160405280929190818152602001828054610be99061421d565b8015610c345780601f10610c0b57610100808354040283529160200191610c34565b820191905f5260205f20905b815481529060010190602001808311610c1757829003601f168201915b5050506009840154600a850154600b860154600c870154600d8801805497986001600160a01b03958616989490951696509194509291610c739061421d565b80601f0160208091040260200160405190810160405280929190818152602001828054610c9f9061421d565b8015610cea5780601f10610cc157610100808354040283529160200191610cea565b820191905f5260205f20905b815481529060010190602001808311610ccd57829003601f168201915b505050600e90930154919250506001600160a01b0381169060ff600160a01b909104168e565b610d18613830565b5f8281526008602090815260409182902082516101e08101909352805483526001810154909183019060ff166003811115610d5557610d55613c93565b6003811115610d6657610d66613c93565b8152600282810154602083015260408051808201808352919093019291600385019182845b815481526020019060010190808311610d8b5750505091835250506005820154602082015260068201546001600160a01b03166040820152600782018054606090920191610dd89061421d565b80601f0160208091040260200160405190810160405280929190818152602001828054610e049061421d565b8015610e4f5780601f10610e2657610100808354040283529160200191610e4f565b820191905f5260205f20905b815481529060010190602001808311610e3257829003601f168201915b50505050508152602001600882018054610e689061421d565b80601f0160208091040260200160405190810160405280929190818152602001828054610e949061421d565b8015610edf5780601f10610eb657610100808354040283529160200191610edf565b820191905f5260205f20905b815481529060010190602001808311610ec257829003601f168201915b505050918352505060098201546001600160a01b039081166020830152600a830154166040820152600b8201546060820152600c8201546080820152600d8201805460a090920191610f309061421d565b80601f0160208091040260200160405190810160405280929190818152602001828054610f5c9061421d565b8015610fa75780601f10610f7e57610100808354040283529160200191610fa7565b820191905f5260205f20905b815481529060010190602001808311610f8a57829003601f168201915b5050509183525050600e91909101546001600160a01b038082166020840152600160a01b90910460ff16151560409092019190915260a08201519192508391166110075760405163cd6f4a4f60e01b815260040161099f91815260200190565b50919050565b611015612de1565b5f8181526009602052604090205481906001600160a01b031661104e576040516381c4951960e01b815260040161099f91815260200190565b505f818152600960205260409081902080546001600160a01b0319169055517f104eb329a192aef26eddea07c2af5ad2587792e62b37ed4045b6ba59bc5540fc90610ac79083815260200190565b6110a4612de1565b6001600160a01b0381165f90815260076020526040902054819060ff166110df576040516321ac7c5f60e01b815260040161099f9190613c2a565b506001600160a01b0381165f9081526007602052604090819020805460ff19169055517f56070b80bd617fcd2f7a284861edb488830a38f9dedcd77b2cb2f4eac17743e790610ac7908390613c2a565b5f611138613830565b5f601281611149602087018761424f565b600381111561115a5761115a613c93565b600381111561116b5761116b613c93565b8152602081019190915260409081015f20815180830190925260028282826020028201915f905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411611192579050505050505090505f816001600281106111e9576111e9614268565b602002015163ffffffff1611845f016020810190611207919061424f565b906112265760405163286c068d60e11b815260040161099f919061427c565b5060208401354281101561125057604051630b99e87960e01b815260040161099f91815260200190565b506040840135602085013581101561127e5760405163174b5a0760e21b815260040161099f91815260200190565b506015546014545f919061129642604089013561429e565b6112a091906142b1565b6112aa91906142b1565b9050600554811081906112d3576040516313b783af60e21b815260040161099f91815260200190565b5060075f6112e76080880160608901613beb565b6001600160a01b0316815260208101919091526040015f205460ff166113136080870160608801613beb565b906113325760405163295a6a6f60e11b815260040161099f9190613c2a565b505f61133d866127c0565b60068054965090915085905f611352836142c4565b9091555050604080514460208201529081018690525f9060600160408051808303601f1901815291815281516020928301205f898152600c84528281208690556004546011855283822080546001600160a01b039092166001600160a01b0319928316179055600d8552838220805460ff1916600117905560109094528290208054339416939093179092556014549192506113f191908901356142b1565b5f878152600e60209081526040909120600101919091558186526114179088018861424f565b8560200190600381111561142d5761142d613c93565b9081600381111561144057611440613c93565b905250436040808701919091528051808201825290602089019060029083908390808284375f9201919091525050506060808701919091526114889060808901908901613beb565b6001600160a01b031660a08601526114a360808801886142dc565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050505060c0808701919091526114eb908801886142dc565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050505060e08087019190915261153890610100890190890161432b565b15156101c08601525f610140860181905261016086018190526040805160208101909152908152610180860152336101a08601819052600454611588916001600160a01b03909116903085612e13565b5f6115996080890160608a01613beb565b6001600160a01b031663fefd9a8b88846115b660808d018d6142dc565b6115c360a08f018f6142dc565b8f8060c001906115d391906142dc565b6040518963ffffffff1660e01b81526004016115f698979695949392919061436e565b6020604051808303815f875af1158015611612573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061163691906143c4565b5f818152600960205260409020549091506001600160a01b03168181611672576040516381c4951960e01b815260040161099f91815260200190565b505f828152600a60205260409020546001600160a01b031682816116ac576040516381c4951960e01b815260040161099f91815260200190565b50608088018390526001600160a01b038083166101008a015281166101208901525f8981526008602090815260409091208951815590890151600180830180548c94939260ff19919091169083600381111561170a5761170a613c93565b0217905550604082015181600201556060820151816003019060026117309291906138ad565b506080820151600582015560a08201516006820180546001600160a01b0319166001600160a01b0390921691909117905560c08201516007820190611775908261443a565b5060e0820151600882019061178a908261443a565b506101008201516009820180546001600160a01b039283166001600160a01b031991821617909155610120840151600a84018054919093169116179055610140820151600b820155610160820151600c820155610180820151600d8201906117f2908261443a565b506101a0820151600e90910180546101c0909301511515600160a01b026001600160a81b03199093166001600160a01b0392831617929092179091555f5460405163291a691b60e01b815291169063291a691b90611858908c9088908c906004016144ef565b6020604051808303815f875af1158015611874573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118989190614534565b6118b557604051630d8dbe2560e01b815260040160405180910390fd5b6118c560808b0160608c01613beb565b6001600160a01b03167f5904e83d57e704fba4d92c5617f6b50ae993cd42d78babfcb239d0a6775f30708a8a6040516118ff929190613f79565b60405180910390a2885f516020614a1c5f395f51905f525f600160405161192792919061454f565b60405180910390a250505050505050915091565b611943612de1565b61194c5f612e80565b565b611956612de1565b80515f5b818110156119aa57600b83828151811061197657611976614268565b602002602001015160405161198b919061456a565b908152604051908190036020019020805460ff1916905560010161195a565b507fd1b46e030b48add7bc03225cc5a6f403970976b36983f99ec31d535d627fc7db826040516119da9190614580565b60405180910390a15050565b6119ee612de1565b6001600160a01b03811615801590611a1f57505f828152600a60205260409020546001600160a01b03828116911614155b8290611a41576040516381c4951960e01b815260040161099f91815260200190565b505f918252600a602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b5f546001600160a01b03163314611a985760405162461bcd60e51b815260040161099f906145e3565b5f818152600d602052604090205460ff166001816006811115611abd57611abd613c93565b14611ae257816001826040516337e1404160e01b815260040161099f93929190614614565b5f828152600d60205260409020805460ff19166002179055601354611b0790426142b1565b5f838152600e602052604080822092909255905183917fc44405af9078047712501f519e1fb900c2896c62b488336f84529c72ae16e6f191a2815f516020614a1c5f395f51905f5260016002604051611b6192919061454f565b60405180910390a25050565b5f546001600160a01b03163314611b965760405162461bcd60e51b815260040161099f906145e3565b5f828152600860209081526040808320600d9092529091205460ff166002816006811115611bc657611bc6613c93565b14611beb57836002826040516337e1404160e01b815260040161099f93929190614614565b5f848152600d6020526040808220805460ff19166003179055600b84018590555185917f11df18edb9bc9cd90a79068e0e208b630202148643d797d6150e7bacb733e63c91a2835f516020614a1c5f395f51905f5260026003604051611c5292919061454f565b60405180910390a250505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b611caf60405180606001604052805f81526020015f81526020015f81525090565b5060408051606081018252601354815260145460208201526015549181019190915290565b5f818152600d602052604090205460ff166006816006811115611cf957611cf9613c93565b14611d365760405162461bcd60e51b815260206004820152600d60248201526c114cc81b9bdd0819985a5b1959609a1b604482015260640161099f565b5f828152600c602052604090205480611d885760405162461bcd60e51b8152602060048201526014602482015273139bc81c185e5b595b9d081d1bc81c99599d5b9960621b604482015260640161099f565b5f838152600c60205260408120819055611da184612ef0565b5f858152601160205260409020546002549192506001600160a01b0390811691611dce9183911685612fe4565b60025460405163da19b69760e01b81526001600160a01b039091169063da19b69790611e04908890879087908790600401614678565b5f604051808303815f87803b158015611e1b575f5ffd5b505af1158015611e2d573d5f5f3e3d5ffd5b50505050847f5297818f48a66292b8b3e2caab83eec531b669bb20807fd38cf006adb2a07317848451604051611e6d929190918252602082015260400190565b60405180910390a25050505050565b611e9d60405180606001604052805f81526020015f81526020015f81525090565b505f908152600e6020908152604091829020825160608101845281548152600182015492810192909252600201549181019190915290565b5f818152600d6020526040812054819060ff16611ef2848261300f565b9250925050915091565b5f5f611f0787610d10565b5f888152600d602052604090205490915060ff166003816006811115611f2f57611f2f613c93565b1488600383909192611f57576040516337e1404160e01b815260040161099f93929190614614565b5050505f888152600e6020908152604091829020825160608101845281548152600182015492810183905260029091015492810192909252899042811015611fbb576040516308f3034360e31b81526004810192909252602482015260440161099f565b5050606083015160200151899042811115611ff25760405163017e35e560e71b81526004810192909252602482015260440161099f565b505061016083015189901561201d57604051637eb9cea960e11b815260040161099f91815260200190565b505f888860405161202f9291906146af565b60408051918290039091205f8c815260086020908152838220600c01839055600d905291909120805460ff1916600417905560155490915061207190426142b1565b5f8b8152600e6020526040908190206002019190915560a08501519051632f0e1bbf60e01b81526001600160a01b0390911690632f0e1bbf906120be908d9085908c908c906004016146be565b6020604051808303815f875af11580156120da573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120fe9190614534565b945088888661212257604051632f9f8ab960e01b815260040161099f9291906146dd565b5050897f7cc27e4a5626cbc4f8ba1a927b0448de55e6a114bc87660331270c5109ade0718a8a6040516121569291906146dd565b60405180910390a2895f516020614a1c5f395f51905f526003600460405161217f92919061454f565b60405180910390a25050505095945050505050565b5f5f61219f89610d10565b5f8a8152600d602052604090205490915060ff1660048160068111156121c7576121c7613c93565b148a6004839091926121ef576040516337e1404160e01b815260040161099f93929190614614565b5050505f8a8152600e602090815260409182902082516060810184528154815260018201549281019290925260020154918101829052908b9042811015612252576040516308f3034360e31b81526004810192909252602482015260440161099f565b50505f8b8152600860205260409020600d0161226f8a8c836146f0565b505f8b8152600d6020526040902080546005919060ff191660018302179055508261010001516001600160a01b0316635bf48e3a8b8b6040516122b39291906146af565b6040519081900381206001600160e01b031960e084901b1682526122e1918c908c908c908c906004016147a4565b602060405180830381865afa1580156122fc573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123209190614534565b935089898561234457604051632f9f8ab960e01b815260040161099f9291906146dd565b505061234f8b613197565b8a7f3a140076c461ebc41d74833ae0ee8bbc8079a135a63392098cd381e84350b69b8b8b8b8b60405161238594939291906147dc565b60405180910390a28a5f516020614a1c5f395f51905f52600460056040516123ae92919061454f565b60405180910390a2505050979650505050505050565b6123cc612de1565b80515f5b8181101561242b576001600b8483815181106123ee576123ee614268565b6020026020010151604051612403919061456a565b908152604051908190036020019020805491151560ff199092169190911790556001016123d0565b507f027b83cad653f54850fef6faa8c705f73a53e7f8de50a3a33ac1e0e3a5c0be81826040516119da9190614580565b5f546001600160a01b031633148061247d57506003546001600160a01b031633145b6124c95760405162461bcd60e51b815260206004820152601c60248201527f4f6e6c79205265676973747279206f7220536c617368696e674d677200000000604482015260640161099f565b5f8160ff161180156124df5750600d60ff821611155b6125245760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b2103330b4b63ab932903932b0b9b7b760511b604482015260640161099f565b612542828260ff16600d81111561253d5761253d613c93565b613546565b5050565b61254e612de1565b6001600160a01b0381166125a45760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420536c617368696e674d616e61676572206164647265737300604482015260640161099f565b600380546001600160a01b0319166001600160a01b0383169081179091556040517f4ccc8ed483c7c44c3602c3c38afc2c014a8f1d2dc210dfe58ebeeeead230f8e0905f90a250565b6003546001600160a01b0316331461263e5760405162461bcd60e51b815260206004820152601460248201527327b7363c9029b630b9b434b733a6b0b730b3b2b960611b604482015260640161099f565b60025460405163c1ab0f1f60e01b815260048101849052602481018390526001600160a01b039091169063c1ab0f1f906044015f604051808303815f87803b158015612688575f5ffd5b505af115801561269a573d5f5f3e3d5ffd5b50505050817f4f41a3b0a032ebcae925f2ace77d507435840ca4b2dbaffdd7723fa8d72ee54282604051611b6191815260200190565b6126d8612de1565b6001600160a01b0381161580159061270957505f828152600960205260409020546001600160a01b03828116911614155b829061272b576040516381c4951960e01b815260040161099f91815260200190565b505f8281526009602090815260409182902080546001600160a01b0319166001600160a01b03851617905590518381527ff4041a3f914dac3bc9bf5f003ba41f28dbb84abe42f4e07c76266f5c8ceecb6991016119da565b61278b612de1565b60058190556040518181527fba0716ba1ee2ea8ecc4c64119b4537cdb42a99d82acf92af5b87607b8b52355290602001610ac7565b620f424080611007565b6127d2612de1565b6001600160a01b038116158015906127f857506001546001600160a01b03828116911614155b8190612818576040516320252f0b60e01b815260040161099f9190613c2a565b50600180546001600160a01b0319166001600160a01b0383161790556040517fad4055f18cdad6f4bdd71afe3a72cbeee964217943e1bde38f138289e981a9a790610ac7908390613c2a565b61286c612de1565b6128796020820182614820565b63ffffffff1661288f6040830160208401614820565b63ffffffff16101580156128b457505f6128ac6020830183614820565b63ffffffff16115b6128f45760405162461bcd60e51b8152602060048201526011602482015270125b9d985b1a59081d1a1c995cda1bdb19607a1b604482015260640161099f565b8060125f84600381111561290a5761290a613c93565b600381111561291b5761291b613c93565b815260208101919091526040015f206129359160026138eb565b5081600381111561294857612948613c93565b7f8b56fae526eee054f0849759a99fc7d4ff3823824ebf097a56f7d78adb6b34fa82604051611b619190614839565b61297f612de1565b6001600160a01b0381166129a8575f604051631e4fbdf760e01b815260040161099f9190613c2a565b610ae381612e80565b5f818152600d602052604081205460ff16818160068111156129d5576129d5613c93565b036129fa57826001826040516337e1404160e01b815260040161099f93929190614614565b6005816006811115612a0e57612a0e613c93565b03612a2f5760405163462c7bed60e01b81526004810184905260240161099f565b6006816006811115612a4357612a43613c93565b03612a6457604051633de16e3560e11b81526004810184905260240161099f565b5f612a6f848361300f565b9350905080612a9457604051639f65d93560e01b81526004810185905260240161099f565b5f848152600d6020526040902080546006919060ff191660018302179055505f848152600f60205260409020805484919060ff1916600183600d811115612add57612add613c93565b0217905550835f516020614a1c5f395f51905f52836006604051612b0292919061454f565b60405180910390a2837fe20209be7caae6e76291267cfa711353981274bf127e94f16eb9ec44b68582bb8385604051612b3c929190614877565b60405180910390a25050919050565b612b53612de1565b6001600160a01b03811615801590612b7857505f546001600160a01b03828116911614155b8190612b98576040516375ac4eb760e11b815260040161099f9190613c2a565b505f80546001600160a01b0319166001600160a01b0383161790556040517f80052b810d39120cf6c976cca504a21703f585521dc7a41c6d241090e6c579b690610ac7908390613c2a565b6001600160a01b0381165f90815260076020526040902054819060ff1615612c1f5760405163b29d459560e01b815260040161099f9190613c2a565b506001600160a01b0381165f9081526007602052604090819020805460ff19166001179055517fb8d368517268f297fff00825d67d098763117d061360d31027be5b2e1a59d46790610ac7908390613c2a565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005b92915050565b612ca46136ae565b610ae3816136d3565b8035612cf05760405162461bcd60e51b8152602060048201526012602482015271496e76616c696420444b472077696e646f7760701b604482015260640161099f565b5f816020013511612d3c5760405162461bcd60e51b8152602060048201526016602482015275496e76616c696420636f6d707574652077696e646f7760501b604482015260640161099f565b5f816040013511612d8b5760405162461bcd60e51b8152602060048201526019602482015278496e76616c69642064656372797074696f6e2077696e646f7760381b604482015260640161099f565b80356013819055602080830135601481905560408085013560158190558151948552928401919091528201527f7e86ba16b805e2835af5c5b7aa5a942ced8bcc1fb95a05fbe42dae3862350a1690606001610ac7565b33612dea611c60565b6001600160a01b03161461194c573360405163118cdaa760e01b815260040161099f9190613c2a565b6040516001600160a01b038481166024830152838116604483015260648201839052612e7a9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506136db565b50505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b5f818152600f602052604090205460609060ff16600181600d811115612f1857612f18613c93565b1480612f355750600281600d811115612f3357612f33613c93565b145b15612f6d575f5b604051908082528060200260200182016040528015612f65578160200160208202803683370190505b509392505050565b5f5460405162beb08960e51b8152600481018590526001600160a01b03909116906317d61120906024015f60405180830381865afa925050508015612fd357506040513d5f823e601f3d908101601f19168201604052612fd09190810190614892565b60015b612fdd575f612f3c565b9392505050565b61300a83846001600160a01b031663a9059cbb8585604051602401612e48929190614921565b505050565b5f828152600e60209081526040808320815160608101835281548152600182015493810193909352600201548282015282549051632800d82960e01b81526004810186905283929183916001600160a01b0390911690632800d82990602401602060405180830381865afa158015613089573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130ad91906143c4565b905060018560068111156130c3576130c3613c93565b1480156130cf57508042115b156130e257600180935093505050613190565b60028560068111156130f6576130f6613c93565b1480156131035750815142115b156131175760016003935093505050613190565b600385600681111561312b5761312b613c93565b14801561313b5750816020015142115b1561314f5760016006935093505050613190565b600485600681111561316357613163613c93565b1480156131735750816040015142115b15613187576001600a935093505050613190565b5f5f9350935050505b9250929050565b5f805460405162beb08960e51b8152600481018490526001600160a01b03909116906317d61120906024015f60405180830381865afa1580156131dc573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526132039190810190614892565b80515f848152600c60209081526040808320805490849055601190925282205493945091926001600160a01b0316908290036132a1576002546040516341489f1560e01b81526001600160a01b03909116906341489f159061326d9088908890869060040161493a565b5f604051808303815f87803b158015613284575f5ffd5b505af1158015613296573d5f5f3e3d5ffd5b505050505050505050565b825f03613342575f858152601060205260409020546001600160a01b031680156132d9576132d96001600160a01b0383168285612fe4565b6002546040516341489f1560e01b81526001600160a01b03909116906341489f159061330d9089908990879060040161493a565b5f604051808303815f87803b158015613324575f5ffd5b505af1158015613336573d5f5f3e3d5ffd5b50505050505050505050565b5f836001600160401b0381111561335b5761335b6139dd565b604051908082528060200260200182016040528015613384578160200160208202803683370190505b5090505f613392858561496a565b90505f805b868110156133d157828482815181106133b2576133b2614268565b60209081029190910101526133c783836142b1565b9150600101613397565b505f6133dd828761429e565b9050801561341a5780846133f260018a61429e565b8151811061340257613402614268565b6020026020010181815161341691906142b1565b9052505b600154613434906001600160a01b0387811691168861373e565b600154604051636ec640c760e11b81526001600160a01b039091169063dd8c818e906134689088908c9089906004016149b9565b5f604051808303815f87803b15801561347f575f5ffd5b505af1158015613491573d5f5f3e3d5ffd5b50506001546134af92506001600160a01b038881169250165f61373e565b887fac9fe8ad7f55eac03284399116ecafc104f10459773f4cdf47063c46e5be335a89866040516134e19291906149ee565b60405180910390a26002546040516341489f1560e01b81526001600160a01b03909116906341489f159061351d908c908c908a9060040161493a565b5f604051808303815f87803b158015613534575f5ffd5b505af1158015610936573d5f5f3e3d5ffd5b5f828152600d602052604081205460ff169081600681111561356a5761356a613c93565b0361358f57826001826040516337e1404160e01b815260040161099f93929190614614565b60058160068111156135a3576135a3613c93565b036135c45760405163462c7bed60e01b81526004810184905260240161099f565b60068160068111156135d8576135d8613c93565b036135f957604051633de16e3560e11b81526004810184905260240161099f565b5f838152600d6020526040902080546006919060ff191660018302179055505f838152600f60205260409020805483919060ff1916600183600d81111561364257613642613c93565b0217905550825f516020614a1c5f395f51905f5282600660405161366792919061454f565b60405180910390a2827fe20209be7caae6e76291267cfa711353981274bf127e94f16eb9ec44b68582bb82846040516136a1929190614877565b60405180910390a2505050565b6136b66137ce565b61194c57604051631afcd79f60e31b815260040160405180910390fd5b61297f6136ae565b5f5f60205f8451602086015f885af1806136fa576040513d5f823e3d81fd5b50505f513d9150811561371157806001141561371e565b6001600160a01b0384163b155b15612e7a5783604051635274afe760e01b815260040161099f9190613c2a565b5f836001600160a01b031663095ea7b38484604051602401613761929190614921565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050905061379a84826137e7565b612e7a576137c484856001600160a01b031663095ea7b3865f604051602401612e48929190614921565b612e7a84826136db565b5f6137d7612c72565b54600160401b900460ff16919050565b5f5f5f5f60205f8651602088015f8a5af192503d91505f519050828015613826575081156138185780600114613826565b5f866001600160a01b03163b115b9695505050505050565b604080516101e081019091525f808252602082019081526020015f8152602001613858613987565b81525f602082018190526040820181905260608083018190526080830181905260a0830182905260c0830182905260e08301829052610100830182905261012083015261014082018190526101609091015290565b82600281019282156138db579160200282015b828111156138db5782518255916020019190600101906138c0565b506138e79291506139a5565b5090565b6001830191839082156138db579160200282015f5b8382111561394a57833563ffffffff1683826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302613900565b801561397a5782816101000a81549063ffffffff021916905560040160208160030104928301926001030261394a565b50506138e79291506139a5565b60405180604001604052806002906020820280368337509192915050565b5b808211156138e7575f81556001016139a6565b6001600160a01b0381168114610ae3575f5ffd5b5f60608284031215611007575f5ffd5b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b0381118282101715613a1957613a196139dd565b604052919050565b5f6001600160401b03821115613a3957613a396139dd565b5060051b60200190565b5f82601f830112613a52575f5ffd5b81356001600160401b03811115613a6b57613a6b6139dd565b613a7e601f8201601f19166020016139f1565b818152846020838601011115613a92575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f82601f830112613abd575f5ffd5b8135613ad0613acb82613a21565b6139f1565b8082825260208201915060208360051b860101925085831115613af1575f5ffd5b602085015b83811015613b315780356001600160401b03811115613b13575f5ffd5b613b22886020838a0101613a43565b84525060209283019201613af6565b5095945050505050565b5f5f5f5f5f5f5f5f610140898b031215613b53575f5ffd5b8835613b5e816139b9565b97506020890135613b6e816139b9565b96506040890135613b7e816139b9565b95506060890135613b8e816139b9565b94506080890135613b9e816139b9565b935060a08901359250613bb48a60c08b016139cd565b91506101208901356001600160401b03811115613bcf575f5ffd5b613bdb8b828c01613aae565b9150509295985092959890939650565b5f60208284031215613bfb575f5ffd5b8135612fdd816139b9565b5f60208284031215613c16575f5ffd5b5035919050565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b803560048110613c4c575f5ffd5b919050565b5f5f60408385031215613c62575f5ffd5b613c6b83613c3e565b946020939093013593505050565b5f60608284031215613c89575f5ffd5b612fdd83836139cd565b634e487b7160e01b5f52602160045260245ffd5b600e8110613cb757613cb7613c93565b9052565b60208101612c968284613ca7565b60048110613cb757613cb7613c93565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b8e8152613d17602082018f613cc9565b8c60408201528b6060820152613d30608082018c613c1d565b6101c060a08201525f613d476101c083018c613cd9565b82810360c0840152613d59818c613cd9565b9050613d6860e084018b613c1d565b613d7661010084018a613c1d565b8761012084015286610140840152828103610160840152613d978187613cd9565b915050613da8610180830185613c1d565b8215156101a08301529f9e505050505050505050505050505050565b805f5b6002811015612e7a578151845260209384019390910190600101613dc7565b805182525f6020820151613dfd6020850182613cc9565b50604082015160408401526060820151613e1a6060850182613dc4565b50608082015160a084015260a0820151613e3760c0850182613c1d565b5060c082015161020060e0850152613e53610200850182613cd9565b905060e0830151848203610100860152613e6d8282613cd9565b915050610100830151613e84610120860182613c1d565b50610120830151613e99610140860182613c1d565b506101408301516101608501526101608301516101808501526101808301518482036101a0860152613ecb8282613cd9565b9150506101a0830151613ee26101c0860182613c1d565b506101c08301518015156101e0860152612f65565b602081525f612fdd6020830184613de6565b5f60208284031215613f19575f5ffd5b81356001600160401b03811115613f2e575f5ffd5b613f3a84828501613a43565b949350505050565b5f60208284031215613f52575f5ffd5b81356001600160401b03811115613f67575f5ffd5b82016101008185031215612fdd575f5ffd5b828152604060208201525f613f3a6040830184613de6565b5f60208284031215613fa1575f5ffd5b81356001600160401b03811115613fb6575f5ffd5b613f3a84828501613aae565b5f5f60408385031215613fd3575f5ffd5b823591506020830135613fe5816139b9565b809150509250929050565b5f5f60408385031215614001575f5ffd5b50508035926020909101359150565b81518152602080830151908201526040808301519082015260608101612c96565b821515815260408101612fdd6020830184613ca7565b5f5f83601f840112614057575f5ffd5b5081356001600160401b0381111561406d575f5ffd5b602083019150836020828501011115613190575f5ffd5b5f5f5f5f5f60608688031215614098575f5ffd5b8535945060208601356001600160401b038111156140b4575f5ffd5b6140c088828901614047565b90955093505060408601356001600160401b038111156140de575f5ffd5b6140ea88828901614047565b969995985093965092949392505050565b5f5f5f5f5f5f5f6080888a031215614111575f5ffd5b8735965060208801356001600160401b0381111561412d575f5ffd5b6141398a828b01614047565b90975095505060408801356001600160401b03811115614157575f5ffd5b6141638a828b01614047565b90955093505060608801356001600160401b03811115614181575f5ffd5b61418d8a828b01614047565b989b979a50959850939692959293505050565b5f5f604083850312156141b1575f5ffd5b82359150602083013560ff81168114613fe5575f5ffd5b60078110613cb757613cb7613c93565b60208101612c9682846141c8565b5f5f606083850312156141f7575f5ffd5b61420083613c3e565b915083606084011115614211575f5ffd5b50926020919091019150565b600181811c9082168061423157607f821691505b60208210810361100757634e487b7160e01b5f52602260045260245ffd5b5f6020828403121561425f575f5ffd5b612fdd82613c3e565b634e487b7160e01b5f52603260045260245ffd5b60208101612c968284613cc9565b634e487b7160e01b5f52601160045260245ffd5b81810381811115612c9657612c9661428a565b80820180821115612c9657612c9661428a565b5f600182016142d5576142d561428a565b5060010190565b5f5f8335601e198436030181126142f1575f5ffd5b8301803591506001600160401b0382111561430a575f5ffd5b602001915036819003821315613190575f5ffd5b8015158114610ae3575f5ffd5b5f6020828403121561433b575f5ffd5b8135612fdd8161431e565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b88815287602082015260a060408201525f61438d60a08301888a614346565b82810360608401526143a0818789614346565b905082810360808401526143b5818587614346565b9b9a5050505050505050505050565b5f602082840312156143d4575f5ffd5b5051919050565b601f82111561300a57805f5260205f20601f840160051c810160208510156144005750805b601f840160051c820191505b8181101561441f575f815560010161440c565b5050505050565b5f19600383901b1c191660019190911b1790565b81516001600160401b03811115614453576144536139dd565b61446781614461845461421d565b846143db565b6020601f821160018114614494575f83156144825750848201515b61448c8482614426565b85555061441f565b5f84815260208120601f198516915b828110156144c357878501518255602094850194600190920191016144a3565b50848210156144e057868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b838152602081018390526080810160408201835f5b600281101561452957815163ffffffff16835260209283019290910190600101614504565b505050949350505050565b5f60208284031215614544575f5ffd5b8151612fdd8161431e565b6040810161455d82856141c8565b612fdd60208301846141c8565b5f82518060208501845e5f920191825250919050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b828110156145d757603f198786030184526145c2858351613cd9565b945060209384019391909101906001016145a6565b50929695505050505050565b6020808252601790820152764f6e6c79204369706865726e6f6465526567697374727960481b604082015260600190565b8381526060810161462860208301856141c8565b613f3a60408301846141c8565b5f8151808452602084019350602083015f5b8281101561466e5781516001600160a01b0316865260209586019590910190600101614647565b5093949350505050565b848152836020820152608060408201525f6146966080830185614635565b905060018060a01b038316606083015295945050505050565b818382375f9101908152919050565b848152836020820152606060408201525f613826606083018486614346565b602081525f613f3a602083018486614346565b6001600160401b03831115614707576147076139dd565b61471b83614715835461421d565b836143db565b5f601f841160018114614747575f85156147355750838201355b61473f8682614426565b84555061441f565b5f83815260208120601f198716915b828110156147765786850135825560209485019460019092019101614756565b5086821015614792575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b858152606060208201525f6147bd606083018688614346565b82810360408401526147d0818587614346565b98975050505050505050565b604081525f6147ef604083018688614346565b8281036020840152614802818587614346565b979650505050505050565b803563ffffffff81168114613c4c575f5ffd5b5f60208284031215614830575f5ffd5b612fdd8261480d565b6040810181835f5b600281101561486e5763ffffffff6148588361480d565b1683526020928301929190910190600101614841565b50505092915050565b6040810161488582856141c8565b612fdd6020830184613ca7565b5f602082840312156148a2575f5ffd5b81516001600160401b038111156148b7575f5ffd5b8201601f810184136148c7575f5ffd5b80516148d5613acb82613a21565b8082825260208201915060208360051b8501019250868311156148f6575f5ffd5b6020840193505b82841015613826578351614910816139b9565b8252602093840193909101906148fd565b6001600160a01b03929092168252602082015260400190565b838152606060208201525f6149526060830185614635565b905060018060a01b0383166040830152949350505050565b5f8261498457634e487b7160e01b5f52601260045260245ffd5b500490565b5f8151808452602084019350602083015f5b8281101561466e57815186526020958601959091019060010161499b565b6001600160a01b03841681526060602082018190525f906149dc90830185614635565b82810360408401526138268185614989565b604081525f614a006040830185614635565b8281036020840152614a128185614989565b9594505050505056fe1b418a230a21d37a078bf8f16decbde8ccceacd77159371f62f0d4ea00d19967a164736f6c634300081c000a", + "bytecode": "0x6080604052348015600e575f5ffd5b5060156019565b60c9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff161560685760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b039081161460c65780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b615a72806100d65f395ff3fe608060405234801561000f575f5ffd5b50600436106102d9575f3560e01c80639117173c11610182578063cb649617116100e0578063ea71aa571161008f578063ea71aa57146108c0578063f0691cba146108d3578063f2fde38b146108e6578063f81b8ef6146108f9578063fad8e1111461090c578063fbdb32371461091f578063fd2f3d0114610947575f5ffd5b8063cb64961714610829578063cbd1687214610832578063cf0f34c414610845578063cfbdc98d14610858578063d8afed3e14610887578063da16fb2f1461089a578063e59e4695146108ad575f5ffd5b8063ac3d2f421161013c578063ac3d2f4214610780578063b27392d5146107a8578063b68fd1be146107bb578063bb2d1b82146107ce578063bff232c1146107e1578063c1ab0f1f146107f4578063c4ccafa214610807575f5ffd5b80639117173c146105ac57806392312386146105bf578063929a8faf146105d257806399c6679d146105f35780639c8570c81461061b578063a87f4ab91461062e575f5ffd5b80634fc772641161023a5780637cfa9d74116101e95780637cfa9d741461053157806381476ec21461054457806385814243146105575780638da5cb5b1461056a5780638dcdd86b146105725780638e5ce3ad1461058457806390173a4114610597575f5ffd5b80634fc77264146104b357806364226409146104c6578063647846a5146104e75780636db5c8fd146104fa578063715018a61461050357806377868ae41461050b5780637c8c3b4d1461051e575f5ffd5b80631ba72945116102965780631ba72945146103a657806336c5d38a146103b95780634017daf0146103e8578063406ed35c146104155780634147a36014610435578063459d9294146104625780634e92ec63146104a0575f5ffd5b806301d12f1c146102dd57806302a3a9c9146102f25780630ef81b2f1461030557806310bc62811461034357806311bd61d91461036b57806315cce22414610393575b5f5ffd5b6102f06102eb36600461472f565b61095a565b005b6102f06103003660046147df565b610ba1565b61032d6103133660046147fa565b5f908152600960205260409020546001600160a01b031690565b60405161033a919061481e565b60405180910390f35b61032d6103513660046147fa565b60096020525f90815260409020546001600160a01b031681565b61037e610379366004614840565b610c4d565b60405163ffffffff909116815260200161033a565b6102f06103a13660046147df565b610c89565b6102f06103b4366004614868565b610d2e565b6103db6103c73660046147fa565b5f908152600f602052604090205460ff1690565b60405161033a91906148aa565b6103fb6103f63660046147fa565b610d42565b60405161033a9e9d9c9b9a999897969594939291906148f6565b6104286104233660046147fa565b610f6c565b60405161033a9190614ae6565b6104546104433660046147fa565b600c6020525f908152604090205481565b60405190815260200161033a565b610490610470366004614af8565b8051602081830181018051600b8252928201919093012091525460ff1681565b604051901515815260200161033a565b6102f06104ae3660046147fa565b611269565b6102f06104c13660046147df565b6112f8565b6104d96104d4366004614b31565b61138b565b60405161033a929190614b68565b60045461032d906001600160a01b031681565b61045460055481565b6102f0611bd3565b6102f0610519366004614b80565b611be6565b6102f061052c366004614bb1565b611c7e565b6102f061053f3660046147fa565b611d07565b6102f0610552366004614bdf565b611e06565b60015461032d906001600160a01b031681565b61032d611efa565b5f5461032d906001600160a01b031681565b60035461032d906001600160a01b031681565b61059f611f28565b60405161033a9190614bff565b6102f06105ba3660046147fa565b611f6e565b61059f6105cd3660046147fa565b6120dc565b6105e56105e03660046147fa565b612135565b60405161033a929190614c20565b61032d6106013660046147fa565b5f908152601060205260409020546001600160a01b031690565b610490610629366004614c73565b61215c565b610773604080516101e0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081019190915250604080516101e0810182526018548152601954602080830191909152601a5492820192909252601b546060820152601c546080820152601d5460a0820152601e5460c0820152601f546001600160a01b03811660e083015261ffff600160a01b82048116610100840152600160b01b82048116610120840152600160c01b82048116610140840152600160d01b82048116610160840152600160e01b90910416610180820152905463ffffffff8082166101a0840152640100000000909104166101c082015290565b60405161033a9190614cea565b61032d61078e3660046147fa565b5f908152600a60205260409020546001600160a01b031690565b6104906107b6366004614df7565b6123f4565b6102f06107c9366004614b80565b612624565b6102f06107dc366004614e9c565b6126bb565b6102f06107ef3660046147df565b612777565b6102f0610802366004614bdf565b61281e565b6104906108153660046147df565b60076020525f908152604090205460ff1681565b61045460065481565b6102f0610840366004614bb1565b6128db565b6102f06108533660046147fa565b61298e565b61087a6108663660046147fa565b5f908152600d602052604090205460ff1690565b60405161033a9190614ed4565b6102f0610895366004614ee2565b6129cb565b6104546108a8366004614b31565b612c58565b6102f06108bb3660046147df565b6131dc565b6102f06108ce366004614efc565b613276565b60025461032d906001600160a01b031681565b6102f06108f43660046147df565b613523565b6103db6109073660046147fa565b61355d565b6102f061091a3660046147df565b6136f7565b61032d61092d3660046147fa565b600a6020525f90815260409020546001600160a01b031681565b6102f06109553660046147df565b61378f565b5f61096361381e565b805490915060ff600160401b82041615906001600160401b03165f811580156109895750825b90505f826001600160401b031660011480156109a45750303b155b9050811580156109b2575080155b156109d05760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156109fa57845460ff60401b1916600160401b1785555b610a0333613848565b610a0c8861298e565b610a158c6136f7565b610a1e8b6131dc565b610a278a610ba1565b610a3089610c89565b610a3987613859565b610a4286612624565b604080516101e08101825261c3508082526161a86020808401829052611388948401859052601460608501819052620249f0608086018190526207a12060a087018190526107d060c088018190525f60e089018190526103e86101008a015261012089018190526109c46101408a018190526101608a018b90526101808a01526101a089018190526101c090980197909752601895909555601993909355601a95909555601b94909455601c55601d55601e55601f80546001600160f01b031916690138827101388000007d60a31b179055805467ffffffffffffffff19169055610b2b611efa565b6001600160a01b03168d6001600160a01b031614610b4c57610b4c8d613523565b8315610b9257845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050505050565b610ba9613916565b6001600160a01b038116610c045760405162461bcd60e51b815260206004820152601f60248201527f496e76616c6964204533526566756e644d616e6167657220616464726573730060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040517f9557d04c1c0b16f93f13b69aed23b3b6ab935bff3c53ac81d17896d3583542ed905f90a250565b6012602052815f5260405f208160028110610c66575f80fd5b60089182820401919006600402915091509054906101000a900463ffffffff1681565b610c91613916565b6001600160a01b03811615801590610cb757506004546001600160a01b03828116911614155b8190610cd75760405163eddf07f560e01b8152600401610bfb919061481e565b50600480546001600160a01b0319166001600160a01b0383161790556040517f722ff84c1234b2482061def5c82c6b5080c117b3cbb69d686844a051e4b8e7f390610d2390839061481e565b60405180910390a150565b610d36613916565b610d3f81613859565b50565b60086020525f9081526040902080546001820154600283015460058401546006850154600786018054959660ff90951695939492936001600160a01b039092169291610d8d90614f33565b80601f0160208091040260200160405190810160405280929190818152602001828054610db990614f33565b8015610e045780601f10610ddb57610100808354040283529160200191610e04565b820191905f5260205f20905b815481529060010190602001808311610de757829003601f168201915b505050505090806008018054610e1990614f33565b80601f0160208091040260200160405190810160405280929190818152602001828054610e4590614f33565b8015610e905780601f10610e6757610100808354040283529160200191610e90565b820191905f5260205f20905b815481529060010190602001808311610e7357829003601f168201915b5050506009840154600a850154600b860154600c870154600d8801805497986001600160a01b03958616989490951696509194509291610ecf90614f33565b80601f0160208091040260200160405190810160405280929190818152602001828054610efb90614f33565b8015610f465780601f10610f1d57610100808354040283529160200191610f46565b820191905f5260205f20905b815481529060010190602001808311610f2957829003601f168201915b505050600e90930154919250506001600160a01b0381169060ff600160a01b909104168e565b610f74614414565b5f8281526008602090815260409182902082516101e08101909352805483526001810154909183019060ff166003811115610fb157610fb1614882565b6003811115610fc257610fc2614882565b8152600282810154602083015260408051808201808352919093019291600385019182845b815481526020019060010190808311610fe75750505091835250506005820154602082015260068201546001600160a01b0316604082015260078201805460609092019161103490614f33565b80601f016020809104026020016040519081016040528092919081815260200182805461106090614f33565b80156110ab5780601f10611082576101008083540402835291602001916110ab565b820191905f5260205f20905b81548152906001019060200180831161108e57829003601f168201915b505050505081526020016008820180546110c490614f33565b80601f01602080910402602001604051908101604052809291908181526020018280546110f090614f33565b801561113b5780601f106111125761010080835404028352916020019161113b565b820191905f5260205f20905b81548152906001019060200180831161111e57829003601f168201915b505050918352505060098201546001600160a01b039081166020830152600a830154166040820152600b8201546060820152600c8201546080820152600d8201805460a09092019161118c90614f33565b80601f01602080910402602001604051908101604052809291908181526020018280546111b890614f33565b80156112035780601f106111da57610100808354040283529160200191611203565b820191905f5260205f20905b8154815290600101906020018083116111e657829003601f168201915b5050509183525050600e91909101546001600160a01b038082166020840152600160a01b90910460ff16151560409092019190915260a08201519192508391166112635760405163cd6f4a4f60e01b8152600401610bfb91815260200190565b50919050565b611271613916565b5f8181526009602052604090205481906001600160a01b03166112aa576040516381c4951960e01b8152600401610bfb91815260200190565b505f818152600960205260409081902080546001600160a01b0319169055517f104eb329a192aef26eddea07c2af5ad2587792e62b37ed4045b6ba59bc5540fc90610d239083815260200190565b611300613916565b6001600160a01b0381165f90815260076020526040902054819060ff1661133b576040516321ac7c5f60e01b8152600401610bfb919061481e565b506001600160a01b0381165f9081526007602052604090819020805460ff19169055517f56070b80bd617fcd2f7a284861edb488830a38f9dedcd77b2cb2f4eac17743e790610d2390839061481e565b5f611394614414565b5f6012816113a56020870187614f65565b60038111156113b6576113b6614882565b60038111156113c7576113c7614882565b8152602081019190915260409081015f20815180830190925260028282826020028201915f905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116113ee579050505050505090505f8160016002811061144557611445614f7e565b602002015163ffffffff1611845f0160208101906114639190614f65565b906114825760405163286c068d60e11b8152600401610bfb9190614f92565b506020840135428110156114ac57604051630b99e87960e01b8152600401610bfb91815260200190565b50604084013560208501358110156114da5760405163174b5a0760e21b8152600401610bfb91815260200190565b506017546016545f91906114f2426040890135614fb4565b6114fc9190614fc7565b6115069190614fc7565b90506005548110819061152f576040516313b783af60e21b8152600401610bfb91815260200190565b5060075f61154360808801606089016147df565b6001600160a01b0316815260208101919091526040015f205460ff1661156f60808701606088016147df565b9061158e5760405163295a6a6f60e11b8152600401610bfb919061481e565b505f61159986612c58565b60068054965090915085905f6115ae83614fda565b9091555050604080514460208201529081018690525f9060600160408051601f1981840301815291815281516020928301205f898152600c84528281208690556004546011855283822080546001600160a01b03199081166001600160a01b0393841617909155601f805460138852868520805461ffff191661ffff600160b01b909304929092169190911790555460148752858420805483169190931617909155600d8552838220805460ff1916600117905560109094528290208054339416939093179092556016549192506116899190890135614fc7565b5f878152600e60209081526040909120600101919091558186526116af90880188614f65565b856020019060038111156116c5576116c5614882565b908160038111156116d8576116d8614882565b905250436040808701919091528051808201825290602089019060029083908390808284375f92019190915250505060608087019190915261172090608089019089016147df565b6001600160a01b031660a086015261173b6080880188614ff2565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050505060c08087019190915261178390880188614ff2565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050505060e0808701919091526117d0906101008901908901615041565b15156101c08601525f610140860181905261016086018190526040805160208101909152908152610180860152336101a08601819052600454611820916001600160a01b03909116903085613948565b5f6118316080890160608a016147df565b6001600160a01b031663fefd9a8b888461184e60808d018d614ff2565b61185b60a08f018f614ff2565b8f8060c0019061186b9190614ff2565b6040518963ffffffff1660e01b815260040161188e989796959493929190615084565b6020604051808303815f875af11580156118aa573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118ce91906150da565b5f818152600960205260409020549091506001600160a01b0316818161190a576040516381c4951960e01b8152600401610bfb91815260200190565b505f828152600a60205260409020546001600160a01b03168281611944576040516381c4951960e01b8152600401610bfb91815260200190565b50608088018390526001600160a01b038083166101008a015281166101208901525f8981526008602090815260409091208951815590890151600180830180548c94939260ff1991909116908360038111156119a2576119a2614882565b0217905550604082015181600201556060820151816003019060026119c8929190614491565b506080820151600582015560a08201516006820180546001600160a01b0319166001600160a01b0390921691909117905560c08201516007820190611a0d9082615150565b5060e08201516008820190611a229082615150565b506101008201516009820180546001600160a01b039283166001600160a01b031991821617909155610120840151600a84018054919093169116179055610140820151600b820155610160820151600c820155610180820151600d820190611a8a9082615150565b506101a0820151600e90910180546101c0909301511515600160a01b026001600160a81b03199093166001600160a01b0392831617929092179091555f5460405163291a691b60e01b815291169063291a691b90611af0908c9088908c90600401615205565b6020604051808303815f875af1158015611b0c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b30919061524a565b611b4d57604051630d8dbe2560e01b815260040160405180910390fd5b611b5d60808b0160608c016147df565b6001600160a01b03167f5904e83d57e704fba4d92c5617f6b50ae993cd42d78babfcb239d0a6775f30708a8a604051611b97929190614b68565b60405180910390a2885f516020615a465f395f51905f525f6001604051611bbf929190615265565b60405180910390a250505050505050915091565b611bdb613916565b611be45f6139b5565b565b611bee613916565b80515f5b81811015611c4257600b838281518110611c0e57611c0e614f7e565b6020026020010151604051611c239190615280565b908152604051908190036020019020805460ff19169055600101611bf2565b507fd1b46e030b48add7bc03225cc5a6f403970976b36983f99ec31d535d627fc7db82604051611c729190615296565b60405180910390a15050565b611c86613916565b6001600160a01b03811615801590611cb757505f828152600a60205260409020546001600160a01b03828116911614155b8290611cd9576040516381c4951960e01b8152600401610bfb91815260200190565b505f918252600a602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b5f546001600160a01b03163314611d315760405163b56831db60e01b815260040160405180910390fd5b5f818152600d602052604090205460ff166001816006811115611d5657611d56614882565b14611d7b57816001826040516337e1404160e01b8152600401610bfb939291906152f9565b5f828152600d60205260409020805460ff19166002179055601554611da09042614fc7565b5f838152600e602052604080822092909255905183917fc44405af9078047712501f519e1fb900c2896c62b488336f84529c72ae16e6f191a2815f516020615a465f395f51905f5260016002604051611dfa929190615265565b60405180910390a25050565b5f546001600160a01b03163314611e305760405163b56831db60e01b815260040160405180910390fd5b5f828152600860209081526040808320600d9092529091205460ff166002816006811115611e6057611e60614882565b14611e8557836002826040516337e1404160e01b8152600401610bfb939291906152f9565b5f848152600d6020526040808220805460ff19166003179055600b84018590555185917f11df18edb9bc9cd90a79068e0e208b630202148643d797d6150e7bacb733e63c91a2835f516020615a465f395f51905f5260026003604051611eec929190615265565b60405180910390a250505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b611f4960405180606001604052805f81526020015f81526020015f81525090565b5060408051606081018252601554815260165460208201526017549181019190915290565b5f818152600d602052604090205460ff166006816006811115611f9357611f93614882565b148290611fb657604051637cb2d48360e11b8152600401610bfb91815260200190565b505f828152600c60205260409020548281611fe7576040516345ba89d560e11b8152600401610bfb91815260200190565b505f838152600c6020526040812081905561200184613a25565b5f858152601160205260409020546002549192506001600160a01b039081169161202e9183911685613b19565b60025460405163da19b69760e01b81526001600160a01b039091169063da19b6979061206490889087908790879060040161535d565b5f604051808303815f87803b15801561207b575f5ffd5b505af115801561208d573d5f5f3e3d5ffd5b50505050847f5297818f48a66292b8b3e2caab83eec531b669bb20807fd38cf006adb2a073178484516040516120cd929190918252602082015260400190565b60405180910390a25050505050565b6120fd60405180606001604052805f81526020015f81526020015f81525090565b505f908152600e6020908152604091829020825160608101845281548152600182015492810192909252600201549181019190915290565b5f818152600d6020526040812054819060ff166121528482613b44565b9250925050915091565b5f5f61216787610f6c565b5f888152600d602052604090205490915060ff16600381600681111561218f5761218f614882565b14886003839091926121b7576040516337e1404160e01b8152600401610bfb939291906152f9565b5050505f888152600e602090815260409182902082516060810184528154815260018201549281018390526002909101549281019290925289904281101561221b576040516308f3034360e31b815260048101929092526024820152604401610bfb565b50506060830151602001518990428111156122525760405163017e35e560e71b815260048101929092526024820152604401610bfb565b505061016083015189901561227d57604051637eb9cea960e11b8152600401610bfb91815260200190565b505f888860405161228f929190615394565b60408051918290039091205f8c815260086020908152838220600c01839055600d905291909120805460ff191660041790556017549091506122d19042614fc7565b5f8b8152600e6020526040908190206002019190915560a08501519051632f0e1bbf60e01b81526001600160a01b0390911690632f0e1bbf9061231e908d9085908c908c906004016153a3565b6020604051808303815f875af115801561233a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061235e919061524a565b945088888661238257604051632f9f8ab960e01b8152600401610bfb9291906153c2565b5050897f7cc27e4a5626cbc4f8ba1a927b0448de55e6a114bc87660331270c5109ade0718a8a6040516123b69291906153c2565b60405180910390a2895f516020615a465f395f51905f52600360046040516123df929190615265565b60405180910390a25050505095945050505050565b5f5f6123ff89610f6c565b5f8a8152600d602052604090205490915060ff16600481600681111561242757612427614882565b148a60048390919261244f576040516337e1404160e01b8152600401610bfb939291906152f9565b5050505f8a8152600e602090815260409182902082516060810184528154815260018201549281019290925260020154918101829052908b90428110156124b2576040516308f3034360e31b815260048101929092526024820152604401610bfb565b50505f8b8152600860205260409020600d016124cf8a8c836153d5565b505f8b8152600d6020526040902080546005919060ff191660018302179055508261010001516001600160a01b0316635bf48e3a8b8b604051612513929190615394565b6040519081900381206001600160e01b031960e084901b168252612541918c908c908c908c90600401615489565b602060405180830381865afa15801561255c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612580919061524a565b93508989856125a457604051632f9f8ab960e01b8152600401610bfb9291906153c2565b50506125af8b613ccc565b8a7f3a140076c461ebc41d74833ae0ee8bbc8079a135a63392098cd381e84350b69b8b8b8b8b6040516125e594939291906154c1565b60405180910390a28a5f516020615a465f395f51905f526004600560405161260e929190615265565b60405180910390a2505050979650505050505050565b61262c613916565b80515f5b8181101561268b576001600b84838151811061264e5761264e614f7e565b60200260200101516040516126639190615280565b908152604051908190036020019020805491151560ff19909216919091179055600101612630565b507f027b83cad653f54850fef6faa8c705f73a53e7f8de50a3a33ac1e0e3a5c0be8182604051611c729190615296565b5f546001600160a01b03163314806126dd57506003546001600160a01b031633145b6126fa57604051639e75a8b560e01b815260040160405180910390fd5b5f8160ff161180156127105750600d60ff821611155b6127555760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b2103330b4b63ab932903932b0b9b7b760511b6044820152606401610bfb565b612773828260ff16600d81111561276e5761276e614882565b614137565b5050565b61277f613916565b6001600160a01b0381166127d55760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420536c617368696e674d616e616765722061646472657373006044820152606401610bfb565b600380546001600160a01b0319166001600160a01b0383169081179091556040517f4ccc8ed483c7c44c3602c3c38afc2c014a8f1d2dc210dfe58ebeeeead230f8e0905f90a250565b6003546001600160a01b03163314612849576040516357d6948d60e11b815260040160405180910390fd5b60025460405163c1ab0f1f60e01b815260048101849052602481018390526001600160a01b039091169063c1ab0f1f906044015f604051808303815f87803b158015612893575f5ffd5b505af11580156128a5573d5f5f3e3d5ffd5b50505050817f4f41a3b0a032ebcae925f2ace77d507435840ca4b2dbaffdd7723fa8d72ee54282604051611dfa91815260200190565b6128e3613916565b6001600160a01b0381161580159061291457505f828152600960205260409020546001600160a01b03828116911614155b8290612936576040516381c4951960e01b8152600401610bfb91815260200190565b505f8281526009602090815260409182902080546001600160a01b0319166001600160a01b03851617905590518381527ff4041a3f914dac3bc9bf5f003ba41f28dbb84abe42f4e07c76266f5c8ceecb699101611c72565b612996613916565b60058190556040518181527fba0716ba1ee2ea8ecc4c64119b4537cdb42a99d82acf92af5b87607b8b52355290602001610d23565b6129d3613916565b6127106129e86101208301610100840161550c565b61ffff161115612a006101208301610100840161550c565b90612a25576040516301027fc160e21b815261ffff9091166004820152602401610bfb565b50612710612a3b6101408301610120840161550c565b61ffff161115612a536101408301610120840161550c565b90612a78576040516301027fc160e21b815261ffff9091166004820152602401610bfb565b50612710612a8e6101608301610140840161550c565b61ffff161115612aa66101608301610140840161550c565b90612acb57604051633239953960e01b815261ffff9091166004820152602401610bfb565b50612710612ae16101808301610160840161550c565b61ffff161115612af96101808301610160840161550c565b90612b1e57604051633239953960e01b815261ffff9091166004820152602401610bfb565b50612710612b346101a08301610180840161550c565b61ffff161115612b4c6101a08301610180840161550c565b90612b7157604051633239953960e01b815261ffff9091166004820152602401610bfb565b50612b846101408201610120830161550c565b61ffff161580612bad57505f612ba1610100830160e084016147df565b6001600160a01b031614155b612bca5760405163015f92ff60e51b815260040160405180910390fd5b612bdc6101e082016101c08301615543565b63ffffffff16612bf46101c083016101a08401615543565b63ffffffff161015612c19576040516392f55c6560e01b815260040160405180910390fd5b806018612c268282615582565b9050507fbf3951313e980027eb48ce363fdb707286195ec6a0f802ac153927cf929c3fc681604051610d239190615740565b5f80601281612c6a6020860186614f65565b6003811115612c7b57612c7b614882565b6003811115612c8c57612c8c614882565b8152602081019190915260409081015f20815180830190925260028282826020028201915f905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411612cb3579050505050505090505f81600160028110612d0a57612d0a614f7e565b602002015163ffffffff1611835f016020810190612d289190614f65565b90612d475760405163286c068d60e11b8152600401610bfb9190614f92565b506020808201518251604080516101e081018252601854815260195481860152601a5491810191909152601b546060820152601c546080820152601d5460a0820152601e5460c0820152601f546001600160a01b03811660e0830152600160a01b810461ffff908116610100840152600160b01b82048116610120840152600160c01b82048116610140840152600160d01b82048116610160840152600160e01b90910416610180820152925463ffffffff8181166101a0860181905264010000000090920481166101c086015292831693919092169115612e72576101a081015163ffffffff16846001602002015163ffffffff161015865f016020810190612e519190614f65565b90612e705760405163010b971d60e31b8152600401610bfb9190614f92565b505b6101c081015163ffffffff1615612ec1576101c081015184519063ffffffff9081169082161015612ebf57604051630a4b6b6360e11b815263ffffffff9091166004820152602401610bfb565b505b60408601356020870135811015612eee5760405163174b5a0760e21b8152600401610bfb91815260200190565b506101808101516017545f9161271091612f0c9161ffff169061584a565b612f169190615861565b61271061ffff1683610160015161ffff16601560010154612f37919061584a565b612f419190615861565b61271061ffff1684610140015161ffff1660155f0154612f61919061584a565b612f6b9190615861565b5f5460408051634f87c3a560e11b8152815160208e81013594938f0135936001600160a01b031692639f0f874a92600480830193928290030181865afa158015612fb7573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612fdb91906150da565b612fe59190614fc7565b612fef9190614fb4565b612ff99190614fc7565b6130039190614fc7565b61300d9190614fc7565b90505f61301b600186614fb4565b61302690600261584a565b61303190600261584a565b61303c906006614fc7565b90505f85845f015161304e919061584a565b905081868560200151613061919061584a565b61306b919061584a565b6130759082614fc7565b905060018611156130bd57600261308d600188614fb4565b613097908861584a565b85604001516130a6919061584a565b6130b09190615861565b6130ba9082614fc7565b90505b81868560c001516130ce919061584a565b6130d8919061584a565b6130e29082614fc7565b9050828685606001516130f5919061584a565b6130ff919061584a565b6131099082614fc7565b905084846080015161311b919061584a565b6131259082614fc7565b9050600185111561316d57600261313d600187614fb4565b613147908761584a565b8560400151613156919061584a565b6131609190615861565b61316a9082614fc7565b90505b60a084015161317c9082614fc7565b610100850151909150612710906131979061ffff1682614fc7565b6131a1908361584a565b6131ab9190615861565b975087806131cf57604051638c4fcd9360e01b8152600401610bfb91815260200190565b5050505050505050919050565b6131e4613916565b6001600160a01b0381161580159061320a57506001546001600160a01b03828116911614155b819061322a576040516320252f0b60e01b8152600401610bfb919061481e565b50600180546001600160a01b0319166001600160a01b0383161790556040517fad4055f18cdad6f4bdd71afe3a72cbeee964217943e1bde38f138289e981a9a790610d2390839061481e565b61327e613916565b61328b6020820182615543565b63ffffffff166132a16040830160208401615543565b63ffffffff16101580156132c657505f6132be6020830183615543565b63ffffffff16115b6132e357604051634564ab9b60e01b815260040160405180910390fd5b604080516101e0810182526018548152601954602080830191909152601a5492820192909252601b546060820152601c546080820152601d5460a0820152601e5460c0820152601f546001600160a01b03811660e083015261ffff600160a01b82048116610100840152600160b01b82048116610120840152600160c01b82048116610140840152600160d01b82048116610160840152600160e01b90910416610180820152905463ffffffff8082166101a08401819052640100000000909204166101c08301521561341c576101a081015163ffffffff166133cc6040840160208501615543565b63ffffffff1610156133e46040840160208501615543565b826101a00151909161341957604051633ccc4c2160e21b815263ffffffff928316600482015291166024820152604401610bfb565b50505b6101c081015163ffffffff1615613493576101c081015163ffffffff166134466020840184615543565b63ffffffff16101561345b6020840184615543565b826101c0015190916134905760405163156c4e5b60e11b815263ffffffff928316600482015291166024820152604401610bfb565b50505b8160125f8560038111156134a9576134a9614882565b60038111156134ba576134ba614882565b815260208101919091526040015f206134d49160026144cf565b508260038111156134e7576134e7614882565b7f8b56fae526eee054f0849759a99fc7d4ff3823824ebf097a56f7d78adb6b34fa836040516135169190615880565b60405180910390a2505050565b61352b613916565b6001600160a01b038116613554575f604051631e4fbdf760e01b8152600401610bfb919061481e565b610d3f816139b5565b5f818152600d602052604081205460ff168181600681111561358157613581614882565b036135a657826001826040516337e1404160e01b8152600401610bfb939291906152f9565b60058160068111156135ba576135ba614882565b036135db5760405163462c7bed60e01b815260048101849052602401610bfb565b60068160068111156135ef576135ef614882565b0361361057604051633de16e3560e11b815260048101849052602401610bfb565b5f61361b8483613b44565b935090508061364057604051639f65d93560e01b815260048101859052602401610bfb565b5f848152600d6020526040902080546006919060ff191660018302179055505f848152600f60205260409020805484919060ff1916600183600d81111561368957613689614882565b0217905550835f516020615a465f395f51905f528360066040516136ae929190615265565b60405180910390a2837fe20209be7caae6e76291267cfa711353981274bf127e94f16eb9ec44b68582bb83856040516136e89291906158c0565b60405180910390a25050919050565b6136ff613916565b6001600160a01b0381161580159061372457505f546001600160a01b03828116911614155b8190613744576040516375ac4eb760e11b8152600401610bfb919061481e565b505f80546001600160a01b0319166001600160a01b0383161790556040517f80052b810d39120cf6c976cca504a21703f585521dc7a41c6d241090e6c579b690610d2390839061481e565b6001600160a01b0381165f90815260076020526040902054819060ff16156137cb5760405163b29d459560e01b8152600401610bfb919061481e565b506001600160a01b0381165f9081526007602052604090819020805460ff19166001179055517fb8d368517268f297fff00825d67d098763117d061360d31027be5b2e1a59d46790610d2390839061481e565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005b92915050565b613850614292565b610d3f816142b7565b80356138785760405163055f269d60e01b815260040160405180910390fd5b5f81602001351161389c5760405163055f269d60e01b815260040160405180910390fd5b5f8160400135116138c05760405163055f269d60e01b815260040160405180910390fd5b80356015819055602080830135601681905560408085013560178190558151948552928401919091528201527f7e86ba16b805e2835af5c5b7aa5a942ced8bcc1fb95a05fbe42dae3862350a1690606001610d23565b3361391f611efa565b6001600160a01b031614611be4573360405163118cdaa760e01b8152600401610bfb919061481e565b6040516001600160a01b0384811660248301528381166044830152606482018390526139af9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506142bf565b50505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b5f818152600f602052604090205460609060ff16600181600d811115613a4d57613a4d614882565b1480613a6a5750600281600d811115613a6857613a68614882565b145b15613aa2575f5b604051908082528060200260200182016040528015613a9a578160200160208202803683370190505b509392505050565b5f5460405162beb08960e51b8152600481018590526001600160a01b03909116906317d61120906024015f60405180830381865afa925050508015613b0857506040513d5f823e601f3d908101601f19168201604052613b0591908101906158db565b60015b613b12575f613a71565b9392505050565b613b3f83846001600160a01b031663a9059cbb858560405160240161397d92919061596a565b505050565b5f828152600e60209081526040808320815160608101835281548152600182015493810193909352600201548282015282549051632800d82960e01b81526004810186905283929183916001600160a01b0390911690632800d82990602401602060405180830381865afa158015613bbe573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613be291906150da565b90506001856006811115613bf857613bf8614882565b148015613c0457508042115b15613c1757600180935093505050613cc5565b6002856006811115613c2b57613c2b614882565b148015613c385750815142115b15613c4c5760016003935093505050613cc5565b6003856006811115613c6057613c60614882565b148015613c705750816020015142115b15613c845760016006935093505050613cc5565b6004856006811115613c9857613c98614882565b148015613ca85750816040015142115b15613cbc576001600a935093505050613cc5565b5f5f9350935050505b9250929050565b5f805460405162beb08960e51b8152600481018490526001600160a01b03909116906317d61120906024015f60405180830381865afa158015613d11573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052613d3891908101906158db565b80515f848152600c60209081526040808320805490849055601190925282205493945091926001600160a01b031690829003613dd6576002546040516341489f1560e01b81526001600160a01b03909116906341489f1590613da290889088908690600401615983565b5f604051808303815f87803b158015613db9575f5ffd5b505af1158015613dcb573d5f5f3e3d5ffd5b505050505050505050565b825f03613e77575f858152601060205260409020546001600160a01b03168015613e0e57613e0e6001600160a01b0383168285613b19565b6002546040516341489f1560e01b81526001600160a01b03909116906341489f1590613e4290899089908790600401615983565b5f604051808303815f87803b158015613e59575f5ffd5b505af1158015613e6b573d5f5f3e3d5ffd5b50505050505050505050565b5f85815260136020908152604080832054601490925282205461ffff909116906001600160a01b03168115801590613eb757506001600160a01b03811615155b15613ef357612710613ecd61ffff84168761584a565b613ed79190615861565b92508215613ef357613ef36001600160a01b0385168285613b19565b5f613efe8487614fb4565b90505f876001600160401b03811115613f1957613f196145d1565b604051908082528060200260200182016040528015613f42578160200160208202803683370190505b5090505f613f508984615861565b90505f805b8a811015613f8f5782848281518110613f7057613f70614f7e565b6020908102919091010152613f858383614fc7565b9150600101613f55565b505f613f9b8286614fb4565b90508015613fd8578084613fb060018e614fb4565b81518110613fc057613fc0614f7e565b60200260200101818151613fd49190614fc7565b9052505b600154613ff2906001600160a01b038b8116911687614322565b60015f9054906101000a90046001600160a01b03166001600160a01b031663dd8c818e8a8e876040518463ffffffff1660e01b8152600401614036939291906159e3565b5f604051808303815f87803b15801561404d575f5ffd5b505af115801561405f573d5f5f3e3d5ffd5b505060015461407d92506001600160a01b038c81169250165f614322565b8c7fac9fe8ad7f55eac03284399116ecafc104f10459773f4cdf47063c46e5be335a8d866040516140af929190615a18565b60405180910390a260025f9054906101000a90046001600160a01b03166001600160a01b03166341489f158e8e8c6040518463ffffffff1660e01b81526004016140fb93929190615983565b5f604051808303815f87803b158015614112575f5ffd5b505af1158015614124573d5f5f3e3d5ffd5b5050505050505050505050505050505050565b5f828152600d602052604081205460ff169081600681111561415b5761415b614882565b0361418057826001826040516337e1404160e01b8152600401610bfb939291906152f9565b600581600681111561419457614194614882565b036141b55760405163462c7bed60e01b815260048101849052602401610bfb565b60068160068111156141c9576141c9614882565b036141ea57604051633de16e3560e11b815260048101849052602401610bfb565b5f838152600d6020526040902080546006919060ff191660018302179055505f838152600f60205260409020805483919060ff1916600183600d81111561423357614233614882565b0217905550825f516020615a465f395f51905f52826006604051614258929190615265565b60405180910390a2827fe20209be7caae6e76291267cfa711353981274bf127e94f16eb9ec44b68582bb82846040516135169291906158c0565b61429a6143b2565b611be457604051631afcd79f60e31b815260040160405180910390fd5b61352b614292565b5f5f60205f8451602086015f885af1806142de576040513d5f823e3d81fd5b50505f513d915081156142f5578060011415614302565b6001600160a01b0384163b155b156139af5783604051635274afe760e01b8152600401610bfb919061481e565b5f836001600160a01b031663095ea7b3848460405160240161434592919061596a565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050905061437e84826143cb565b6139af576143a884856001600160a01b031663095ea7b3865f60405160240161397d92919061596a565b6139af84826142bf565b5f6143bb61381e565b54600160401b900460ff16919050565b5f5f5f5f60205f8651602088015f8a5af192503d91505f51905082801561440a575081156143fc578060011461440a565b5f866001600160a01b03163b115b9695505050505050565b604080516101e081019091525f808252602082019081526020015f815260200161443c61456b565b81525f602082018190526040820181905260608083018190526080830181905260a0830182905260c0830182905260e08301829052610100830182905261012083015261014082018190526101609091015290565b82600281019282156144bf579160200282015b828111156144bf5782518255916020019190600101906144a4565b506144cb929150614589565b5090565b6001830191839082156144bf579160200282015f5b8382111561452e57833563ffffffff1683826101000a81548163ffffffff021916908363ffffffff16021790555092602001926004016020816003010492830192600103026144e4565b801561455e5782816101000a81549063ffffffff021916905560040160208160030104928301926001030261452e565b50506144cb929150614589565b60405180604001604052806002906020820280368337509192915050565b5b808211156144cb575f815560010161458a565b6001600160a01b0381168114610d3f575f5ffd5b80356145bc8161459d565b919050565b5f60608284031215611263575f5ffd5b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b038111828210171561460d5761460d6145d1565b604052919050565b5f6001600160401b0382111561462d5761462d6145d1565b5060051b60200190565b5f82601f830112614646575f5ffd5b81356001600160401b0381111561465f5761465f6145d1565b614672601f8201601f19166020016145e5565b818152846020838601011115614686575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f82601f8301126146b1575f5ffd5b81356146c46146bf82614615565b6145e5565b8082825260208201915060208360051b8601019250858311156146e5575f5ffd5b602085015b838110156147255780356001600160401b03811115614707575f5ffd5b614716886020838a0101614637565b845250602092830192016146ea565b5095945050505050565b5f5f5f5f5f5f5f5f610140898b031215614747575f5ffd5b88356147528161459d565b975060208901356147628161459d565b965060408901356147728161459d565b955060608901356147828161459d565b945060808901356147928161459d565b935060a089013592506147a88a60c08b016145c1565b91506101208901356001600160401b038111156147c3575f5ffd5b6147cf8b828c016146a2565b9150509295985092959890939650565b5f602082840312156147ef575f5ffd5b8135613b128161459d565b5f6020828403121561480a575f5ffd5b5035919050565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b8035600481106145bc575f5ffd5b5f5f60408385031215614851575f5ffd5b61485a83614832565b946020939093013593505050565b5f60608284031215614878575f5ffd5b613b1283836145c1565b634e487b7160e01b5f52602160045260245ffd5b600e81106148a6576148a6614882565b9052565b602081016138428284614896565b600481106148a6576148a6614882565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b8e8152614906602082018f6148b8565b8c60408201528b606082015261491f608082018c614811565b6101c060a08201525f6149366101c083018c6148c8565b82810360c0840152614948818c6148c8565b905061495760e084018b614811565b61496561010084018a614811565b876101208401528661014084015282810361016084015261498681876148c8565b915050614997610180830185614811565b8215156101a08301529f9e505050505050505050505050505050565b805f5b60028110156139af5781518452602093840193909101906001016149b6565b805182525f60208201516149ec60208501826148b8565b50604082015160408401526060820151614a0960608501826149b3565b50608082015160a084015260a0820151614a2660c0850182614811565b5060c082015161020060e0850152614a426102008501826148c8565b905060e0830151848203610100860152614a5c82826148c8565b915050610100830151614a73610120860182614811565b50610120830151614a88610140860182614811565b506101408301516101608501526101608301516101808501526101808301518482036101a0860152614aba82826148c8565b9150506101a0830151614ad16101c0860182614811565b506101c08301518015156101e0860152613a9a565b602081525f613b1260208301846149d5565b5f60208284031215614b08575f5ffd5b81356001600160401b03811115614b1d575f5ffd5b614b2984828501614637565b949350505050565b5f60208284031215614b41575f5ffd5b81356001600160401b03811115614b56575f5ffd5b82016101008185031215613b12575f5ffd5b828152604060208201525f614b2960408301846149d5565b5f60208284031215614b90575f5ffd5b81356001600160401b03811115614ba5575f5ffd5b614b29848285016146a2565b5f5f60408385031215614bc2575f5ffd5b823591506020830135614bd48161459d565b809150509250929050565b5f5f60408385031215614bf0575f5ffd5b50508035926020909101359150565b81518152602080830151908201526040808301519082015260608101613842565b821515815260408101613b126020830184614896565b5f5f83601f840112614c46575f5ffd5b5081356001600160401b03811115614c5c575f5ffd5b602083019150836020828501011115613cc5575f5ffd5b5f5f5f5f5f60608688031215614c87575f5ffd5b8535945060208601356001600160401b03811115614ca3575f5ffd5b614caf88828901614c36565b90955093505060408601356001600160401b03811115614ccd575f5ffd5b614cd988828901614c36565b969995985093965092949392505050565b5f6101e082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e0830151614d4460e0840182614811565b50610100830151614d5c61010084018261ffff169052565b50610120830151614d7461012084018261ffff169052565b50610140830151614d8c61014084018261ffff169052565b50610160830151614da461016084018261ffff169052565b50610180830151614dbc61018084018261ffff169052565b506101a0830151614dd66101a084018263ffffffff169052565b506101c0830151614df06101c084018263ffffffff169052565b5092915050565b5f5f5f5f5f5f5f6080888a031215614e0d575f5ffd5b8735965060208801356001600160401b03811115614e29575f5ffd5b614e358a828b01614c36565b90975095505060408801356001600160401b03811115614e53575f5ffd5b614e5f8a828b01614c36565b90955093505060608801356001600160401b03811115614e7d575f5ffd5b614e898a828b01614c36565b989b979a50959850939692959293505050565b5f5f60408385031215614ead575f5ffd5b82359150602083013560ff81168114614bd4575f5ffd5b600781106148a6576148a6614882565b602081016138428284614ec4565b5f6101e0828403128015614ef4575f5ffd5b509092915050565b5f5f60608385031215614f0d575f5ffd5b614f1683614832565b915083606084011115614f27575f5ffd5b50926020919091019150565b600181811c90821680614f4757607f821691505b60208210810361126357634e487b7160e01b5f52602260045260245ffd5b5f60208284031215614f75575f5ffd5b613b1282614832565b634e487b7160e01b5f52603260045260245ffd5b6020810161384282846148b8565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561384257613842614fa0565b8082018082111561384257613842614fa0565b5f60018201614feb57614feb614fa0565b5060010190565b5f5f8335601e19843603018112615007575f5ffd5b8301803591506001600160401b03821115615020575f5ffd5b602001915036819003821315613cc5575f5ffd5b8015158114610d3f575f5ffd5b5f60208284031215615051575f5ffd5b8135613b1281615034565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b88815287602082015260a060408201525f6150a360a08301888a61505c565b82810360608401526150b681878961505c565b905082810360808401526150cb81858761505c565b9b9a5050505050505050505050565b5f602082840312156150ea575f5ffd5b5051919050565b601f821115613b3f57805f5260205f20601f840160051c810160208510156151165750805b601f840160051c820191505b81811015615135575f8155600101615122565b5050505050565b5f19600383901b1c191660019190911b1790565b81516001600160401b03811115615169576151696145d1565b61517d816151778454614f33565b846150f1565b6020601f8211600181146151aa575f83156151985750848201515b6151a2848261513c565b855550615135565b5f84815260208120601f198516915b828110156151d957878501518255602094850194600190920191016151b9565b50848210156151f657868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b838152602081018390526080810160408201835f5b600281101561523f57815163ffffffff1683526020928301929091019060010161521a565b505050949350505050565b5f6020828403121561525a575f5ffd5b8151613b1281615034565b604081016152738285614ec4565b613b126020830184614ec4565b5f82518060208501845e5f920191825250919050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b828110156152ed57603f198786030184526152d88583516148c8565b945060209384019391909101906001016152bc565b50929695505050505050565b8381526060810161530d6020830185614ec4565b614b296040830184614ec4565b5f8151808452602084019350602083015f5b828110156153535781516001600160a01b031686526020958601959091019060010161532c565b5093949350505050565b848152836020820152608060408201525f61537b608083018561531a565b905060018060a01b038316606083015295945050505050565b818382375f9101908152919050565b848152836020820152606060408201525f61440a60608301848661505c565b602081525f614b2960208301848661505c565b6001600160401b038311156153ec576153ec6145d1565b615400836153fa8354614f33565b836150f1565b5f601f84116001811461542c575f851561541a5750838201355b615424868261513c565b845550615135565b5f83815260208120601f198716915b8281101561545b578685013582556020948501946001909201910161543b565b5086821015615477575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b858152606060208201525f6154a260608301868861505c565b82810360408401526154b581858761505c565b98975050505050505050565b604081525f6154d460408301868861505c565b82810360208401526154e781858761505c565b979650505050505050565b61ffff81168114610d3f575f5ffd5b80356145bc816154f2565b5f6020828403121561551c575f5ffd5b8135613b12816154f2565b63ffffffff81168114610d3f575f5ffd5b80356145bc81615527565b5f60208284031215615553575f5ffd5b8135613b1281615527565b5f81356138428161459d565b5f8135613842816154f2565b5f813561384281615527565b813581556020820135600182015560408201356002820155606082013560038201556080820135600482015560a0820135600582015560c08201356006820155600781016155f26155d560e0850161555e565b82546001600160a01b0319166001600160a01b0391909116178255565b615622615602610100850161556a565b82805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b615652615632610120850161556a565b82805461ffff60b01b191660b09290921b61ffff60b01b16919091179055565b615682615662610140850161556a565b82805461ffff60c01b191660c09290921b61ffff60c01b16919091179055565b6156b2615692610160850161556a565b82805461ffff60d01b191660d09290921b61ffff60d01b16919091179055565b6156e26156c2610180850161556a565b82805461ffff60e01b191660e09290921b61ffff60e01b16919091179055565b506008810161570e6156f76101a08501615576565b825463ffffffff191663ffffffff91909116178255565b613b3f61571e6101c08501615576565b825467ffffffff00000000191660209190911b67ffffffff0000000016178255565b813581526020808301359082015260408083013590820152606080830135908201526080808301359082015260a0808301359082015260c080830135908201526101e0810161579160e084016145b1565b61579e60e0840182614811565b506157ac6101008401615501565b61ffff166101008301526157c36101208401615501565b61ffff166101208301526157da6101408401615501565b61ffff166101408301526157f16101608401615501565b61ffff166101608301526158086101808401615501565b61ffff1661018083015261581f6101a08401615538565b63ffffffff166101a08301526158386101c08401615538565b63ffffffff81166101c0840152614df0565b808202811582820484141761384257613842614fa0565b5f8261587b57634e487b7160e01b5f52601260045260245ffd5b500490565b6040810181835f5b60028110156158b757813561589c81615527565b63ffffffff1683526020928301929190910190600101615888565b50505092915050565b604081016158ce8285614ec4565b613b126020830184614896565b5f602082840312156158eb575f5ffd5b81516001600160401b03811115615900575f5ffd5b8201601f81018413615910575f5ffd5b805161591e6146bf82614615565b8082825260208201915060208360051b85010192508683111561593f575f5ffd5b6020840193505b8284101561440a5783516159598161459d565b825260209384019390910190615946565b6001600160a01b03929092168252602082015260400190565b838152606060208201525f61599b606083018561531a565b905060018060a01b0383166040830152949350505050565b5f8151808452602084019350602083015f5b828110156153535781518652602095860195909101906001016159c5565b6001600160a01b03841681526060602082018190525f90615a069083018561531a565b828103604084015261440a81856159b3565b604081525f615a2a604083018561531a565b8281036020840152615a3c81856159b3565b9594505050505056fe1b418a230a21d37a078bf8f16decbde8ccceacd77159371f62f0d4ea00d19967a164736f6c634300081c000a", + "deployedBytecode": "0x608060405234801561000f575f5ffd5b50600436106102d9575f3560e01c80639117173c11610182578063cb649617116100e0578063ea71aa571161008f578063ea71aa57146108c0578063f0691cba146108d3578063f2fde38b146108e6578063f81b8ef6146108f9578063fad8e1111461090c578063fbdb32371461091f578063fd2f3d0114610947575f5ffd5b8063cb64961714610829578063cbd1687214610832578063cf0f34c414610845578063cfbdc98d14610858578063d8afed3e14610887578063da16fb2f1461089a578063e59e4695146108ad575f5ffd5b8063ac3d2f421161013c578063ac3d2f4214610780578063b27392d5146107a8578063b68fd1be146107bb578063bb2d1b82146107ce578063bff232c1146107e1578063c1ab0f1f146107f4578063c4ccafa214610807575f5ffd5b80639117173c146105ac57806392312386146105bf578063929a8faf146105d257806399c6679d146105f35780639c8570c81461061b578063a87f4ab91461062e575f5ffd5b80634fc772641161023a5780637cfa9d74116101e95780637cfa9d741461053157806381476ec21461054457806385814243146105575780638da5cb5b1461056a5780638dcdd86b146105725780638e5ce3ad1461058457806390173a4114610597575f5ffd5b80634fc77264146104b357806364226409146104c6578063647846a5146104e75780636db5c8fd146104fa578063715018a61461050357806377868ae41461050b5780637c8c3b4d1461051e575f5ffd5b80631ba72945116102965780631ba72945146103a657806336c5d38a146103b95780634017daf0146103e8578063406ed35c146104155780634147a36014610435578063459d9294146104625780634e92ec63146104a0575f5ffd5b806301d12f1c146102dd57806302a3a9c9146102f25780630ef81b2f1461030557806310bc62811461034357806311bd61d91461036b57806315cce22414610393575b5f5ffd5b6102f06102eb36600461472f565b61095a565b005b6102f06103003660046147df565b610ba1565b61032d6103133660046147fa565b5f908152600960205260409020546001600160a01b031690565b60405161033a919061481e565b60405180910390f35b61032d6103513660046147fa565b60096020525f90815260409020546001600160a01b031681565b61037e610379366004614840565b610c4d565b60405163ffffffff909116815260200161033a565b6102f06103a13660046147df565b610c89565b6102f06103b4366004614868565b610d2e565b6103db6103c73660046147fa565b5f908152600f602052604090205460ff1690565b60405161033a91906148aa565b6103fb6103f63660046147fa565b610d42565b60405161033a9e9d9c9b9a999897969594939291906148f6565b6104286104233660046147fa565b610f6c565b60405161033a9190614ae6565b6104546104433660046147fa565b600c6020525f908152604090205481565b60405190815260200161033a565b610490610470366004614af8565b8051602081830181018051600b8252928201919093012091525460ff1681565b604051901515815260200161033a565b6102f06104ae3660046147fa565b611269565b6102f06104c13660046147df565b6112f8565b6104d96104d4366004614b31565b61138b565b60405161033a929190614b68565b60045461032d906001600160a01b031681565b61045460055481565b6102f0611bd3565b6102f0610519366004614b80565b611be6565b6102f061052c366004614bb1565b611c7e565b6102f061053f3660046147fa565b611d07565b6102f0610552366004614bdf565b611e06565b60015461032d906001600160a01b031681565b61032d611efa565b5f5461032d906001600160a01b031681565b60035461032d906001600160a01b031681565b61059f611f28565b60405161033a9190614bff565b6102f06105ba3660046147fa565b611f6e565b61059f6105cd3660046147fa565b6120dc565b6105e56105e03660046147fa565b612135565b60405161033a929190614c20565b61032d6106013660046147fa565b5f908152601060205260409020546001600160a01b031690565b610490610629366004614c73565b61215c565b610773604080516101e0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081019190915250604080516101e0810182526018548152601954602080830191909152601a5492820192909252601b546060820152601c546080820152601d5460a0820152601e5460c0820152601f546001600160a01b03811660e083015261ffff600160a01b82048116610100840152600160b01b82048116610120840152600160c01b82048116610140840152600160d01b82048116610160840152600160e01b90910416610180820152905463ffffffff8082166101a0840152640100000000909104166101c082015290565b60405161033a9190614cea565b61032d61078e3660046147fa565b5f908152600a60205260409020546001600160a01b031690565b6104906107b6366004614df7565b6123f4565b6102f06107c9366004614b80565b612624565b6102f06107dc366004614e9c565b6126bb565b6102f06107ef3660046147df565b612777565b6102f0610802366004614bdf565b61281e565b6104906108153660046147df565b60076020525f908152604090205460ff1681565b61045460065481565b6102f0610840366004614bb1565b6128db565b6102f06108533660046147fa565b61298e565b61087a6108663660046147fa565b5f908152600d602052604090205460ff1690565b60405161033a9190614ed4565b6102f0610895366004614ee2565b6129cb565b6104546108a8366004614b31565b612c58565b6102f06108bb3660046147df565b6131dc565b6102f06108ce366004614efc565b613276565b60025461032d906001600160a01b031681565b6102f06108f43660046147df565b613523565b6103db6109073660046147fa565b61355d565b6102f061091a3660046147df565b6136f7565b61032d61092d3660046147fa565b600a6020525f90815260409020546001600160a01b031681565b6102f06109553660046147df565b61378f565b5f61096361381e565b805490915060ff600160401b82041615906001600160401b03165f811580156109895750825b90505f826001600160401b031660011480156109a45750303b155b9050811580156109b2575080155b156109d05760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156109fa57845460ff60401b1916600160401b1785555b610a0333613848565b610a0c8861298e565b610a158c6136f7565b610a1e8b6131dc565b610a278a610ba1565b610a3089610c89565b610a3987613859565b610a4286612624565b604080516101e08101825261c3508082526161a86020808401829052611388948401859052601460608501819052620249f0608086018190526207a12060a087018190526107d060c088018190525f60e089018190526103e86101008a015261012089018190526109c46101408a018190526101608a018b90526101808a01526101a089018190526101c090980197909752601895909555601993909355601a95909555601b94909455601c55601d55601e55601f80546001600160f01b031916690138827101388000007d60a31b179055805467ffffffffffffffff19169055610b2b611efa565b6001600160a01b03168d6001600160a01b031614610b4c57610b4c8d613523565b8315610b9257845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050505050565b610ba9613916565b6001600160a01b038116610c045760405162461bcd60e51b815260206004820152601f60248201527f496e76616c6964204533526566756e644d616e6167657220616464726573730060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040517f9557d04c1c0b16f93f13b69aed23b3b6ab935bff3c53ac81d17896d3583542ed905f90a250565b6012602052815f5260405f208160028110610c66575f80fd5b60089182820401919006600402915091509054906101000a900463ffffffff1681565b610c91613916565b6001600160a01b03811615801590610cb757506004546001600160a01b03828116911614155b8190610cd75760405163eddf07f560e01b8152600401610bfb919061481e565b50600480546001600160a01b0319166001600160a01b0383161790556040517f722ff84c1234b2482061def5c82c6b5080c117b3cbb69d686844a051e4b8e7f390610d2390839061481e565b60405180910390a150565b610d36613916565b610d3f81613859565b50565b60086020525f9081526040902080546001820154600283015460058401546006850154600786018054959660ff90951695939492936001600160a01b039092169291610d8d90614f33565b80601f0160208091040260200160405190810160405280929190818152602001828054610db990614f33565b8015610e045780601f10610ddb57610100808354040283529160200191610e04565b820191905f5260205f20905b815481529060010190602001808311610de757829003601f168201915b505050505090806008018054610e1990614f33565b80601f0160208091040260200160405190810160405280929190818152602001828054610e4590614f33565b8015610e905780601f10610e6757610100808354040283529160200191610e90565b820191905f5260205f20905b815481529060010190602001808311610e7357829003601f168201915b5050506009840154600a850154600b860154600c870154600d8801805497986001600160a01b03958616989490951696509194509291610ecf90614f33565b80601f0160208091040260200160405190810160405280929190818152602001828054610efb90614f33565b8015610f465780601f10610f1d57610100808354040283529160200191610f46565b820191905f5260205f20905b815481529060010190602001808311610f2957829003601f168201915b505050600e90930154919250506001600160a01b0381169060ff600160a01b909104168e565b610f74614414565b5f8281526008602090815260409182902082516101e08101909352805483526001810154909183019060ff166003811115610fb157610fb1614882565b6003811115610fc257610fc2614882565b8152600282810154602083015260408051808201808352919093019291600385019182845b815481526020019060010190808311610fe75750505091835250506005820154602082015260068201546001600160a01b0316604082015260078201805460609092019161103490614f33565b80601f016020809104026020016040519081016040528092919081815260200182805461106090614f33565b80156110ab5780601f10611082576101008083540402835291602001916110ab565b820191905f5260205f20905b81548152906001019060200180831161108e57829003601f168201915b505050505081526020016008820180546110c490614f33565b80601f01602080910402602001604051908101604052809291908181526020018280546110f090614f33565b801561113b5780601f106111125761010080835404028352916020019161113b565b820191905f5260205f20905b81548152906001019060200180831161111e57829003601f168201915b505050918352505060098201546001600160a01b039081166020830152600a830154166040820152600b8201546060820152600c8201546080820152600d8201805460a09092019161118c90614f33565b80601f01602080910402602001604051908101604052809291908181526020018280546111b890614f33565b80156112035780601f106111da57610100808354040283529160200191611203565b820191905f5260205f20905b8154815290600101906020018083116111e657829003601f168201915b5050509183525050600e91909101546001600160a01b038082166020840152600160a01b90910460ff16151560409092019190915260a08201519192508391166112635760405163cd6f4a4f60e01b8152600401610bfb91815260200190565b50919050565b611271613916565b5f8181526009602052604090205481906001600160a01b03166112aa576040516381c4951960e01b8152600401610bfb91815260200190565b505f818152600960205260409081902080546001600160a01b0319169055517f104eb329a192aef26eddea07c2af5ad2587792e62b37ed4045b6ba59bc5540fc90610d239083815260200190565b611300613916565b6001600160a01b0381165f90815260076020526040902054819060ff1661133b576040516321ac7c5f60e01b8152600401610bfb919061481e565b506001600160a01b0381165f9081526007602052604090819020805460ff19169055517f56070b80bd617fcd2f7a284861edb488830a38f9dedcd77b2cb2f4eac17743e790610d2390839061481e565b5f611394614414565b5f6012816113a56020870187614f65565b60038111156113b6576113b6614882565b60038111156113c7576113c7614882565b8152602081019190915260409081015f20815180830190925260028282826020028201915f905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116113ee579050505050505090505f8160016002811061144557611445614f7e565b602002015163ffffffff1611845f0160208101906114639190614f65565b906114825760405163286c068d60e11b8152600401610bfb9190614f92565b506020840135428110156114ac57604051630b99e87960e01b8152600401610bfb91815260200190565b50604084013560208501358110156114da5760405163174b5a0760e21b8152600401610bfb91815260200190565b506017546016545f91906114f2426040890135614fb4565b6114fc9190614fc7565b6115069190614fc7565b90506005548110819061152f576040516313b783af60e21b8152600401610bfb91815260200190565b5060075f61154360808801606089016147df565b6001600160a01b0316815260208101919091526040015f205460ff1661156f60808701606088016147df565b9061158e5760405163295a6a6f60e11b8152600401610bfb919061481e565b505f61159986612c58565b60068054965090915085905f6115ae83614fda565b9091555050604080514460208201529081018690525f9060600160408051601f1981840301815291815281516020928301205f898152600c84528281208690556004546011855283822080546001600160a01b03199081166001600160a01b0393841617909155601f805460138852868520805461ffff191661ffff600160b01b909304929092169190911790555460148752858420805483169190931617909155600d8552838220805460ff1916600117905560109094528290208054339416939093179092556016549192506116899190890135614fc7565b5f878152600e60209081526040909120600101919091558186526116af90880188614f65565b856020019060038111156116c5576116c5614882565b908160038111156116d8576116d8614882565b905250436040808701919091528051808201825290602089019060029083908390808284375f92019190915250505060608087019190915261172090608089019089016147df565b6001600160a01b031660a086015261173b6080880188614ff2565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050505060c08087019190915261178390880188614ff2565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050505060e0808701919091526117d0906101008901908901615041565b15156101c08601525f610140860181905261016086018190526040805160208101909152908152610180860152336101a08601819052600454611820916001600160a01b03909116903085613948565b5f6118316080890160608a016147df565b6001600160a01b031663fefd9a8b888461184e60808d018d614ff2565b61185b60a08f018f614ff2565b8f8060c0019061186b9190614ff2565b6040518963ffffffff1660e01b815260040161188e989796959493929190615084565b6020604051808303815f875af11580156118aa573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118ce91906150da565b5f818152600960205260409020549091506001600160a01b0316818161190a576040516381c4951960e01b8152600401610bfb91815260200190565b505f828152600a60205260409020546001600160a01b03168281611944576040516381c4951960e01b8152600401610bfb91815260200190565b50608088018390526001600160a01b038083166101008a015281166101208901525f8981526008602090815260409091208951815590890151600180830180548c94939260ff1991909116908360038111156119a2576119a2614882565b0217905550604082015181600201556060820151816003019060026119c8929190614491565b506080820151600582015560a08201516006820180546001600160a01b0319166001600160a01b0390921691909117905560c08201516007820190611a0d9082615150565b5060e08201516008820190611a229082615150565b506101008201516009820180546001600160a01b039283166001600160a01b031991821617909155610120840151600a84018054919093169116179055610140820151600b820155610160820151600c820155610180820151600d820190611a8a9082615150565b506101a0820151600e90910180546101c0909301511515600160a01b026001600160a81b03199093166001600160a01b0392831617929092179091555f5460405163291a691b60e01b815291169063291a691b90611af0908c9088908c90600401615205565b6020604051808303815f875af1158015611b0c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b30919061524a565b611b4d57604051630d8dbe2560e01b815260040160405180910390fd5b611b5d60808b0160608c016147df565b6001600160a01b03167f5904e83d57e704fba4d92c5617f6b50ae993cd42d78babfcb239d0a6775f30708a8a604051611b97929190614b68565b60405180910390a2885f516020615a465f395f51905f525f6001604051611bbf929190615265565b60405180910390a250505050505050915091565b611bdb613916565b611be45f6139b5565b565b611bee613916565b80515f5b81811015611c4257600b838281518110611c0e57611c0e614f7e565b6020026020010151604051611c239190615280565b908152604051908190036020019020805460ff19169055600101611bf2565b507fd1b46e030b48add7bc03225cc5a6f403970976b36983f99ec31d535d627fc7db82604051611c729190615296565b60405180910390a15050565b611c86613916565b6001600160a01b03811615801590611cb757505f828152600a60205260409020546001600160a01b03828116911614155b8290611cd9576040516381c4951960e01b8152600401610bfb91815260200190565b505f918252600a602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b5f546001600160a01b03163314611d315760405163b56831db60e01b815260040160405180910390fd5b5f818152600d602052604090205460ff166001816006811115611d5657611d56614882565b14611d7b57816001826040516337e1404160e01b8152600401610bfb939291906152f9565b5f828152600d60205260409020805460ff19166002179055601554611da09042614fc7565b5f838152600e602052604080822092909255905183917fc44405af9078047712501f519e1fb900c2896c62b488336f84529c72ae16e6f191a2815f516020615a465f395f51905f5260016002604051611dfa929190615265565b60405180910390a25050565b5f546001600160a01b03163314611e305760405163b56831db60e01b815260040160405180910390fd5b5f828152600860209081526040808320600d9092529091205460ff166002816006811115611e6057611e60614882565b14611e8557836002826040516337e1404160e01b8152600401610bfb939291906152f9565b5f848152600d6020526040808220805460ff19166003179055600b84018590555185917f11df18edb9bc9cd90a79068e0e208b630202148643d797d6150e7bacb733e63c91a2835f516020615a465f395f51905f5260026003604051611eec929190615265565b60405180910390a250505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b611f4960405180606001604052805f81526020015f81526020015f81525090565b5060408051606081018252601554815260165460208201526017549181019190915290565b5f818152600d602052604090205460ff166006816006811115611f9357611f93614882565b148290611fb657604051637cb2d48360e11b8152600401610bfb91815260200190565b505f828152600c60205260409020548281611fe7576040516345ba89d560e11b8152600401610bfb91815260200190565b505f838152600c6020526040812081905561200184613a25565b5f858152601160205260409020546002549192506001600160a01b039081169161202e9183911685613b19565b60025460405163da19b69760e01b81526001600160a01b039091169063da19b6979061206490889087908790879060040161535d565b5f604051808303815f87803b15801561207b575f5ffd5b505af115801561208d573d5f5f3e3d5ffd5b50505050847f5297818f48a66292b8b3e2caab83eec531b669bb20807fd38cf006adb2a073178484516040516120cd929190918252602082015260400190565b60405180910390a25050505050565b6120fd60405180606001604052805f81526020015f81526020015f81525090565b505f908152600e6020908152604091829020825160608101845281548152600182015492810192909252600201549181019190915290565b5f818152600d6020526040812054819060ff166121528482613b44565b9250925050915091565b5f5f61216787610f6c565b5f888152600d602052604090205490915060ff16600381600681111561218f5761218f614882565b14886003839091926121b7576040516337e1404160e01b8152600401610bfb939291906152f9565b5050505f888152600e602090815260409182902082516060810184528154815260018201549281018390526002909101549281019290925289904281101561221b576040516308f3034360e31b815260048101929092526024820152604401610bfb565b50506060830151602001518990428111156122525760405163017e35e560e71b815260048101929092526024820152604401610bfb565b505061016083015189901561227d57604051637eb9cea960e11b8152600401610bfb91815260200190565b505f888860405161228f929190615394565b60408051918290039091205f8c815260086020908152838220600c01839055600d905291909120805460ff191660041790556017549091506122d19042614fc7565b5f8b8152600e6020526040908190206002019190915560a08501519051632f0e1bbf60e01b81526001600160a01b0390911690632f0e1bbf9061231e908d9085908c908c906004016153a3565b6020604051808303815f875af115801561233a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061235e919061524a565b945088888661238257604051632f9f8ab960e01b8152600401610bfb9291906153c2565b5050897f7cc27e4a5626cbc4f8ba1a927b0448de55e6a114bc87660331270c5109ade0718a8a6040516123b69291906153c2565b60405180910390a2895f516020615a465f395f51905f52600360046040516123df929190615265565b60405180910390a25050505095945050505050565b5f5f6123ff89610f6c565b5f8a8152600d602052604090205490915060ff16600481600681111561242757612427614882565b148a60048390919261244f576040516337e1404160e01b8152600401610bfb939291906152f9565b5050505f8a8152600e602090815260409182902082516060810184528154815260018201549281019290925260020154918101829052908b90428110156124b2576040516308f3034360e31b815260048101929092526024820152604401610bfb565b50505f8b8152600860205260409020600d016124cf8a8c836153d5565b505f8b8152600d6020526040902080546005919060ff191660018302179055508261010001516001600160a01b0316635bf48e3a8b8b604051612513929190615394565b6040519081900381206001600160e01b031960e084901b168252612541918c908c908c908c90600401615489565b602060405180830381865afa15801561255c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612580919061524a565b93508989856125a457604051632f9f8ab960e01b8152600401610bfb9291906153c2565b50506125af8b613ccc565b8a7f3a140076c461ebc41d74833ae0ee8bbc8079a135a63392098cd381e84350b69b8b8b8b8b6040516125e594939291906154c1565b60405180910390a28a5f516020615a465f395f51905f526004600560405161260e929190615265565b60405180910390a2505050979650505050505050565b61262c613916565b80515f5b8181101561268b576001600b84838151811061264e5761264e614f7e565b60200260200101516040516126639190615280565b908152604051908190036020019020805491151560ff19909216919091179055600101612630565b507f027b83cad653f54850fef6faa8c705f73a53e7f8de50a3a33ac1e0e3a5c0be8182604051611c729190615296565b5f546001600160a01b03163314806126dd57506003546001600160a01b031633145b6126fa57604051639e75a8b560e01b815260040160405180910390fd5b5f8160ff161180156127105750600d60ff821611155b6127555760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b2103330b4b63ab932903932b0b9b7b760511b6044820152606401610bfb565b612773828260ff16600d81111561276e5761276e614882565b614137565b5050565b61277f613916565b6001600160a01b0381166127d55760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420536c617368696e674d616e616765722061646472657373006044820152606401610bfb565b600380546001600160a01b0319166001600160a01b0383169081179091556040517f4ccc8ed483c7c44c3602c3c38afc2c014a8f1d2dc210dfe58ebeeeead230f8e0905f90a250565b6003546001600160a01b03163314612849576040516357d6948d60e11b815260040160405180910390fd5b60025460405163c1ab0f1f60e01b815260048101849052602481018390526001600160a01b039091169063c1ab0f1f906044015f604051808303815f87803b158015612893575f5ffd5b505af11580156128a5573d5f5f3e3d5ffd5b50505050817f4f41a3b0a032ebcae925f2ace77d507435840ca4b2dbaffdd7723fa8d72ee54282604051611dfa91815260200190565b6128e3613916565b6001600160a01b0381161580159061291457505f828152600960205260409020546001600160a01b03828116911614155b8290612936576040516381c4951960e01b8152600401610bfb91815260200190565b505f8281526009602090815260409182902080546001600160a01b0319166001600160a01b03851617905590518381527ff4041a3f914dac3bc9bf5f003ba41f28dbb84abe42f4e07c76266f5c8ceecb699101611c72565b612996613916565b60058190556040518181527fba0716ba1ee2ea8ecc4c64119b4537cdb42a99d82acf92af5b87607b8b52355290602001610d23565b6129d3613916565b6127106129e86101208301610100840161550c565b61ffff161115612a006101208301610100840161550c565b90612a25576040516301027fc160e21b815261ffff9091166004820152602401610bfb565b50612710612a3b6101408301610120840161550c565b61ffff161115612a536101408301610120840161550c565b90612a78576040516301027fc160e21b815261ffff9091166004820152602401610bfb565b50612710612a8e6101608301610140840161550c565b61ffff161115612aa66101608301610140840161550c565b90612acb57604051633239953960e01b815261ffff9091166004820152602401610bfb565b50612710612ae16101808301610160840161550c565b61ffff161115612af96101808301610160840161550c565b90612b1e57604051633239953960e01b815261ffff9091166004820152602401610bfb565b50612710612b346101a08301610180840161550c565b61ffff161115612b4c6101a08301610180840161550c565b90612b7157604051633239953960e01b815261ffff9091166004820152602401610bfb565b50612b846101408201610120830161550c565b61ffff161580612bad57505f612ba1610100830160e084016147df565b6001600160a01b031614155b612bca5760405163015f92ff60e51b815260040160405180910390fd5b612bdc6101e082016101c08301615543565b63ffffffff16612bf46101c083016101a08401615543565b63ffffffff161015612c19576040516392f55c6560e01b815260040160405180910390fd5b806018612c268282615582565b9050507fbf3951313e980027eb48ce363fdb707286195ec6a0f802ac153927cf929c3fc681604051610d239190615740565b5f80601281612c6a6020860186614f65565b6003811115612c7b57612c7b614882565b6003811115612c8c57612c8c614882565b8152602081019190915260409081015f20815180830190925260028282826020028201915f905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411612cb3579050505050505090505f81600160028110612d0a57612d0a614f7e565b602002015163ffffffff1611835f016020810190612d289190614f65565b90612d475760405163286c068d60e11b8152600401610bfb9190614f92565b506020808201518251604080516101e081018252601854815260195481860152601a5491810191909152601b546060820152601c546080820152601d5460a0820152601e5460c0820152601f546001600160a01b03811660e0830152600160a01b810461ffff908116610100840152600160b01b82048116610120840152600160c01b82048116610140840152600160d01b82048116610160840152600160e01b90910416610180820152925463ffffffff8181166101a0860181905264010000000090920481166101c086015292831693919092169115612e72576101a081015163ffffffff16846001602002015163ffffffff161015865f016020810190612e519190614f65565b90612e705760405163010b971d60e31b8152600401610bfb9190614f92565b505b6101c081015163ffffffff1615612ec1576101c081015184519063ffffffff9081169082161015612ebf57604051630a4b6b6360e11b815263ffffffff9091166004820152602401610bfb565b505b60408601356020870135811015612eee5760405163174b5a0760e21b8152600401610bfb91815260200190565b506101808101516017545f9161271091612f0c9161ffff169061584a565b612f169190615861565b61271061ffff1683610160015161ffff16601560010154612f37919061584a565b612f419190615861565b61271061ffff1684610140015161ffff1660155f0154612f61919061584a565b612f6b9190615861565b5f5460408051634f87c3a560e11b8152815160208e81013594938f0135936001600160a01b031692639f0f874a92600480830193928290030181865afa158015612fb7573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612fdb91906150da565b612fe59190614fc7565b612fef9190614fb4565b612ff99190614fc7565b6130039190614fc7565b61300d9190614fc7565b90505f61301b600186614fb4565b61302690600261584a565b61303190600261584a565b61303c906006614fc7565b90505f85845f015161304e919061584a565b905081868560200151613061919061584a565b61306b919061584a565b6130759082614fc7565b905060018611156130bd57600261308d600188614fb4565b613097908861584a565b85604001516130a6919061584a565b6130b09190615861565b6130ba9082614fc7565b90505b81868560c001516130ce919061584a565b6130d8919061584a565b6130e29082614fc7565b9050828685606001516130f5919061584a565b6130ff919061584a565b6131099082614fc7565b905084846080015161311b919061584a565b6131259082614fc7565b9050600185111561316d57600261313d600187614fb4565b613147908761584a565b8560400151613156919061584a565b6131609190615861565b61316a9082614fc7565b90505b60a084015161317c9082614fc7565b610100850151909150612710906131979061ffff1682614fc7565b6131a1908361584a565b6131ab9190615861565b975087806131cf57604051638c4fcd9360e01b8152600401610bfb91815260200190565b5050505050505050919050565b6131e4613916565b6001600160a01b0381161580159061320a57506001546001600160a01b03828116911614155b819061322a576040516320252f0b60e01b8152600401610bfb919061481e565b50600180546001600160a01b0319166001600160a01b0383161790556040517fad4055f18cdad6f4bdd71afe3a72cbeee964217943e1bde38f138289e981a9a790610d2390839061481e565b61327e613916565b61328b6020820182615543565b63ffffffff166132a16040830160208401615543565b63ffffffff16101580156132c657505f6132be6020830183615543565b63ffffffff16115b6132e357604051634564ab9b60e01b815260040160405180910390fd5b604080516101e0810182526018548152601954602080830191909152601a5492820192909252601b546060820152601c546080820152601d5460a0820152601e5460c0820152601f546001600160a01b03811660e083015261ffff600160a01b82048116610100840152600160b01b82048116610120840152600160c01b82048116610140840152600160d01b82048116610160840152600160e01b90910416610180820152905463ffffffff8082166101a08401819052640100000000909204166101c08301521561341c576101a081015163ffffffff166133cc6040840160208501615543565b63ffffffff1610156133e46040840160208501615543565b826101a00151909161341957604051633ccc4c2160e21b815263ffffffff928316600482015291166024820152604401610bfb565b50505b6101c081015163ffffffff1615613493576101c081015163ffffffff166134466020840184615543565b63ffffffff16101561345b6020840184615543565b826101c0015190916134905760405163156c4e5b60e11b815263ffffffff928316600482015291166024820152604401610bfb565b50505b8160125f8560038111156134a9576134a9614882565b60038111156134ba576134ba614882565b815260208101919091526040015f206134d49160026144cf565b508260038111156134e7576134e7614882565b7f8b56fae526eee054f0849759a99fc7d4ff3823824ebf097a56f7d78adb6b34fa836040516135169190615880565b60405180910390a2505050565b61352b613916565b6001600160a01b038116613554575f604051631e4fbdf760e01b8152600401610bfb919061481e565b610d3f816139b5565b5f818152600d602052604081205460ff168181600681111561358157613581614882565b036135a657826001826040516337e1404160e01b8152600401610bfb939291906152f9565b60058160068111156135ba576135ba614882565b036135db5760405163462c7bed60e01b815260048101849052602401610bfb565b60068160068111156135ef576135ef614882565b0361361057604051633de16e3560e11b815260048101849052602401610bfb565b5f61361b8483613b44565b935090508061364057604051639f65d93560e01b815260048101859052602401610bfb565b5f848152600d6020526040902080546006919060ff191660018302179055505f848152600f60205260409020805484919060ff1916600183600d81111561368957613689614882565b0217905550835f516020615a465f395f51905f528360066040516136ae929190615265565b60405180910390a2837fe20209be7caae6e76291267cfa711353981274bf127e94f16eb9ec44b68582bb83856040516136e89291906158c0565b60405180910390a25050919050565b6136ff613916565b6001600160a01b0381161580159061372457505f546001600160a01b03828116911614155b8190613744576040516375ac4eb760e11b8152600401610bfb919061481e565b505f80546001600160a01b0319166001600160a01b0383161790556040517f80052b810d39120cf6c976cca504a21703f585521dc7a41c6d241090e6c579b690610d2390839061481e565b6001600160a01b0381165f90815260076020526040902054819060ff16156137cb5760405163b29d459560e01b8152600401610bfb919061481e565b506001600160a01b0381165f9081526007602052604090819020805460ff19166001179055517fb8d368517268f297fff00825d67d098763117d061360d31027be5b2e1a59d46790610d2390839061481e565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005b92915050565b613850614292565b610d3f816142b7565b80356138785760405163055f269d60e01b815260040160405180910390fd5b5f81602001351161389c5760405163055f269d60e01b815260040160405180910390fd5b5f8160400135116138c05760405163055f269d60e01b815260040160405180910390fd5b80356015819055602080830135601681905560408085013560178190558151948552928401919091528201527f7e86ba16b805e2835af5c5b7aa5a942ced8bcc1fb95a05fbe42dae3862350a1690606001610d23565b3361391f611efa565b6001600160a01b031614611be4573360405163118cdaa760e01b8152600401610bfb919061481e565b6040516001600160a01b0384811660248301528381166044830152606482018390526139af9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506142bf565b50505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b5f818152600f602052604090205460609060ff16600181600d811115613a4d57613a4d614882565b1480613a6a5750600281600d811115613a6857613a68614882565b145b15613aa2575f5b604051908082528060200260200182016040528015613a9a578160200160208202803683370190505b509392505050565b5f5460405162beb08960e51b8152600481018590526001600160a01b03909116906317d61120906024015f60405180830381865afa925050508015613b0857506040513d5f823e601f3d908101601f19168201604052613b0591908101906158db565b60015b613b12575f613a71565b9392505050565b613b3f83846001600160a01b031663a9059cbb858560405160240161397d92919061596a565b505050565b5f828152600e60209081526040808320815160608101835281548152600182015493810193909352600201548282015282549051632800d82960e01b81526004810186905283929183916001600160a01b0390911690632800d82990602401602060405180830381865afa158015613bbe573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613be291906150da565b90506001856006811115613bf857613bf8614882565b148015613c0457508042115b15613c1757600180935093505050613cc5565b6002856006811115613c2b57613c2b614882565b148015613c385750815142115b15613c4c5760016003935093505050613cc5565b6003856006811115613c6057613c60614882565b148015613c705750816020015142115b15613c845760016006935093505050613cc5565b6004856006811115613c9857613c98614882565b148015613ca85750816040015142115b15613cbc576001600a935093505050613cc5565b5f5f9350935050505b9250929050565b5f805460405162beb08960e51b8152600481018490526001600160a01b03909116906317d61120906024015f60405180830381865afa158015613d11573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052613d3891908101906158db565b80515f848152600c60209081526040808320805490849055601190925282205493945091926001600160a01b031690829003613dd6576002546040516341489f1560e01b81526001600160a01b03909116906341489f1590613da290889088908690600401615983565b5f604051808303815f87803b158015613db9575f5ffd5b505af1158015613dcb573d5f5f3e3d5ffd5b505050505050505050565b825f03613e77575f858152601060205260409020546001600160a01b03168015613e0e57613e0e6001600160a01b0383168285613b19565b6002546040516341489f1560e01b81526001600160a01b03909116906341489f1590613e4290899089908790600401615983565b5f604051808303815f87803b158015613e59575f5ffd5b505af1158015613e6b573d5f5f3e3d5ffd5b50505050505050505050565b5f85815260136020908152604080832054601490925282205461ffff909116906001600160a01b03168115801590613eb757506001600160a01b03811615155b15613ef357612710613ecd61ffff84168761584a565b613ed79190615861565b92508215613ef357613ef36001600160a01b0385168285613b19565b5f613efe8487614fb4565b90505f876001600160401b03811115613f1957613f196145d1565b604051908082528060200260200182016040528015613f42578160200160208202803683370190505b5090505f613f508984615861565b90505f805b8a811015613f8f5782848281518110613f7057613f70614f7e565b6020908102919091010152613f858383614fc7565b9150600101613f55565b505f613f9b8286614fb4565b90508015613fd8578084613fb060018e614fb4565b81518110613fc057613fc0614f7e565b60200260200101818151613fd49190614fc7565b9052505b600154613ff2906001600160a01b038b8116911687614322565b60015f9054906101000a90046001600160a01b03166001600160a01b031663dd8c818e8a8e876040518463ffffffff1660e01b8152600401614036939291906159e3565b5f604051808303815f87803b15801561404d575f5ffd5b505af115801561405f573d5f5f3e3d5ffd5b505060015461407d92506001600160a01b038c81169250165f614322565b8c7fac9fe8ad7f55eac03284399116ecafc104f10459773f4cdf47063c46e5be335a8d866040516140af929190615a18565b60405180910390a260025f9054906101000a90046001600160a01b03166001600160a01b03166341489f158e8e8c6040518463ffffffff1660e01b81526004016140fb93929190615983565b5f604051808303815f87803b158015614112575f5ffd5b505af1158015614124573d5f5f3e3d5ffd5b5050505050505050505050505050505050565b5f828152600d602052604081205460ff169081600681111561415b5761415b614882565b0361418057826001826040516337e1404160e01b8152600401610bfb939291906152f9565b600581600681111561419457614194614882565b036141b55760405163462c7bed60e01b815260048101849052602401610bfb565b60068160068111156141c9576141c9614882565b036141ea57604051633de16e3560e11b815260048101849052602401610bfb565b5f838152600d6020526040902080546006919060ff191660018302179055505f838152600f60205260409020805483919060ff1916600183600d81111561423357614233614882565b0217905550825f516020615a465f395f51905f52826006604051614258929190615265565b60405180910390a2827fe20209be7caae6e76291267cfa711353981274bf127e94f16eb9ec44b68582bb82846040516135169291906158c0565b61429a6143b2565b611be457604051631afcd79f60e31b815260040160405180910390fd5b61352b614292565b5f5f60205f8451602086015f885af1806142de576040513d5f823e3d81fd5b50505f513d915081156142f5578060011415614302565b6001600160a01b0384163b155b156139af5783604051635274afe760e01b8152600401610bfb919061481e565b5f836001600160a01b031663095ea7b3848460405160240161434592919061596a565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050905061437e84826143cb565b6139af576143a884856001600160a01b031663095ea7b3865f60405160240161397d92919061596a565b6139af84826142bf565b5f6143bb61381e565b54600160401b900460ff16919050565b5f5f5f5f60205f8651602088015f8a5af192503d91505f51905082801561440a575081156143fc578060011461440a565b5f866001600160a01b03163b115b9695505050505050565b604080516101e081019091525f808252602082019081526020015f815260200161443c61456b565b81525f602082018190526040820181905260608083018190526080830181905260a0830182905260c0830182905260e08301829052610100830182905261012083015261014082018190526101609091015290565b82600281019282156144bf579160200282015b828111156144bf5782518255916020019190600101906144a4565b506144cb929150614589565b5090565b6001830191839082156144bf579160200282015f5b8382111561452e57833563ffffffff1683826101000a81548163ffffffff021916908363ffffffff16021790555092602001926004016020816003010492830192600103026144e4565b801561455e5782816101000a81549063ffffffff021916905560040160208160030104928301926001030261452e565b50506144cb929150614589565b60405180604001604052806002906020820280368337509192915050565b5b808211156144cb575f815560010161458a565b6001600160a01b0381168114610d3f575f5ffd5b80356145bc8161459d565b919050565b5f60608284031215611263575f5ffd5b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b038111828210171561460d5761460d6145d1565b604052919050565b5f6001600160401b0382111561462d5761462d6145d1565b5060051b60200190565b5f82601f830112614646575f5ffd5b81356001600160401b0381111561465f5761465f6145d1565b614672601f8201601f19166020016145e5565b818152846020838601011115614686575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f82601f8301126146b1575f5ffd5b81356146c46146bf82614615565b6145e5565b8082825260208201915060208360051b8601019250858311156146e5575f5ffd5b602085015b838110156147255780356001600160401b03811115614707575f5ffd5b614716886020838a0101614637565b845250602092830192016146ea565b5095945050505050565b5f5f5f5f5f5f5f5f610140898b031215614747575f5ffd5b88356147528161459d565b975060208901356147628161459d565b965060408901356147728161459d565b955060608901356147828161459d565b945060808901356147928161459d565b935060a089013592506147a88a60c08b016145c1565b91506101208901356001600160401b038111156147c3575f5ffd5b6147cf8b828c016146a2565b9150509295985092959890939650565b5f602082840312156147ef575f5ffd5b8135613b128161459d565b5f6020828403121561480a575f5ffd5b5035919050565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b8035600481106145bc575f5ffd5b5f5f60408385031215614851575f5ffd5b61485a83614832565b946020939093013593505050565b5f60608284031215614878575f5ffd5b613b1283836145c1565b634e487b7160e01b5f52602160045260245ffd5b600e81106148a6576148a6614882565b9052565b602081016138428284614896565b600481106148a6576148a6614882565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b8e8152614906602082018f6148b8565b8c60408201528b606082015261491f608082018c614811565b6101c060a08201525f6149366101c083018c6148c8565b82810360c0840152614948818c6148c8565b905061495760e084018b614811565b61496561010084018a614811565b876101208401528661014084015282810361016084015261498681876148c8565b915050614997610180830185614811565b8215156101a08301529f9e505050505050505050505050505050565b805f5b60028110156139af5781518452602093840193909101906001016149b6565b805182525f60208201516149ec60208501826148b8565b50604082015160408401526060820151614a0960608501826149b3565b50608082015160a084015260a0820151614a2660c0850182614811565b5060c082015161020060e0850152614a426102008501826148c8565b905060e0830151848203610100860152614a5c82826148c8565b915050610100830151614a73610120860182614811565b50610120830151614a88610140860182614811565b506101408301516101608501526101608301516101808501526101808301518482036101a0860152614aba82826148c8565b9150506101a0830151614ad16101c0860182614811565b506101c08301518015156101e0860152613a9a565b602081525f613b1260208301846149d5565b5f60208284031215614b08575f5ffd5b81356001600160401b03811115614b1d575f5ffd5b614b2984828501614637565b949350505050565b5f60208284031215614b41575f5ffd5b81356001600160401b03811115614b56575f5ffd5b82016101008185031215613b12575f5ffd5b828152604060208201525f614b2960408301846149d5565b5f60208284031215614b90575f5ffd5b81356001600160401b03811115614ba5575f5ffd5b614b29848285016146a2565b5f5f60408385031215614bc2575f5ffd5b823591506020830135614bd48161459d565b809150509250929050565b5f5f60408385031215614bf0575f5ffd5b50508035926020909101359150565b81518152602080830151908201526040808301519082015260608101613842565b821515815260408101613b126020830184614896565b5f5f83601f840112614c46575f5ffd5b5081356001600160401b03811115614c5c575f5ffd5b602083019150836020828501011115613cc5575f5ffd5b5f5f5f5f5f60608688031215614c87575f5ffd5b8535945060208601356001600160401b03811115614ca3575f5ffd5b614caf88828901614c36565b90955093505060408601356001600160401b03811115614ccd575f5ffd5b614cd988828901614c36565b969995985093965092949392505050565b5f6101e082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e0830151614d4460e0840182614811565b50610100830151614d5c61010084018261ffff169052565b50610120830151614d7461012084018261ffff169052565b50610140830151614d8c61014084018261ffff169052565b50610160830151614da461016084018261ffff169052565b50610180830151614dbc61018084018261ffff169052565b506101a0830151614dd66101a084018263ffffffff169052565b506101c0830151614df06101c084018263ffffffff169052565b5092915050565b5f5f5f5f5f5f5f6080888a031215614e0d575f5ffd5b8735965060208801356001600160401b03811115614e29575f5ffd5b614e358a828b01614c36565b90975095505060408801356001600160401b03811115614e53575f5ffd5b614e5f8a828b01614c36565b90955093505060608801356001600160401b03811115614e7d575f5ffd5b614e898a828b01614c36565b989b979a50959850939692959293505050565b5f5f60408385031215614ead575f5ffd5b82359150602083013560ff81168114614bd4575f5ffd5b600781106148a6576148a6614882565b602081016138428284614ec4565b5f6101e0828403128015614ef4575f5ffd5b509092915050565b5f5f60608385031215614f0d575f5ffd5b614f1683614832565b915083606084011115614f27575f5ffd5b50926020919091019150565b600181811c90821680614f4757607f821691505b60208210810361126357634e487b7160e01b5f52602260045260245ffd5b5f60208284031215614f75575f5ffd5b613b1282614832565b634e487b7160e01b5f52603260045260245ffd5b6020810161384282846148b8565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561384257613842614fa0565b8082018082111561384257613842614fa0565b5f60018201614feb57614feb614fa0565b5060010190565b5f5f8335601e19843603018112615007575f5ffd5b8301803591506001600160401b03821115615020575f5ffd5b602001915036819003821315613cc5575f5ffd5b8015158114610d3f575f5ffd5b5f60208284031215615051575f5ffd5b8135613b1281615034565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b88815287602082015260a060408201525f6150a360a08301888a61505c565b82810360608401526150b681878961505c565b905082810360808401526150cb81858761505c565b9b9a5050505050505050505050565b5f602082840312156150ea575f5ffd5b5051919050565b601f821115613b3f57805f5260205f20601f840160051c810160208510156151165750805b601f840160051c820191505b81811015615135575f8155600101615122565b5050505050565b5f19600383901b1c191660019190911b1790565b81516001600160401b03811115615169576151696145d1565b61517d816151778454614f33565b846150f1565b6020601f8211600181146151aa575f83156151985750848201515b6151a2848261513c565b855550615135565b5f84815260208120601f198516915b828110156151d957878501518255602094850194600190920191016151b9565b50848210156151f657868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b838152602081018390526080810160408201835f5b600281101561523f57815163ffffffff1683526020928301929091019060010161521a565b505050949350505050565b5f6020828403121561525a575f5ffd5b8151613b1281615034565b604081016152738285614ec4565b613b126020830184614ec4565b5f82518060208501845e5f920191825250919050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b828110156152ed57603f198786030184526152d88583516148c8565b945060209384019391909101906001016152bc565b50929695505050505050565b8381526060810161530d6020830185614ec4565b614b296040830184614ec4565b5f8151808452602084019350602083015f5b828110156153535781516001600160a01b031686526020958601959091019060010161532c565b5093949350505050565b848152836020820152608060408201525f61537b608083018561531a565b905060018060a01b038316606083015295945050505050565b818382375f9101908152919050565b848152836020820152606060408201525f61440a60608301848661505c565b602081525f614b2960208301848661505c565b6001600160401b038311156153ec576153ec6145d1565b615400836153fa8354614f33565b836150f1565b5f601f84116001811461542c575f851561541a5750838201355b615424868261513c565b845550615135565b5f83815260208120601f198716915b8281101561545b578685013582556020948501946001909201910161543b565b5086821015615477575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b858152606060208201525f6154a260608301868861505c565b82810360408401526154b581858761505c565b98975050505050505050565b604081525f6154d460408301868861505c565b82810360208401526154e781858761505c565b979650505050505050565b61ffff81168114610d3f575f5ffd5b80356145bc816154f2565b5f6020828403121561551c575f5ffd5b8135613b12816154f2565b63ffffffff81168114610d3f575f5ffd5b80356145bc81615527565b5f60208284031215615553575f5ffd5b8135613b1281615527565b5f81356138428161459d565b5f8135613842816154f2565b5f813561384281615527565b813581556020820135600182015560408201356002820155606082013560038201556080820135600482015560a0820135600582015560c08201356006820155600781016155f26155d560e0850161555e565b82546001600160a01b0319166001600160a01b0391909116178255565b615622615602610100850161556a565b82805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b615652615632610120850161556a565b82805461ffff60b01b191660b09290921b61ffff60b01b16919091179055565b615682615662610140850161556a565b82805461ffff60c01b191660c09290921b61ffff60c01b16919091179055565b6156b2615692610160850161556a565b82805461ffff60d01b191660d09290921b61ffff60d01b16919091179055565b6156e26156c2610180850161556a565b82805461ffff60e01b191660e09290921b61ffff60e01b16919091179055565b506008810161570e6156f76101a08501615576565b825463ffffffff191663ffffffff91909116178255565b613b3f61571e6101c08501615576565b825467ffffffff00000000191660209190911b67ffffffff0000000016178255565b813581526020808301359082015260408083013590820152606080830135908201526080808301359082015260a0808301359082015260c080830135908201526101e0810161579160e084016145b1565b61579e60e0840182614811565b506157ac6101008401615501565b61ffff166101008301526157c36101208401615501565b61ffff166101208301526157da6101408401615501565b61ffff166101408301526157f16101608401615501565b61ffff166101608301526158086101808401615501565b61ffff1661018083015261581f6101a08401615538565b63ffffffff166101a08301526158386101c08401615538565b63ffffffff81166101c0840152614df0565b808202811582820484141761384257613842614fa0565b5f8261587b57634e487b7160e01b5f52601260045260245ffd5b500490565b6040810181835f5b60028110156158b757813561589c81615527565b63ffffffff1683526020928301929190910190600101615888565b50505092915050565b604081016158ce8285614ec4565b613b126020830184614896565b5f602082840312156158eb575f5ffd5b81516001600160401b03811115615900575f5ffd5b8201601f81018413615910575f5ffd5b805161591e6146bf82614615565b8082825260208201915060208360051b85010192508683111561593f575f5ffd5b6020840193505b8284101561440a5783516159598161459d565b825260209384019390910190615946565b6001600160a01b03929092168252602082015260400190565b838152606060208201525f61599b606083018561531a565b905060018060a01b0383166040830152949350505050565b5f8151808452602084019350602083015f5b828110156153535781518652602095860195909101906001016159c5565b6001600160a01b03841681526060602082018190525f90615a069083018561531a565b828103604084015261440a81856159b3565b604081525f615a2a604083018561531a565b8281036020840152615a3c81856159b3565b9594505050505056fe1b418a230a21d37a078bf8f16decbde8ccceacd77159371f62f0d4ea00d19967a164736f6c634300081c000a", "linkReferences": {}, "deployedLinkReferences": {}, "immutableReferences": {}, "inputSourceName": "project/contracts/Enclave.sol", - "buildInfoId": "solc-0_8_28-4e1d4326aa586bce7ef3b38a9e93aeff5ca3ac8f" + "buildInfoId": "solc-0_8_28-74ea8e366bd07fddf0065d16be962bc1ae5e80d7" } \ No newline at end of file diff --git a/packages/enclave-contracts/artifacts/contracts/interfaces/IBondingRegistry.sol/IBondingRegistry.json b/packages/enclave-contracts/artifacts/contracts/interfaces/IBondingRegistry.sol/IBondingRegistry.json index 00f3df517f..35149dca85 100644 --- a/packages/enclave-contracts/artifacts/contracts/interfaces/IBondingRegistry.sol/IBondingRegistry.json +++ b/packages/enclave-contracts/artifacts/contracts/interfaces/IBondingRegistry.sol/IBondingRegistry.json @@ -940,5 +940,5 @@ "deployedLinkReferences": {}, "immutableReferences": {}, "inputSourceName": "project/contracts/interfaces/IBondingRegistry.sol", - "buildInfoId": "solc-0_8_28-4e1d4326aa586bce7ef3b38a9e93aeff5ca3ac8f" + "buildInfoId": "solc-0_8_28-74ea8e366bd07fddf0065d16be962bc1ae5e80d7" } \ No newline at end of file diff --git a/packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json b/packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json index cb5d780f9f..bf4d0a6cda 100644 --- a/packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json +++ b/packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json @@ -3,6 +3,154 @@ "contractName": "ICiphernodeRegistry", "sourceName": "contracts/interfaces/ICiphernodeRegistry.sol", "abi": [ + { + "inputs": [], + "name": "BondingRegistryNotSet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "node", + "type": "address" + } + ], + "name": "CiphernodeNotEnabled", + "type": "error" + }, + { + "inputs": [], + "name": "CommitteeAlreadyFinalized", + "type": "error" + }, + { + "inputs": [], + "name": "CommitteeAlreadyPublished", + "type": "error" + }, + { + "inputs": [], + "name": "CommitteeAlreadyRequested", + "type": "error" + }, + { + "inputs": [], + "name": "CommitteeDeadlineReached", + "type": "error" + }, + { + "inputs": [], + "name": "CommitteeNotFinalized", + "type": "error" + }, + { + "inputs": [], + "name": "CommitteeNotInitializedOrFinalized", + "type": "error" + }, + { + "inputs": [], + "name": "CommitteeNotPublished", + "type": "error" + }, + { + "inputs": [], + "name": "CommitteeNotRequested", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "requested", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "available", + "type": "uint256" + } + ], + "name": "InsufficientCiphernodes", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTicketNumber", + "type": "error" + }, + { + "inputs": [], + "name": "NodeAlreadySubmitted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "node", + "type": "address" + } + ], + "name": "NodeNotBonded", + "type": "error" + }, + { + "inputs": [], + "name": "NodeNotEligible", + "type": "error" + }, + { + "inputs": [], + "name": "NodeNotSubmitted", + "type": "error" + }, + { + "inputs": [], + "name": "NotOwnerOrBondingRegistry", + "type": "error" + }, + { + "inputs": [], + "name": "NotSlashingManager", + "type": "error" + }, + { + "inputs": [], + "name": "OnlyBondingRegistry", + "type": "error" + }, + { + "inputs": [], + "name": "OnlyEnclave", + "type": "error" + }, + { + "inputs": [], + "name": "SubmissionWindowClosed", + "type": "error" + }, + { + "inputs": [], + "name": "SubmissionWindowNotClosed", + "type": "error" + }, + { + "inputs": [], + "name": "ThresholdNotMet", + "type": "error" + }, + { + "inputs": [], + "name": "Unauthorized", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, { "anonymous": false, "inputs": [ @@ -755,6 +903,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "sortitionSubmissionWindow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -793,5 +954,5 @@ "deployedLinkReferences": {}, "immutableReferences": {}, "inputSourceName": "project/contracts/interfaces/ICiphernodeRegistry.sol", - "buildInfoId": "solc-0_8_28-4e1d4326aa586bce7ef3b38a9e93aeff5ca3ac8f" + "buildInfoId": "solc-0_8_28-74ea8e366bd07fddf0065d16be962bc1ae5e80d7" } \ No newline at end of file diff --git a/packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json b/packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json index 262e25c88b..9f95a33a78 100644 --- a/packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json +++ b/packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json @@ -3,6 +3,428 @@ "contractName": "IEnclave", "sourceName": "contracts/interfaces/IEnclave.sol", "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "size", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minimum", + "type": "uint256" + } + ], + "name": "BelowMinCommitteeSize", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "threshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minimum", + "type": "uint256" + } + ], + "name": "BelowMinThreshold", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "BpsExceedsMax", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "CiphertextOutputAlreadyPublished", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "CiphertextOutputNotPublished", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + } + ], + "name": "CommitteeDutiesCompleted", + "type": "error" + }, + { + "inputs": [], + "name": "CommitteeSelectionFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum IEnclave.CommitteeSize", + "name": "committeeSize", + "type": "uint8" + } + ], + "name": "CommitteeSizeNotConfigured", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum IEnclave.CommitteeSize", + "name": "committeeSize", + "type": "uint8" + } + ], + "name": "CommitteeSizeTooSmall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "E3AlreadyComplete", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "E3AlreadyFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "E3DoesNotExist", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "E3NotFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IE3Program", + "name": "e3Program", + "type": "address" + } + ], + "name": "E3ProgramNotAllowed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "FailureConditionNotMet", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "inputDeadline", + "type": "uint256" + } + ], + "name": "InputDeadlineNotReached", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IBondingRegistry", + "name": "bondingRegistry", + "type": "address" + } + ], + "name": "InvalidBondingRegistry", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract ICiphernodeRegistry", + "name": "ciphernodeRegistry", + "type": "address" + } + ], + "name": "InvalidCiphernodeRegistry", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "InvalidDuration", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "encryptionSchemeId", + "type": "bytes32" + } + ], + "name": "InvalidEncryptionScheme", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "feeToken", + "type": "address" + } + ], + "name": "InvalidFeeToken", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "InvalidInputDeadline", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "end", + "type": "uint256" + } + ], + "name": "InvalidInputDeadlineEnd", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "start", + "type": "uint256" + } + ], + "name": "InvalidInputDeadlineStart", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "output", + "type": "bytes" + } + ], + "name": "InvalidOutput", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "internalType": "enum IEnclave.E3Stage", + "name": "expected", + "type": "uint8" + }, + { + "internalType": "enum IEnclave.E3Stage", + "name": "actual", + "type": "uint8" + } + ], + "name": "InvalidStage", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidThresholdValues", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTimeoutWindow", + "type": "error" + }, + { + "inputs": [], + "name": "MinSizeBelowMinThreshold", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "module", + "type": "address" + } + ], + "name": "ModuleAlreadyEnabled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "module", + "type": "address" + } + ], + "name": "ModuleNotEnabled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "NoPaymentToRefund", + "type": "error" + }, + { + "inputs": [], + "name": "OnlyCiphernodeRegistry", + "type": "error" + }, + { + "inputs": [], + "name": "OnlyCiphernodeRegistryOrSlashingManager", + "type": "error" + }, + { + "inputs": [], + "name": "OnlySlashingManager", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "PaymentRequired", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "PlaintextOutputAlreadyPublished", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "threshold", + "type": "uint256" + } + ], + "name": "ThresholdTooSmall", + "type": "error" + }, + { + "inputs": [], + "name": "TreasuryRequired", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "UtilizationBpsExceedsMax", + "type": "error" + }, { "anonymous": false, "inputs": [ @@ -443,6 +865,96 @@ "name": "PlaintextOutputPublished", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "keyGenFixedPerNode", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "keyGenPerEncryptionProof", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "coordinationPerPair", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "availabilityPerNodePerSec", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decryptionPerNode", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "publicationBase", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "verificationPerProof", + "type": "uint256" + }, + { + "internalType": "address", + "name": "protocolTreasury", + "type": "address" + }, + { + "internalType": "uint16", + "name": "marginBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "protocolShareBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "dkgUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "computeUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "decryptUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint32", + "name": "minCommitteeSize", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "minThreshold", + "type": "uint32" + } + ], + "indexed": false, + "internalType": "struct IEnclave.PricingConfig", + "name": "config", + "type": "tuple" + } + ], + "name": "PricingConfigUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -901,6 +1413,96 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "getPricingConfig", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "keyGenFixedPerNode", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "keyGenPerEncryptionProof", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "coordinationPerPair", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "availabilityPerNodePerSec", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decryptionPerNode", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "publicationBase", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "verificationPerProof", + "type": "uint256" + }, + { + "internalType": "address", + "name": "protocolTreasury", + "type": "address" + }, + { + "internalType": "uint16", + "name": "marginBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "protocolShareBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "dkgUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "computeUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "decryptUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint32", + "name": "minCommitteeSize", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "minThreshold", + "type": "uint32" + } + ], + "internalType": "struct IEnclave.PricingConfig", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1364,6 +1966,96 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "keyGenFixedPerNode", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "keyGenPerEncryptionProof", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "coordinationPerPair", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "availabilityPerNodePerSec", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decryptionPerNode", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "publicationBase", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "verificationPerProof", + "type": "uint256" + }, + { + "internalType": "address", + "name": "protocolTreasury", + "type": "address" + }, + { + "internalType": "uint16", + "name": "marginBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "protocolShareBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "dkgUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "computeUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "decryptUtilizationBps", + "type": "uint16" + }, + { + "internalType": "uint32", + "name": "minCommitteeSize", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "minThreshold", + "type": "uint32" + } + ], + "internalType": "struct IEnclave.PricingConfig", + "name": "config", + "type": "tuple" + } + ], + "name": "setPricingConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1401,5 +2093,5 @@ "deployedLinkReferences": {}, "immutableReferences": {}, "inputSourceName": "project/contracts/interfaces/IEnclave.sol", - "buildInfoId": "solc-0_8_28-4e1d4326aa586bce7ef3b38a9e93aeff5ca3ac8f" + "buildInfoId": "solc-0_8_28-74ea8e366bd07fddf0065d16be962bc1ae5e80d7" } \ No newline at end of file diff --git a/packages/enclave-contracts/artifacts/contracts/interfaces/ISlashingManager.sol/ISlashingManager.json b/packages/enclave-contracts/artifacts/contracts/interfaces/ISlashingManager.sol/ISlashingManager.json index 399e4b928b..152cd54269 100644 --- a/packages/enclave-contracts/artifacts/contracts/interfaces/ISlashingManager.sol/ISlashingManager.json +++ b/packages/enclave-contracts/artifacts/contracts/interfaces/ISlashingManager.sol/ISlashingManager.json @@ -954,5 +954,5 @@ "deployedLinkReferences": {}, "immutableReferences": {}, "inputSourceName": "project/contracts/interfaces/ISlashingManager.sol", - "buildInfoId": "solc-0_8_28-4e1d4326aa586bce7ef3b38a9e93aeff5ca3ac8f" + "buildInfoId": "solc-0_8_28-74ea8e366bd07fddf0065d16be962bc1ae5e80d7" } \ No newline at end of file diff --git a/packages/enclave-contracts/artifacts/contracts/registry/CiphernodeRegistryOwnable.sol/CiphernodeRegistryOwnable.json b/packages/enclave-contracts/artifacts/contracts/registry/CiphernodeRegistryOwnable.sol/CiphernodeRegistryOwnable.json index c3e535bd60..acd5887045 100644 --- a/packages/enclave-contracts/artifacts/contracts/registry/CiphernodeRegistryOwnable.sol/CiphernodeRegistryOwnable.json +++ b/packages/enclave-contracts/artifacts/contracts/registry/CiphernodeRegistryOwnable.sol/CiphernodeRegistryOwnable.json @@ -1309,5 +1309,5 @@ }, "immutableReferences": {}, "inputSourceName": "project/contracts/registry/CiphernodeRegistryOwnable.sol", - "buildInfoId": "solc-0_8_28-4e1d4326aa586bce7ef3b38a9e93aeff5ca3ac8f" + "buildInfoId": "solc-0_8_28-74ea8e366bd07fddf0065d16be962bc1ae5e80d7" } \ No newline at end of file diff --git a/packages/enclave-contracts/artifacts/contracts/token/EnclaveTicketToken.sol/EnclaveTicketToken.json b/packages/enclave-contracts/artifacts/contracts/token/EnclaveTicketToken.sol/EnclaveTicketToken.json index 433586d3fb..65becc23d6 100644 --- a/packages/enclave-contracts/artifacts/contracts/token/EnclaveTicketToken.sol/EnclaveTicketToken.json +++ b/packages/enclave-contracts/artifacts/contracts/token/EnclaveTicketToken.sol/EnclaveTicketToken.json @@ -1223,5 +1223,5 @@ ] }, "inputSourceName": "project/contracts/token/EnclaveTicketToken.sol", - "buildInfoId": "solc-0_8_28-4e1d4326aa586bce7ef3b38a9e93aeff5ca3ac8f" + "buildInfoId": "solc-0_8_28-3f0df73226c7ff72a6c756321d5f230fe39ed6a0" } \ No newline at end of file diff --git a/packages/enclave-contracts/contracts/Enclave.sol b/packages/enclave-contracts/contracts/Enclave.sol index 6f09b2f219..0945f27aaa 100644 --- a/packages/enclave-contracts/contracts/Enclave.sol +++ b/packages/enclave-contracts/contracts/Enclave.sol @@ -107,107 +107,20 @@ contract Enclave is IEnclave, OwnableUpgradeable { /// @notice Maps committee size to threshold values [quorum, total] mapping(CommitteeSize => uint32[2] threshold) public committeeThresholds; + /// @notice Maps E3 ID to the protocol share BPS snapshotted at request time + mapping(uint256 e3Id => uint16 protocolShareBps) + internal _e3ProtocolShareBps; + + /// @notice Maps E3 ID to the protocol treasury snapshotted at request time + mapping(uint256 e3Id => address protocolTreasury) + internal _e3ProtocolTreasury; /// @notice Global timeout configuration E3TimeoutConfig internal _timeoutConfig; - //////////////////////////////////////////////////////////// - // // - // Errors // - // // - //////////////////////////////////////////////////////////// - - /// @notice Thrown when committee selection fails during E3 request or activation. - error CommitteeSelectionFailed(); - - /// @notice Thrown when an E3 request uses a program that is not enabled. - /// @param e3Program The E3 program address that is not allowed. - error E3ProgramNotAllowed(IE3Program e3Program); - - /// @notice Thrown when attempting to access an E3 that does not exist. - /// @param e3Id The ID of the non-existent E3. - error E3DoesNotExist(uint256 e3Id); - - /// @notice Thrown when attempting to enable a module or program that is already enabled. - /// @param module The address of the module that is already enabled. - error ModuleAlreadyEnabled(address module); - - /// @notice Thrown when attempting to disable a module or program that is not enabled. - /// @param module The address of the module that is not enabled. - error ModuleNotEnabled(address module); - - /// @notice Thrown when an invalid or disabled encryption scheme is used. - /// @param encryptionSchemeId The ID of the invalid encryption scheme. - error InvalidEncryptionScheme(bytes32 encryptionSchemeId); - - /// @notice Thrown when attempting to set an invalid ciphernode registry address. - /// @param ciphernodeRegistry The invalid ciphernode registry address. - error InvalidCiphernodeRegistry(ICiphernodeRegistry ciphernodeRegistry); - - /// @notice Thrown when the requested duration exceeds maxDuration or is zero. - /// @param duration The invalid duration value. - error InvalidDuration(uint256 duration); - - /// @notice Thrown when output verification fails. - /// @param output The invalid output data. - error InvalidOutput(bytes output); - - /// @notice Thrown when the committee size has not been configured with thresholds. - /// @param committeeSize The unconfigured committee size. - error CommitteeSizeNotConfigured(CommitteeSize committeeSize); - - /// @notice Thrown when attempting to publish ciphertext output that has already been published. - /// @param e3Id The ID of the E3. - error CiphertextOutputAlreadyPublished(uint256 e3Id); - - /// @notice Thrown when attempting to publish plaintext output before ciphertext output. - /// @param e3Id The ID of the E3. - error CiphertextOutputNotPublished(uint256 e3Id); - - /// @notice Thrown when payment is required but not provided or insufficient. - /// @param value The required payment amount. - error PaymentRequired(uint256 value); - - /// @notice Thrown when attempting to publish plaintext output that has already been published. - /// @param e3Id The ID of the E3. - error PlaintextOutputAlreadyPublished(uint256 e3Id); - - /// @notice Thrown when attempting to set an invalid bonding registry address. - /// @param bondingRegistry The invalid bonding registry address. - error InvalidBondingRegistry(IBondingRegistry bondingRegistry); - - /// @notice Thrown when attempting to set an invalid fee token address. - /// @param feeToken The invalid fee token address. - error InvalidFeeToken(IERC20 feeToken); - - /// @notice E3 is not in expected stage - error InvalidStage(uint256 e3Id, E3Stage expected, E3Stage actual); - - /// @notice E3 has already been marked as failed - error E3AlreadyFailed(uint256 e3Id); - - /// @notice E3 has already completed - error E3AlreadyComplete(uint256 e3Id); - - /// @notice Failure condition not yet met - error FailureConditionNotMet(uint256 e3Id); - - /// @notice The Input deadline is invalid - error InvalidInputDeadline(uint256 deadline); - - /// @notice The input deadline start is in the past - error InvalidInputDeadlineStart(uint256 start); - /// @notice The input deadline end is before the start - error InvalidInputDeadlineEnd(uint256 end); - - /// @notice The duties are completed, and ciphernodes are not required to act anymore for this E3 - /// @param e3Id The ID of the E3 - /// @param expiration The expiration timestamp of the E3 - error CommitteeDutiesCompleted(uint256 e3Id, uint256 expiration); - - /// @notice The input deadline has not yet been reached - /// @param e3Id The ID of the E3 - /// @param inputDeadline The input deadline timestamp of the E3 - error InputDeadlineNotReached(uint256 e3Id, uint256 inputDeadline); + /// @notice All pricing-related configuration + PricingConfig internal _pricingConfig; + /// @notice Basis points denominator + uint16 internal constant BPS_BASE = 10000; //////////////////////////////////////////////////////////// // // @@ -219,7 +132,7 @@ contract Enclave is IEnclave, OwnableUpgradeable { modifier onlyCiphernodeRegistry() { require( msg.sender == address(ciphernodeRegistry), - "Only CiphernodeRegistry" + OnlyCiphernodeRegistry() ); _; } @@ -229,14 +142,14 @@ contract Enclave is IEnclave, OwnableUpgradeable { require( msg.sender == address(ciphernodeRegistry) || msg.sender == address(slashingManager), - "Only Registry or SlashingMgr" + OnlyCiphernodeRegistryOrSlashingManager() ); _; } /// @notice Restricts function to SlashingManager contract only modifier onlySlashingManager() { - require(msg.sender == address(slashingManager), "Only SlashingManager"); + require(msg.sender == address(slashingManager), OnlySlashingManager()); _; } @@ -280,6 +193,26 @@ contract Enclave is IEnclave, OwnableUpgradeable { setFeeToken(_feeToken); _setTimeoutConfig(config); setE3ProgramsParams(_e3ProgramsParams); + + // Set default pricing parameters + _pricingConfig = PricingConfig({ + keyGenFixedPerNode: 50000, // 0.05 USDC + keyGenPerEncryptionProof: 25000, // 0.025 USDC + coordinationPerPair: 5000, // 0.005 USDC + availabilityPerNodePerSec: 20, // 0.00002 USDC + decryptionPerNode: 150000, // 0.15 USDC + publicationBase: 500000, // 0.50 USDC + verificationPerProof: 2000, // 0.002 USDC + protocolTreasury: address(0), + marginBps: 1000, // 10% + protocolShareBps: 0, + dkgUtilizationBps: 2500, // 25% — typical DKG completes in ~25% of window + computeUtilizationBps: 5000, // 50% — compute has moderate variance + decryptUtilizationBps: 2500, // 25% — decryption is fast when nodes cooperate + minCommitteeSize: 0, + minThreshold: 0 + }); + if (_owner != owner()) transferOwnership(_owner); } @@ -334,6 +267,8 @@ contract Enclave is IEnclave, OwnableUpgradeable { e3Payments[e3Id] = e3Fee; _e3FeeTokens[e3Id] = feeToken; + _e3ProtocolShareBps[e3Id] = _pricingConfig.protocolShareBps; + _e3ProtocolTreasury[e3Id] = _pricingConfig.protocolTreasury; // Initialize E3 Lifecycle _e3Stages[e3Id] = E3Stage.Requested; @@ -521,6 +456,9 @@ contract Enclave is IEnclave, OwnableUpgradeable { return; } + // If all committee members were expelled (all malicious), refund the + // requester in full — the protocol should not profit from a + // compromised E3. if (activeLength == 0) { address requester = _e3Requesters[e3Id]; if (requester != address(0)) { @@ -534,21 +472,36 @@ contract Enclave is IEnclave, OwnableUpgradeable { return; } + // Split between protocol treasury and CN rewards + uint256 protocolAmount = 0; + uint16 _protocolShareBps = _e3ProtocolShareBps[e3Id]; + address _protocolTreasury = _e3ProtocolTreasury[e3Id]; + if (_protocolShareBps > 0 && _protocolTreasury != address(0)) { + protocolAmount = + (totalAmount * uint256(_protocolShareBps)) / + uint256(BPS_BASE); + if (protocolAmount > 0) { + paymentToken.safeTransfer(_protocolTreasury, protocolAmount); + } + } + + uint256 cnAmount = totalAmount - protocolAmount; + uint256[] memory amounts = new uint256[](activeLength); - // Distribute equally among active (non-expelled) committee members - uint256 amount = totalAmount / activeLength; + // Distribute CN share equally among active (non-expelled) committee members + uint256 amount = cnAmount / activeLength; uint256 distributed = 0; for (uint256 i = 0; i < activeLength; i++) { amounts[i] = amount; distributed += amount; } - uint256 dust = totalAmount - distributed; + uint256 dust = cnAmount - distributed; if (dust > 0) { amounts[activeLength - 1] += dust; } - paymentToken.forceApprove(address(bondingRegistry), totalAmount); + paymentToken.forceApprove(address(bondingRegistry), cnAmount); bondingRegistry.distributeRewards(paymentToken, activeNodes, amounts); @@ -752,10 +705,10 @@ contract Enclave is IEnclave, OwnableUpgradeable { /// @param e3Id The ID of the failed E3 function processE3Failure(uint256 e3Id) external { E3Stage stage = _e3Stages[e3Id]; - require(stage == E3Stage.Failed, "E3 not failed"); + require(stage == E3Stage.Failed, E3NotFailed(e3Id)); uint256 payment = e3Payments[e3Id]; - require(payment > 0, "No payment to refund"); + require(payment > 0, NoPaymentToRefund(e3Id)); e3Payments[e3Id] = 0; // Prevent double processing address[] memory honestNodes = _getHonestNodes(e3Id); @@ -990,9 +943,9 @@ contract Enclave is IEnclave, OwnableUpgradeable { /// @notice Internal function to set timeout config function _setTimeoutConfig(E3TimeoutConfig calldata config) internal { - require(config.dkgWindow > 0, "Invalid DKG window"); - require(config.computeWindow > 0, "Invalid compute window"); - require(config.decryptionWindow > 0, "Invalid decryption window"); + require(config.dkgWindow > 0, InvalidTimeoutWindow()); + require(config.computeWindow > 0, InvalidTimeoutWindow()); + require(config.decryptionWindow > 0, InvalidTimeoutWindow()); _timeoutConfig = config; @@ -1006,12 +959,58 @@ contract Enclave is IEnclave, OwnableUpgradeable { ) external onlyOwner { require( threshold[1] >= threshold[0] && threshold[0] > 0, - "Invalid threshold" + InvalidThresholdValues() ); + // Enforce minimum committee bounds if configured + PricingConfig memory pc = _pricingConfig; + if (pc.minCommitteeSize > 0) { + require( + threshold[1] >= pc.minCommitteeSize, + BelowMinCommitteeSize(threshold[1], pc.minCommitteeSize) + ); + } + if (pc.minThreshold > 0) { + require( + threshold[0] >= pc.minThreshold, + BelowMinThreshold(threshold[0], pc.minThreshold) + ); + } committeeThresholds[size] = threshold; emit CommitteeThresholdsUpdated(size, threshold); } + /// @inheritdoc IEnclave + function setPricingConfig(PricingConfig calldata config) public onlyOwner { + require(config.marginBps <= BPS_BASE, BpsExceedsMax(config.marginBps)); + require( + config.protocolShareBps <= BPS_BASE, + BpsExceedsMax(config.protocolShareBps) + ); + require( + config.dkgUtilizationBps <= BPS_BASE, + UtilizationBpsExceedsMax(config.dkgUtilizationBps) + ); + require( + config.computeUtilizationBps <= BPS_BASE, + UtilizationBpsExceedsMax(config.computeUtilizationBps) + ); + require( + config.decryptUtilizationBps <= BPS_BASE, + UtilizationBpsExceedsMax(config.decryptUtilizationBps) + ); + require( + config.protocolShareBps == 0 || + config.protocolTreasury != address(0), + TreasuryRequired() + ); + require( + config.minCommitteeSize >= config.minThreshold, + MinSizeBelowMinThreshold() + ); + _pricingConfig = config; + emit PricingConfigUpdated(config); + } + //////////////////////////////////////////////////////////// // // // Get Functions // @@ -1026,12 +1025,94 @@ contract Enclave is IEnclave, OwnableUpgradeable { /// @inheritdoc IEnclave function getE3Quote( - E3RequestParams calldata - ) public pure returns (uint256 fee) { - fee = 1 * 10 ** 6; + E3RequestParams calldata requestParams + ) public view returns (uint256 fee) { + uint32[2] memory threshold = committeeThresholds[ + requestParams.committeeSize + ]; + require( + threshold[1] > 0, + CommitteeSizeNotConfigured(requestParams.committeeSize) + ); + uint256 n = uint256(threshold[1]); // total committee size + uint256 m = uint256(threshold[0]); // quorum/decryption threshold + + PricingConfig memory pc = _pricingConfig; + + if (pc.minCommitteeSize > 0) { + require( + threshold[1] >= pc.minCommitteeSize, + CommitteeSizeTooSmall(requestParams.committeeSize) + ); + } + if (pc.minThreshold > 0) { + require( + threshold[0] >= pc.minThreshold, + ThresholdTooSmall(threshold[0]) + ); + } + + require( + requestParams.inputWindow[1] >= requestParams.inputWindow[0], + InvalidInputDeadlineEnd(requestParams.inputWindow[1]) + ); + + // Duration covers the full availability period, using expected-case + // utilization fractions for protocol-controlled timeout windows. + // sortitionSubmissionWindow is included — CNs are locked during this phase. + uint256 duration = ciphernodeRegistry.sortitionSubmissionWindow() + + requestParams.inputWindow[1] - + requestParams.inputWindow[0] + + (_timeoutConfig.dkgWindow * uint256(pc.dkgUtilizationBps)) / + uint256(BPS_BASE) + + (_timeoutConfig.computeWindow * uint256(pc.computeUtilizationBps)) / + uint256(BPS_BASE) + + (_timeoutConfig.decryptionWindow * + uint256(pc.decryptUtilizationBps)) / + uint256(BPS_BASE); + + // ZK proof count per node: 6 fixed + 2 × (N-1) × L_dkg scaling + // TODO: get dkgModuliCount from E3 params instead of hardcoding + uint256 proofsPerNode = 6 + 2 * (n - 1) * 2; + + // Key generation cost: fixed per-node + per-proof (quadratic in n) + uint256 baseFee = pc.keyGenFixedPerNode * n; + baseFee += pc.keyGenPerEncryptionProof * n * proofsPerNode; + + // Key generation coordination cost (quadratic in n) + if (n > 1) { + baseFee += (pc.coordinationPerPair * (n * (n - 1))) / 2; + } + + // Proof verification cost: each node verifies all others' proofs (quadratic) + baseFee += pc.verificationPerProof * n * proofsPerNode; + + // Availability cost (linear in n × duration) + baseFee += pc.availabilityPerNodePerSec * n * duration; + + // Decryption cost (linear in m) + baseFee += pc.decryptionPerNode * m; + // Decryption coordination cost (quadratic in m) + if (m > 1) { + baseFee += (pc.coordinationPerPair * (m * (m - 1))) / 2; + } + + // Publication base cost + baseFee += pc.publicationBase; + + // Apply margin markup + fee = + (baseFee * (uint256(BPS_BASE) + uint256(pc.marginBps))) / + uint256(BPS_BASE); + require(fee > 0, PaymentRequired(fee)); } + /// @inheritdoc IEnclave + function getPricingConfig() external view returns (PricingConfig memory) { + return _pricingConfig; + } + /// @inheritdoc IEnclave function getDecryptionVerifier( bytes32 encryptionSchemeId diff --git a/packages/enclave-contracts/contracts/interfaces/ICiphernodeRegistry.sol b/packages/enclave-contracts/contracts/interfaces/ICiphernodeRegistry.sol index a2d59c78fc..e0b29b8e8d 100644 --- a/packages/enclave-contracts/contracts/interfaces/ICiphernodeRegistry.sol +++ b/packages/enclave-contracts/contracts/interfaces/ICiphernodeRegistry.sol @@ -168,6 +168,97 @@ interface ICiphernodeRegistry { /// @param sortitionSubmissionWindow The submission window for the E3 sortition in seconds. event SortitionSubmissionWindowSet(uint256 sortitionSubmissionWindow); + //////////////////////////////////////////////////////////// + // // + // Errors // + // // + //////////////////////////////////////////////////////////// + + /// @notice Committee has already been requested for this E3 + error CommitteeAlreadyRequested(); + + /// @notice Committee has already been published for this E3 + error CommitteeAlreadyPublished(); + + /// @notice Committee has not been published yet for this E3 + error CommitteeNotPublished(); + + /// @notice Committee has not been requested yet for this E3 + error CommitteeNotRequested(); + + /// @notice Committee Not Initialized or Finalized + error CommitteeNotInitializedOrFinalized(); + + /// @notice Submission Window has been closed for this E3 + error SubmissionWindowClosed(); + + /// @notice Committee deadline has been reached for this E3 + error CommitteeDeadlineReached(); + + /// @notice Committee has already been finalized for this E3 + error CommitteeAlreadyFinalized(); + + /// @notice Committee has not been finalized yet for this E3 + error CommitteeNotFinalized(); + + /// @notice Node has already submitted a ticket for this E3 + error NodeAlreadySubmitted(); + + /// @notice Node has not submitted a ticket for this E3 + error NodeNotSubmitted(); + + /// @notice Node is not eligible for this E3 + error NodeNotEligible(); + + /// @notice Ciphernode is not enabled in the registry + /// @param node Address of the ciphernode + error CiphernodeNotEnabled(address node); + + /// @notice Caller is not the Enclave contract + error OnlyEnclave(); + + /// @notice Caller is not the bonding registry + error OnlyBondingRegistry(); + + /// @notice Caller is neither owner nor bonding registry + error NotOwnerOrBondingRegistry(); + + /// @notice Node is not bonded + /// @param node Address of the node + error NodeNotBonded(address node); + + /// @notice Address cannot be zero + error ZeroAddress(); + + /// @notice Bonding registry has not been set + error BondingRegistryNotSet(); + + /// @notice Invalid ticket number + error InvalidTicketNumber(); + + /// @notice Submission window not closed yet + error SubmissionWindowNotClosed(); + + /// @notice Threshold not met for this E3 + error ThresholdNotMet(); + + /// @notice Caller is not authorized + error Unauthorized(); + + /// @notice Caller is not the slashing manager + error NotSlashingManager(); + + /// @notice Not enough registered ciphernodes to meet threshold + /// @param requested The requested committee size (N) + /// @param available The number of registered ciphernodes + error InsufficientCiphernodes(uint256 requested, uint256 available); + + //////////////////////////////////////////////////////////// + // // + // Function Signatures // + // // + //////////////////////////////////////////////////////////// + /// @notice Check if a ciphernode is eligible for committee selection /// @dev A ciphernode is eligible if it is enabled in the registry and meets bonding requirements /// @param ciphernode Address of the ciphernode to check @@ -258,6 +349,10 @@ interface ICiphernodeRegistry { /// @param _bondingRegistry Address of the bonding registry contract function setBondingRegistry(IBondingRegistry _bondingRegistry) external; + /// @notice Returns the current sortition submission window. + /// @return The sortition submission window in seconds. + function sortitionSubmissionWindow() external view returns (uint256); + /// @notice This function should be called to set the submission window for the E3 sortition. /// @param _sortitionSubmissionWindow The submission window for the E3 sortition in seconds. function setSortitionSubmissionWindow( diff --git a/packages/enclave-contracts/contracts/interfaces/IEnclave.sol b/packages/enclave-contracts/contracts/interfaces/IEnclave.sol index 323e64d0c5..0c64edf242 100644 --- a/packages/enclave-contracts/contracts/interfaces/IEnclave.sol +++ b/packages/enclave-contracts/contracts/interfaces/IEnclave.sol @@ -77,6 +77,25 @@ interface IEnclave { uint256 decryptionDeadline; } + /// @notice All pricing-related configuration for parametric E3 fee calculation + struct PricingConfig { + uint256 keyGenFixedPerNode; + uint256 keyGenPerEncryptionProof; + uint256 coordinationPerPair; + uint256 availabilityPerNodePerSec; + uint256 decryptionPerNode; + uint256 publicationBase; + uint256 verificationPerProof; + address protocolTreasury; + uint16 marginBps; + uint16 protocolShareBps; + uint16 dkgUtilizationBps; + uint16 computeUtilizationBps; + uint16 decryptUtilizationBps; + uint32 minCommitteeSize; + uint32 minThreshold; + } + //////////////////////////////////////////////////////////// // // // Events // @@ -226,6 +245,162 @@ interface IEnclave { uint32[2] threshold ); + /// @notice Emitted when pricing configuration is updated + event PricingConfigUpdated(PricingConfig config); + + //////////////////////////////////////////////////////////// + // // + // Errors // + // // + //////////////////////////////////////////////////////////// + + /// @notice Thrown when committee selection fails during E3 request or activation. + error CommitteeSelectionFailed(); + + /// @notice Thrown when an E3 request uses a program that is not enabled. + /// @param e3Program The E3 program address that is not allowed. + error E3ProgramNotAllowed(IE3Program e3Program); + + /// @notice Thrown when attempting to access an E3 that does not exist. + /// @param e3Id The ID of the non-existent E3. + error E3DoesNotExist(uint256 e3Id); + + /// @notice Thrown when attempting to enable a module or program that is already enabled. + /// @param module The address of the module that is already enabled. + error ModuleAlreadyEnabled(address module); + + /// @notice Thrown when attempting to disable a module or program that is not enabled. + /// @param module The address of the module that is not enabled. + error ModuleNotEnabled(address module); + + /// @notice Thrown when an invalid or disabled encryption scheme is used. + /// @param encryptionSchemeId The ID of the invalid encryption scheme. + error InvalidEncryptionScheme(bytes32 encryptionSchemeId); + + /// @notice Thrown when attempting to set an invalid ciphernode registry address. + /// @param ciphernodeRegistry The invalid ciphernode registry address. + error InvalidCiphernodeRegistry(ICiphernodeRegistry ciphernodeRegistry); + + /// @notice Thrown when the requested duration exceeds maxDuration or is zero. + /// @param duration The invalid duration value. + error InvalidDuration(uint256 duration); + + /// @notice Thrown when output verification fails. + /// @param output The invalid output data. + error InvalidOutput(bytes output); + + /// @notice Thrown when the committee size has not been configured with thresholds. + /// @param committeeSize The unconfigured committee size. + error CommitteeSizeNotConfigured(CommitteeSize committeeSize); + + /// @notice Thrown when attempting to publish ciphertext output that has already been published. + /// @param e3Id The ID of the E3. + error CiphertextOutputAlreadyPublished(uint256 e3Id); + + /// @notice Thrown when attempting to publish plaintext output before ciphertext output. + /// @param e3Id The ID of the E3. + error CiphertextOutputNotPublished(uint256 e3Id); + + /// @notice Thrown when payment is required but not provided or insufficient. + /// @param value The required payment amount. + error PaymentRequired(uint256 value); + + /// @notice Thrown when attempting to publish plaintext output that has already been published. + /// @param e3Id The ID of the E3. + error PlaintextOutputAlreadyPublished(uint256 e3Id); + + /// @notice Thrown when attempting to set an invalid bonding registry address. + /// @param bondingRegistry The invalid bonding registry address. + error InvalidBondingRegistry(IBondingRegistry bondingRegistry); + + /// @notice Thrown when attempting to set an invalid fee token address. + /// @param feeToken The invalid fee token address. + error InvalidFeeToken(IERC20 feeToken); + + /// @notice E3 is not in expected stage + error InvalidStage(uint256 e3Id, E3Stage expected, E3Stage actual); + + /// @notice E3 has already been marked as failed + error E3AlreadyFailed(uint256 e3Id); + + /// @notice E3 has already completed + error E3AlreadyComplete(uint256 e3Id); + + /// @notice Failure condition not yet met + error FailureConditionNotMet(uint256 e3Id); + + /// @notice The Input deadline is invalid + error InvalidInputDeadline(uint256 deadline); + + /// @notice The input deadline start is in the past + error InvalidInputDeadlineStart(uint256 start); + + /// @notice The input deadline end is before the start + error InvalidInputDeadlineEnd(uint256 end); + + /// @notice Below minimum committee size + error CommitteeSizeTooSmall(CommitteeSize committeeSize); + + /// @notice Below minimum threshold + error ThresholdTooSmall(uint256 threshold); + + /// @notice The duties are completed, and ciphernodes are not required to act anymore for this E3 + /// @param e3Id The ID of the E3 + /// @param expiration The expiration timestamp of the E3 + error CommitteeDutiesCompleted(uint256 e3Id, uint256 expiration); + + /// @notice The input deadline has not yet been reached + /// @param e3Id The ID of the E3 + /// @param inputDeadline The input deadline timestamp of the E3 + error InputDeadlineNotReached(uint256 e3Id, uint256 inputDeadline); + + /// @notice Caller is not the CiphernodeRegistry + error OnlyCiphernodeRegistry(); + + /// @notice Caller is not the CiphernodeRegistry or SlashingManager + error OnlyCiphernodeRegistryOrSlashingManager(); + + /// @notice Caller is not the SlashingManager + error OnlySlashingManager(); + + /// @notice E3 is not in the Failed stage + /// @param e3Id The ID of the E3 + error E3NotFailed(uint256 e3Id); + + /// @notice No payment available to refund for this E3 + /// @param e3Id The ID of the E3 + error NoPaymentToRefund(uint256 e3Id); + + /// @notice Timeout window value is invalid (must be > 0) + error InvalidTimeoutWindow(); + + /// @notice Threshold values are invalid + error InvalidThresholdValues(); + + /// @notice Committee size is below the configured minimum + /// @param size The provided committee size + /// @param minimum The required minimum + error BelowMinCommitteeSize(uint256 size, uint256 minimum); + + /// @notice Threshold is below the configured minimum + /// @param threshold The provided threshold + /// @param minimum The required minimum + error BelowMinThreshold(uint256 threshold, uint256 minimum); + + /// @notice A basis-points value exceeds 100% (10000) + /// @param value The invalid BPS value + error BpsExceedsMax(uint256 value); + + /// @notice Protocol treasury address required when protocol share > 0 + error TreasuryRequired(); + + /// @notice Minimum committee size must be >= minimum threshold + error MinSizeBelowMinThreshold(); + + /// @notice Utilization BPS exceeds 100% + /// @param value The invalid utilization BPS value + error UtilizationBpsExceedsMax(uint256 value); + //////////////////////////////////////////////////////////// // // // Structs // @@ -362,6 +537,10 @@ interface IEnclave { /// @param _e3ProgramsParams Array of ABI encoded parameter sets to remove. function removeE3ProgramsParams(bytes[] memory _e3ProgramsParams) external; + /// @notice Sets the full pricing configuration. + /// @param config The new pricing configuration. + function setPricingConfig(PricingConfig calldata config) external; + //////////////////////////////////////////////////////////// // // // Get Functions // @@ -382,6 +561,9 @@ interface IEnclave { E3RequestParams calldata e3Params ) external view returns (uint256 fee); + /// @notice Returns the full pricing configuration. + function getPricingConfig() external view returns (PricingConfig memory); + /// @notice Returns the decryption verifier for a given encryption scheme. /// @param encryptionSchemeId The unique identifier for the encryption scheme. /// @return The decryption verifier contract for the specified encryption scheme. diff --git a/packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol b/packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol index 08935fce8e..305181ffbb 100644 --- a/packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol +++ b/packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol @@ -80,91 +80,6 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { /// @notice Address of the slashing manager authorized to expel committee members ISlashingManager public slashingManager; - //////////////////////////////////////////////////////////// - // // - // Errors // - // // - //////////////////////////////////////////////////////////// - - /// @notice Committee has already been requested for this E3 - error CommitteeAlreadyRequested(); - - /// @notice Committee has already been published for this E3 - error CommitteeAlreadyPublished(); - - /// @notice Committee has not been published yet for this E3 - error CommitteeNotPublished(); - - /// @notice Committee has not been requested yet for this E3 - error CommitteeNotRequested(); - - /// @notice Committee Not Initialized or Finalized - error CommitteeNotInitializedOrFinalized(); - - /// @notice Submission Window has been closed for this E3 - error SubmissionWindowClosed(); - - /// @notice Committee deadline has been reached for this E3 - error CommitteeDeadlineReached(); - - /// @notice Committee has already been finalized for this E3 - error CommitteeAlreadyFinalized(); - - /// @notice Committee has not been finalized yet for this E3 - error CommitteeNotFinalized(); - - /// @notice Node has already submitted a ticket for this E3 - error NodeAlreadySubmitted(); - - /// @notice Node has not submitted a ticket for this E3 - error NodeNotSubmitted(); - - /// @notice Node is not eligible for this E3 - error NodeNotEligible(); - - /// @notice Ciphernode is not enabled in the registry - /// @param node Address of the ciphernode - error CiphernodeNotEnabled(address node); - - /// @notice Caller is not the Enclave contract - error OnlyEnclave(); - - /// @notice Caller is not the bonding registry - error OnlyBondingRegistry(); - - /// @notice Caller is neither owner nor bonding registry - error NotOwnerOrBondingRegistry(); - - /// @notice Node is not bonded - /// @param node Address of the node - error NodeNotBonded(address node); - - /// @notice Address cannot be zero - error ZeroAddress(); - - /// @notice Bonding registry has not been set - error BondingRegistryNotSet(); - - /// @notice Invalid ticket number - error InvalidTicketNumber(); - - /// @notice Submission window not closed yet - error SubmissionWindowNotClosed(); - - /// @notice Threshold not met for this E3 - error ThresholdNotMet(); - - /// @notice Caller is not authorized - error Unauthorized(); - - /// @notice Caller is not the slashing manager - error NotSlashingManager(); - - /// @notice Not enough registered ciphernodes to meet threshold - /// @param requested The requested committee size (N) - /// @param available The number of registered ciphernodes - error InsufficientCiphernodes(uint256 requested, uint256 available); - //////////////////////////////////////////////////////////// // // // Modifiers // diff --git a/packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol b/packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol index c7fe477c34..ee3a608b60 100644 --- a/packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol +++ b/packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol @@ -110,6 +110,10 @@ contract MockCiphernodeRegistry is ICiphernodeRegistry { return true; } + function sortitionSubmissionWindow() external pure returns (uint256) { + return 0; + } + // solhint-disable-next-line no-empty-blocks function setSortitionSubmissionWindow(uint256) external pure {} @@ -172,8 +176,6 @@ contract MockCiphernodeRegistry is ICiphernodeRegistry { } contract MockCiphernodeRegistryEmptyKey is ICiphernodeRegistry { - error CommitteeNotPublished(); - function requestCommittee( uint256, uint256, @@ -241,6 +243,10 @@ contract MockCiphernodeRegistryEmptyKey is ICiphernodeRegistry { // solhint-disable-next-line no-empty-blocks function setBondingRegistry(IBondingRegistry) external pure {} + function sortitionSubmissionWindow() external pure returns (uint256) { + return 0; + } + // solhint-disable-next-line no-empty-blocks function setSortitionSubmissionWindow(uint256) external pure {} diff --git a/packages/enclave-contracts/scripts/deployEnclave.ts b/packages/enclave-contracts/scripts/deployEnclave.ts index 1fd03f4a44..c0051a6486 100644 --- a/packages/enclave-contracts/scripts/deployEnclave.ts +++ b/packages/enclave-contracts/scripts/deployEnclave.ts @@ -233,6 +233,28 @@ export const deployEnclave = async ( const encryptionSchemeId = ethers.keccak256(ethers.toUtf8Bytes("fhe.rs:BFV")); + // Set pricing config with protocol treasury + const protocolTreasury = process.env.PROTOCOL_TREASURY || ownerAddress; + console.log("Setting pricing config..."); + await enclave.setPricingConfig({ + keyGenFixedPerNode: 50000, // 0.05 USDC + keyGenPerEncryptionProof: 25000, // 0.025 USDC + coordinationPerPair: 5000, // 0.005 USDC + availabilityPerNodePerSec: 20, // 0.00002 USDC + decryptionPerNode: 150000, // 0.15 USDC + publicationBase: 500000, // 0.50 USDC + verificationPerProof: 2000, // 0.002 USDC + protocolTreasury: protocolTreasury, + marginBps: 1000, // 10% + protocolShareBps: 2000, // 20% + dkgUtilizationBps: 2500, // 25% + computeUtilizationBps: 5000, // 50% + decryptUtilizationBps: 2500, // 25% + minCommitteeSize: 0, + minThreshold: 0, + }); + console.log("Pricing config set (treasury:", protocolTreasury, ")"); + if (shouldDeployMocks) { const { decryptionVerifierAddress: mockDecryptionVerifierAddress, diff --git a/packages/enclave-contracts/test/E3Lifecycle/E3Integration.spec.ts b/packages/enclave-contracts/test/E3Lifecycle/E3Integration.spec.ts index b1faa93a65..d8eac31daa 100644 --- a/packages/enclave-contracts/test/E3Lifecycle/E3Integration.spec.ts +++ b/packages/enclave-contracts/test/E3Lifecycle/E3Integration.spec.ts @@ -558,8 +558,9 @@ describe("E3 Integration - Refund/Timeout Mechanism", function () { await makeRequest(); // E3 is in Requested state, not Failed - await expect(enclave.processE3Failure(0)).to.be.revertedWith( - "E3 not failed", + await expect(enclave.processE3Failure(0)).to.be.revertedWithCustomError( + enclave, + "E3NotFailed", ); }); @@ -659,8 +660,9 @@ describe("E3 Integration - Refund/Timeout Mechanism", function () { await enclave.processE3Failure(0); // Second call should fail - payment already cleared - await expect(enclave.processE3Failure(0)).to.be.revertedWith( - "No payment to refund", + await expect(enclave.processE3Failure(0)).to.be.revertedWithCustomError( + enclave, + "NoPaymentToRefund", ); }); diff --git a/packages/enclave-contracts/test/Pricing/Pricing.spec.ts b/packages/enclave-contracts/test/Pricing/Pricing.spec.ts new file mode 100644 index 0000000000..a4c5c2e4c9 --- /dev/null +++ b/packages/enclave-contracts/test/Pricing/Pricing.spec.ts @@ -0,0 +1,821 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. +import { expect } from "chai"; +import type { Signer } from "ethers"; +import { network } from "hardhat"; + +import BondingRegistryModule from "../../ignition/modules/bondingRegistry"; +import CiphernodeRegistryModule from "../../ignition/modules/ciphernodeRegistry"; +import E3RefundManagerModule from "../../ignition/modules/e3RefundManager"; +import EnclaveModule from "../../ignition/modules/enclave"; +import EnclaveTicketTokenModule from "../../ignition/modules/enclaveTicketToken"; +import EnclaveTokenModule from "../../ignition/modules/enclaveToken"; +import mockComputeProviderModule from "../../ignition/modules/mockComputeProvider"; +import MockDecryptionVerifierModule from "../../ignition/modules/mockDecryptionVerifier"; +import MockE3ProgramModule from "../../ignition/modules/mockE3Program"; +import MockPkVerifierModule from "../../ignition/modules/mockPkVerifier"; +import MockStableTokenModule from "../../ignition/modules/mockStableToken"; +import SlashingManagerModule from "../../ignition/modules/slashingManager"; +import { + BondingRegistry__factory as BondingRegistryFactory, + CiphernodeRegistryOwnable__factory as CiphernodeRegistryOwnableFactory, + Enclave__factory as EnclaveFactory, + MockUSDC__factory as MockUSDCFactory, +} from "../../types"; +import type { Enclave } from "../../types/contracts/Enclave"; +import type { MockUSDC } from "../../types/contracts/test/MockStableToken.sol/MockUSDC"; +import { encodePkProof } from "../fixtures"; + +const { ethers, ignition, networkHelpers } = await network.connect(); +const { loadFixture, time, mine } = networkHelpers; + +describe("E3 Pricing", function () { + const THIRTY_DAYS_IN_SECONDS = 60 * 60 * 24 * 30; + const SORTITION_SUBMISSION_WINDOW = 10; + const addressOne = "0x0000000000000000000000000000000000000001"; + + const timeoutConfig = { + committeeFormationWindow: 3600, + dkgWindow: 3600, + computeWindow: 3600, + decryptionWindow: 3600, + }; + + // Default pricing config matching initialize() defaults + const defaultPricingConfig = { + keyGenFixedPerNode: 50000n, + keyGenPerEncryptionProof: 25000n, + coordinationPerPair: 5000n, + availabilityPerNodePerSec: 20n, + decryptionPerNode: 150000n, + publicationBase: 500000n, + verificationPerProof: 2000n, + protocolTreasury: ethers.ZeroAddress, + marginBps: 1000, + protocolShareBps: 0, + dkgUtilizationBps: 2500, + computeUtilizationBps: 5000, + decryptUtilizationBps: 2500, + minCommitteeSize: 0, + minThreshold: 0, + }; + + // Convert ethers Result to a plain object that can be spread + const toPlainConfig = (pc: any) => ({ + keyGenFixedPerNode: pc.keyGenFixedPerNode, + keyGenPerEncryptionProof: pc.keyGenPerEncryptionProof, + coordinationPerPair: pc.coordinationPerPair, + availabilityPerNodePerSec: pc.availabilityPerNodePerSec, + decryptionPerNode: pc.decryptionPerNode, + publicationBase: pc.publicationBase, + verificationPerProof: pc.verificationPerProof, + protocolTreasury: pc.protocolTreasury, + marginBps: pc.marginBps, + protocolShareBps: pc.protocolShareBps, + dkgUtilizationBps: pc.dkgUtilizationBps, + computeUtilizationBps: pc.computeUtilizationBps, + decryptUtilizationBps: pc.decryptUtilizationBps, + minCommitteeSize: pc.minCommitteeSize, + minThreshold: pc.minThreshold, + }); + + const inputWindowDuration = 300; + + const encryptionSchemeId = + "0x2c2a814a0495f913a3a312fc4771e37552bc14f8a2d4075a08122d356f0849c6"; + + const abiCoder = ethers.AbiCoder.defaultAbiCoder(); + const polynomial_degree = ethers.toBigInt(512); + const plaintext_modulus = ethers.toBigInt(10); + const moduli = [ + ethers.toBigInt("0xffffee001"), + ethers.toBigInt("0xffffc4001"), + ]; + const encodedE3ProgramParams = abiCoder.encode( + ["uint256", "uint256", "uint256[]"], + [polynomial_degree, plaintext_modulus, moduli], + ); + const data = "0xda7a"; + const proof = "0x1337"; + + async function setupOperatorForSortition( + operator: Signer, + bondingRegistry: any, + licenseToken: any, + usdcToken: any, + ticketToken: any, + registry: any, + ): Promise { + const operatorAddress = await operator.getAddress(); + await licenseToken.mintAllocation( + operatorAddress, + ethers.parseEther("10000"), + "Test allocation", + ); + await usdcToken.mint(operatorAddress, ethers.parseUnits("100000", 6)); + await licenseToken + .connect(operator) + .approve(await bondingRegistry.getAddress(), ethers.parseEther("2000")); + await bondingRegistry + .connect(operator) + .bondLicense(ethers.parseEther("1000")); + await bondingRegistry.connect(operator).registerOperator(); + const ticketAmount = ethers.parseUnits("100", 6); + await usdcToken + .connect(operator) + .approve(await ticketToken.getAddress(), ticketAmount); + await bondingRegistry.connect(operator).addTicketBalance(ticketAmount); + await registry.addCiphernode(operatorAddress); + } + + const setupAndPublishCommittee = async ( + registry: any, + e3Id: number, + nodes: string[], + publicKey: string, + operators: Signer[], + ): Promise => { + for (const operator of operators) { + await registry.connect(operator).submitTicket(e3Id, 1); + } + await time.increase(SORTITION_SUBMISSION_WINDOW + 1); + await registry.finalizeCommittee(e3Id); + const proof = encodePkProof(ethers.keccak256(publicKey)); + await registry.publishCommittee(e3Id, nodes, publicKey, proof, "0x"); + }; + + const setup = async () => { + const [owner, notTheOwner, operator1, operator2, operator3, treasury] = + await ethers.getSigners(); + const ownerAddress = await owner.getAddress(); + const treasuryAddress = await treasury.getAddress(); + + const { mockUSDC } = await ignition.deploy(MockStableTokenModule, { + parameters: { MockUSDC: { initialSupply: 1_000_000 } }, + }); + const usdcToken = MockUSDCFactory.connect( + await mockUSDC.getAddress(), + owner, + ); + + const { enclaveToken: licenseToken } = await ignition.deploy( + EnclaveTokenModule, + { parameters: { EnclaveToken: { owner: ownerAddress } } }, + ); + const { enclaveTicketToken: ticketToken } = await ignition.deploy( + EnclaveTicketTokenModule, + { + parameters: { + EnclaveTicketToken: { + baseToken: await usdcToken.getAddress(), + registry: addressOne, + owner: ownerAddress, + }, + }, + }, + ); + + const { slashingManager } = await ignition.deploy(SlashingManagerModule, { + parameters: { SlashingManager: { admin: ownerAddress } }, + }); + const { cipherNodeRegistry } = await ignition.deploy( + CiphernodeRegistryModule, + { + parameters: { + CiphernodeRegistry: { + owner: ownerAddress, + submissionWindow: SORTITION_SUBMISSION_WINDOW, + }, + }, + }, + ); + const ciphernodeRegistryAddress = await cipherNodeRegistry.getAddress(); + const ciphernodeRegistryContract = CiphernodeRegistryOwnableFactory.connect( + ciphernodeRegistryAddress, + owner, + ); + + const { bondingRegistry: _bondingRegistry } = await ignition.deploy( + BondingRegistryModule, + { + parameters: { + BondingRegistry: { + owner: ownerAddress, + ticketToken: await ticketToken.getAddress(), + licenseToken: await licenseToken.getAddress(), + registry: ciphernodeRegistryAddress, + slashedFundsTreasury: ownerAddress, + ticketPrice: ethers.parseUnits("10", 6), + licenseRequiredBond: ethers.parseEther("1000"), + minTicketBalance: 5, + exitDelay: 7 * 24 * 60 * 60, + }, + }, + }, + ); + const bondingRegistry = BondingRegistryFactory.connect( + await _bondingRegistry.getAddress(), + owner, + ); + + const { enclave: _enclave } = await ignition.deploy(EnclaveModule, { + parameters: { + Enclave: { + params: encodedE3ProgramParams, + owner: ownerAddress, + maxDuration: THIRTY_DAYS_IN_SECONDS, + registry: ciphernodeRegistryAddress, + bondingRegistry: await bondingRegistry.getAddress(), + e3RefundManager: addressOne, + feeToken: await usdcToken.getAddress(), + timeoutConfig, + }, + }, + }); + const enclaveAddress = await _enclave.getAddress(); + const enclave = EnclaveFactory.connect(enclaveAddress, owner); + + const { e3RefundManager } = await ignition.deploy(E3RefundManagerModule, { + parameters: { + E3RefundManager: { + owner: ownerAddress, + enclave: enclaveAddress, + treasury: treasuryAddress, + }, + }, + }); + await enclave.setE3RefundManager(await e3RefundManager.getAddress()); + + // Wire up + await ciphernodeRegistryContract.setEnclave(enclaveAddress); + await ciphernodeRegistryContract.setBondingRegistry( + await bondingRegistry.getAddress(), + ); + await ticketToken.setRegistry(await bondingRegistry.getAddress()); + await bondingRegistry.setSlashingManager( + await slashingManager.getAddress(), + ); + await bondingRegistry.setRewardDistributor(enclaveAddress); + await slashingManager.setBondingRegistry( + await bondingRegistry.getAddress(), + ); + + // Mocks + const { mockComputeProvider } = await ignition.deploy( + mockComputeProviderModule, + ); + const { mockDecryptionVerifier: decryptionVerifier } = + await ignition.deploy(MockDecryptionVerifierModule); + const { mockE3Program: e3Program } = + await ignition.deploy(MockE3ProgramModule); + const { mockPkVerifier: pkVerifier } = + await ignition.deploy(MockPkVerifierModule); + + await enclave.enableE3Program(await e3Program.getAddress()); + await enclave.setE3ProgramsParams([encodedE3ProgramParams]); + await enclave.setDecryptionVerifier( + encryptionSchemeId, + await decryptionVerifier.getAddress(), + ); + await enclave.setPkVerifier( + encryptionSchemeId, + await pkVerifier.getAddress(), + ); + + // Operators + await licenseToken.setTransferRestriction(false); + for (const operator of [operator1, operator2, operator3]) { + await setupOperatorForSortition( + operator, + bondingRegistry, + licenseToken, + usdcToken, + ticketToken, + ciphernodeRegistryContract, + ); + } + await mine(1); + + // Mint USDC + const mintAmount = ethers.parseUnits("1000000", 6); + await usdcToken.mint(ownerAddress, mintAmount); + await usdcToken.mint(await notTheOwner.getAddress(), mintAmount); + + // Committee Thresholds: Micro [1,3], Small [2,5] + await enclave.setCommitteeThresholds(0, [1, 3]); + await enclave.setCommitteeThresholds(1, [2, 5]); + + // Build request params + const now = await time.latest(); + const request = { + committeeSize: 0, // Micro + inputWindow: [now + 10, now + inputWindowDuration] as [number, number], + e3Program: await e3Program.getAddress(), + e3ProgramParams: encodedE3ProgramParams, + computeProviderParams: abiCoder.encode( + ["address"], + [await decryptionVerifier.getAddress()], + ), + customParams: abiCoder.encode( + ["address"], + ["0x1234567890123456789012345678901234567890"], + ), + proofAggregationEnabled: false, + }; + + return { + owner, + notTheOwner, + operator1, + operator2, + operator3, + treasury, + enclave, + ciphernodeRegistryContract, + bondingRegistry, + licenseToken, + ticketToken, + usdcToken, + slashingManager, + e3RefundManager, + request, + mocks: { decryptionVerifier, e3Program, mockComputeProvider, pkVerifier }, + }; + }; + + // Helper to make a request + const makeRequest = async ( + enclave: Enclave, + usdcToken: MockUSDC, + requestParams: Parameters[0], + signer?: Signer, + ) => { + const fee = await enclave.getE3Quote(requestParams); + const tokenContract = signer ? usdcToken.connect(signer) : usdcToken; + const enclaveContract = signer ? enclave.connect(signer) : enclave; + await tokenContract.approve(await enclave.getAddress(), fee); + return enclaveContract.request(requestParams); + }; + + // ────────────────────────────────────────────────────────────────────────── + // getE3Quote() — Parametric Fee Calculation + // ────────────────────────────────────────────────────────────────────────── + + describe("getE3Quote()", function () { + it("returns a fee based on BaseCosts, committee size, and duration", async function () { + const { enclave, request } = await loadFixture(setup); + + const fee = await enclave.getE3Quote(request); + // Fee must be > 0 with default baseCosts + expect(fee).to.be.gt(0); + }); + + it("computes fee correctly using the parametric formula", async function () { + const { enclave, request, ciphernodeRegistryContract } = + await loadFixture(setup); + + // Get the resolved threshold for Micro (committeeSize = 0) → [1, 3] + const n = 3n; // total committee + const m = 1n; // quorum + + // Get pricing config + const pc = await enclave.getPricingConfig(); + + // Get timeout config + const config = await enclave.getTimeoutConfig(); + const sortitionWindow = + await ciphernodeRegistryContract.sortitionSubmissionWindow(); + const duration = + sortitionWindow + + BigInt(request.inputWindow[1] - request.inputWindow[0]) + + (config.dkgWindow * BigInt(pc.dkgUtilizationBps)) / 10000n + + (config.computeWindow * BigInt(pc.computeUtilizationBps)) / 10000n + + (config.decryptionWindow * BigInt(pc.decryptUtilizationBps)) / 10000n; + + // Calculate expected fee (proof-aware) + const proofsPerNode = 6n + 2n * (n - 1n) * 2n; + let baseFee = pc.keyGenFixedPerNode * n; + baseFee += pc.keyGenPerEncryptionProof * n * proofsPerNode; + if (n > 1n) baseFee += (pc.coordinationPerPair * n * (n - 1n)) / 2n; + baseFee += pc.verificationPerProof * n * proofsPerNode; + baseFee += pc.availabilityPerNodePerSec * n * duration; + baseFee += pc.decryptionPerNode * m; + if (m > 1n) baseFee += (pc.coordinationPerPair * m * (m - 1n)) / 2n; + baseFee += pc.publicationBase; + + const marginBps = pc.marginBps; + const expectedFee = (baseFee * (10000n + BigInt(marginBps))) / 10000n; + + const actualFee = await enclave.getE3Quote(request); + expect(actualFee).to.equal(expectedFee); + }); + + it("fee increases with larger committee size", async function () { + const { enclave, request } = await loadFixture(setup); + + const microFee = await enclave.getE3Quote(request); + + // Build request with Small committee (larger) + const now = await time.latest(); + const smallRequest = { + ...request, + committeeSize: 1, // Small → [2, 5] + inputWindow: [now + 10, now + inputWindowDuration] as [number, number], + }; + const smallFee = await enclave.getE3Quote(smallRequest); + + expect(smallFee).to.be.gt(microFee); + }); + + it("fee increases with longer input window", async function () { + const { enclave, request } = await loadFixture(setup); + + const shortFee = await enclave.getE3Quote(request); + + const now = await time.latest(); + const longRequest = { + ...request, + inputWindow: [now + 10, now + 3600] as [number, number], // 1 hour vs 5min + }; + const longFee = await enclave.getE3Quote(longRequest); + + expect(longFee).to.be.gt(shortFee); + }); + + it("fee reflects margin changes", async function () { + const { enclave, request } = await loadFixture(setup); + + const fee10Pct = await enclave.getE3Quote(request); + + // Set margin to 20% + const pc = toPlainConfig(await enclave.getPricingConfig()); + await enclave.setPricingConfig({ ...pc, marginBps: 2000 }); + const fee20Pct = await enclave.getE3Quote(request); + + expect(fee20Pct).to.be.gt(fee10Pct); + + // Set margin to 0% + const pc2 = toPlainConfig(await enclave.getPricingConfig()); + await enclave.setPricingConfig({ ...pc2, marginBps: 0 }); + const feeZero = await enclave.getE3Quote(request); + + expect(feeZero).to.be.lt(fee10Pct); + }); + }); + + // ────────────────────────────────────────────────────────────────────────── + // setPricingConfig() — Governance + // ────────────────────────────────────────────────────────────────────────── + + describe("setPricingConfig()", function () { + it("reverts if not called by owner", async function () { + const { enclave, notTheOwner } = await loadFixture(setup); + await expect( + enclave.connect(notTheOwner).setPricingConfig(defaultPricingConfig), + ).to.be.revertedWithCustomError(enclave, "OwnableUnauthorizedAccount"); + }); + + it("updates config and emits event", async function () { + const { enclave } = await loadFixture(setup); + const newConfig = { + ...defaultPricingConfig, + keyGenFixedPerNode: 100000n, + keyGenPerEncryptionProof: 50000n, + coordinationPerPair: 10000n, + availabilityPerNodePerSec: 40n, + decryptionPerNode: 300000n, + publicationBase: 1000000n, + }; + + await expect(enclave.setPricingConfig(newConfig)).to.emit( + enclave, + "PricingConfigUpdated", + ); + + const stored = await enclave.getPricingConfig(); + expect(stored.keyGenFixedPerNode).to.equal(100000n); + expect(stored.keyGenPerEncryptionProof).to.equal(50000n); + expect(stored.coordinationPerPair).to.equal(10000n); + expect(stored.availabilityPerNodePerSec).to.equal(40n); + expect(stored.decryptionPerNode).to.equal(300000n); + expect(stored.publicationBase).to.equal(1000000n); + }); + + it("changes the fee returned by getE3Quote", async function () { + const { enclave, request } = await loadFixture(setup); + + const feeBefore = await enclave.getE3Quote(request); + + // Double base costs + await enclave.setPricingConfig({ + ...defaultPricingConfig, + keyGenFixedPerNode: 100000n, + keyGenPerEncryptionProof: 50000n, + coordinationPerPair: 10000n, + availabilityPerNodePerSec: 40n, + decryptionPerNode: 300000n, + publicationBase: 1000000n, + }); + + const feeAfter = await enclave.getE3Quote(request); + expect(feeAfter).to.be.gt(feeBefore); + }); + + it("reverts if margin exceeds 100%", async function () { + const { enclave } = await loadFixture(setup); + await expect( + enclave.setPricingConfig({ ...defaultPricingConfig, marginBps: 10001 }), + ).to.be.revertedWithCustomError(enclave, "BpsExceedsMax"); + }); + + it("allows setting margin to 0", async function () { + const { enclave } = await loadFixture(setup); + await enclave.setPricingConfig({ ...defaultPricingConfig, marginBps: 0 }); + const pc = await enclave.getPricingConfig(); + expect(pc.marginBps).to.equal(0); + }); + + it("reverts if protocolShareBps exceeds 100%", async function () { + const { enclave } = await loadFixture(setup); + await expect( + enclave.setPricingConfig({ + ...defaultPricingConfig, + protocolShareBps: 10001, + }), + ).to.be.revertedWithCustomError(enclave, "BpsExceedsMax"); + }); + + it("reverts if minCommitteeSize < minThreshold", async function () { + const { enclave } = await loadFixture(setup); + await expect( + enclave.setPricingConfig({ + ...defaultPricingConfig, + minCommitteeSize: 2, + minThreshold: 5, + }), + ).to.be.revertedWithCustomError(enclave, "MinSizeBelowMinThreshold"); + }); + + it("enforces bounds on setCommitteeThresholds", async function () { + const { enclave } = await loadFixture(setup); + + // Set minimum bounds via pricing config + await enclave.setPricingConfig({ + ...defaultPricingConfig, + minCommitteeSize: 5, + minThreshold: 3, + }); + + // Should fail: committee size 4 < min 5 + await expect( + enclave.setCommitteeThresholds(0, [3, 4]), + ).to.be.revertedWithCustomError(enclave, "BelowMinCommitteeSize"); + + // Should fail: threshold 2 < min 3 + await expect( + enclave.setCommitteeThresholds(0, [2, 6]), + ).to.be.revertedWithCustomError(enclave, "BelowMinThreshold"); + + // Should succeed: meets both minimums + await expect(enclave.setCommitteeThresholds(0, [3, 5])).to.not.be.revert( + ethers, + ); + }); + }); + + // ────────────────────────────────────────────────────────────────────────── + // Protocol Treasury Share on Reward Distribution + // ────────────────────────────────────────────────────────────────────────── + + describe("Protocol treasury share on success", function () { + it("sends 100% to CNs when protocolShareBps is 0 (default)", async function () { + const { + enclave, + usdcToken, + ciphernodeRegistryContract, + operator1, + operator2, + operator3, + mocks: { decryptionVerifier, e3Program }, + } = await loadFixture(setup); + + // Build a fresh request with current timestamps + const now = await time.latest(); + const freshRequest = { + committeeSize: 0, + inputWindow: [now + 100, now + inputWindowDuration + 100] as [ + number, + number, + ], + e3Program: await e3Program.getAddress(), + e3ProgramParams: encodedE3ProgramParams, + computeProviderParams: abiCoder.encode( + ["address"], + [await decryptionVerifier.getAddress()], + ), + customParams: abiCoder.encode( + ["address"], + ["0x1234567890123456789012345678901234567890"], + ), + proofAggregationEnabled: false, + }; + + // Make request with large approval to avoid fee mismatch + await usdcToken.approve(await enclave.getAddress(), ethers.MaxUint256); + await enclave.request(freshRequest); + const e3Id = 0; + const fee = await enclave.e3Payments(e3Id); + + // Setup committee + const nodes = [ + await operator1.getAddress(), + await operator2.getAddress(), + await operator3.getAddress(), + ]; + await setupAndPublishCommittee( + ciphernodeRegistryContract, + e3Id, + nodes, + "0x1234", + [operator1, operator2, operator3], + ); + + // Publish ciphertext + await time.increase(inputWindowDuration + 200); + await enclave.publishCiphertextOutput(e3Id, data, proof); + + // Record operator balances before distribution + const op1Before = await usdcToken.balanceOf(nodes[0]); + const op2Before = await usdcToken.balanceOf(nodes[1]); + const op3Before = await usdcToken.balanceOf(nodes[2]); + + // Publish plaintext (triggers _distributeRewards) + await enclave.publishPlaintextOutput(e3Id, data, proof, proof); + + const op1After = await usdcToken.balanceOf(nodes[0]); + const op2After = await usdcToken.balanceOf(nodes[1]); + const op3After = await usdcToken.balanceOf(nodes[2]); + + // All fee distributed to operators (100%, no protocol share) + const totalDistributed = + op1After - op1Before + (op2After - op2Before) + (op3After - op3Before); + expect(totalDistributed).to.equal(fee); + }); + + it("splits fee between CNs and treasury when protocolShareBps > 0", async function () { + const { + enclave, + usdcToken, + ciphernodeRegistryContract, + treasury, + operator1, + operator2, + operator3, + mocks: { decryptionVerifier, e3Program }, + } = await loadFixture(setup); + + // Configure 20% protocol share + const treasuryAddr = await treasury.getAddress(); + await enclave.setPricingConfig({ + ...defaultPricingConfig, + protocolTreasury: treasuryAddr, + protocolShareBps: 2000, + }); + + // Build a fresh request with current timestamps + const now = await time.latest(); + const freshRequest = { + committeeSize: 0, + inputWindow: [now + 100, now + inputWindowDuration + 100] as [ + number, + number, + ], + e3Program: await e3Program.getAddress(), + e3ProgramParams: encodedE3ProgramParams, + computeProviderParams: abiCoder.encode( + ["address"], + [await decryptionVerifier.getAddress()], + ), + customParams: abiCoder.encode( + ["address"], + ["0x1234567890123456789012345678901234567890"], + ), + proofAggregationEnabled: false, + }; + + // Make request with large approval + await usdcToken.approve(await enclave.getAddress(), ethers.MaxUint256); + await enclave.request(freshRequest); + const e3Id = 0; + const fee = await enclave.e3Payments(e3Id); + + // Setup committee + const nodes = [ + await operator1.getAddress(), + await operator2.getAddress(), + await operator3.getAddress(), + ]; + await setupAndPublishCommittee( + ciphernodeRegistryContract, + e3Id, + nodes, + "0x1234", + [operator1, operator2, operator3], + ); + + // Publish outputs + await time.increase(inputWindowDuration + 200); + await enclave.publishCiphertextOutput(e3Id, data, proof); + + const treasuryBefore = await usdcToken.balanceOf(treasuryAddr); + const op1Before = await usdcToken.balanceOf(nodes[0]); + const op2Before = await usdcToken.balanceOf(nodes[1]); + const op3Before = await usdcToken.balanceOf(nodes[2]); + + await enclave.publishPlaintextOutput(e3Id, data, proof, proof); + + const treasuryAfter = await usdcToken.balanceOf(treasuryAddr); + const op1After = await usdcToken.balanceOf(nodes[0]); + const op2After = await usdcToken.balanceOf(nodes[1]); + const op3After = await usdcToken.balanceOf(nodes[2]); + + const expectedProtocol = (fee * 2000n) / 10000n; + const expectedCN = fee - expectedProtocol; + const totalOpDistributed = + op1After - op1Before + (op2After - op2Before) + (op3After - op3Before); + + expect(treasuryAfter - treasuryBefore).to.equal(expectedProtocol); + expect(totalOpDistributed).to.equal(expectedCN); + }); + }); + + // ────────────────────────────────────────────────────────────────────────── + // Default Pricing Parameters (set in initialize) + // ────────────────────────────────────────────────────────────────────────── + + describe("Default pricing parameters", function () { + it("has correct default pricing config from initialize", async function () { + const { enclave } = await loadFixture(setup); + const pc = await enclave.getPricingConfig(); + expect(pc.keyGenFixedPerNode).to.equal(50000); + expect(pc.keyGenPerEncryptionProof).to.equal(25000); + expect(pc.coordinationPerPair).to.equal(5000); + expect(pc.availabilityPerNodePerSec).to.equal(20); + expect(pc.decryptionPerNode).to.equal(150000); + expect(pc.publicationBase).to.equal(500000); + expect(pc.verificationPerProof).to.equal(2000); + expect(pc.marginBps).to.equal(1000); + expect(pc.protocolShareBps).to.equal(0); + expect(pc.dkgUtilizationBps).to.equal(2500); + expect(pc.computeUtilizationBps).to.equal(5000); + expect(pc.decryptUtilizationBps).to.equal(2500); + expect(pc.protocolTreasury).to.equal(ethers.ZeroAddress); + expect(pc.minCommitteeSize).to.equal(0); + expect(pc.minThreshold).to.equal(0); + }); + }); + + // ────────────────────────────────────────────────────────────────────────── + // E3 Request with Parametric Pricing (end-to-end) + // ────────────────────────────────────────────────────────────────────────── + + describe("End-to-end request with parametric pricing", function () { + it("charges the computed fee and completes successfully", async function () { + const { + enclave, + usdcToken, + request, + ciphernodeRegistryContract, + operator1, + operator2, + operator3, + owner, + } = await loadFixture(setup); + + const fee = await enclave.getE3Quote(request); + const ownerAddr = await owner.getAddress(); + const balanceBefore = await usdcToken.balanceOf(ownerAddr); + + await usdcToken.approve(await enclave.getAddress(), fee); + await enclave.request(request); + + const balanceAfter = await usdcToken.balanceOf(ownerAddr); + expect(balanceBefore - balanceAfter).to.equal(fee); + }); + + it("reverts if USDC allowance is less than computed fee", async function () { + const { enclave, usdcToken, request } = await loadFixture(setup); + + // Approve only 1 unit + await usdcToken.approve(await enclave.getAddress(), 1); + + await expect(enclave.request(request)).to.be.revertedWithCustomError( + usdcToken, + "ERC20InsufficientAllowance", + ); + }); + }); +}); diff --git a/templates/default/enclave.config.yaml b/templates/default/enclave.config.yaml index 682b02a85f..143048a50a 100644 --- a/templates/default/enclave.config.yaml +++ b/templates/default/enclave.config.yaml @@ -18,7 +18,7 @@ chains: address: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" deploy_block: 5 e3_program: - address: "0x9d4454B023096f34B160D6B654540c56A1F81688" + address: "0x5eb3Bc0a489C5A8288765d2336659EbCA68FCd00" deploy_block: 34 program: dev: true