diff --git a/.env.example b/.env.example index e98e5bb..fd4bd5a 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,4 @@ -ACCOUNT_ADDRESS= +ADDRESS= PRIVATE_KEY= ETHERSCAN_API_KEY= diff --git a/.gitignore b/.gitignore index d4c0598..b28ee46 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,7 @@ lib/ # Coverage reports lcov.info + +# Slither reports +mutation_campaign/ +mutation.results diff --git a/CAST_COMMANDS.md b/CAST_COMMANDS.md index 063cdd8..86c50aa 100644 --- a/CAST_COMMANDS.md +++ b/CAST_COMMANDS.md @@ -33,7 +33,7 @@ For Radius Testnet, you can use the `--gas-price 0` flag to avoid needing enough ## Check ETH Balance ```sh -cast balance $ADDRESS --rpc-url radius-testnet +cast balance $ADDRESS --rpc-url $RPC ``` ## EVMAuth View Functions (Read-Only) diff --git a/README.md b/README.md index 6334c8b..2a255dc 100644 --- a/README.md +++ b/README.md @@ -121,15 +121,15 @@ Choose [ERC-6909] when you: - Prefer a simpler token transfer model - Want to extend the contract with custom features -Both versions of EVMAuth are fairly large. EVMAuth1155 is right near the limit, while EVMAuth6909 has a bit more headroom for exapnsion. +Both versions of EVMAuth are fairly large. EVMAuth1155 is right near the limit, while EVMAuth6909 has a bit more headroom for expansion. ```text ╭------------------------------+------------------+-------------------+--------------------+---------------------╮ | Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) | +================================================================================================================+ -| EVMAuth1155 | 24,555 | 24,614 | 21 | 24,538 | +| EVMAuth1155 | 24,516 | 24,575 | 60 | 24,577 | |------------------------------+------------------+-------------------+--------------------+---------------------| -| EVMAuth6909 | 22,424 | 22,483 | 2,152 | 26,669 | +| EVMAuth6909 | 22,247 | 22,306 | 2,329 | 26,846 | ╰------------------------------+------------------+-------------------+--------------------+---------------------╯ ``` diff --git a/script/ExampleDeploy.s.sol b/script/ExampleDeploy.s.sol index cf73452..cc9b1ad 100644 --- a/script/ExampleDeploy.s.sol +++ b/script/ExampleDeploy.s.sol @@ -4,60 +4,69 @@ pragma solidity ^0.8.24; import { EVMAuth } from "src/base/EVMAuth.sol"; import { BaseDeploy1155, BaseDeploy6909 } from "script/BaseDeploy.s.sol"; +abstract contract Deploy { + uint48 public initialDelay = 2 days; // 48-hour admin transfer delay + address public initialDefaultAdmin = address(0); + address payable public initialTreasury = payable(address(0)); + address public upgradeManager = address(0); + address public accessManager = address(0); + address public tokenManager = address(0); + address public minter = address(0); + address public burner = address(0); + address public treasurer = address(0); + + function setUp() public virtual { + if (initialDefaultAdmin == address(0)) initialDefaultAdmin = msg.sender; + if (initialTreasury == payable(address(0))) initialTreasury = payable(msg.sender); + if (upgradeManager == address(0)) upgradeManager = msg.sender; + if (accessManager == address(0)) accessManager = msg.sender; + if (tokenManager == address(0)) tokenManager = msg.sender; + if (minter == address(0)) minter = msg.sender; + if (burner == address(0)) burner = msg.sender; + if (treasurer == address(0)) treasurer = msg.sender; + } +} + /** - * @dev Example deployment script for EVMAuth1155 + * @dev Deployment script for EVMAuth1155 */ -contract ExampleDeploy1155 is BaseDeploy1155 { +contract Deploy1155 is BaseDeploy1155, Deploy { /** * @dev Main deployment function. Sets initializer parameters, then executes the deployment. */ function run() public { - uint48 initialDelay = 2 days; // 48-hour admin transfer delay - address initialDefaultAdmin = msg.sender; // Deployer as initial admin - address payable initialTreasury = payable(msg.sender); // Deployer address as initial treasury + setUp(); - // Grant all roles to the deployer EVMAuth.RoleGrant[] memory roleGrants = new EVMAuth.RoleGrant[](6); - roleGrants[0] = EVMAuth.RoleGrant(UPGRADE_MANAGER_ROLE, msg.sender); - roleGrants[1] = EVMAuth.RoleGrant(ACCESS_MANAGER_ROLE, msg.sender); - roleGrants[2] = EVMAuth.RoleGrant(TOKEN_MANAGER_ROLE, msg.sender); - roleGrants[3] = EVMAuth.RoleGrant(MINTER_ROLE, msg.sender); - roleGrants[4] = EVMAuth.RoleGrant(BURNER_ROLE, msg.sender); - roleGrants[5] = EVMAuth.RoleGrant(TREASURER_ROLE, msg.sender); - - // Example token URI with {id} placeholder, per ERC-1155 metadata standard - string memory uri = "https://token-cdn-domain/{id}.json"; - - // Execute the deployment - deploy(initialDelay, initialDefaultAdmin, initialTreasury, roleGrants, uri); + roleGrants[0] = EVMAuth.RoleGrant(UPGRADE_MANAGER_ROLE, upgradeManager); + roleGrants[1] = EVMAuth.RoleGrant(ACCESS_MANAGER_ROLE, accessManager); + roleGrants[2] = EVMAuth.RoleGrant(TOKEN_MANAGER_ROLE, tokenManager); + roleGrants[3] = EVMAuth.RoleGrant(MINTER_ROLE, minter); + roleGrants[4] = EVMAuth.RoleGrant(BURNER_ROLE, burner); + roleGrants[5] = EVMAuth.RoleGrant(TREASURER_ROLE, treasurer); + + deploy(initialDelay, initialDefaultAdmin, initialTreasury, roleGrants, ""); } } /** - * @dev Example deployment script for EVMAuth6909 + * @dev Deployment script for EVMAuth6909 */ -contract ExampleDeploy6909 is BaseDeploy6909 { +contract Deploy6909 is BaseDeploy6909, Deploy { /** * @dev Main deployment function. Sets initializer parameters, then executes the deployment. */ function run() public { - uint48 initialDelay = 2 days; // 48-hour admin transfer delay - address initialDefaultAdmin = msg.sender; // Deployer as initial admin - address payable initialTreasury = payable(msg.sender); // Deployer address as initial treasury + setUp(); - // Grant all roles to the deployer EVMAuth.RoleGrant[] memory roleGrants = new EVMAuth.RoleGrant[](6); - roleGrants[0] = EVMAuth.RoleGrant(UPGRADE_MANAGER_ROLE, msg.sender); - roleGrants[1] = EVMAuth.RoleGrant(ACCESS_MANAGER_ROLE, msg.sender); - roleGrants[2] = EVMAuth.RoleGrant(TOKEN_MANAGER_ROLE, msg.sender); - roleGrants[3] = EVMAuth.RoleGrant(MINTER_ROLE, msg.sender); - roleGrants[4] = EVMAuth.RoleGrant(BURNER_ROLE, msg.sender); - roleGrants[5] = EVMAuth.RoleGrant(TREASURER_ROLE, msg.sender); - - // Example contract URI, per EIP-6909 content URI extension - string memory uri = "https://token-cdn-domain/contract-metadata.json"; - - // Execute the deployment - deploy(initialDelay, initialDefaultAdmin, initialTreasury, roleGrants, uri); + roleGrants[0] = EVMAuth.RoleGrant(UPGRADE_MANAGER_ROLE, upgradeManager); + roleGrants[1] = EVMAuth.RoleGrant(ACCESS_MANAGER_ROLE, accessManager); + roleGrants[2] = EVMAuth.RoleGrant(TOKEN_MANAGER_ROLE, tokenManager); + roleGrants[3] = EVMAuth.RoleGrant(MINTER_ROLE, minter); + roleGrants[4] = EVMAuth.RoleGrant(BURNER_ROLE, burner); + roleGrants[5] = EVMAuth.RoleGrant(TREASURER_ROLE, treasurer); + + deploy(initialDelay, initialDefaultAdmin, initialTreasury, roleGrants, ""); } } diff --git a/src/EVMAuth1155.abi b/src/EVMAuth1155.abi index d67175c..1dbca57 100644 --- a/src/EVMAuth1155.abi +++ b/src/EVMAuth1155.abi @@ -555,30 +555,6 @@ "outputs": [], "stateMutability": "nonpayable" }, - { - "type": "function", - "name": "isAcceptedERC20PaymentToken", - "inputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "paymentToken", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, { "type": "function", "name": "isApprovedForAll", @@ -1520,6 +1496,31 @@ ], "anonymous": false }, + { + "type": "event", + "name": "ExpiredTokensPruned", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "id", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, { "type": "event", "name": "Initialized", diff --git a/src/EVMAuth1155.bin b/src/EVMAuth1155.bin index 7f05d10..8699be9 100644 --- a/src/EVMAuth1155.bin +++ b/src/EVMAuth1155.bin @@ -1 +1 @@ -0x60a060405230608052348015610013575f80fd5b50608051615feb6200003b5f395f81816123a5015281816123ce015261252f0152615feb5ff3fe6080604052600436106103e8575f3560e01c8063788649ea1161020a578063c55be5d01161011e578063e5839836116100a8578063f101e48111610078578063f101e48114610c83578063f242432a14610ca3578063f26c159f14610cc2578063f5298aca14610ce1578063febbd07014610d00575f80fd5b8063e583983614610bcf578063e985e9c514610c12578063f0a3a97c14610c31578063f0f4426014610c64575f80fd5b8063d2c7db1c116100ee578063d2c7db1c14610b29578063d4ddce8a14610b4a578063d539139314610b69578063d547741f14610b9c578063d602b9fd14610bbb575f80fd5b8063c55be5d014610aa8578063cc8463c814610ac7578063cefc142914610adb578063cf6eefb714610aef575f80fd5b8063a1eda53c1161019f578063a5a2a6451161016f578063a5a2a645146109e7578063ad3cb1cc14610a06578063b256456914610a36578063c0a2103414610a55578063c2840e6014610a88575f80fd5b8063a1eda53c14610962578063a217fddf14610995578063a22cb465146109a8578063a3b546f2146109c7575f80fd5b80638da5cb5b116101da5780638da5cb5b146108ef57806391d14854146109035780639526c2d914610922578063994757c514610936575f80fd5b8063788649ea1461087557806379c44ca2146108945780638456cb59146108c757806384ef8ffc146108db575f80fd5b8063440e806e1161030157806355f804b311610296578063649a5ec711610266578063649a5ec7146107f25780636b20c454146108115780636d51282c1461083057806370876c9814610843578063731133e914610856575f80fd5b806355f804b3146107545780635c975abb1461077357806361d027b314610796578063634e93da146107d3575f80fd5b80634f1ef286116102d15780634f1ef286146106ef5780634f558e791461070257806352d1902d1461072157806354efdcf614610735575f80fd5b8063440e806e1461065957806345cc05a01461068557806347aa3a2e146106a45780634e1273f4146106c3575f80fd5b8063248a9ca3116103825780632eb2c2d6116103525780632eb2c2d6146105b55780632f2ff15d146105d457806336568abe146105f35780633f4ba83a1461061257806343ffa64e14610626575f80fd5b8063248a9ca31461052557806327276d9814610544578063282c51f3146105635780632d99179e14610596575f80fd5b80630aa6220b116103bd5780630aa6220b146104a55780630e89341c146104bb578063162094c4146104e75780631f7fdffa14610506575f80fd5b8062e6449d146103ec578062fdd58e1461042157806301ffc9a71461044e578063022d63fb1461047d575b5f80fd5b3480156103f7575f80fd5b5061040b610406366004614f0c565b610d62565b6040516104189190614f36565b60405180910390f35b34801561042c575f80fd5b5061044061043b366004614f0c565b610dfe565b604051908152602001610418565b348015610459575f80fd5b5061046d610468366004614f99565b610e10565b6040519015158152602001610418565b348015610488575f80fd5b50620697805b60405165ffffffffffff9091168152602001610418565b3480156104b0575f80fd5b506104b9610e1a565b005b3480156104c6575f80fd5b506104da6104d5366004614fb4565b610e2f565b6040516104189190615018565b3480156104f2575f80fd5b506104b96105013660046150d9565b610e3a565b348015610511575f80fd5b506104b96105203660046151aa565b610e60565b348015610530575f80fd5b5061044061053f366004614fb4565b610e9d565b34801561054f575f80fd5b5061044061055e36600461524e565b610ebd565b34801561056e575f80fd5b506104407f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84881565b3480156105a1575f80fd5b506104b96105b0366004615299565b610ee7565b3480156105c0575f80fd5b506104b96105cf36600461535e565b610fe8565b3480156105df575f80fd5b506104b96105ee366004615404565b611054565b3480156105fe575f80fd5b506104b961060d366004615404565b611080565b34801561061d575f80fd5b506104b961113d565b348015610631575f80fd5b506104407fa76ace73a908083d89af9ff88e5b4f7cadb3591a80631063f68b695fda726db581565b348015610664575f80fd5b50610678610673366004614fb4565b61115c565b6040516104189190615480565b348015610690575f80fd5b506104b961069f3660046154d8565b6111ea565b3480156106af575f80fd5b506104b96106be36600461551b565b611214565b3480156106ce575f80fd5b506106e26106dd366004615554565b611235565b6040516104189190615634565b6104b96106fd366004615646565b6112ff565b34801561070d575f80fd5b5061046d61071c366004614fb4565b61131a565b34801561072c575f80fd5b5061044061133c565b348015610740575f80fd5b506104b961074f366004614f0c565b611357565b34801561075f575f80fd5b506104b961076e36600461567c565b611565565b34801561077e575f80fd5b505f80516020615f568339815191525460ff1661046d565b3480156107a1575f80fd5b505f80516020615f96833981519152546001600160a01b03165b6040516001600160a01b039091168152602001610418565b3480156107de575f80fd5b506104b96107ed3660046156ad565b611585565b3480156107fd575f80fd5b506104b961080c3660046156c8565b611598565b34801561081c575f80fd5b506104b961082b3660046156e1565b6115ab565b6104b961083e366004615751565b6115e0565b6104b9610851366004615783565b611603565b348015610861575f80fd5b506104b96108703660046157a3565b611626565b348015610880575f80fd5b506104b961088f3660046156ad565b61165c565b34801561089f575f80fd5b506104407f6f58fc3760b5743cf76087dfed697597f39c204c204718113b3ee0e4d995fc3b81565b3480156108d2575f80fd5b506104b961167c565b3480156108e6575f80fd5b506107bb61169b565b3480156108fa575f80fd5b506107bb6116b6565b34801561090e575f80fd5b5061046d61091d366004615404565b6116c4565b34801561092d575f80fd5b50610440606481565b348015610941575f80fd5b50610955610950366004614fb4565b6116fa565b60405161041891906157f5565b34801561096d575f80fd5b5061097661172f565b6040805165ffffffffffff938416815292909116602083015201610418565b3480156109a0575f80fd5b506104405f81565b3480156109b3575f80fd5b506104b96109c2366004615816565b61179e565b3480156109d2575f80fd5b506104405f80516020615f3683398151915281565b3480156109f2575f80fd5b50610440610a01366004614fb4565b6117a9565b348015610a11575f80fd5b506104da604051806040016040528060058152602001640352e302e360dc1b81525081565b348015610a41575f80fd5b5061046d610a50366004614fb4565b611806565b348015610a60575f80fd5b506104407f7d2be5e40a0d45d9af5c7db1fc1fa7822674e1d5f550082d32be1b8bf80c015f81565b348015610a93575f80fd5b506104405f80516020615e1683398151915281565b348015610ab3575f80fd5b506104b9610ac2366004615751565b611866565b348015610ad2575f80fd5b5061048e611882565b348015610ae6575f80fd5b506104b96118fd565b348015610afa575f80fd5b50610b0361193c565b604080516001600160a01b03909316835265ffffffffffff909116602083015201610418565b348015610b34575f80fd5b50610b3d611969565b6040516104189190615849565b348015610b55575f80fd5b50610440610b64366004614fb4565b6119d8565b348015610b74575f80fd5b506104407f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b348015610ba7575f80fd5b506104b9610bb6366004615404565b611a0c565b348015610bc6575f80fd5b506104b9611a34565b348015610bda575f80fd5b5061046d610be93660046156ad565b6001600160a01b03165f9081525f80516020615e56833981519152602052604090205460ff1690565b348015610c1d575f80fd5b5061046d610c2c366004615889565b611a46565b348015610c3c575f80fd5b506104407f3496e2e73c4d42b75d702e60d9e48102720b8691234415963a5a857b86425d0781565b348015610c6f575f80fd5b506104b9610c7e3660046156ad565b611a92565b348015610c8e575f80fd5b505f80516020615e9683398151915254610440565b348015610cae575f80fd5b506104b9610cbd3660046158b5565b611ac5565b348015610ccd575f80fd5b506104b9610cdc3660046156ad565b611b24565b348015610cec575f80fd5b506104b9610cfb366004615751565b611b44565b348015610d0b575f80fd5b5061046d610d1a366004615404565b5f9182527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff602602090815260408084206001600160a01b03939093168452919052902054151590565b6001600160a01b0382165f9081525f80516020615e36833981519152602081815260408084208585528252808420805482518185028101850190935280835260609592939192909184015b82821015610df0578382905f5260205f2090600202016040518060400160405290815f820154815260200160018201548152505081526020019060010190610dad565b505050509150505b92915050565b5f610e098383611b79565b9392505050565b5f610df882611c21565b5f610e2481611c45565b610e2c611c4f565b50565b6060610df882611c5b565b5f80516020615e16833981519152610e5181611c45565b610e5b8383611d65565b505050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6610e8a81611c45565b610e9685858585611df0565b5050505050565b5f9081525f80516020615f16833981519152602052604090206001015490565b5f5f80516020615e16833981519152610ed581611c45565b610ede83611e26565b91505b50919050565b5f610ef0611eb6565b805490915060ff600160401b82041615906001600160401b03165f81158015610f165750825b90505f826001600160401b03166001148015610f315750303b155b905081158015610f3f575080155b15610f5d5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610f8757845460ff60401b1916600160401b1785555b610f958b8b8b8b8b8b611ede565b8315610fdb57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050505050565b336001600160a01b038616811480159061100957506110078682611a46565b155b1561103f5760405163711bec9160e11b81526001600160a01b038083166004830152871660248201526044015b60405180910390fd5b61104c8686868686611f0c565b505050505050565b8161107257604051631fe1e13d60e11b815260040160405180910390fd5b61107c8282611f6a565b5050565b5f80516020615ed6833981519152821580156110b4575061109f61169b565b6001600160a01b0316826001600160a01b0316145b15611133575f806110c361193c565b90925090506001600160a01b0382161515806110e5575065ffffffffffff8116155b806110f857504265ffffffffffff821610155b15611120576040516319ca5ebb60e01b815265ffffffffffff82166004820152602401611036565b5050805465ffffffffffff60a01b191681555b610e5b8383611f86565b5f80516020615f3683398151915261115481611c45565b610e2c611fb9565b611164614eb8565b8161116e8161131a565b61118e5760405163b7c882eb60e01b815260048101829052602401611036565b604051806040016040528084815260200160405180608001604052806111b3876119d8565b81526020016111c1876116fa565b81526020016111cf876117a9565b81526020016111dd87611806565b1515905290529392505050565b6111f2612018565b6111fa612048565b611206848484846120b5565b61120e6122d8565b50505050565b5f80516020615e1683398151915261122b81611c45565b610e5b8383612302565b606081518351146112665781518351604051635b05999160e01b815260048101929092526024820152604401611036565b5f83516001600160401b038111156112805761128061502a565b6040519080825280602002602001820160405280156112a9578160200160208202803683370190505b5090505f5b84518110156112f7576020808202860101516112d290602080840287010151610dfe565b8282815181106112e4576112e4615918565b60209081029190910101526001016112ae565b509392505050565b61130761239a565b6113108261243e565b61107c8282612468565b5f5f80516020615e968339815191528215801590610ede575054909110919050565b5f611345612524565b505f80516020615eb683398151915290565b6001600160a01b0382165f9081525f80516020615e36833981519152602081815260408084208585529091528220805491929091429190815b8181101561145c575f808683815481106113ac576113ac615918565b905f5260205f2090600202015f01541180156113e85750848683815481106113d6576113d6615918565b905f5260205f20906002020160010154115b90508015611453578382146114455785828154811061140957611409615918565b905f5260205f20906002020186858154811061142757611427615918565b5f918252602090912082546002909202019081556001918201549101555b8361144f81615940565b9450505b50600101611390565b50815b818110156114b25760405180604001604052805f81526020015f81525085828154811061148e5761148e615918565b5f91825260209182902083516002909202019081559101516001918201550161145f565b50811580156114c057505f81115b15611503575b8354156114fe57838054806114dd576114dd615958565b5f8281526020812060025f19909301928302018181556001015590556114c6565b61155c565b61150e82600261596c565b8111801561151c5750600a81115b1561155c575b835482101561155c578380548061153b5761153b615958565b5f8281526020812060025f1990930192830201818155600101559055611522565b50505050505050565b5f80516020615e1683398151915261157c81611c45565b61107c8261256d565b5f61158f81611c45565b61107c82612586565b5f6115a281611c45565b61107c826125f9565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a8486115d581611c45565b61120e848484612668565b6115e8612018565b6115f0612048565b6115fb8383836126ab565b610e5b6122d8565b61160b612018565b611613612048565b61161e3383836126ab565b61107c6122d8565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a661165081611c45565b610e96858585856127c4565b5f80516020615f3683398151915261167381611c45565b61107c8261281f565b5f80516020615f3683398151915261169381611c45565b610e2c6129c9565b5f80516020615f76833981519152546001600160a01b031690565b5f6116bf61169b565b905090565b5f9182525f80516020615f16833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6060816117068161131a565b6117265760405163b7c882eb60e01b815260048101829052602401611036565b610ede83612a11565b5f80516020615f76833981519152545f90600160d01b900465ffffffffffff165f80516020615ed6833981519152811580159061177457504265ffffffffffff831610155b61177f575f80611795565b6001810154600160a01b900465ffffffffffff16825b92509250509091565b61107c338383612b46565b5f816117b48161131a565b6117d45760405163b7c882eb60e01b815260048101829052602401611036565b5f8381527fec3c1253ecdf88a29ff53024f0721fc3faa1b42abcff612deb5b22d1f94e2d016020526040902054610ede565b5f816118118161131a565b6118315760405163b7c882eb60e01b815260048101829052602401611036565b5f8381527fdaa3d1cf82c71b982a9e24ff7dadd71a10e8c3e82a219c0e60ca5c6b8e617700602052604090205460ff16610ede565b61186e612018565b611876612048565b6115fb338484846120b5565b5f80516020615f76833981519152545f905f80516020615ed683398151915290600160d01b900465ffffffffffff1680158015906118c757504265ffffffffffff8216105b6118e1578154600160d01b900465ffffffffffff166118f6565b6001820154600160a01b900465ffffffffffff165b9250505090565b5f61190661193c565b509050336001600160a01b0382161461193457604051636116401160e11b8152336004820152602401611036565b610e2c612bec565b5f80516020615ed6833981519152546001600160a01b03811691600160a01b90910465ffffffffffff1690565b60605f5f80516020615e56833981519152600181018054604080516020808402820181019092528281529394508301828280156119cd57602002820191905f5260205f20905b81546001600160a01b031681526001909101906020018083116119af575b505050505091505090565b5f816119e38161131a565b611a035760405163b7c882eb60e01b815260048101829052602401611036565b610ede83612c85565b81611a2a57604051631fe1e13d60e11b815260040160405180910390fd5b61107c8282612ce5565b5f611a3e81611c45565b610e2c612d01565b6001600160a01b039182165f9081527f88be536d5240c274a3b1d3a1be54482fd9caa294f08c62a7cde569f49a3c45016020908152604080832093909416825291909152205460ff1690565b7f3496e2e73c4d42b75d702e60d9e48102720b8691234415963a5a857b86425d07611abc81611c45565b61107c82612d0b565b336001600160a01b0386168114801590611ae65750611ae48682611a46565b155b15611b175760405163711bec9160e11b81526001600160a01b03808316600483015287166024820152604401611036565b61104c8686868686612d96565b5f80516020615f36833981519152611b3b81611c45565b61107c82612e19565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848611b6e81611c45565b61120e848484612f11565b6001600160a01b0382165f9081525f80516020615e3683398151915260208181526040808420858552909152822080548390815b81811015611c155742848281548110611bc857611bc8615918565b905f5260205f209060020201600101541115611c0d57838181548110611bf057611bf0615918565b905f5260205f2090600202015f015483611c0a9190615983565b92505b600101611bad565b50909695505050505050565b5f6001600160e01b031982166318a4c3c360e11b1480610df85750610df882612f77565b610e2c8133612f9b565b611c595f80612fd4565b565b5f8181527f89fc852226e759c7c636cf34d732f0198fc56a54876b2374a52beb7b0c5586016020526040812080546060925f80516020615e76833981519152929091611ca690615996565b80601f0160208091040260200160405190810160405280929190818152602001828054611cd290615996565b8015611d1d5780601f10611cf457610100808354040283529160200191611d1d565b820191905f5260205f20905b815481529060010190602001808311611d0057829003601f168201915b505050505090505f815111611d3a57611d35846130ac565b611d5d565b604051611d4d90839083906020016159c8565b6040516020818303038152906040525b949350505050565b5f8281527f89fc852226e759c7c636cf34d732f0198fc56a54876b2374a52beb7b0c558601602052604090205f80516020615e7683398151915290611daa8382615a8f565b50827f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b611dd685610e2f565b604051611de39190615018565b60405180910390a2505050565b6001600160a01b038416611e1957604051632bfa23e760e11b81525f6004820152602401611036565b61120e5f8585858561316e565b5f611e2f6131c1565b9050611e3c8183356131e7565b611e5281611e4d6020850185615b4a565b61321b565b611e60818360400135613250565b611e7981611e746080850160608601615b96565b6132ab565b807f76e35084bc84f178215c72d32676286f16ca2d3a80d3e80e317c858d61eb5a3783604051611ea99190615bf5565b60405180910390a2919050565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00610df8565b611ee6613314565b611eef81613339565b611ef761334a565b611f04868686868661335a565b61104c613387565b6001600160a01b038416611f3557604051632bfa23e760e11b81525f6004820152602401611036565b6001600160a01b038516611f5d57604051626a0d4560e21b81525f6004820152602401611036565b610e96858585858561316e565b611f7382610e9d565b611f7c81611c45565b61120e838361338f565b6001600160a01b0381163314611faf5760405163334bd91960e11b815260040160405180910390fd5b610e5b82826133fb565b611fc1613452565b5f80516020615f56833981519152805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b5f80516020615f568339815191525460ff1615611c595760405163d93c066560e01b815260040160405180910390fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c1561208857604051633ee5aeb560e01b815260040160405180910390fd5b611c5960017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b90613481565b5f80516020615f968339815191526120cc85613488565b6120d5826134ba565b5f83815260028201602090815260408083206001600160a01b03881684529091528120549081900361212c5760405163ec40a7ab60e01b8152600481018590526001600160a01b0386166024820152604401611036565b5f612137848361596c565b9050855f6001600160a01b03821663dd62ed3e336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa158015612193573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121b79190615c7e565b9050828110156121f3576040516303dfb80d60e11b81526001600160a01b03891660048201526024810184905260448101829052606401611036565b5f6001600160a01b0383166370a08231336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612246573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061226a9190615c7e565b9050838110156122a657604051633514dc2360e21b81526001600160a01b038a1660048201526024810185905260448101829052606401611036565b6122c03387546001600160a01b03868116929116876134dd565b6122cc8a898987613537565b50505050505050505050565b611c595f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f006120af565b8161230c8161131a565b61232c5760405163b7c882eb60e01b815260048101829052602401611036565b6123378383356131e7565b61234883611e4d6020850185615b4a565b612356838360400135613250565b61236a83611e746080850160608601615b96565b827f76e35084bc84f178215c72d32676286f16ca2d3a80d3e80e317c858d61eb5a3783604051611de39190615bf5565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061242057507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166124145f80516020615eb6833981519152546001600160a01b031690565b6001600160a01b031614155b15611c595760405163703e46dd60e11b815260040160405180910390fd5b7fa76ace73a908083d89af9ff88e5b4f7cadb3591a80631063f68b695fda726db561107c81611c45565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156124c2575060408051601f3d908101601f191682019092526124bf91810190615c7e565b60015b6124ea57604051634c9c8ce360e01b81526001600160a01b0383166004820152602401611036565b5f80516020615eb6833981519152811461251a57604051632a87526960e21b815260048101829052602401611036565b610e5b8383613594565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611c595760405163703e46dd60e11b815260040160405180910390fd5b5f80516020615e7683398151915280610e5b8382615a8f565b5f61258f611882565b612598426135e9565b6125a29190615c95565b90506125ae828261361f565b60405165ffffffffffff821681526001600160a01b038316907f3377dc44241e779dd06afab5b788a35ca5f3b778836e2990bdb26a2a4b2e5ed6906020015b60405180910390a25050565b5f612603826136a9565b61260c426135e9565b6126169190615c95565b90506126228282612fd4565b6040805165ffffffffffff8085168252831660208201527ff1038c18cf84a56e432fdbfaf746924b7ea511dfe03a6506a0ceba4888788d9b910160405180910390a15050565b6001600160a01b03831661269057604051626a0d4560e21b81525f6004820152602401611036565b610e5b835f848460405180602001604052805f81525061316e565b5f80516020615f968339815191526126c284613488565b6126cb826134ba565b5f838152600182016020526040812054908190036126ff576040516384e7368960e01b815260048101859052602401611036565b5f61270a848361596c565b905080341015612744576040516301b1e28360e21b8152600481018690526024810185905260448101829052346064820152608401611036565b8034111561278157336108fc61275a8334615cb4565b6040518115909202915f818181858888f1935050505015801561277f573d5f803e3d5ffd5b505b82546040516001600160a01b039091169082156108fc029083905f818181858888f193505050501580156127b7573d5f803e3d5ffd5b5061104c86868684613537565b6001600160a01b0384166127ed57604051632bfa23e760e11b81525f6004820152602401611036565b6040805160018082526020820186905281830190815260608201859052608082019092529061104c5f8784848761316e565b6001600160a01b0381165f9081525f80516020615e56833981519152602081905260409091205460ff16612851575050565b6001600160a01b0382165f908152602082905260408120805460ff191690555b600182015481101561296f57826001600160a01b031682600101828154811061289c5761289c615918565b5f918252602090912001546001600160a01b031603612967576001808301805490916128c791615cb4565b815481106128d7576128d7615918565b5f918252602090912001546001830180546001600160a01b03909216918390811061290457612904615918565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055508160010180548061294257612942615958565b5f8281526020902081015f1990810180546001600160a01b031916905501905561296f565b600101612871565b506040517f7d2be5e40a0d45d9af5c7db1fc1fa7822674e1d5f550082d32be1b8bf80c015f906001600160a01b038416907f233494033cad48d751b00c55d58da5f087d21031a3859563c7b6a7f3a2ccf04d905f90a35050565b6129d1612018565b5f80516020615f56833981519152805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833611ffa565b5f8181527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff6036020526040902080546060915f80516020615f96833981519152916001600160401b03811115612a6857612a6861502a565b604051908082528060200260200182016040528015612aac57816020015b604080518082019091525f8082526020820152815260200190600190039081612a865790505b5092505f5b8154811015612b3e575f828281548110612acd57612acd615918565b5f91825260208083209091015488835260028701825260408084206001600160a01b03909216808552918352928390205483518085019094528184529183018290528751909350909190879085908110612b2957612b29615918565b60209081029190910101525050600101612ab1565b505050919050565b5f80516020615ef68339815191526001600160a01b038316612b7c5760405162ced3e160e81b81525f6004820152602401611036565b6001600160a01b038481165f818152600184016020908152604080832094881680845294825291829020805460ff191687151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3191015b60405180910390a350505050565b5f80516020615ed68339815191525f80612c0461193c565b91509150612c198165ffffffffffff16151590565b1580612c2d57504265ffffffffffff821610155b15612c55576040516319ca5ebb60e01b815265ffffffffffff82166004820152602401611036565b612c665f612c6161169b565b6133fb565b50612c715f8361338f565b505081546001600160d01b03191690915550565b5f8181527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff6016020526040812054905f80516020615f9683398151915290829003610ee1576040516384e7368960e01b815260048101849052602401611036565b612cee82610e9d565b612cf781611c45565b61120e83836133fb565b611c595f8061361f565b5f80516020615f968339815191526001600160a01b038216612d4b576040516334d5d27d60e21b81526001600160a01b0383166004820152602401611036565b80546001600160a01b0319166001600160a01b03831690811782556040513381527f4ab5be82436d353e61ca18726e984e561f5c1cc7c6d38b29d2553c790434705a906020016125ed565b6001600160a01b038416612dbf57604051632bfa23e760e11b81525f6004820152602401611036565b6001600160a01b038516612de757604051626a0d4560e21b81525f6004820152602401611036565b6040805160018082526020820186905281830190815260608201859052608082019092529061155c878784848761316e565b6001600160a01b038116612e4b57604051634726455360e11b81526001600160a01b0382166004820152602401611036565b6001600160a01b0381165f9081525f80516020615e56833981519152602081905260409091205460ff1615612e7e575050565b6001600160a01b0382165f81815260208381526040808320805460ff1916600190811790915585810180549182018155845291832090910180546001600160a01b03191684179055517f6f58fc3760b5743cf76087dfed697597f39c204c204718113b3ee0e4d995fc3b92917f233494033cad48d751b00c55d58da5f087d21031a3859563c7b6a7f3a2ccf04d91a35050565b6001600160a01b038316612f3957604051626a0d4560e21b81525f6004820152602401611036565b604080516001808252602082018590528183019081526060820184905260a082019092525f60808201818152919291610e969187918590859061316e565b5f6001600160e01b03198216637965db0b60e01b1480610df85750610df8826136f0565b612fa582826116c4565b61107c5760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401611036565b5f80516020615f76833981519152545f80516020615ed683398151915290600160d01b900465ffffffffffff16801561306e574265ffffffffffff8216101561304557600182015482546001600160d01b0316600160a01b90910465ffffffffffff16600160d01b0217825561306e565b6040517f2b1fa2edafe6f7b9e97c1a9e0c3660e645beb2dcaa2d45bdbf9beaf5472e1ec5905f90a15b5060010180546001600160a01b0316600160a01b65ffffffffffff948516026001600160d01b031617600160d01b9290931691909102919091179055565b7f88be536d5240c274a3b1d3a1be54482fd9caa294f08c62a7cde569f49a3c450280546060915f80516020615ef6833981519152916130ea90615996565b80601f016020809104026020016040519081016040528092919081815260200182805461311690615996565b80156131615780601f1061313857610100808354040283529160200191613161565b820191905f5260205f20905b81548152906001019060200180831161314457829003601f168201915b5050505050915050919050565b61317a8585858561373f565b6001600160a01b03841615610e9657825133906001036131b357602084810151908401516131ac838989858589613a2c565b505061104c565b61104c818787878787613b4d565b5f80516020615e9683398151915280549081815f6131de83615940565b91905055505090565b816131f18161131a565b6132115760405163b7c882eb60e01b815260048101829052602401611036565b610e5b8383613c34565b826132258161131a565b6132455760405163b7c882eb60e01b815260048101829052602401611036565b61120e848484613ca5565b8161325a8161131a565b61327a5760405163b7c882eb60e01b815260048101829052602401611036565b505f9182527fec3c1253ecdf88a29ff53024f0721fc3faa1b42abcff612deb5b22d1f94e2d01602052604090912055565b816132b58161131a565b6132d55760405163b7c882eb60e01b815260048101829052602401611036565b5f8381527fdaa3d1cf82c71b982a9e24ff7dadd71a10e8c3e82a219c0e60ca5c6b8e61770060205260409020805483151560ff19909116179055505050565b61331c613d04565b611c5957604051631afcd79f60e31b815260040160405180910390fd5b613341613314565b610e2c81613d1d565b613352613314565b611c59613d2e565b613362613314565b61336c8585613d5f565b613374613d81565b61337d83613d99565b610e968282613daa565b611c59613314565b5f5f80516020615ed6833981519152836133f1575f6133ac61169b565b6001600160a01b0316146133d357604051631fe1e13d60e11b815260040160405180910390fd5b6001810180546001600160a01b0319166001600160a01b0385161790555b611d5d8484613e12565b5f5f80516020615ed683398151915283158015613430575061341b61169b565b6001600160a01b0316836001600160a01b0316145b15613448576001810180546001600160a01b03191690555b611d5d8484613eba565b5f80516020615f568339815191525460ff16611c5957604051638dfc202b60e01b815260040160405180910390fd5b80825d5050565b6001600160a01b038116610e2c5760405163094293a160e31b81526001600160a01b0382166004820152602401611036565b805f03610e2c5760405163023d875560e41b815260048101829052602401611036565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b17905261120e908590613f33565b613542848484613f9f565b826001600160a01b0385167f0a9521815fb3c5bc7dd6f4c9f89dc270322e46b945b104c18981f81c3f2cd1aa33604080516001600160a01b039092168252602082018790528101859052606001612bde565b61359d82613fb9565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156135e157610e5b828261401c565b61107c61408e565b5f65ffffffffffff82111561361b576040516306dfcc6560e41b81526030600482015260248101839052604401611036565b5090565b5f80516020615ed68339815191525f61363661193c565b835465ffffffffffff8616600160a01b026001600160d01b03199091166001600160a01b03881617178455915061367690508165ffffffffffff16151590565b1561120e576040517f8886ebfc4259abdbc16601dd8fb5678e54878f47b3c34836cfc51154a9605109905f90a150505050565b5f806136b3611882565b90508065ffffffffffff168365ffffffffffff16116136db576136d68382615cc7565b610ede565b610ede65ffffffffffff8416620697806140ad565b5f6001600160e01b03198216636cdb3d1360e11b148061372057506001600160e01b031982166303a24d0760e21b145b80610df857506301ffc9a760e01b6001600160e01b0319831614610df8565b613747612018565b6001600160a01b0384165f9081525f80516020615e56833981519152602081905260409091205485919060ff161561379d576040516327951b3f60e11b81526001600160a01b0383166004820152602401611036565b6001600160a01b0385165f9081525f80516020615e56833981519152602081905260409091205486919060ff16156137f3576040516327951b3f60e11b81526001600160a01b0383166004820152602401611036565b855f5b81518110156138635761382182828151811061381457613814615918565b602002602001015161131a565b61385b5781818151811061383757613837615918565b602002602001015160405163b7c882eb60e01b815260040161103691815260200190565b6001016137f6565b508888886001600160a01b0383161580159061388757506001600160a01b03821615155b15613936577fdaa3d1cf82c71b982a9e24ff7dadd71a10e8c3e82a219c0e60ca5c6b8e6177005f5b825181101561393357815f015f8483815181106138ce576138ce615918565b60209081029190910181015182528101919091526040015f9081205460ff161515900361392b5782818151811061390757613907615918565b60200260200101516040516368ee0b2f60e11b815260040161103691815260200190565b6001016138af565b50505b8a6001600160a01b03168c6001600160a01b03160361397357604051633ef2228f60e21b81526001600160a01b038d166004820152602401611036565b5f5b89518110156139bf5789818151811061399057613990615918565b60200260200101515f036139b7576040516323cf7d7d60e01b815260040160405180910390fd5b600101613975565b505f5b8a51811015613a1157613a098d8d8d84815181106139e2576139e2615918565b60200260200101518d85815181106139fc576139fc615918565b60200260200101516140bc565b6001016139c2565b50613a1e8c8c8c8c614130565b505050505050505050505050565b6001600160a01b0384163b1561104c5760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190613a709089908990889088908890600401615ce6565b6020604051808303815f875af1925050508015613aaa575060408051601f3d908101601f19168201909252613aa791810190615d2a565b60015b613b11573d808015613ad7576040519150601f19603f3d011682016040523d82523d5f602084013e613adc565b606091505b5080515f03613b0957604051632bfa23e760e11b81526001600160a01b0386166004820152602401611036565b805160208201fd5b6001600160e01b0319811663f23a6e6160e01b1461155c57604051632bfa23e760e11b81526001600160a01b0386166004820152602401611036565b6001600160a01b0384163b1561104c5760405163bc197c8160e01b81526001600160a01b0385169063bc197c8190613b919089908990889088908890600401615d45565b6020604051808303815f875af1925050508015613bcb575060408051601f3d908101601f19168201909252613bc891810190615d2a565b60015b613bf8573d808015613ad7576040519150601f19603f3d011682016040523d82523d5f602084013e613adc565b6001600160e01b0319811663bc197c8160e01b1461155c57604051632bfa23e760e11b81526001600160a01b0386166004820152602401611036565b5f8281527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff601602090815260409182902083905590518281525f80516020615f968339815191529184917fa12c47d56c27d127f5f74f842a31dcfca20ecb155635a6ec6cb060a39cac2b339101611de3565b5f5b8181101561120e57613cfc84848484818110613cc557613cc5615918565b613cdb92602060409092020190810191506156ad565b858585818110613ced57613ced615918565b9050604002016020013561434f565b600101613ca7565b5f613d0d611eb6565b54600160401b900460ff16919050565b613d25613314565b610e2c81614384565b613d36613314565b60408051602081019091525f81525f80516020615e7683398151915290819061107c9082615a8f565b613d67613314565b613d7182826143bd565b613d796143cf565b61107c613387565b613d89613314565b613d91613387565b611c596143df565b613da1613314565b610e2c816143fa565b613db2613314565b5f5b81811015610e5b57613e09838383818110613dd157613dd1615918565b9050604002015f0135848484818110613dec57613dec615918565b9050604002016020016020810190613e0491906156ad565b61338f565b50600101613db4565b5f5f80516020615f16833981519152613e2b84846116c4565b613eaa575f848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055613e603390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a46001915050610df8565b5f915050610df8565b5092915050565b5f5f80516020615f16833981519152613ed384846116c4565b15613eaa575f848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a46001915050610df8565b5f8060205f8451602086015f885af180613f52576040513d5f823e3d81fd5b50505f513d91508115613f69578060011415613f76565b6001600160a01b0384163b155b1561120e57604051635274afe760e01b81526001600160a01b0385166004820152602401611036565b610e5b83838360405180602001604052805f8152506127c4565b806001600160a01b03163b5f03613fee57604051634c9c8ce360e01b81526001600160a01b0382166004820152602401611036565b5f80516020615eb683398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80846001600160a01b0316846040516140389190615da2565b5f60405180830381855af49150503d805f8114614070576040519150601f19603f3d011682016040523d82523d5f602084013e614075565b606091505b509150915061408585838361440b565b95945050505050565b3415611c595760405163b398979f60e01b815260040160405180910390fd5b5f828218828410028218610e09565b6001600160a01b0384166140ed576140d48383611357565b6140e88383836140e386614460565b6144db565b61120e565b6001600160a01b03831661411057614106848383614805565b6140e88483611357565b61411a8383611357565b614126848484846149b8565b61120e8483611357565b805182515f80516020615ef6833981519152911461416e5782518251604051635b05999160e01b815260048101929092526024820152604401611036565b335f5b8451811015614270576020818102868101820151908601909101516001600160a01b03891615614222575f828152602086815260408083206001600160a01b038d168452909152902054818110156141fc576040516303dee4c560e01b81526001600160a01b038b166004820152602481018290526044810183905260648101849052608401611036565b5f838152602087815260408083206001600160a01b038e16845290915290209082900390555b6001600160a01b03881615614266575f828152602086815260408083206001600160a01b038c16845290915281208054839290614260908490615983565b90915550505b5050600101614171565b5083516001036142f05760208401515f906020850151909150866001600160a01b0316886001600160a01b0316846001600160a01b03167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6285856040516142e1929190918252602082015260400190565b60405180910390a4505061104c565b846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb878760405161433f929190615dbd565b60405180910390a4505050505050565b826143598161131a565b6143795760405163b7c882eb60e01b815260048101829052602401611036565b61120e848484614bc5565b5f80516020615ef68339815191527f88be536d5240c274a3b1d3a1be54482fd9caa294f08c62a7cde569f49a3c4502610e5b8382615a8f565b6143c5613314565b61107c8282614e2a565b6143d7613314565b611c59613387565b6143e7613314565b60015f80516020615e9683398151915255565b614402613314565b610e2c81612d0b565b6060826144205761441b82614e90565b610e09565b815115801561443757506001600160a01b0384163b155b15613eb357604051639996b31560e01b81526001600160a01b0385166004820152602401611036565b5f8061446b836117a9565b9050805f0361447d57505f1992915050565b5f6144888242615983565b90505f614496606484615de1565b9050805f036144a3575060015b5f8160016144b18286615983565b6144bb9190615cb4565b6144c59190615de1565b90506144d1828261596c565b9695505050505050565b6001600160a01b0384165f9081525f80516020615e368339815191526020818152604080842087855290915282208054919290919081905b828110156146175783818154811061452d5761452d615918565b905f5260205f2090600202015f01545f14801561456a575083818154811061455757614557615918565b905f5260205f209060020201600101545f145b1561457757809150614617565b8584828154811061458a5761458a615918565b905f5260205f20906002020160010154036145de57868482815481106145b2576145b2615918565b905f5260205f2090600202015f015f8282546145ce9190615983565b9091555061120e95505050505050565b858482815481106145f1576145f1615918565b905f5260205f20906002020160010154111561460f57809150614617565b600101614513565b5081811061465b576040805180820190915286815260208082018781528554600181810188555f8881529390932093516002909102909301928355519101556147fb565b82818154811061466d5761466d615918565b905f5260205f2090600202015f01545f1480156146aa575082818154811061469757614697615918565b905f5260205f209060020201600101545f145b156146f9576040518060400160405280878152602001868152508382815481106146d6576146d6615918565b5f91825260209182902083516002909202019081559101516001909101556147fb565b604080518082019091525f80825260208083018281528654600181810189558885529284209451600290910290940193845551928101929092558454909161474091615cb4565b90505b818111156147b45783614757600183615cb4565b8154811061476757614767615918565b905f5260205f20906002020184828154811061478557614785615918565b5f91825260209091208254600290920201908155600191820154910155806147ac81615e00565b915050614743565b506040518060400160405280878152602001868152508382815481106147dc576147dc615918565b5f91825260209182902083516002909202019081559101516001909101555b5050505050505050565b6001600160a01b0383165f9081525f80516020615e3683398151915260208181526040808420868552909152822080549192909184914291905b818110801561484d57505f84115b1561496e578285828154811061486557614865615918565b905f5260205f209060020201600101541115806148a1575084818154811061488f5761488f615918565b905f5260205f2090600202015f01545f145b61495c57838582815481106148b8576148b8615918565b905f5260205f2090600202015f0154111561490a57838582815481106148e0576148e0615918565b905f5260205f2090600202015f015f8282546148fc9190615cb4565b909155505f945061495c9050565b84818154811061491c5761491c615918565b905f5260205f2090600202015f0154846149369190615cb4565b93505f85828154811061494b5761494b615918565b5f9182526020909120600290910201555b8061496681615940565b91505061483f565b5082156147fb57876149808488615cb4565b60405163670f004560e01b81526001600160a01b03909216600483015260248201526044810187905260648101889052608401611036565b826001600160a01b0316846001600160a01b031614806149d6575080155b61120e576001600160a01b0384165f9081525f80516020615e3683398151915260208181526040808420868552909152822080549192909184914291905b8181108015614a2257505f84115b15614ba85782858281548110614a3a57614a3a615918565b905f5260205f20906002020160010154111580614a765750848181548110614a6457614a64615918565b905f5260205f2090600202015f01545f145b614b965783858281548110614a8d57614a8d615918565b905f5260205f2090600202015f01541115614b0c57614acf898986888581548110614aba57614aba615918565b905f5260205f209060020201600101546144db565b83858281548110614ae257614ae2615918565b905f5260205f2090600202015f015f828254614afe9190615cb4565b909155505f9450614b969050565b614b448989878481548110614b2357614b23615918565b905f5260205f2090600202015f0154888581548110614aba57614aba615918565b848181548110614b5657614b56615918565b905f5260205f2090600202015f015484614b709190615cb4565b93505f858281548110614b8557614b85615918565b5f9182526020909120600290910201555b80614ba081615940565b915050614a14565b508215614bba57886149808488615cb4565b505050505050505050565b6001600160a01b038216614bf75760405163aac3232160e01b81526001600160a01b0383166004820152602401611036565b5f8381527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff602602090815260408083206001600160a01b038616845290915290208190555f80516020615f968339815191528115614ce7575f848152600382016020526040812090805b8254811015614caf57856001600160a01b0316838281548110614c8557614c85615918565b5f918252602090912001546001600160a01b031603614ca75760019150614caf565b600101614c60565b5080614ce05781546001810183555f838152602090200180546001600160a01b0319166001600160a01b0387161790555b5050614dee565b5f8481526003820160205260408120905b8154811015614deb57846001600160a01b0316828281548110614d1d57614d1d615918565b5f918252602090912001546001600160a01b031603614de35781548290614d4690600190615cb4565b81548110614d5657614d56615918565b905f5260205f20015f9054906101000a90046001600160a01b0316828281548110614d8357614d83615918565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555081805480614dbe57614dbe615958565b5f8281526020902081015f1990810180546001600160a01b0319169055019055614deb565b600101614cf8565b50505b826001600160a01b0316847ffb08de1e404ab196167a5843d6f4552a93056ed1da04e2f6c958dc6c63f1e4b484604051612bde91815260200190565b614e32613314565b5f80516020615ed68339815191526001600160a01b038216614e6957604051636116401160e11b81525f6004820152602401611036565b80546001600160d01b0316600160d01b65ffffffffffff85160217815561120e5f8361338f565b805115614e9f57805160208201fd5b60405163d6bda27560e01b815260040160405180910390fd5b60405180604001604052805f8152602001614ef360405180608001604052805f8152602001606081526020015f81526020015f151581525090565b905290565b6001600160a01b0381168114610e2c575f80fd5b5f8060408385031215614f1d575f80fd5b8235614f2881614ef8565b946020939093013593505050565b602080825282518282018190525f919060409081850190868401855b82811015614f7757815180518552860151868501529284019290850190600101614f52565b5091979650505050505050565b6001600160e01b031981168114610e2c575f80fd5b5f60208284031215614fa9575f80fd5b8135610e0981614f84565b5f60208284031215614fc4575f80fd5b5035919050565b5f5b83811015614fe5578181015183820152602001614fcd565b50505f910152565b5f8151808452615004816020860160208601614fcb565b601f01601f19169290920160200192915050565b602081525f610e096020830184614fed565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b03811182821017156150665761506661502a565b604052919050565b5f82601f83011261507d575f80fd5b81356001600160401b038111156150965761509661502a565b6150a9601f8201601f191660200161503e565b8181528460208386010111156150bd575f80fd5b816020850160208301375f918101602001919091529392505050565b5f80604083850312156150ea575f80fd5b8235915060208301356001600160401b03811115615106575f80fd5b6151128582860161506e565b9150509250929050565b5f6001600160401b038211156151345761513461502a565b5060051b60200190565b5f82601f83011261514d575f80fd5b8135602061516261515d8361511c565b61503e565b8083825260208201915060208460051b870101935086841115615183575f80fd5b602086015b8481101561519f5780358352918301918301615188565b509695505050505050565b5f805f80608085870312156151bd575f80fd5b84356151c881614ef8565b935060208501356001600160401b03808211156151e3575f80fd5b6151ef8883890161513e565b94506040870135915080821115615204575f80fd5b6152108883890161513e565b93506060870135915080821115615225575f80fd5b506152328782880161506e565b91505092959194509250565b5f60808284031215610ee1575f80fd5b5f6020828403121561525e575f80fd5b81356001600160401b03811115615273575f80fd5b611d5d8482850161523e565b803565ffffffffffff81168114615294575f80fd5b919050565b5f805f805f8060a087890312156152ae575f80fd5b6152b78761527f565b955060208701356152c781614ef8565b945060408701356152d781614ef8565b935060608701356001600160401b03808211156152f2575f80fd5b818901915089601f830112615305575f80fd5b813581811115615313575f80fd5b8a60208260061b8501011115615327575f80fd5b602083019550809450506080890135915080821115615344575f80fd5b5061535189828a0161506e565b9150509295509295509295565b5f805f805f60a08688031215615372575f80fd5b853561537d81614ef8565b9450602086013561538d81614ef8565b935060408601356001600160401b03808211156153a8575f80fd5b6153b489838a0161513e565b945060608801359150808211156153c9575f80fd5b6153d589838a0161513e565b935060808801359150808211156153ea575f80fd5b506153f78882890161506e565b9150509295509295909350565b5f8060408385031215615415575f80fd5b82359150602083013561542781614ef8565b809150509250929050565b5f815180845260208085019450602084015f5b8381101561547557815180516001600160a01b031688528301518388015260409096019590820190600101615445565b509495945050505050565b60208152815160208201525f60208301516040808401528051606084015260208101516080808501526154b660e0850182615432565b604083015160a0860152606090920151151560c0909401939093529392505050565b5f805f80608085870312156154eb575f80fd5b84356154f681614ef8565b9350602085013561550681614ef8565b93969395505050506040820135916060013590565b5f806040838503121561552c575f80fd5b8235915060208301356001600160401b03811115615548575f80fd5b6151128582860161523e565b5f8060408385031215615565575f80fd5b82356001600160401b038082111561557b575f80fd5b818501915085601f83011261558e575f80fd5b8135602061559e61515d8361511c565b82815260059290921b840181019181810190898411156155bc575f80fd5b948201945b838610156155e35785356155d481614ef8565b825294820194908201906155c1565b965050860135925050808211156155f8575f80fd5b506151128582860161513e565b5f815180845260208085019450602084015f5b8381101561547557815187529582019590820190600101615618565b602081525f610e096020830184615605565b5f8060408385031215615657575f80fd5b823561566281614ef8565b915060208301356001600160401b03811115615106575f80fd5b5f6020828403121561568c575f80fd5b81356001600160401b038111156156a1575f80fd5b611d5d8482850161506e565b5f602082840312156156bd575f80fd5b8135610e0981614ef8565b5f602082840312156156d8575f80fd5b610e098261527f565b5f805f606084860312156156f3575f80fd5b83356156fe81614ef8565b925060208401356001600160401b0380821115615719575f80fd5b6157258783880161513e565b9350604086013591508082111561573a575f80fd5b506157478682870161513e565b9150509250925092565b5f805f60608486031215615763575f80fd5b833561576e81614ef8565b95602085013595506040909401359392505050565b5f8060408385031215615794575f80fd5b50508035926020909101359150565b5f805f80608085870312156157b6575f80fd5b84356157c181614ef8565b9350602085013592506040850135915060608501356001600160401b038111156157e9575f80fd5b6152328782880161506e565b602081525f610e096020830184615432565b80358015158114615294575f80fd5b5f8060408385031215615827575f80fd5b823561583281614ef8565b915061584060208401615807565b90509250929050565b602080825282518282018190525f9190848201906040850190845b81811015611c155783516001600160a01b031683529284019291840191600101615864565b5f806040838503121561589a575f80fd5b82356158a581614ef8565b9150602083013561542781614ef8565b5f805f805f60a086880312156158c9575f80fd5b85356158d481614ef8565b945060208601356158e481614ef8565b9350604086013592506060860135915060808601356001600160401b0381111561590c575f80fd5b6153f78882890161506e565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f600182016159515761595161592c565b5060010190565b634e487b7160e01b5f52603160045260245ffd5b8082028115828204841417610df857610df861592c565b80820180821115610df857610df861592c565b600181811c908216806159aa57607f821691505b602082108103610ee157634e487b7160e01b5f52602260045260245ffd5b5f8084546159d581615996565b600182811680156159ed5760018114615a0257615a2e565b60ff1984168752821515830287019450615a2e565b885f526020805f205f5b85811015615a255781548a820152908401908201615a0c565b50505082870194505b505050508351615a42818360208801614fcb565b01949350505050565b601f821115610e5b57805f5260205f20601f840160051c81016020851015615a705750805b601f840160051c820191505b81811015610e96575f8155600101615a7c565b81516001600160401b03811115615aa857615aa861502a565b615abc81615ab68454615996565b84615a4b565b602080601f831160018114615aef575f8415615ad85750858301515b5f19600386901b1c1916600185901b17855561104c565b5f85815260208120601f198616915b82811015615b1d57888601518255948401946001909101908401615afe565b5085821015615b3a57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f808335601e19843603018112615b5f575f80fd5b8301803591506001600160401b03821115615b78575f80fd5b6020019150600681901b3603821315615b8f575f80fd5b9250929050565b5f60208284031215615ba6575f80fd5b610e0982615807565b8183525f60208085019450825f5b85811015615475578135615bd081614ef8565b6001600160a01b03168752818301358388015260409687019690910190600101615bbd565b60208152813560208201525f6020830135601e19843603018112615c17575f80fd5b83016020810190356001600160401b03811115615c32575f80fd5b8060061b3603821315615c43575f80fd5b60806040850152615c5860a085018284615baf565b91505060408401356060840152615c7160608501615807565b80151560808501526112f7565b5f60208284031215615c8e575f80fd5b5051919050565b65ffffffffffff818116838216019080821115613eb357613eb361592c565b81810381811115610df857610df861592c565b65ffffffffffff828116828216039080821115613eb357613eb361592c565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190525f90615d1f90830184614fed565b979650505050505050565b5f60208284031215615d3a575f80fd5b8151610e0981614f84565b6001600160a01b0386811682528516602082015260a0604082018190525f90615d7090830186615605565b8281036060840152615d828186615605565b90508281036080840152615d968185614fed565b98975050505050505050565b5f8251615db3818460208701614fcb565b9190910192915050565b604081525f615dcf6040830185615605565b82810360208401526140858185615605565b5f82615dfb57634e487b7160e01b5f52601260045260245ffd5b500490565b5f81615e0e57615e0e61592c565b505f19019056fe74f7a545c65c11839a48d7453738b30c295408df2d944516167556759ddc6d06ec3c1253ecdf88a29ff53024f0721fc3faa1b42abcff612deb5b22d1f94e2d00a095fe5a3c31691ae0832631cef3701285d36b2af1972f4c23463476b0353a0089fc852226e759c7c636cf34d732f0198fc56a54876b2374a52beb7b0c558600591f2d2df77efc80b9969dfd51dd4fc103fe490745902503f7c21df07a35d600360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbceef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840088be536d5240c274a3b1d3a1be54482fd9caa294f08c62a7cde569f49a3c450002dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680046f3eccdd88dd62792ae8eed1be7b9b658477566c49fd85b0d08cf44261c9208cd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300eef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840154c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff600a264697066735822122064aee9fd83c4de7466b4b29eff10eecae42f9461060e96bde86f95ec02169c4464736f6c63430008180033 +0x60a060405230608052348015610013575f80fd5b50608051615fc46200003b5f395f818161244b0152818161247401526125d50152615fc45ff3fe6080604052600436106103dd575f3560e01c8063788649ea116101ff578063c55be5d011610113578063d602b9fd116100a8578063f0f4426011610078578063f0f4426014610c59578063f101e48114610c78578063f242432a14610c98578063f26c159f14610cb7578063f5298aca14610cd6575f80fd5b8063d602b9fd14610bb0578063e583983614610bc4578063e985e9c514610c07578063f0a3a97c14610c26575f80fd5b8063d2c7db1c116100e3578063d2c7db1c14610b1e578063d4ddce8a14610b3f578063d539139314610b5e578063d547741f14610b91575f80fd5b8063c55be5d014610a9d578063cc8463c814610abc578063cefc142914610ad0578063cf6eefb714610ae4575f80fd5b8063a1eda53c11610194578063a5a2a64511610164578063a5a2a645146109dc578063ad3cb1cc146109fb578063b256456914610a2b578063c0a2103414610a4a578063c2840e6014610a7d575f80fd5b8063a1eda53c14610957578063a217fddf1461098a578063a22cb4651461099d578063a3b546f2146109bc575f80fd5b80638da5cb5b116101cf5780638da5cb5b146108e457806391d14854146108f85780639526c2d914610917578063994757c51461092b575f80fd5b8063788649ea1461086a57806379c44ca2146108895780638456cb59146108bc57806384ef8ffc146108d0575f80fd5b8063440e806e116102f657806355f804b31161028b578063649a5ec71161025b578063649a5ec7146107e75780636b20c454146108065780636d51282c1461082557806370876c9814610838578063731133e91461084b575f80fd5b806355f804b3146107495780635c975abb1461076857806361d027b31461078b578063634e93da146107c8575f80fd5b80634f1ef286116102c65780634f1ef286146106e45780634f558e79146106f757806352d1902d1461071657806354efdcf61461072a575f80fd5b8063440e806e1461064e57806345cc05a01461067a57806347aa3a2e146106995780634e1273f4146106b8575f80fd5b8063248a9ca3116103775780632eb2c2d6116103475780632eb2c2d6146105aa5780632f2ff15d146105c957806336568abe146105e85780633f4ba83a1461060757806343ffa64e1461061b575f80fd5b8063248a9ca31461051a57806327276d9814610539578063282c51f3146105585780632d99179e1461058b575f80fd5b80630aa6220b116103b25780630aa6220b1461049a5780630e89341c146104b0578063162094c4146104dc5780631f7fdffa146104fb575f80fd5b8062e6449d146103e1578062fdd58e1461041657806301ffc9a714610443578063022d63fb14610472575b5f80fd5b3480156103ec575f80fd5b506104006103fb366004614ee5565b610cf5565b60405161040d9190614f0f565b60405180910390f35b348015610421575f80fd5b50610435610430366004614ee5565b610d91565b60405190815260200161040d565b34801561044e575f80fd5b5061046261045d366004614f72565b610da3565b604051901515815260200161040d565b34801561047d575f80fd5b50620697805b60405165ffffffffffff909116815260200161040d565b3480156104a5575f80fd5b506104ae610dad565b005b3480156104bb575f80fd5b506104cf6104ca366004614f8d565b610dc2565b60405161040d9190614ff1565b3480156104e7575f80fd5b506104ae6104f63660046150b2565b610dcd565b348015610506575f80fd5b506104ae610515366004615183565b610df3565b348015610525575f80fd5b50610435610534366004614f8d565b610e30565b348015610544575f80fd5b50610435610553366004615227565b610e50565b348015610563575f80fd5b506104357f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84881565b348015610596575f80fd5b506104ae6105a5366004615272565b610e7a565b3480156105b5575f80fd5b506104ae6105c4366004615337565b610f7b565b3480156105d4575f80fd5b506104ae6105e33660046153dd565b610fe7565b3480156105f3575f80fd5b506104ae6106023660046153dd565b611013565b348015610612575f80fd5b506104ae6110d0565b348015610626575f80fd5b506104357fa76ace73a908083d89af9ff88e5b4f7cadb3591a80631063f68b695fda726db581565b348015610659575f80fd5b5061066d610668366004614f8d565b6110ef565b60405161040d9190615459565b348015610685575f80fd5b506104ae6106943660046154b1565b61117d565b3480156106a4575f80fd5b506104ae6106b33660046154f4565b6111a7565b3480156106c3575f80fd5b506106d76106d236600461552d565b6111c8565b60405161040d919061560d565b6104ae6106f236600461561f565b611292565b348015610702575f80fd5b50610462610711366004614f8d565b6112ad565b348015610721575f80fd5b506104356112cf565b348015610735575f80fd5b506104ae610744366004614ee5565b6112ea565b348015610754575f80fd5b506104ae610763366004615655565b61157a565b348015610773575f80fd5b505f80516020615f2f8339815191525460ff16610462565b348015610796575f80fd5b505f80516020615f6f833981519152546001600160a01b03165b6040516001600160a01b03909116815260200161040d565b3480156107d3575f80fd5b506104ae6107e2366004615686565b61159a565b3480156107f2575f80fd5b506104ae6108013660046156a1565b6115ad565b348015610811575f80fd5b506104ae6108203660046156ba565b6115c0565b6104ae61083336600461572a565b6115f5565b6104ae61084636600461575c565b611618565b348015610856575f80fd5b506104ae61086536600461577c565b61163b565b348015610875575f80fd5b506104ae610884366004615686565b611671565b348015610894575f80fd5b506104357f6f58fc3760b5743cf76087dfed697597f39c204c204718113b3ee0e4d995fc3b81565b3480156108c7575f80fd5b506104ae611691565b3480156108db575f80fd5b506107b06116b0565b3480156108ef575f80fd5b506107b06116cb565b348015610903575f80fd5b506104626109123660046153dd565b6116d9565b348015610922575f80fd5b50610435606481565b348015610936575f80fd5b5061094a610945366004614f8d565b61170f565b60405161040d91906157ce565b348015610962575f80fd5b5061096b611744565b6040805165ffffffffffff93841681529290911660208301520161040d565b348015610995575f80fd5b506104355f81565b3480156109a8575f80fd5b506104ae6109b73660046157ef565b6117b3565b3480156109c7575f80fd5b506104355f80516020615f0f83398151915281565b3480156109e7575f80fd5b506104356109f6366004614f8d565b6117be565b348015610a06575f80fd5b506104cf604051806040016040528060058152602001640352e302e360dc1b81525081565b348015610a36575f80fd5b50610462610a45366004614f8d565b61181b565b348015610a55575f80fd5b506104357f7d2be5e40a0d45d9af5c7db1fc1fa7822674e1d5f550082d32be1b8bf80c015f81565b348015610a88575f80fd5b506104355f80516020615def83398151915281565b348015610aa8575f80fd5b506104ae610ab736600461572a565b61187b565b348015610ac7575f80fd5b50610483611897565b348015610adb575f80fd5b506104ae611912565b348015610aef575f80fd5b50610af8611951565b604080516001600160a01b03909316835265ffffffffffff90911660208301520161040d565b348015610b29575f80fd5b50610b3261197e565b60405161040d9190615822565b348015610b4a575f80fd5b50610435610b59366004614f8d565b6119ed565b348015610b69575f80fd5b506104357f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b348015610b9c575f80fd5b506104ae610bab3660046153dd565b611a21565b348015610bbb575f80fd5b506104ae611a49565b348015610bcf575f80fd5b50610462610bde366004615686565b6001600160a01b03165f9081525f80516020615e2f833981519152602052604090205460ff1690565b348015610c12575f80fd5b50610462610c21366004615862565b611a5b565b348015610c31575f80fd5b506104357f3496e2e73c4d42b75d702e60d9e48102720b8691234415963a5a857b86425d0781565b348015610c64575f80fd5b506104ae610c73366004615686565b611aa7565b348015610c83575f80fd5b505f80516020615e6f83398151915254610435565b348015610ca3575f80fd5b506104ae610cb236600461588e565b611ada565b348015610cc2575f80fd5b506104ae610cd1366004615686565b611b39565b348015610ce1575f80fd5b506104ae610cf036600461572a565b611b59565b6001600160a01b0382165f9081525f80516020615e0f833981519152602081815260408084208585528252808420805482518185028101850190935280835260609592939192909184015b82821015610d83578382905f5260205f2090600202016040518060400160405290815f820154815260200160018201548152505081526020019060010190610d40565b505050509150505b92915050565b5f610d9c8383611b8e565b9392505050565b5f610d8b82611c36565b5f610db781611c5a565b610dbf611c64565b50565b6060610d8b82611c70565b5f80516020615def833981519152610de481611c5a565b610dee8383611d7a565b505050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6610e1d81611c5a565b610e2985858585611e05565b5050505050565b5f9081525f80516020615eef833981519152602052604090206001015490565b5f5f80516020615def833981519152610e6881611c5a565b610e7183611e3b565b91505b50919050565b5f610e83611f31565b805490915060ff600160401b82041615906001600160401b03165f81158015610ea95750825b90505f826001600160401b03166001148015610ec45750303b155b905081158015610ed2575080155b15610ef05760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610f1a57845460ff60401b1916600160401b1785555b610f288b8b8b8b8b8b611f59565b8315610f6e57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050505050565b336001600160a01b0386168114801590610f9c5750610f9a8682611a5b565b155b15610fd25760405163711bec9160e11b81526001600160a01b038083166004830152871660248201526044015b60405180910390fd5b610fdf8686868686611f87565b505050505050565b8161100557604051631fe1e13d60e11b815260040160405180910390fd5b61100f8282611fe5565b5050565b5f80516020615eaf8339815191528215801561104757506110326116b0565b6001600160a01b0316826001600160a01b0316145b156110c6575f80611056611951565b90925090506001600160a01b038216151580611078575065ffffffffffff8116155b8061108b57504265ffffffffffff821610155b156110b3576040516319ca5ebb60e01b815265ffffffffffff82166004820152602401610fc9565b5050805465ffffffffffff60a01b191681555b610dee8383612001565b5f80516020615f0f8339815191526110e781611c5a565b610dbf612034565b6110f7614e91565b81611101816112ad565b6111215760405163b7c882eb60e01b815260048101829052602401610fc9565b60405180604001604052808481526020016040518060800160405280611146876119ed565b81526020016111548761170f565b8152602001611162876117be565b81526020016111708761181b565b1515905290529392505050565b611185612093565b61118d6120c3565b61119984848484612130565b6111a1612353565b50505050565b5f80516020615def8339815191526111be81611c5a565b610dee838361237d565b606081518351146111f95781518351604051635b05999160e01b815260048101929092526024820152604401610fc9565b5f83516001600160401b0381111561121357611213615003565b60405190808252806020026020018201604052801561123c578160200160208202803683370190505b5090505f5b845181101561128a5760208082028601015161126590602080840287010151610d91565b828281518110611277576112776158f1565b6020908102919091010152600101611241565b509392505050565b61129a612440565b6112a3826124e4565b61100f828261250e565b5f5f80516020615e6f8339815191528215801590610e71575054909110919050565b5f6112d86125ca565b505f80516020615e8f83398151915290565b6001600160a01b0382165f9081525f80516020615e0f83398151915260208181526040808420858552909152822080549192909142919081805b8281101561141a5785818154811061133e5761133e6158f1565b5f918252602090912060029091020154156114125784868281548110611366576113666158f1565b905f5260205f2090600202016001015411156113e3578381146113d157858181548110611395576113956158f1565b905f5260205f2090600202018685815481106113b3576113b36158f1565b5f918252602090912082546002909202019081556001918201549101555b836113db81615919565b945050611412565b8581815481106113f5576113f56158f1565b905f5260205f2090600202015f01548261140f9190615931565b91505b600101611324565b50825b828110156114705760405180604001604052805f81526020015f81525086828154811061144c5761144c6158f1565b5f91825260209182902083516002909202019081559101516001918201550161141d565b508215801561147e57505f82115b156114c1575b8454156114bc578480548061149b5761149b615944565b5f8281526020812060025f1990930192830201818155600101559055611484565b61151a565b6114cc836002615958565b821180156114da5750600a82115b1561151a575b845483101561151a57848054806114f9576114f9615944565b5f8281526020812060025f19909301928302018181556001015590556114e0565b80156115705761152b888883612613565b86886001600160a01b03167f6dd845d42097bcb5bd43605815b8ea0407e0022cd38d0a278d336bd0a5643f9d8360405161156791815260200190565b60405180910390a35b5050505050505050565b5f80516020615def83398151915261159181611c5a565b61100f826126a0565b5f6115a481611c5a565b61100f826126b9565b5f6115b781611c5a565b61100f8261272c565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a8486115ea81611c5a565b6111a184848461279b565b6115fd612093565b6116056120c3565b6116108383836127de565b610dee612353565b611620612093565b6116286120c3565b6116333383836127de565b61100f612353565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a661166581611c5a565b610e29858585856128f7565b5f80516020615f0f83398151915261168881611c5a565b61100f82612952565b5f80516020615f0f8339815191526116a881611c5a565b610dbf612afc565b5f80516020615f4f833981519152546001600160a01b031690565b5f6116d46116b0565b905090565b5f9182525f80516020615eef833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b60608161171b816112ad565b61173b5760405163b7c882eb60e01b815260048101829052602401610fc9565b610e7183612b44565b5f80516020615f4f833981519152545f90600160d01b900465ffffffffffff165f80516020615eaf833981519152811580159061178957504265ffffffffffff831610155b611794575f806117aa565b6001810154600160a01b900465ffffffffffff16825b92509250509091565b61100f338383612c79565b5f816117c9816112ad565b6117e95760405163b7c882eb60e01b815260048101829052602401610fc9565b5f8381527fec3c1253ecdf88a29ff53024f0721fc3faa1b42abcff612deb5b22d1f94e2d016020526040902054610e71565b5f81611826816112ad565b6118465760405163b7c882eb60e01b815260048101829052602401610fc9565b5f8381527fdaa3d1cf82c71b982a9e24ff7dadd71a10e8c3e82a219c0e60ca5c6b8e617700602052604090205460ff16610e71565b611883612093565b61188b6120c3565b61161033848484612130565b5f80516020615f4f833981519152545f905f80516020615eaf83398151915290600160d01b900465ffffffffffff1680158015906118dc57504265ffffffffffff8216105b6118f6578154600160d01b900465ffffffffffff1661190b565b6001820154600160a01b900465ffffffffffff165b9250505090565b5f61191b611951565b509050336001600160a01b0382161461194957604051636116401160e11b8152336004820152602401610fc9565b610dbf612d1f565b5f80516020615eaf833981519152546001600160a01b03811691600160a01b90910465ffffffffffff1690565b60605f5f80516020615e2f833981519152600181018054604080516020808402820181019092528281529394508301828280156119e257602002820191905f5260205f20905b81546001600160a01b031681526001909101906020018083116119c4575b505050505091505090565b5f816119f8816112ad565b611a185760405163b7c882eb60e01b815260048101829052602401610fc9565b610e7183612db8565b81611a3f57604051631fe1e13d60e11b815260040160405180910390fd5b61100f8282612e18565b5f611a5381611c5a565b610dbf612e34565b6001600160a01b039182165f9081527f88be536d5240c274a3b1d3a1be54482fd9caa294f08c62a7cde569f49a3c45016020908152604080832093909416825291909152205460ff1690565b7f3496e2e73c4d42b75d702e60d9e48102720b8691234415963a5a857b86425d07611ad181611c5a565b61100f82612e3e565b336001600160a01b0386168114801590611afb5750611af98682611a5b565b155b15611b2c5760405163711bec9160e11b81526001600160a01b03808316600483015287166024820152604401610fc9565b610fdf8686868686612ec9565b5f80516020615f0f833981519152611b5081611c5a565b61100f82612f55565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848611b8381611c5a565b6111a184848461304d565b6001600160a01b0382165f9081525f80516020615e0f83398151915260208181526040808420858552909152822080548390815b81811015611c2a5742848281548110611bdd57611bdd6158f1565b905f5260205f209060020201600101541115611c2257838181548110611c0557611c056158f1565b905f5260205f2090600202015f015483611c1f9190615931565b92505b600101611bc2565b50909695505050505050565b5f6001600160e01b031982166318a4c3c360e11b1480610d8b5750610d8b826130b3565b610dbf81336130d7565b611c6e5f80613110565b565b5f8181527f89fc852226e759c7c636cf34d732f0198fc56a54876b2374a52beb7b0c5586016020526040812080546060925f80516020615e4f833981519152929091611cbb9061596f565b80601f0160208091040260200160405190810160405280929190818152602001828054611ce79061596f565b8015611d325780601f10611d0957610100808354040283529160200191611d32565b820191905f5260205f20905b815481529060010190602001808311611d1557829003601f168201915b505050505090505f815111611d4f57611d4a846131e8565b611d72565b604051611d6290839083906020016159a1565b6040516020818303038152906040525b949350505050565b5f8281527f89fc852226e759c7c636cf34d732f0198fc56a54876b2374a52beb7b0c558601602052604090205f80516020615e4f83398151915290611dbf8382615a68565b50827f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b611deb85610dc2565b604051611df89190614ff1565b60405180910390a2505050565b6001600160a01b038416611e2e57604051632bfa23e760e11b81525f6004820152602401610fc9565b6111a15f858585856132aa565b5f611e446132fd565b9050611e51818335613323565b611e6781611e626020850185615b23565b613394565b611ea08183604001355f9182527fec3c1253ecdf88a29ff53024f0721fc3faa1b42abcff612deb5b22d1f94e2d01602052604090912055565b611ef481611eb46080850160608601615b6f565b5f7fdaa3d1cf82c71b982a9e24ff7dadd71a10e8c3e82a219c0e60ca5c6b8e6177005f938452602052506040909120805460ff1916911515919091179055565b807f76e35084bc84f178215c72d32676286f16ca2d3a80d3e80e317c858d61eb5a3783604051611f249190615bce565b60405180910390a2919050565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00610d8b565b611f616133f3565b611f6a81613418565b611f72613429565b611f7f8686868686613439565b610fdf613466565b6001600160a01b038416611fb057604051632bfa23e760e11b81525f6004820152602401610fc9565b6001600160a01b038516611fd857604051626a0d4560e21b81525f6004820152602401610fc9565b610e2985858585856132aa565b611fee82610e30565b611ff781611c5a565b6111a1838361346e565b6001600160a01b038116331461202a5760405163334bd91960e11b815260040160405180910390fd5b610dee82826134da565b61203c613531565b5f80516020615f2f833981519152805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b5f80516020615f2f8339815191525460ff1615611c6e5760405163d93c066560e01b815260040160405180910390fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c1561210357604051633ee5aeb560e01b815260040160405180910390fd5b611c6e60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b90613560565b5f80516020615f6f83398151915261214785613567565b61215082613599565b5f83815260028201602090815260408083206001600160a01b0388168452909152812054908190036121a75760405163ec40a7ab60e01b8152600481018590526001600160a01b0386166024820152604401610fc9565b5f6121b28483615958565b9050855f6001600160a01b03821663dd62ed3e336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa15801561220e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122329190615c57565b90508281101561226e576040516303dfb80d60e11b81526001600160a01b03891660048201526024810184905260448101829052606401610fc9565b5f6001600160a01b0383166370a08231336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156122c1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122e59190615c57565b90508381101561232157604051633514dc2360e21b81526001600160a01b038a1660048201526024810185905260448101829052606401610fc9565b61233b3387546001600160a01b03868116929116876135bc565b6123478a898987613616565b50505050505050505050565b611c6e5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0061212a565b81612387816112ad565b6123a75760405163b7c882eb60e01b815260048101829052602401610fc9565b6123b2838335613323565b6123c383611e626020850185615b23565b6123fc8383604001355f9182527fec3c1253ecdf88a29ff53024f0721fc3faa1b42abcff612deb5b22d1f94e2d01602052604090912055565b61241083611eb46080850160608601615b6f565b827f76e35084bc84f178215c72d32676286f16ca2d3a80d3e80e317c858d61eb5a3783604051611df89190615bce565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806124c657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166124ba5f80516020615e8f833981519152546001600160a01b031690565b6001600160a01b031614155b15611c6e5760405163703e46dd60e11b815260040160405180910390fd5b7fa76ace73a908083d89af9ff88e5b4f7cadb3591a80631063f68b695fda726db561100f81611c5a565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612568575060408051601f3d908101601f1916820190925261256591810190615c57565b60015b61259057604051634c9c8ce360e01b81526001600160a01b0383166004820152602401610fc9565b5f80516020615e8f83398151915281146125c057604051632a87526960e21b815260048101829052602401610fc9565b610dee8383613673565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611c6e5760405163703e46dd60e11b815260040160405180910390fd5b6040805160018082528183019092525f916020808301908036833750506040805160018082528183019092529293505f9291506020808301908036833701905050905083825f81518110612669576126696158f1565b60200260200101818152505082815f81518110612688576126886158f1565b602002602001018181525050610e29855f84846136c8565b5f80516020615e4f83398151915280610dee8382615a68565b5f6126c2611897565b6126cb426138e7565b6126d59190615c6e565b90506126e1828261391d565b60405165ffffffffffff821681526001600160a01b038316907f3377dc44241e779dd06afab5b788a35ca5f3b778836e2990bdb26a2a4b2e5ed6906020015b60405180910390a25050565b5f612736826139a7565b61273f426138e7565b6127499190615c6e565b90506127558282613110565b6040805165ffffffffffff8085168252831660208201527ff1038c18cf84a56e432fdbfaf746924b7ea511dfe03a6506a0ceba4888788d9b910160405180910390a15050565b6001600160a01b0383166127c357604051626a0d4560e21b81525f6004820152602401610fc9565b610dee835f848460405180602001604052805f8152506132aa565b5f80516020615f6f8339815191526127f584613567565b6127fe82613599565b5f83815260018201602052604081205490819003612832576040516384e7368960e01b815260048101859052602401610fc9565b5f61283d8483615958565b905080341015612877576040516301b1e28360e21b8152600481018690526024810185905260448101829052346064820152608401610fc9565b803411156128b457336108fc61288d8334615c8d565b6040518115909202915f818181858888f193505050501580156128b2573d5f803e3d5ffd5b505b82546040516001600160a01b039091169082156108fc029083905f818181858888f193505050501580156128ea573d5f803e3d5ffd5b50610fdf86868684613616565b6001600160a01b03841661292057604051632bfa23e760e11b81525f6004820152602401610fc9565b60408051600180825260208201869052818301908152606082018590526080820190925290610fdf5f878484876132aa565b6001600160a01b0381165f9081525f80516020615e2f833981519152602081905260409091205460ff16612984575050565b6001600160a01b0382165f908152602082905260408120805460ff191690555b6001820154811015612aa257826001600160a01b03168260010182815481106129cf576129cf6158f1565b5f918252602090912001546001600160a01b031603612a9a576001808301805490916129fa91615c8d565b81548110612a0a57612a0a6158f1565b5f918252602090912001546001830180546001600160a01b039092169183908110612a3757612a376158f1565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555081600101805480612a7557612a75615944565b5f8281526020902081015f1990810180546001600160a01b0319169055019055612aa2565b6001016129a4565b506040517f7d2be5e40a0d45d9af5c7db1fc1fa7822674e1d5f550082d32be1b8bf80c015f906001600160a01b038416907f233494033cad48d751b00c55d58da5f087d21031a3859563c7b6a7f3a2ccf04d905f90a35050565b612b04612093565b5f80516020615f2f833981519152805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833612075565b5f8181527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff6036020526040902080546060915f80516020615f6f833981519152916001600160401b03811115612b9b57612b9b615003565b604051908082528060200260200182016040528015612bdf57816020015b604080518082019091525f8082526020820152815260200190600190039081612bb95790505b5092505f5b8154811015612c71575f828281548110612c0057612c006158f1565b5f91825260208083209091015488835260028701825260408084206001600160a01b03909216808552918352928390205483518085019094528184529183018290528751909350909190879085908110612c5c57612c5c6158f1565b60209081029190910101525050600101612be4565b505050919050565b5f80516020615ecf8339815191526001600160a01b038316612caf5760405162ced3e160e81b81525f6004820152602401610fc9565b6001600160a01b038481165f818152600184016020908152604080832094881680845294825291829020805460ff191687151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3191015b60405180910390a350505050565b5f80516020615eaf8339815191525f80612d37611951565b91509150612d4c8165ffffffffffff16151590565b1580612d6057504265ffffffffffff821610155b15612d88576040516319ca5ebb60e01b815265ffffffffffff82166004820152602401610fc9565b612d995f612d946116b0565b6134da565b50612da45f8361346e565b505081546001600160d01b03191690915550565b5f8181527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff6016020526040812054905f80516020615f6f83398151915290829003610e74576040516384e7368960e01b815260048101849052602401610fc9565b612e2182610e30565b612e2a81611c5a565b6111a183836134da565b611c6e5f8061391d565b5f80516020615f6f8339815191526001600160a01b038216612e7e576040516334d5d27d60e21b81526001600160a01b0383166004820152602401610fc9565b80546001600160a01b0319166001600160a01b03831690811782556040513381527f4ab5be82436d353e61ca18726e984e561f5c1cc7c6d38b29d2553c790434705a90602001612720565b6001600160a01b038416612ef257604051632bfa23e760e11b81525f6004820152602401610fc9565b6001600160a01b038516612f1a57604051626a0d4560e21b81525f6004820152602401610fc9565b60408051600180825260208201869052818301908152606082018590526080820190925290612f4c87878484876132aa565b50505050505050565b6001600160a01b038116612f8757604051634726455360e11b81526001600160a01b0382166004820152602401610fc9565b6001600160a01b0381165f9081525f80516020615e2f833981519152602081905260409091205460ff1615612fba575050565b6001600160a01b0382165f81815260208381526040808320805460ff1916600190811790915585810180549182018155845291832090910180546001600160a01b03191684179055517f6f58fc3760b5743cf76087dfed697597f39c204c204718113b3ee0e4d995fc3b92917f233494033cad48d751b00c55d58da5f087d21031a3859563c7b6a7f3a2ccf04d91a35050565b6001600160a01b03831661307557604051626a0d4560e21b81525f6004820152602401610fc9565b604080516001808252602082018590528183019081526060820184905260a082019092525f60808201818152919291610e29918791859085906132aa565b5f6001600160e01b03198216637965db0b60e01b1480610d8b5750610d8b826139ee565b6130e182826116d9565b61100f5760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610fc9565b5f80516020615f4f833981519152545f80516020615eaf83398151915290600160d01b900465ffffffffffff1680156131aa574265ffffffffffff8216101561318157600182015482546001600160d01b0316600160a01b90910465ffffffffffff16600160d01b021782556131aa565b6040517f2b1fa2edafe6f7b9e97c1a9e0c3660e645beb2dcaa2d45bdbf9beaf5472e1ec5905f90a15b5060010180546001600160a01b0316600160a01b65ffffffffffff948516026001600160d01b031617600160d01b9290931691909102919091179055565b7f88be536d5240c274a3b1d3a1be54482fd9caa294f08c62a7cde569f49a3c450280546060915f80516020615ecf833981519152916132269061596f565b80601f01602080910402602001604051908101604052809291908181526020018280546132529061596f565b801561329d5780601f106132745761010080835404028352916020019161329d565b820191905f5260205f20905b81548152906001019060200180831161328057829003601f168201915b5050505050915050919050565b6132b685858585613a3d565b6001600160a01b03841615610e2957825133906001036132ef57602084810151908401516132e8838989858589613d2a565b5050610fdf565b610fdf818787878787613e4b565b5f80516020615e6f83398151915280549081815f61331a83615919565b91905055505090565b5f8281527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff601602090815260409182902083905590518281525f80516020615f6f8339815191529184917fa12c47d56c27d127f5f74f842a31dcfca20ecb155635a6ec6cb060a39cac2b339101611df8565b5f5b818110156111a1576133eb848484848181106133b4576133b46158f1565b6133ca9260206040909202019081019150615686565b8585858181106133dc576133dc6158f1565b90506040020160200135613f32565b600101613396565b6133fb614197565b611c6e57604051631afcd79f60e31b815260040160405180910390fd5b6134206133f3565b610dbf816141b0565b6134316133f3565b611c6e6141c1565b6134416133f3565b61344b85856141f2565b613453614214565b61345c8361422c565b610e29828261423d565b611c6e6133f3565b5f5f80516020615eaf833981519152836134d0575f61348b6116b0565b6001600160a01b0316146134b257604051631fe1e13d60e11b815260040160405180910390fd5b6001810180546001600160a01b0319166001600160a01b0385161790555b611d7284846142a5565b5f5f80516020615eaf8339815191528315801561350f57506134fa6116b0565b6001600160a01b0316836001600160a01b0316145b15613527576001810180546001600160a01b03191690555b611d72848461434d565b5f80516020615f2f8339815191525460ff16611c6e57604051638dfc202b60e01b815260040160405180910390fd5b80825d5050565b6001600160a01b038116610dbf5760405163094293a160e31b81526001600160a01b0382166004820152602401610fc9565b805f03610dbf5760405163023d875560e41b815260048101829052602401610fc9565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526111a19085906143c6565b613621848484614432565b826001600160a01b0385167f0a9521815fb3c5bc7dd6f4c9f89dc270322e46b945b104c18981f81c3f2cd1aa33604080516001600160a01b039092168252602082018790528101859052606001612d11565b61367c8261444c565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156136c057610dee82826144af565b61100f614521565b805182515f80516020615ecf83398151915291146137065782518251604051635b05999160e01b815260048101929092526024820152604401610fc9565b335f5b8451811015613808576020818102868101820151908601909101516001600160a01b038916156137ba575f828152602086815260408083206001600160a01b038d16845290915290205481811015613794576040516303dee4c560e01b81526001600160a01b038b166004820152602481018290526044810183905260648101849052608401610fc9565b5f838152602087815260408083206001600160a01b038e16845290915290209082900390555b6001600160a01b038816156137fe575f828152602086815260408083206001600160a01b038c168452909152812080548392906137f8908490615931565b90915550505b5050600101613709565b5083516001036138885760208401515f906020850151909150866001600160a01b0316886001600160a01b0316846001600160a01b03167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628585604051613879929190918252602082015260400190565b60405180910390a45050610fdf565b846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb87876040516138d7929190615ca0565b60405180910390a4505050505050565b5f65ffffffffffff821115613919576040516306dfcc6560e41b81526030600482015260248101839052604401610fc9565b5090565b5f80516020615eaf8339815191525f613934611951565b835465ffffffffffff8616600160a01b026001600160d01b03199091166001600160a01b03881617178455915061397490508165ffffffffffff16151590565b156111a1576040517f8886ebfc4259abdbc16601dd8fb5678e54878f47b3c34836cfc51154a9605109905f90a150505050565b5f806139b1611897565b90508065ffffffffffff168365ffffffffffff16116139d9576139d48382615cc4565b610e71565b610e7165ffffffffffff841662069780614540565b5f6001600160e01b03198216636cdb3d1360e11b1480613a1e57506001600160e01b031982166303a24d0760e21b145b80610d8b57506301ffc9a760e01b6001600160e01b0319831614610d8b565b613a45612093565b6001600160a01b0384165f9081525f80516020615e2f833981519152602081905260409091205485919060ff1615613a9b576040516327951b3f60e11b81526001600160a01b0383166004820152602401610fc9565b6001600160a01b0385165f9081525f80516020615e2f833981519152602081905260409091205486919060ff1615613af1576040516327951b3f60e11b81526001600160a01b0383166004820152602401610fc9565b855f5b8151811015613b6157613b1f828281518110613b1257613b126158f1565b60200260200101516112ad565b613b5957818181518110613b3557613b356158f1565b602002602001015160405163b7c882eb60e01b8152600401610fc991815260200190565b600101613af4565b508888886001600160a01b03831615801590613b8557506001600160a01b03821615155b15613c34577fdaa3d1cf82c71b982a9e24ff7dadd71a10e8c3e82a219c0e60ca5c6b8e6177005f5b8251811015613c3157815f015f848381518110613bcc57613bcc6158f1565b60209081029190910181015182528101919091526040015f9081205460ff1615159003613c2957828181518110613c0557613c056158f1565b60200260200101516040516368ee0b2f60e11b8152600401610fc991815260200190565b600101613bad565b50505b8a6001600160a01b03168c6001600160a01b031603613c7157604051633ef2228f60e21b81526001600160a01b038d166004820152602401610fc9565b5f5b8951811015613cbd57898181518110613c8e57613c8e6158f1565b60200260200101515f03613cb5576040516323cf7d7d60e01b815260040160405180910390fd5b600101613c73565b505f5b8a51811015613d0f57613d078d8d8d8481518110613ce057613ce06158f1565b60200260200101518d8581518110613cfa57613cfa6158f1565b602002602001015161454f565b600101613cc0565b50613d1c8c8c8c8c6136c8565b505050505050505050505050565b6001600160a01b0384163b15610fdf5760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190613d6e9089908990889088908890600401615ce3565b6020604051808303815f875af1925050508015613da8575060408051601f3d908101601f19168201909252613da591810190615d27565b60015b613e0f573d808015613dd5576040519150601f19603f3d011682016040523d82523d5f602084013e613dda565b606091505b5080515f03613e0757604051632bfa23e760e11b81526001600160a01b0386166004820152602401610fc9565b805160208201fd5b6001600160e01b0319811663f23a6e6160e01b14612f4c57604051632bfa23e760e11b81526001600160a01b0386166004820152602401610fc9565b6001600160a01b0384163b15610fdf5760405163bc197c8160e01b81526001600160a01b0385169063bc197c8190613e8f9089908990889088908890600401615d42565b6020604051808303815f875af1925050508015613ec9575060408051601f3d908101601f19168201909252613ec691810190615d27565b60015b613ef6573d808015613dd5576040519150601f19603f3d011682016040523d82523d5f602084013e613dda565b6001600160e01b0319811663bc197c8160e01b14612f4c57604051632bfa23e760e11b81526001600160a01b0386166004820152602401610fc9565b6001600160a01b038216613f645760405163aac3232160e01b81526001600160a01b0383166004820152602401610fc9565b5f8381527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff602602090815260408083206001600160a01b038616845290915290208190555f80516020615f6f8339815191528115614054575f848152600382016020526040812090805b825481101561401c57856001600160a01b0316838281548110613ff257613ff26158f1565b5f918252602090912001546001600160a01b031603614014576001915061401c565b600101613fcd565b508061404d5781546001810183555f838152602090200180546001600160a01b0319166001600160a01b0387161790555b505061415b565b5f8481526003820160205260408120905b815481101561415857846001600160a01b031682828154811061408a5761408a6158f1565b5f918252602090912001546001600160a01b03160361415057815482906140b390600190615c8d565b815481106140c3576140c36158f1565b905f5260205f20015f9054906101000a90046001600160a01b03168282815481106140f0576140f06158f1565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055508180548061412b5761412b615944565b5f8281526020902081015f1990810180546001600160a01b0319169055019055614158565b600101614065565b50505b826001600160a01b0316847ffb08de1e404ab196167a5843d6f4552a93056ed1da04e2f6c958dc6c63f1e4b484604051612d1191815260200190565b5f6141a0611f31565b54600160401b900460ff16919050565b6141b86133f3565b610dbf816145c3565b6141c96133f3565b60408051602081019091525f81525f80516020615e4f83398151915290819061100f9082615a68565b6141fa6133f3565b61420482826145fc565b61420c61460e565b61100f613466565b61421c6133f3565b614224613466565b611c6e61461e565b6142346133f3565b610dbf81614639565b6142456133f3565b5f5b81811015610dee5761429c838383818110614264576142646158f1565b9050604002015f013584848481811061427f5761427f6158f1565b90506040020160200160208101906142979190615686565b61346e565b50600101614247565b5f5f80516020615eef8339815191526142be84846116d9565b61433d575f848152602082815260408083206001600160a01b03871684529091529020805460ff191660011790556142f33390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a46001915050610d8b565b5f915050610d8b565b5092915050565b5f5f80516020615eef83398151915261436684846116d9565b1561433d575f848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a46001915050610d8b565b5f8060205f8451602086015f885af1806143e5576040513d5f823e3d81fd5b50505f513d915081156143fc578060011415614409565b6001600160a01b0384163b155b156111a157604051635274afe760e01b81526001600160a01b0385166004820152602401610fc9565b610dee83838360405180602001604052805f8152506128f7565b806001600160a01b03163b5f0361448157604051634c9c8ce360e01b81526001600160a01b0382166004820152602401610fc9565b5f80516020615e8f83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80846001600160a01b0316846040516144cb9190615d9f565b5f60405180830381855af49150503d805f8114614503576040519150601f19603f3d011682016040523d82523d5f602084013e614508565b606091505b509150915061451885838361464a565b95945050505050565b3415611c6e5760405163b398979f60e01b815260040160405180910390fd5b5f828218828410028218610d9c565b6001600160a01b0384166145805761456783836112ea565b61457b8383836145768661469f565b61471a565b6111a1565b6001600160a01b0383166145a357614599848383614a43565b61457b84836112ea565b6145ad83836112ea565b6145b984848484614bf6565b6111a184836112ea565b5f80516020615ecf8339815191527f88be536d5240c274a3b1d3a1be54482fd9caa294f08c62a7cde569f49a3c4502610dee8382615a68565b6146046133f3565b61100f8282614e03565b6146166133f3565b611c6e613466565b6146266133f3565b60015f80516020615e6f83398151915255565b6146416133f3565b610dbf81612e3e565b60608261465f5761465a82614e69565b610d9c565b815115801561467657506001600160a01b0384163b155b1561434657604051639996b31560e01b81526001600160a01b0385166004820152602401610fc9565b5f806146aa836117be565b9050805f036146bc57505f1992915050565b5f6146c78242615931565b90505f6146d5606484615dba565b9050805f036146e2575060015b5f8160016146f08286615931565b6146fa9190615c8d565b6147049190615dba565b90506147108282615958565b9695505050505050565b6001600160a01b0384165f9081525f80516020615e0f8339815191526020818152604080842087855290915282208054919290919081905b828110156148565783818154811061476c5761476c6158f1565b905f5260205f2090600202015f01545f1480156147a95750838181548110614796576147966158f1565b905f5260205f209060020201600101545f145b156147b657809150614856565b858482815481106147c9576147c96158f1565b905f5260205f209060020201600101540361481d57868482815481106147f1576147f16158f1565b905f5260205f2090600202015f015f82825461480d9190615931565b909155506111a195505050505050565b85848281548110614830576148306158f1565b905f5260205f20906002020160010154111561484e57809150614856565b600101614752565b5081811061489a576040805180820190915286815260208082018781528554600181810188555f888152939093209351600290910290930192835551910155611570565b8281815481106148ac576148ac6158f1565b905f5260205f2090600202015f01545f1480156148e957508281815481106148d6576148d66158f1565b905f5260205f209060020201600101545f145b1561493857604051806040016040528087815260200186815250838281548110614915576149156158f1565b5f9182526020918290208351600290920201908155910151600190910155611570565b604080518082019091525f80825260208083018281528654600181810189558885529284209451600290910290940193845551928101929092558454909161497f91615c8d565b90505b818111156149f35783614996600183615c8d565b815481106149a6576149a66158f1565b905f5260205f2090600202018482815481106149c4576149c46158f1565b5f91825260209091208254600290920201908155600191820154910155806149eb81615dd9565b915050614982565b50604051806040016040528087815260200186815250838281548110614a1b57614a1b6158f1565b5f91825260209182902083516002909202019081559101516001909101555050505050505050565b6001600160a01b0383165f9081525f80516020615e0f83398151915260208181526040808420868552909152822080549192909184914291905b8181108015614a8b57505f84115b15614bac5782858281548110614aa357614aa36158f1565b905f5260205f20906002020160010154111580614adf5750848181548110614acd57614acd6158f1565b905f5260205f2090600202015f01545f145b614b9a5783858281548110614af657614af66158f1565b905f5260205f2090600202015f01541115614b485783858281548110614b1e57614b1e6158f1565b905f5260205f2090600202015f015f828254614b3a9190615c8d565b909155505f9450614b9a9050565b848181548110614b5a57614b5a6158f1565b905f5260205f2090600202015f015484614b749190615c8d565b93505f858281548110614b8957614b896158f1565b5f9182526020909120600290910201555b80614ba481615919565b915050614a7d565b5082156115705787614bbe8488615c8d565b60405163670f004560e01b81526001600160a01b03909216600483015260248201526044810187905260648101889052608401610fc9565b826001600160a01b0316846001600160a01b03161480614c14575080155b6111a1576001600160a01b0384165f9081525f80516020615e0f83398151915260208181526040808420868552909152822080549192909184914291905b8181108015614c6057505f84115b15614de65782858281548110614c7857614c786158f1565b905f5260205f20906002020160010154111580614cb45750848181548110614ca257614ca26158f1565b905f5260205f2090600202015f01545f145b614dd45783858281548110614ccb57614ccb6158f1565b905f5260205f2090600202015f01541115614d4a57614d0d898986888581548110614cf857614cf86158f1565b905f5260205f2090600202016001015461471a565b83858281548110614d2057614d206158f1565b905f5260205f2090600202015f015f828254614d3c9190615c8d565b909155505f9450614dd49050565b614d828989878481548110614d6157614d616158f1565b905f5260205f2090600202015f0154888581548110614cf857614cf86158f1565b848181548110614d9457614d946158f1565b905f5260205f2090600202015f015484614dae9190615c8d565b93505f858281548110614dc357614dc36158f1565b5f9182526020909120600290910201555b80614dde81615919565b915050614c52565b508215614df85788614bbe8488615c8d565b505050505050505050565b614e0b6133f3565b5f80516020615eaf8339815191526001600160a01b038216614e4257604051636116401160e11b81525f6004820152602401610fc9565b80546001600160d01b0316600160d01b65ffffffffffff8516021781556111a15f8361346e565b805115614e7857805160208201fd5b60405163d6bda27560e01b815260040160405180910390fd5b60405180604001604052805f8152602001614ecc60405180608001604052805f8152602001606081526020015f81526020015f151581525090565b905290565b6001600160a01b0381168114610dbf575f80fd5b5f8060408385031215614ef6575f80fd5b8235614f0181614ed1565b946020939093013593505050565b602080825282518282018190525f919060409081850190868401855b82811015614f5057815180518552860151868501529284019290850190600101614f2b565b5091979650505050505050565b6001600160e01b031981168114610dbf575f80fd5b5f60208284031215614f82575f80fd5b8135610d9c81614f5d565b5f60208284031215614f9d575f80fd5b5035919050565b5f5b83811015614fbe578181015183820152602001614fa6565b50505f910152565b5f8151808452614fdd816020860160208601614fa4565b601f01601f19169290920160200192915050565b602081525f610d9c6020830184614fc6565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b038111828210171561503f5761503f615003565b604052919050565b5f82601f830112615056575f80fd5b81356001600160401b0381111561506f5761506f615003565b615082601f8201601f1916602001615017565b818152846020838601011115615096575f80fd5b816020850160208301375f918101602001919091529392505050565b5f80604083850312156150c3575f80fd5b8235915060208301356001600160401b038111156150df575f80fd5b6150eb85828601615047565b9150509250929050565b5f6001600160401b0382111561510d5761510d615003565b5060051b60200190565b5f82601f830112615126575f80fd5b8135602061513b615136836150f5565b615017565b8083825260208201915060208460051b87010193508684111561515c575f80fd5b602086015b848110156151785780358352918301918301615161565b509695505050505050565b5f805f8060808587031215615196575f80fd5b84356151a181614ed1565b935060208501356001600160401b03808211156151bc575f80fd5b6151c888838901615117565b945060408701359150808211156151dd575f80fd5b6151e988838901615117565b935060608701359150808211156151fe575f80fd5b5061520b87828801615047565b91505092959194509250565b5f60808284031215610e74575f80fd5b5f60208284031215615237575f80fd5b81356001600160401b0381111561524c575f80fd5b611d7284828501615217565b803565ffffffffffff8116811461526d575f80fd5b919050565b5f805f805f8060a08789031215615287575f80fd5b61529087615258565b955060208701356152a081614ed1565b945060408701356152b081614ed1565b935060608701356001600160401b03808211156152cb575f80fd5b818901915089601f8301126152de575f80fd5b8135818111156152ec575f80fd5b8a60208260061b8501011115615300575f80fd5b60208301955080945050608089013591508082111561531d575f80fd5b5061532a89828a01615047565b9150509295509295509295565b5f805f805f60a0868803121561534b575f80fd5b853561535681614ed1565b9450602086013561536681614ed1565b935060408601356001600160401b0380821115615381575f80fd5b61538d89838a01615117565b945060608801359150808211156153a2575f80fd5b6153ae89838a01615117565b935060808801359150808211156153c3575f80fd5b506153d088828901615047565b9150509295509295909350565b5f80604083850312156153ee575f80fd5b82359150602083013561540081614ed1565b809150509250929050565b5f815180845260208085019450602084015f5b8381101561544e57815180516001600160a01b03168852830151838801526040909601959082019060010161541e565b509495945050505050565b60208152815160208201525f602083015160408084015280516060840152602081015160808085015261548f60e085018261540b565b604083015160a0860152606090920151151560c0909401939093529392505050565b5f805f80608085870312156154c4575f80fd5b84356154cf81614ed1565b935060208501356154df81614ed1565b93969395505050506040820135916060013590565b5f8060408385031215615505575f80fd5b8235915060208301356001600160401b03811115615521575f80fd5b6150eb85828601615217565b5f806040838503121561553e575f80fd5b82356001600160401b0380821115615554575f80fd5b818501915085601f830112615567575f80fd5b81356020615577615136836150f5565b82815260059290921b84018101918181019089841115615595575f80fd5b948201945b838610156155bc5785356155ad81614ed1565b8252948201949082019061559a565b965050860135925050808211156155d1575f80fd5b506150eb85828601615117565b5f815180845260208085019450602084015f5b8381101561544e578151875295820195908201906001016155f1565b602081525f610d9c60208301846155de565b5f8060408385031215615630575f80fd5b823561563b81614ed1565b915060208301356001600160401b038111156150df575f80fd5b5f60208284031215615665575f80fd5b81356001600160401b0381111561567a575f80fd5b611d7284828501615047565b5f60208284031215615696575f80fd5b8135610d9c81614ed1565b5f602082840312156156b1575f80fd5b610d9c82615258565b5f805f606084860312156156cc575f80fd5b83356156d781614ed1565b925060208401356001600160401b03808211156156f2575f80fd5b6156fe87838801615117565b93506040860135915080821115615713575f80fd5b5061572086828701615117565b9150509250925092565b5f805f6060848603121561573c575f80fd5b833561574781614ed1565b95602085013595506040909401359392505050565b5f806040838503121561576d575f80fd5b50508035926020909101359150565b5f805f806080858703121561578f575f80fd5b843561579a81614ed1565b9350602085013592506040850135915060608501356001600160401b038111156157c2575f80fd5b61520b87828801615047565b602081525f610d9c602083018461540b565b8035801515811461526d575f80fd5b5f8060408385031215615800575f80fd5b823561580b81614ed1565b9150615819602084016157e0565b90509250929050565b602080825282518282018190525f9190848201906040850190845b81811015611c2a5783516001600160a01b03168352928401929184019160010161583d565b5f8060408385031215615873575f80fd5b823561587e81614ed1565b9150602083013561540081614ed1565b5f805f805f60a086880312156158a2575f80fd5b85356158ad81614ed1565b945060208601356158bd81614ed1565b9350604086013592506060860135915060808601356001600160401b038111156158e5575f80fd5b6153d088828901615047565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f6001820161592a5761592a615905565b5060010190565b80820180821115610d8b57610d8b615905565b634e487b7160e01b5f52603160045260245ffd5b8082028115828204841417610d8b57610d8b615905565b600181811c9082168061598357607f821691505b602082108103610e7457634e487b7160e01b5f52602260045260245ffd5b5f8084546159ae8161596f565b600182811680156159c657600181146159db57615a07565b60ff1984168752821515830287019450615a07565b885f526020805f205f5b858110156159fe5781548a8201529084019082016159e5565b50505082870194505b505050508351615a1b818360208801614fa4565b01949350505050565b601f821115610dee57805f5260205f20601f840160051c81016020851015615a495750805b601f840160051c820191505b81811015610e29575f8155600101615a55565b81516001600160401b03811115615a8157615a81615003565b615a9581615a8f845461596f565b84615a24565b602080601f831160018114615ac8575f8415615ab15750858301515b5f19600386901b1c1916600185901b178555610fdf565b5f85815260208120601f198616915b82811015615af657888601518255948401946001909101908401615ad7565b5085821015615b1357878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f808335601e19843603018112615b38575f80fd5b8301803591506001600160401b03821115615b51575f80fd5b6020019150600681901b3603821315615b68575f80fd5b9250929050565b5f60208284031215615b7f575f80fd5b610d9c826157e0565b8183525f60208085019450825f5b8581101561544e578135615ba981614ed1565b6001600160a01b03168752818301358388015260409687019690910190600101615b96565b60208152813560208201525f6020830135601e19843603018112615bf0575f80fd5b83016020810190356001600160401b03811115615c0b575f80fd5b8060061b3603821315615c1c575f80fd5b60806040850152615c3160a085018284615b88565b91505060408401356060840152615c4a606085016157e0565b801515608085015261128a565b5f60208284031215615c67575f80fd5b5051919050565b65ffffffffffff81811683821601908082111561434657614346615905565b81810381811115610d8b57610d8b615905565b604081525f615cb260408301856155de565b828103602084015261451881856155de565b65ffffffffffff82811682821603908082111561434657614346615905565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190525f90615d1c90830184614fc6565b979650505050505050565b5f60208284031215615d37575f80fd5b8151610d9c81614f5d565b6001600160a01b0386811682528516602082015260a0604082018190525f90615d6d908301866155de565b8281036060840152615d7f81866155de565b90508281036080840152615d938185614fc6565b98975050505050505050565b5f8251615db0818460208701614fa4565b9190910192915050565b5f82615dd457634e487b7160e01b5f52601260045260245ffd5b500490565b5f81615de757615de7615905565b505f19019056fe74f7a545c65c11839a48d7453738b30c295408df2d944516167556759ddc6d06ec3c1253ecdf88a29ff53024f0721fc3faa1b42abcff612deb5b22d1f94e2d00a095fe5a3c31691ae0832631cef3701285d36b2af1972f4c23463476b0353a0089fc852226e759c7c636cf34d732f0198fc56a54876b2374a52beb7b0c558600591f2d2df77efc80b9969dfd51dd4fc103fe490745902503f7c21df07a35d600360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbceef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840088be536d5240c274a3b1d3a1be54482fd9caa294f08c62a7cde569f49a3c450002dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680046f3eccdd88dd62792ae8eed1be7b9b658477566c49fd85b0d08cf44261c9208cd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300eef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840154c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff600a26469706673582212201f4e2a8c834bf6bd9f6e25be58686fda947c7b4bbc77051399ade30957ff82a064736f6c63430008180033 diff --git a/src/EVMAuth1155.sol b/src/EVMAuth1155.sol index 09bc510..8868d13 100644 --- a/src/EVMAuth1155.sol +++ b/src/EVMAuth1155.sol @@ -162,6 +162,15 @@ contract EVMAuth1155 is ERC1155URIStorageUpgradeable, EVMAuth { _setURI(id, tokenURI); } + /// @inheritdoc TokenEphemeral + function _burnPrunedTokens(address account, uint256 id, uint256 amount) internal virtual override { + uint256[] memory ids = new uint256[](1); + uint256[] memory values = new uint256[](1); + ids[0] = id; + values[0] = amount; + super._update(account, address(0), ids, values); + } + /// @inheritdoc TokenPurchasable function _mintPurchasedTokens(address to, uint256 id, uint256 amount) internal virtual override { _mint(to, id, amount, ""); diff --git a/src/EVMAuth6909.abi b/src/EVMAuth6909.abi index 1e75855..6c30669 100644 --- a/src/EVMAuth6909.abi +++ b/src/EVMAuth6909.abi @@ -598,30 +598,6 @@ "outputs": [], "stateMutability": "nonpayable" }, - { - "type": "function", - "name": "isAcceptedERC20PaymentToken", - "inputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "paymentToken", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, { "type": "function", "name": "isFrozen", @@ -1668,6 +1644,31 @@ ], "anonymous": false }, + { + "type": "event", + "name": "ExpiredTokensPruned", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "id", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, { "type": "event", "name": "Initialized", diff --git a/src/EVMAuth6909.bin b/src/EVMAuth6909.bin index 8f3f7a4..d9fe9c1 100644 --- a/src/EVMAuth6909.bin +++ b/src/EVMAuth6909.bin @@ -1 +1 @@ -0x60a060405230608052348015610013575f80fd5b506080516157986200003b5f395f81816124d0015281816124f9015261265a01526157985ff3fe608060405260043610610413575f3560e01c806379c44ca211610220578063c87b56dd11610129578063d9a5260e116100b3578063f101e48111610078578063f101e48114610d42578063f26c159f14610d62578063f5298aca14610d81578063fe99049a14610da0578063febbd07014610dbf575f80fd5b8063d9a5260e14610c7a578063e583983614610c99578063e8a3d48514610cdc578063f0a3a97c14610cf0578063f0f4426014610d23575f80fd5b8063d2c7db1c116100f9578063d2c7db1c14610bd4578063d4ddce8a14610bf5578063d539139314610c14578063d547741f14610c47578063d602b9fd14610c66575f80fd5b8063c87b56dd14610b53578063cc8463c814610b72578063cefc142914610b86578063cf6eefb714610b9a575f80fd5b8063a217fddf116101aa578063b25645691161017a578063b256456914610aa3578063b6363cf214610ac2578063c0a2103414610ae1578063c2840e6014610b14578063c55be5d014610b34575f80fd5b8063a217fddf14610a21578063a3b546f214610a34578063a5a2a64514610a54578063ad3cb1cc14610a73575f80fd5b806391d14854116101f057806391d1485414610970578063938e3d7b1461098f5780639526c2d9146109ae578063994757c5146109c2578063a1eda53c146109ee575f80fd5b806379c44ca2146109015780638456cb591461093457806384ef8ffc146109485780638da5cb5b1461095c575f80fd5b806343ffa64e11610322578063558a7297116102ac578063634e93da1161027c578063634e93da1461087e578063649a5ec71461089d5780636d51282c146108bc57806370876c98146108cf578063788649ea146108e2575f80fd5b8063558a7297146107e0578063598af9e7146107ff5780635c975abb1461081e57806361d027b314610841575f80fd5b80634e41a1fb116102f25780634e41a1fb1461075c5780634f1ef2861461077b5780634f558e791461078e57806352d1902d146107ad57806354efdcf6146107c1575f80fd5b806343ffa64e146106bf578063440e806e146106f257806345cc05a01461071e57806347aa3a2e1461073d575f80fd5b8063248a9ca3116103a35780632f2ff15d116103735780632f2ff15d146105ff57806336568abe1461061e5780633f47e6621461063d5780633f4ba83a1461068c578063426a8493146106a0575f80fd5b8063248a9ca31461056f57806327276d981461058e578063282c51f3146105ad5780632d99179e146105e0575f80fd5b8063022d63fb116103e9578063022d63fb146104d4578063095bcdb6146104fc5780630aa6220b1461051b578063156e29f614610531578063162094c414610550575f80fd5b8062ad800c14610417578062e6449d1461044c578062fdd58e1461047857806301ffc9a7146104a5575b5f80fd5b348015610422575f80fd5b50610436610431366004614ae1565b610e21565b6040516104439190614b1a565b60405180910390f35b348015610457575f80fd5b5061046b610466366004614b60565b610ed1565b6040516104439190614b8a565b348015610483575f80fd5b50610497610492366004614b60565b610f6d565b604051908152602001610443565b3480156104b0575f80fd5b506104c46104bf366004614bd8565b610f7f565b6040519015158152602001610443565b3480156104df575f80fd5b50620697805b60405165ffffffffffff9091168152602001610443565b348015610507575f80fd5b506104c4610516366004614bff565b610f89565b348015610526575f80fd5b5061052f610fa0565b005b34801561053c575f80fd5b5061052f61054b366004614bff565b610fb5565b34801561055b575f80fd5b5061052f61056a366004614cd5565b610ff0565b34801561057a575f80fd5b50610497610589366004614ae1565b611016565b348015610599575f80fd5b506104976105a8366004614d28565b611036565b3480156105b8575f80fd5b506104977f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84881565b3480156105eb575f80fd5b5061052f6105fa366004614d73565b611060565b34801561060a575f80fd5b5061052f610619366004614e38565b611161565b348015610629575f80fd5b5061052f610638366004614e38565b61118d565b348015610648575f80fd5b5061067a610657366004614ae1565b5f9081525f805160206155a3833981519152602052604090206002015460ff1690565b60405160ff9091168152602001610443565b348015610697575f80fd5b5061052f61124f565b3480156106ab575f80fd5b506104c46106ba366004614bff565b61126e565b3480156106ca575f80fd5b506104977fa76ace73a908083d89af9ff88e5b4f7cadb3591a80631063f68b695fda726db581565b3480156106fd575f80fd5b5061071161070c366004614ae1565b61127b565b6040516104439190614eb4565b348015610729575f80fd5b5061052f610738366004614f0c565b611309565b348015610748575f80fd5b5061052f610757366004614f4f565b61132d565b348015610767575f80fd5b50610436610776366004614ae1565b61134e565b61052f610789366004614f88565b61137d565b348015610799575f80fd5b506104c46107a8366004614ae1565b611398565b3480156107b8575f80fd5b506104976113ba565b3480156107cc575f80fd5b5061052f6107db366004614b60565b6113d5565b3480156107eb575f80fd5b506104c46107fa366004614fec565b6115e3565b34801561080a575f80fd5b5061049761081936600461501f565b6115f8565b348015610829575f80fd5b505f805160206157038339815191525460ff166104c4565b34801561084c575f80fd5b505f80516020615743833981519152546001600160a01b03165b6040516001600160a01b039091168152602001610443565b348015610889575f80fd5b5061052f61089836600461505d565b611648565b3480156108a8575f80fd5b5061052f6108b7366004615078565b61165b565b61052f6108ca366004614bff565b61166e565b61052f6108dd366004615091565b611691565b3480156108ed575f80fd5b5061052f6108fc36600461505d565b6116b4565b34801561090c575f80fd5b506104977f6f58fc3760b5743cf76087dfed697597f39c204c204718113b3ee0e4d995fc3b81565b34801561093f575f80fd5b5061052f6116d4565b348015610953575f80fd5b506108666116f3565b348015610967575f80fd5b5061086661170e565b34801561097b575f80fd5b506104c461098a366004614e38565b61171c565b34801561099a575f80fd5b5061052f6109a93660046150b1565b611752565b3480156109b9575f80fd5b50610497606481565b3480156109cd575f80fd5b506109e16109dc366004614ae1565b611772565b60405161044391906150e2565b3480156109f9575f80fd5b50610a026117a7565b6040805165ffffffffffff938416815292909116602083015201610443565b348015610a2c575f80fd5b506104975f81565b348015610a3f575f80fd5b506104975f805160206156e383398151915281565b348015610a5f575f80fd5b50610497610a6e366004614ae1565b611816565b348015610a7e575f80fd5b50610436604051806040016040528060058152602001640352e302e360dc1b81525081565b348015610aae575f80fd5b506104c4610abd366004614ae1565b611873565b348015610acd575f80fd5b506104c4610adc3660046150f4565b6118d3565b348015610aec575f80fd5b506104977f7d2be5e40a0d45d9af5c7db1fc1fa7822674e1d5f550082d32be1b8bf80c015f81565b348015610b1f575f80fd5b506104975f805160206155c383398151915281565b348015610b3f575f80fd5b5061052f610b4e366004614bff565b61191f565b348015610b5e575f80fd5b50610436610b6d366004614ae1565b61193b565b348015610b7d575f80fd5b506104e5611984565b348015610b91575f80fd5b5061052f6119ff565b348015610ba5575f80fd5b50610bae611a3e565b604080516001600160a01b03909316835265ffffffffffff909116602083015201610443565b348015610bdf575f80fd5b50610be8611a6b565b6040516104439190615120565b348015610c00575f80fd5b50610497610c0f366004614ae1565b611ada565b348015610c1f575f80fd5b506104977f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b348015610c52575f80fd5b5061052f610c61366004614e38565b611b0e565b348015610c71575f80fd5b5061052f611b36565b348015610c85575f80fd5b5061052f610c94366004615160565b611b48565b348015610ca4575f80fd5b506104c4610cb336600461505d565b6001600160a01b03165f9081525f80516020615623833981519152602052604090205460ff1690565b348015610ce7575f80fd5b50610436611b84565b348015610cfb575f80fd5b506104977f3496e2e73c4d42b75d702e60d9e48102720b8691234415963a5a857b86425d0781565b348015610d2e575f80fd5b5061052f610d3d36600461505d565b611c1c565b348015610d4d575f80fd5b505f8051602061566383398151915254610497565b348015610d6d575f80fd5b5061052f610d7c36600461505d565b611c4f565b348015610d8c575f80fd5b5061052f610d9b366004614bff565b611c6f565b348015610dab575f80fd5b506104c4610dba366004614f0c565b611ca4565b348015610dca575f80fd5b506104c4610dd9366004614e38565b5f9182527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff602602090815260408084206001600160a01b03939093168452919052902054151590565b5f8181525f805160206155a38339815191526020819052604090912080546060929190610e4d906151df565b80601f0160208091040260200160405190810160405280929190818152602001828054610e79906151df565b8015610ec45780601f10610e9b57610100808354040283529160200191610ec4565b820191905f5260205f20905b815481529060010190602001808311610ea757829003601f168201915b5050505050915050919050565b6001600160a01b0382165f9081525f805160206155e3833981519152602081815260408084208585528252808420805482518185028101850190935280835260609592939192909184015b82821015610f5f578382905f5260205f2090600202016040518060400160405290815f820154815260200160018201548152505081526020019060010190610f1c565b505050509150505b92915050565b5f610f788383611cef565b9392505050565b5f610f6782611d97565b5f610f9633858585611dbb565b5060019392505050565b5f610faa81611e19565b610fb2611e23565b50565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6610fdf81611e19565b610fea848484611e2f565b50505050565b5f805160206155c383398151915261100781611e19565b6110118383611e64565b505050565b5f9081525f805160206156c3833981519152602052604090206001015490565b5f5f805160206155c383398151915261104e81611e19565b61105783611ee7565b91505b50919050565b5f611069611f77565b805490915060ff600160401b82041615906001600160401b03165f8115801561108f5750825b90505f826001600160401b031660011480156110aa5750303b155b9050811580156110b8575080155b156110d65760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561110057845460ff60401b1916600160401b1785555b61110e8b8b8b8b8b8b611f9f565b831561115457845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050505050565b8161117f57604051631fe1e13d60e11b815260040160405180910390fd5b6111898282611fc5565b5050565b5f805160206156a3833981519152821580156111c157506111ac6116f3565b6001600160a01b0316826001600160a01b0316145b15611245575f806111d0611a3e565b90925090506001600160a01b0382161515806111f2575065ffffffffffff8116155b8061120557504265ffffffffffff821610155b15611232576040516319ca5ebb60e01b815265ffffffffffff821660048201526024015b60405180910390fd5b5050805465ffffffffffff60a01b191681555b6110118383611fe1565b5f805160206156e383398151915261126681611e19565b610fb2612014565b5f610f9633858585612073565b611283614aa1565b8161128d81611398565b6112ad5760405163b7c882eb60e01b815260048101829052602401611229565b604051806040016040528084815260200160405180608001604052806112d287611ada565b81526020016112e087611772565b81526020016112ee87611816565b81526020016112fc87611873565b1515905290529392505050565b611311612143565b611319612173565b611325848484846121e0565b610fea612403565b5f805160206155c383398151915261134481611e19565b611011838361242d565b5f8181525f805160206155a38339815191526020819052604090912060010180546060929190610e4d906151df565b6113856124c5565b61138e82612569565b6111898282612593565b5f5f805160206156638339815191528215801590611057575054909110919050565b5f6113c361264f565b505f8051602061568383398151915290565b6001600160a01b0382165f9081525f805160206155e3833981519152602081815260408084208585529091528220805491929091429190815b818110156114da575f8086838154811061142a5761142a615211565b905f5260205f2090600202015f015411801561146657508486838154811061145457611454615211565b905f5260205f20906002020160010154115b905080156114d1578382146114c35785828154811061148757611487615211565b905f5260205f2090600202018685815481106114a5576114a5615211565b5f918252602090912082546002909202019081556001918201549101555b836114cd81615239565b9450505b5060010161140e565b50815b818110156115305760405180604001604052805f81526020015f81525085828154811061150c5761150c615211565b5f9182526020918290208351600290920201908155910151600191820155016114dd565b508115801561153e57505f81115b15611581575b83541561157c578380548061155b5761155b615251565b5f8281526020812060025f1990930192830201818155600101559055611544565b6115da565b61158c826002615265565b8111801561159a5750600a81115b156115da575b83548210156115da57838054806115b9576115b9615251565b5f8281526020812060025f19909301928302018181556001015590556115a0565b50505050505050565b5f6115ef338484612698565b50600192915050565b6001600160a01b039283165f9081527f9e75074fe7582401cc58901f6bda367c4d687c51437956963a7c06ef5cfaf902602090815260408083209490951682529283528381209181529152205490565b5f61165281611e19565b61118982612768565b5f61166581611e19565b611189826127db565b611676612143565b61167e612173565b61168983838361284a565b611011612403565b611699612143565b6116a1612173565b6116ac33838361284a565b611189612403565b5f805160206156e38339815191526116cb81611e19565b61118982612963565b5f805160206156e38339815191526116eb81611e19565b610fb2612b0d565b5f80516020615723833981519152546001600160a01b031690565b5f6117176116f3565b905090565b5f9182525f805160206156c3833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b5f805160206155c383398151915261176981611e19565b61118982612b55565b60608161177e81611398565b61179e5760405163b7c882eb60e01b815260048101829052602401611229565b61105783612b9b565b5f80516020615723833981519152545f90600160d01b900465ffffffffffff165f805160206156a383398151915281158015906117ec57504265ffffffffffff831610155b6117f7575f8061180d565b6001810154600160a01b900465ffffffffffff16825b92509250509091565b5f8161182181611398565b6118415760405163b7c882eb60e01b815260048101829052602401611229565b5f8381527fec3c1253ecdf88a29ff53024f0721fc3faa1b42abcff612deb5b22d1f94e2d016020526040902054611057565b5f8161187e81611398565b61189e5760405163b7c882eb60e01b815260048101829052602401611229565b5f8381527fdaa3d1cf82c71b982a9e24ff7dadd71a10e8c3e82a219c0e60ca5c6b8e617700602052604090205460ff16611057565b6001600160a01b039182165f9081527f9e75074fe7582401cc58901f6bda367c4d687c51437956963a7c06ef5cfaf9016020908152604080832093909416825291909152205460ff1690565b611927612143565b61192f612173565b611689338484846121e0565b5f8181527f2ada2772a8c4d40c4be8741992e423a9f97d5f4ef76852e5c17a40aa7fb9e5016020526040902080546060915f8051602061564383398151915291610e4d906151df565b5f80516020615723833981519152545f905f805160206156a383398151915290600160d01b900465ffffffffffff1680158015906119c957504265ffffffffffff8216105b6119e3578154600160d01b900465ffffffffffff166119f8565b6001820154600160a01b900465ffffffffffff165b9250505090565b5f611a08611a3e565b509050336001600160a01b03821614611a3657604051636116401160e11b8152336004820152602401611229565b610fb2612cd0565b5f805160206156a3833981519152546001600160a01b03811691600160a01b90910465ffffffffffff1690565b60605f5f8051602061562383398151915260018101805460408051602080840282018101909252828152939450830182828015611acf57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311611ab1575b505050505091505090565b5f81611ae581611398565b611b055760405163b7c882eb60e01b815260048101829052602401611229565b61105783612d69565b81611b2c57604051631fe1e13d60e11b815260040160405180910390fd5b6111898282612dc9565b5f611b4081611e19565b610fb2612de5565b5f805160206155c3833981519152611b5f81611e19565b611b698585612def565b611b738584612e46565b611b7d8583612ea0565b5050505050565b5f805160206156438339815191528054606091908190611ba3906151df565b80601f0160208091040260200160405190810160405280929190818152602001828054611bcf906151df565b8015611acf5780601f10611bf157610100808354040283529160200191611acf565b820191905f5260205f20905b815481529060010190602001808311611bfd5750939695505050505050565b7f3496e2e73c4d42b75d702e60d9e48102720b8691234415963a5a857b86425d07611c4681611e19565b61118982612f01565b5f805160206156e3833981519152611c6681611e19565b61118982612f8c565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848611c9981611e19565b610fea848484613084565b5f336001600160a01b0386168114801590611cc65750611cc486826118d3565b155b15611cd757611cd7868286866130b9565b611ce386868686611dbb565b50600195945050505050565b6001600160a01b0382165f9081525f805160206155e383398151915260208181526040808420858552909152822080548390815b81811015611d8b5742848281548110611d3e57611d3e615211565b905f5260205f209060020201600101541115611d8357838181548110611d6657611d66615211565b905f5260205f2090600202015f015483611d80919061527c565b92505b600101611d23565b50909695505050505050565b5f6001600160e01b031982166318a4c3c360e11b1480610f675750610f6782613142565b6001600160a01b038416611de4576040516301486a4160e71b81525f6004820152602401611229565b6001600160a01b038316611e0d57604051630b8bbd6160e41b81525f6004820152602401611229565b610fea84848484613166565b610fb28133613347565b611e2d5f80613380565b565b6001600160a01b038316611e5857604051630b8bbd6160e41b81525f6004820152602401611229565b6110115f848484613166565b5f8281527f2ada2772a8c4d40c4be8741992e423a9f97d5f4ef76852e5c17a40aa7fb9e501602052604090205f8051602061564383398151915290611ea983826152d3565b50827f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b83604051611eda9190614b1a565b60405180910390a2505050565b5f611ef0613458565b9050611efd81833561347e565b611f1381611f0e602085018561538e565b6134b2565b611f218183604001356134e7565b611f3a81611f3560808501606086016153da565b613542565b807f76e35084bc84f178215c72d32676286f16ca2d3a80d3e80e317c858d61eb5a3783604051611f6a9190615439565b60405180910390a2919050565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00610f67565b611fa76135ab565b611fb486868686866135d0565b611fbd816135fd565b505050505050565b611fce82611016565b611fd781611e19565b610fea838361360e565b6001600160a01b038116331461200a5760405163334bd91960e11b815260040160405180910390fd5b6110118282613682565b61201c6136d9565b5f80516020615703833981519152805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b5f805160206156038339815191526001600160a01b0385166120aa5760405163198ecd5360e31b81525f6004820152602401611229565b6001600160a01b0384166120d357604051636f65f46560e01b81525f6004820152602401611229565b6001600160a01b038581165f81815260028401602090815260408083209489168084529482528083208884528252918290208690559051858152869392917fb3fd5071835887567a0671151121894ddccc2842f1d10bedad13e0d17cace9a7910160405180910390a45050505050565b5f805160206157038339815191525460ff1615611e2d5760405163d93c066560e01b815260040160405180910390fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c156121b357604051633ee5aeb560e01b815260040160405180910390fd5b611e2d60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b90613708565b5f805160206157438339815191526121f78561370f565b61220082613741565b5f83815260028201602090815260408083206001600160a01b0388168452909152812054908190036122575760405163ec40a7ab60e01b8152600481018590526001600160a01b0386166024820152604401611229565b5f6122628483615265565b9050855f6001600160a01b03821663dd62ed3e336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa1580156122be573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122e291906154c5565b90508281101561231e576040516303dfb80d60e11b81526001600160a01b03891660048201526024810184905260448101829052606401611229565b5f6001600160a01b0383166370a08231336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612371573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061239591906154c5565b9050838110156123d157604051633514dc2360e21b81526001600160a01b038a1660048201526024810185905260448101829052606401611229565b6123eb3387546001600160a01b0386811692911687613764565b6123f78a8989876137be565b50505050505050505050565b611e2d5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f006121da565b8161243781611398565b6124575760405163b7c882eb60e01b815260048101829052602401611229565b61246283833561347e565b61247383611f0e602085018561538e565b6124818383604001356134e7565b61249583611f3560808501606086016153da565b827f76e35084bc84f178215c72d32676286f16ca2d3a80d3e80e317c858d61eb5a3783604051611eda9190615439565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061254b57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661253f5f80516020615683833981519152546001600160a01b031690565b6001600160a01b031614155b15611e2d5760405163703e46dd60e11b815260040160405180910390fd5b7fa76ace73a908083d89af9ff88e5b4f7cadb3591a80631063f68b695fda726db561118981611e19565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156125ed575060408051601f3d908101601f191682019092526125ea918101906154c5565b60015b61261557604051634c9c8ce360e01b81526001600160a01b0383166004820152602401611229565b5f80516020615683833981519152811461264557604051632a87526960e21b815260048101829052602401611229565b611011838361381b565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611e2d5760405163703e46dd60e11b815260040160405180910390fd5b5f805160206156038339815191526001600160a01b0384166126cf5760405163198ecd5360e31b81525f6004820152602401611229565b6001600160a01b0383166126f857604051636f65f46560e01b81525f6004820152602401611229565b6001600160a01b038481165f818152600184016020908152604080832094881680845294825291829020805460ff191687151590811790915591519182527fceb576d9f15e4e200fdb5096d64d5dfd667e16def20c1eefd14256d8e3faa26791015b60405180910390a350505050565b5f612771611984565b61277a42613870565b61278491906154dc565b905061279082826138a6565b60405165ffffffffffff821681526001600160a01b038316907f3377dc44241e779dd06afab5b788a35ca5f3b778836e2990bdb26a2a4b2e5ed6906020015b60405180910390a25050565b5f6127e582613930565b6127ee42613870565b6127f891906154dc565b90506128048282613380565b6040805165ffffffffffff8085168252831660208201527ff1038c18cf84a56e432fdbfaf746924b7ea511dfe03a6506a0ceba4888788d9b910160405180910390a15050565b5f805160206157438339815191526128618461370f565b61286a82613741565b5f8381526001820160205260408120549081900361289e576040516384e7368960e01b815260048101859052602401611229565b5f6128a98483615265565b9050803410156128e3576040516301b1e28360e21b8152600481018690526024810185905260448101829052346064820152608401611229565b8034111561292057336108fc6128f983346154fb565b6040518115909202915f818181858888f1935050505015801561291e573d5f803e3d5ffd5b505b82546040516001600160a01b039091169082156108fc029083905f818181858888f19350505050158015612956573d5f803e3d5ffd5b50611fbd868686846137be565b6001600160a01b0381165f9081525f80516020615623833981519152602081905260409091205460ff16612995575050565b6001600160a01b0382165f908152602082905260408120805460ff191690555b6001820154811015612ab357826001600160a01b03168260010182815481106129e0576129e0615211565b5f918252602090912001546001600160a01b031603612aab57600180830180549091612a0b916154fb565b81548110612a1b57612a1b615211565b5f918252602090912001546001830180546001600160a01b039092169183908110612a4857612a48615211565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555081600101805480612a8657612a86615251565b5f8281526020902081015f1990810180546001600160a01b0319169055019055612ab3565b6001016129b5565b506040517f7d2be5e40a0d45d9af5c7db1fc1fa7822674e1d5f550082d32be1b8bf80c015f906001600160a01b038416907f233494033cad48d751b00c55d58da5f087d21031a3859563c7b6a7f3a2ccf04d905f90a35050565b612b15612143565b5f80516020615703833981519152805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833612055565b5f8051602061564383398151915280612b6e83826152d3565b506040517fa5d4097edda6d87cb9329af83fb3712ef77eeb13738ffe43cc35a4ce305ad962905f90a15050565b5f8181527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff6036020526040902080546060915f80516020615743833981519152916001600160401b03811115612bf257612bf2614c31565b604051908082528060200260200182016040528015612c3657816020015b604080518082019091525f8082526020820152815260200190600190039081612c105790505b5092505f5b8154811015612cc8575f828281548110612c5757612c57615211565b5f91825260208083209091015488835260028701825260408084206001600160a01b03909216808552918352928390205483518085019094528184529183018290528751909350909190879085908110612cb357612cb3615211565b60209081029190910101525050600101612c3b565b505050919050565b5f805160206156a38339815191525f80612ce8611a3e565b91509150612cfd8165ffffffffffff16151590565b1580612d1157504265ffffffffffff821610155b15612d39576040516319ca5ebb60e01b815265ffffffffffff82166004820152602401611229565b612d4a5f612d456116f3565b613682565b50612d555f8361360e565b505081546001600160d01b03191690915550565b5f8181527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff6016020526040812054905f805160206157438339815191529082900361105a576040516384e7368960e01b815260048101849052602401611229565b612dd282611016565b612ddb81611e19565b610fea8383613682565b611e2d5f806138a6565b5f8281525f805160206155a383398151915260208190526040909120612e1583826152d3565b50827f6846707b16f55a3623d38bf118700af63d0784698270a53ce28b116dbaa8b79483604051611eda9190614b1a565b5f8281525f805160206155a383398151915260208190526040909120600101612e6f83826152d3565b50827f8fabcb7b4fbdde605303a7339bc80fb6956cd01a42e9cdf2d15d0f2fdd3b06fa83604051611eda9190614b1a565b5f8281525f805160206155a38339815191526020818152604092839020600201805460ff191660ff86169081179091559251928352909184917fc7435874568017e6134c851002a405d733521c0f4c63f9f25f3a32a4d595b7299101611eda565b5f805160206157438339815191526001600160a01b038216612f41576040516334d5d27d60e21b81526001600160a01b0383166004820152602401611229565b80546001600160a01b0319166001600160a01b03831690811782556040513381527f4ab5be82436d353e61ca18726e984e561f5c1cc7c6d38b29d2553c790434705a906020016127cf565b6001600160a01b038116612fbe57604051634726455360e11b81526001600160a01b0382166004820152602401611229565b6001600160a01b0381165f9081525f80516020615623833981519152602081905260409091205460ff1615612ff1575050565b6001600160a01b0382165f81815260208381526040808320805460ff1916600190811790915585810180549182018155845291832090910180546001600160a01b03191684179055517f6f58fc3760b5743cf76087dfed697597f39c204c204718113b3ee0e4d995fc3b92917f233494033cad48d751b00c55d58da5f087d21031a3859563c7b6a7f3a2ccf04d91a35050565b6001600160a01b0383166130ad576040516301486a4160e71b81525f6004820152602401611229565b611011835f8484613166565b5f805160206156038339815191525f6130d38686866115f8565b90505f19811015611fbd57828110156131075784818486604051632c51fead60e11b8152600401611229949392919061550e565b6001600160a01b038087165f908152600284016020908152604080832093891683529281528282208783529052208382039055505050505050565b5f6001600160e01b03198216637965db0b60e01b1480610f675750610f6782613977565b61316e612143565b6001600160a01b0384165f9081525f80516020615623833981519152602081905260409091205485919060ff16156131c4576040516327951b3f60e11b81526001600160a01b0383166004820152602401611229565b6001600160a01b0385165f9081525f80516020615623833981519152602081905260409091205486919060ff161561321a576040516327951b3f60e11b81526001600160a01b0383166004820152602401611229565b8561322481611398565b6132445760405163b7c882eb60e01b815260048101829052602401611229565b8888887fdaa3d1cf82c71b982a9e24ff7dadd71a10e8c3e82a219c0e60ca5c6b8e6177006001600160a01b0384161580159061328857506001600160a01b03831615155b80156132a257505f8281526020829052604090205460ff16155b156132c3576040516368ee0b2f60e11b815260048101839052602401611229565b8b6001600160a01b03168d6001600160a01b03160361330057604051633ef2228f60e21b81526001600160a01b038e166004820152602401611229565b895f03613320576040516323cf7d7d60e01b815260040160405180910390fd5b61332c8d8d8d8d6139ab565b6133388d8d8d8d613a1f565b50505050505050505050505050565b613351828261171c565b6111895760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401611229565b5f80516020615723833981519152545f805160206156a383398151915290600160d01b900465ffffffffffff16801561341a574265ffffffffffff821610156133f157600182015482546001600160d01b0316600160a01b90910465ffffffffffff16600160d01b0217825561341a565b6040517f2b1fa2edafe6f7b9e97c1a9e0c3660e645beb2dcaa2d45bdbf9beaf5472e1ec5905f90a15b5060010180546001600160a01b0316600160a01b65ffffffffffff948516026001600160d01b031617600160d01b9290931691909102919091179055565b5f8051602061566383398151915280549081815f61347583615239565b91905055505090565b8161348881611398565b6134a85760405163b7c882eb60e01b815260048101829052602401611229565b6110118383613b48565b826134bc81611398565b6134dc5760405163b7c882eb60e01b815260048101829052602401611229565b610fea848484613bb9565b816134f181611398565b6135115760405163b7c882eb60e01b815260048101829052602401611229565b505f9182527fec3c1253ecdf88a29ff53024f0721fc3faa1b42abcff612deb5b22d1f94e2d01602052604090912055565b8161354c81611398565b61356c5760405163b7c882eb60e01b815260048101829052602401611229565b5f8381527fdaa3d1cf82c71b982a9e24ff7dadd71a10e8c3e82a219c0e60ca5c6b8e61770060205260409020805483151560ff19909116179055505050565b6135b3613c18565b611e2d57604051631afcd79f60e31b815260040160405180910390fd5b6135d86135ab565b6135e28585613c31565b6135ea613c53565b6135f383613c6b565b611b7d8282613c7c565b6136056135ab565b610fb281612b55565b5f5f805160206156a383398151915283613670575f61362b6116f3565b6001600160a01b03161461365257604051631fe1e13d60e11b815260040160405180910390fd5b6001810180546001600160a01b0319166001600160a01b0385161790555b61367a8484613ce4565b949350505050565b5f5f805160206156a3833981519152831580156136b757506136a26116f3565b6001600160a01b0316836001600160a01b0316145b156136cf576001810180546001600160a01b03191690555b61367a8484613d8c565b5f805160206157038339815191525460ff16611e2d57604051638dfc202b60e01b815260040160405180910390fd5b80825d5050565b6001600160a01b038116610fb25760405163094293a160e31b81526001600160a01b0382166004820152602401611229565b805f03610fb25760405163023d875560e41b815260048101829052602401611229565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052610fea908590613e05565b6137c9848484613e71565b826001600160a01b0385167f0a9521815fb3c5bc7dd6f4c9f89dc270322e46b945b104c18981f81c3f2cd1aa33604080516001600160a01b03909216825260208201879052810185905260600161275a565b61382482613e7c565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a2805115613868576110118282613edf565b611189613f51565b5f65ffffffffffff8211156138a2576040516306dfcc6560e41b81526030600482015260248101839052604401611229565b5090565b5f805160206156a38339815191525f6138bd611a3e565b835465ffffffffffff8616600160a01b026001600160d01b03199091166001600160a01b0388161717845591506138fd90508165ffffffffffff16151590565b15610fea576040517f8886ebfc4259abdbc16601dd8fb5678e54878f47b3c34836cfc51154a9605109905f90a150505050565b5f8061393a611984565b90508065ffffffffffff168365ffffffffffff16116139625761395d8382615534565b611057565b61105765ffffffffffff841662069780613f70565b5f6001600160e01b03198216630f632fb360e01b1480610f6757506301ffc9a760e01b6001600160e01b0319831614610f67565b6001600160a01b0384166139dc576139c383836113d5565b6139d78383836139d286613f7f565b613ffa565b610fea565b6001600160a01b0383166139ff576139f5848383614324565b6139d784836113d5565b613a0983836113d5565b613a15848484846144be565b610fea84836113d5565b5f80516020615603833981519152336001600160a01b03861615613aae576001600160a01b0386165f9081526020838152604080832087845290915290205483811015613a8757868185876040516302c6d3fb60e61b8152600401611229949392919061550e565b6001600160a01b0387165f9081526020848152604080832088845290915290209084900390555b6001600160a01b03851615613af3576001600160a01b0385165f9081526020838152604080832087845290915281208054859290613aed90849061527c565b90915550505b604080516001600160a01b03838116825260208201869052869281891692918a16917f1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac728859910160405180910390a4505050505050565b5f8281527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff601602090815260409182902083905590518281525f805160206157438339815191529184917fa12c47d56c27d127f5f74f842a31dcfca20ecb155635a6ec6cb060a39cac2b339101611eda565b5f5b81811015610fea57613c1084848484818110613bd957613bd9615211565b613bef926020604090920201908101915061505d565b858585818110613c0157613c01615211565b905060400201602001356146cb565b600101613bbb565b5f613c21611f77565b54600160401b900460ff16919050565b613c396135ab565b613c438282614700565b613c4b614712565b61118961471e565b613c5b6135ab565b613c6361471e565b611e2d614726565b613c736135ab565b610fb281614741565b613c846135ab565b5f5b8181101561101157613cdb838383818110613ca357613ca3615211565b9050604002015f0135848484818110613cbe57613cbe615211565b9050604002016020016020810190613cd6919061505d565b61360e565b50600101613c86565b5f5f805160206156c3833981519152613cfd848461171c565b613d7c575f848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055613d323390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a46001915050610f67565b5f915050610f67565b5092915050565b5f5f805160206156c3833981519152613da5848461171c565b15613d7c575f848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a46001915050610f67565b5f8060205f8451602086015f885af180613e24576040513d5f823e3d81fd5b50505f513d91508115613e3b578060011415613e48565b6001600160a01b0384163b155b15610fea57604051635274afe760e01b81526001600160a01b0385166004820152602401611229565b611011838383611e2f565b806001600160a01b03163b5f03613eb157604051634c9c8ce360e01b81526001600160a01b0382166004820152602401611229565b5f8051602061568383398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80846001600160a01b031684604051613efb9190615553565b5f60405180830381855af49150503d805f8114613f33576040519150601f19603f3d011682016040523d82523d5f602084013e613f38565b606091505b5091509150613f48858383614752565b95945050505050565b3415611e2d5760405163b398979f60e01b815260040160405180910390fd5b5f828218828410028218610f78565b5f80613f8a83611816565b9050805f03613f9c57505f1992915050565b5f613fa7824261527c565b90505f613fb560648461556e565b9050805f03613fc2575060015b5f816001613fd0828661527c565b613fda91906154fb565b613fe4919061556e565b9050613ff08282615265565b9695505050505050565b6001600160a01b0384165f9081525f805160206155e38339815191526020818152604080842087855290915282208054919290919081905b828110156141365783818154811061404c5761404c615211565b905f5260205f2090600202015f01545f148015614089575083818154811061407657614076615211565b905f5260205f209060020201600101545f145b1561409657809150614136565b858482815481106140a9576140a9615211565b905f5260205f20906002020160010154036140fd57868482815481106140d1576140d1615211565b905f5260205f2090600202015f015f8282546140ed919061527c565b90915550610fea95505050505050565b8584828154811061411057614110615211565b905f5260205f20906002020160010154111561412e57809150614136565b600101614032565b5081811061417a576040805180820190915286815260208082018781528554600181810188555f88815293909320935160029091029093019283555191015561431a565b82818154811061418c5761418c615211565b905f5260205f2090600202015f01545f1480156141c957508281815481106141b6576141b6615211565b905f5260205f209060020201600101545f145b15614218576040518060400160405280878152602001868152508382815481106141f5576141f5615211565b5f918252602091829020835160029092020190815591015160019091015561431a565b604080518082019091525f80825260208083018281528654600181810189558885529284209451600290910290940193845551928101929092558454909161425f916154fb565b90505b818111156142d357836142766001836154fb565b8154811061428657614286615211565b905f5260205f2090600202018482815481106142a4576142a4615211565b5f91825260209091208254600290920201908155600191820154910155806142cb8161558d565b915050614262565b506040518060400160405280878152602001868152508382815481106142fb576142fb615211565b5f91825260209182902083516002909202019081559101516001909101555b5050505050505050565b6001600160a01b0383165f9081525f805160206155e383398151915260208181526040808420868552909152822080549192909184914291905b818110801561436c57505f84115b1561448d578285828154811061438457614384615211565b905f5260205f209060020201600101541115806143c057508481815481106143ae576143ae615211565b905f5260205f2090600202015f01545f145b61447b57838582815481106143d7576143d7615211565b905f5260205f2090600202015f0154111561442957838582815481106143ff576143ff615211565b905f5260205f2090600202015f015f82825461441b91906154fb565b909155505f945061447b9050565b84818154811061443b5761443b615211565b905f5260205f2090600202015f01548461445591906154fb565b93505f85828154811061446a5761446a615211565b5f9182526020909120600290910201555b8061448581615239565b91505061435e565b50821561431a578761449f84886154fb565b878960405163670f004560e01b8152600401611229949392919061550e565b826001600160a01b0316846001600160a01b031614806144dc575080155b610fea576001600160a01b0384165f9081525f805160206155e383398151915260208181526040808420868552909152822080549192909184914291905b818110801561452857505f84115b156146ae578285828154811061454057614540615211565b905f5260205f2090600202016001015411158061457c575084818154811061456a5761456a615211565b905f5260205f2090600202015f01545f145b61469c578385828154811061459357614593615211565b905f5260205f2090600202015f01541115614612576145d58989868885815481106145c0576145c0615211565b905f5260205f20906002020160010154613ffa565b838582815481106145e8576145e8615211565b905f5260205f2090600202015f015f82825461460491906154fb565b909155505f945061469c9050565b61464a898987848154811061462957614629615211565b905f5260205f2090600202015f01548885815481106145c0576145c0615211565b84818154811061465c5761465c615211565b905f5260205f2090600202015f01548461467691906154fb565b93505f85828154811061468b5761468b615211565b5f9182526020909120600290910201555b806146a681615239565b91505061451a565b5082156146c0578861449f84886154fb565b505050505050505050565b826146d581611398565b6146f55760405163b7c882eb60e01b815260048101829052602401611229565b610fea8484846147ae565b6147086135ab565b6111898282614a13565b61471a6135ab565b611e2d5b611e2d6135ab565b61472e6135ab565b60015f8051602061566383398151915255565b6147496135ab565b610fb281612f01565b6060826147675761476282614a79565b610f78565b815115801561477e57506001600160a01b0384163b155b156147a757604051639996b31560e01b81526001600160a01b0385166004820152602401611229565b5080610f78565b6001600160a01b0382166147e05760405163aac3232160e01b81526001600160a01b0383166004820152602401611229565b5f8381527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff602602090815260408083206001600160a01b038616845290915290208190555f8051602061574383398151915281156148d0575f848152600382016020526040812090805b825481101561489857856001600160a01b031683828154811061486e5761486e615211565b5f918252602090912001546001600160a01b0316036148905760019150614898565b600101614849565b50806148c95781546001810183555f838152602090200180546001600160a01b0319166001600160a01b0387161790555b50506149d7565b5f8481526003820160205260408120905b81548110156149d457846001600160a01b031682828154811061490657614906615211565b5f918252602090912001546001600160a01b0316036149cc578154829061492f906001906154fb565b8154811061493f5761493f615211565b905f5260205f20015f9054906101000a90046001600160a01b031682828154811061496c5761496c615211565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550818054806149a7576149a7615251565b5f8281526020902081015f1990810180546001600160a01b03191690550190556149d4565b6001016148e1565b50505b826001600160a01b0316847ffb08de1e404ab196167a5843d6f4552a93056ed1da04e2f6c958dc6c63f1e4b48460405161275a91815260200190565b614a1b6135ab565b5f805160206156a38339815191526001600160a01b038216614a5257604051636116401160e11b81525f6004820152602401611229565b80546001600160d01b0316600160d01b65ffffffffffff851602178155610fea5f8361360e565b805115614a8857805160208201fd5b60405163d6bda27560e01b815260040160405180910390fd5b60405180604001604052805f8152602001614adc60405180608001604052805f8152602001606081526020015f81526020015f151581525090565b905290565b5f60208284031215614af1575f80fd5b5035919050565b5f5b83811015614b12578181015183820152602001614afa565b50505f910152565b602081525f8251806020840152614b38816040850160208701614af8565b601f01601f19169190910160400192915050565b6001600160a01b0381168114610fb2575f80fd5b5f8060408385031215614b71575f80fd5b8235614b7c81614b4c565b946020939093013593505050565b602080825282518282018190525f919060409081850190868401855b82811015614bcb57815180518552860151868501529284019290850190600101614ba6565b5091979650505050505050565b5f60208284031215614be8575f80fd5b81356001600160e01b031981168114610f78575f80fd5b5f805f60608486031215614c11575f80fd5b8335614c1c81614b4c565b95602085013595506040909401359392505050565b634e487b7160e01b5f52604160045260245ffd5b5f6001600160401b0380841115614c5e57614c5e614c31565b604051601f8501601f19908116603f01168101908282118183101715614c8657614c86614c31565b81604052809350858152868686011115614c9e575f80fd5b858560208301375f602087830101525050509392505050565b5f82601f830112614cc6575f80fd5b610f7883833560208501614c45565b5f8060408385031215614ce6575f80fd5b8235915060208301356001600160401b03811115614d02575f80fd5b614d0e85828601614cb7565b9150509250929050565b5f6080828403121561105a575f80fd5b5f60208284031215614d38575f80fd5b81356001600160401b03811115614d4d575f80fd5b61367a84828501614d18565b803565ffffffffffff81168114614d6e575f80fd5b919050565b5f805f805f8060a08789031215614d88575f80fd5b614d9187614d59565b95506020870135614da181614b4c565b94506040870135614db181614b4c565b935060608701356001600160401b0380821115614dcc575f80fd5b818901915089601f830112614ddf575f80fd5b813581811115614ded575f80fd5b8a60208260061b8501011115614e01575f80fd5b602083019550809450506080890135915080821115614e1e575f80fd5b50614e2b89828a01614cb7565b9150509295509295509295565b5f8060408385031215614e49575f80fd5b823591506020830135614e5b81614b4c565b809150509250929050565b5f815180845260208085019450602084015f5b83811015614ea957815180516001600160a01b031688528301518388015260409096019590820190600101614e79565b509495945050505050565b60208152815160208201525f6020830151604080840152805160608401526020810151608080850152614eea60e0850182614e66565b604083015160a0860152606090920151151560c0909401939093529392505050565b5f805f8060808587031215614f1f575f80fd5b8435614f2a81614b4c565b93506020850135614f3a81614b4c565b93969395505050506040820135916060013590565b5f8060408385031215614f60575f80fd5b8235915060208301356001600160401b03811115614f7c575f80fd5b614d0e85828601614d18565b5f8060408385031215614f99575f80fd5b8235614fa481614b4c565b915060208301356001600160401b03811115614fbe575f80fd5b8301601f81018513614fce575f80fd5b614d0e85823560208401614c45565b80358015158114614d6e575f80fd5b5f8060408385031215614ffd575f80fd5b823561500881614b4c565b915061501660208401614fdd565b90509250929050565b5f805f60608486031215615031575f80fd5b833561503c81614b4c565b9250602084013561504c81614b4c565b929592945050506040919091013590565b5f6020828403121561506d575f80fd5b8135610f7881614b4c565b5f60208284031215615088575f80fd5b610f7882614d59565b5f80604083850312156150a2575f80fd5b50508035926020909101359150565b5f602082840312156150c1575f80fd5b81356001600160401b038111156150d6575f80fd5b61367a84828501614cb7565b602081525f610f786020830184614e66565b5f8060408385031215615105575f80fd5b823561511081614b4c565b91506020830135614e5b81614b4c565b602080825282518282018190525f9190848201906040850190845b81811015611d8b5783516001600160a01b03168352928401929184019160010161513b565b5f805f8060808587031215615173575f80fd5b8435935060208501356001600160401b0380821115615190575f80fd5b61519c88838901614cb7565b945060408701359150808211156151b1575f80fd5b506151be87828801614cb7565b925050606085013560ff811681146151d4575f80fd5b939692955090935050565b600181811c908216806151f357607f821691505b60208210810361105a57634e487b7160e01b5f52602260045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f6001820161524a5761524a615225565b5060010190565b634e487b7160e01b5f52603160045260245ffd5b8082028115828204841417610f6757610f67615225565b80820180821115610f6757610f67615225565b601f82111561101157805f5260205f20601f840160051c810160208510156152b45750805b601f840160051c820191505b81811015611b7d575f81556001016152c0565b81516001600160401b038111156152ec576152ec614c31565b615300816152fa84546151df565b8461528f565b602080601f831160018114615333575f841561531c5750858301515b5f19600386901b1c1916600185901b178555611fbd565b5f85815260208120601f198616915b8281101561536157888601518255948401946001909101908401615342565b508582101561537e57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f808335601e198436030181126153a3575f80fd5b8301803591506001600160401b038211156153bc575f80fd5b6020019150600681901b36038213156153d3575f80fd5b9250929050565b5f602082840312156153ea575f80fd5b610f7882614fdd565b8183525f60208085019450825f5b85811015614ea957813561541481614b4c565b6001600160a01b03168752818301358388015260409687019690910190600101615401565b60208152813560208201525f6020830135601e1984360301811261545b575f80fd5b83016020810190356001600160401b03811115615476575f80fd5b8060061b3603821315615487575f80fd5b6080604085015261549c60a0850182846153f3565b915050604084013560608401526154b560608501614fdd565b8015156080850152509392505050565b5f602082840312156154d5575f80fd5b5051919050565b65ffffffffffff818116838216019080821115613d8557613d85615225565b81810381811115610f6757610f67615225565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b65ffffffffffff828116828216039080821115613d8557613d85615225565b5f8251615564818460208701614af8565b9190910192915050565b5f8261558857634e487b7160e01b5f52601260045260245ffd5b500490565b5f8161559b5761559b615225565b505f19019056fea0651e3d105d335a33d7d04897e080112be09c416f44637d6543e5b47885f80074f7a545c65c11839a48d7453738b30c295408df2d944516167556759ddc6d06ec3c1253ecdf88a29ff53024f0721fc3faa1b42abcff612deb5b22d1f94e2d009e75074fe7582401cc58901f6bda367c4d687c51437956963a7c06ef5cfaf900a095fe5a3c31691ae0832631cef3701285d36b2af1972f4c23463476b0353a002ada2772a8c4d40c4be8741992e423a9f97d5f4ef76852e5c17a40aa7fb9e500591f2d2df77efc80b9969dfd51dd4fc103fe490745902503f7c21df07a35d600360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbceef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840002dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680046f3eccdd88dd62792ae8eed1be7b9b658477566c49fd85b0d08cf44261c9208cd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300eef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840154c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff600a2646970667358221220698537606b9ad491ef44fd788baae867537e1612f909e5a03ac125de924bbd0c64736f6c63430008180033 +0x60a060405230608052348015610013575f80fd5b506080516156e76200003b5f395f81816125760152818161259f015261270001526156e75ff3fe608060405260043610610408575f3560e01c806379c44ca211610215578063c87b56dd1161011e578063d9a5260e116100a8578063f0f4426011610078578063f0f4426014610d18578063f101e48114610d37578063f26c159f14610d57578063f5298aca14610d76578063fe99049a14610d95575f80fd5b8063d9a5260e14610c6f578063e583983614610c8e578063e8a3d48514610cd1578063f0a3a97c14610ce5575f80fd5b8063d2c7db1c116100ee578063d2c7db1c14610bc9578063d4ddce8a14610bea578063d539139314610c09578063d547741f14610c3c578063d602b9fd14610c5b575f80fd5b8063c87b56dd14610b48578063cc8463c814610b67578063cefc142914610b7b578063cf6eefb714610b8f575f80fd5b8063a217fddf1161019f578063b25645691161016f578063b256456914610a98578063b6363cf214610ab7578063c0a2103414610ad6578063c2840e6014610b09578063c55be5d014610b29575f80fd5b8063a217fddf14610a16578063a3b546f214610a29578063a5a2a64514610a49578063ad3cb1cc14610a68575f80fd5b806391d14854116101e557806391d1485414610965578063938e3d7b146109845780639526c2d9146109a3578063994757c5146109b7578063a1eda53c146109e3575f80fd5b806379c44ca2146108f65780638456cb591461092957806384ef8ffc1461093d5780638da5cb5b14610951575f80fd5b806343ffa64e11610317578063558a7297116102a1578063634e93da11610271578063634e93da14610873578063649a5ec7146108925780636d51282c146108b157806370876c98146108c4578063788649ea146108d7575f80fd5b8063558a7297146107d5578063598af9e7146107f45780635c975abb1461081357806361d027b314610836575f80fd5b80634e41a1fb116102e75780634e41a1fb146107515780634f1ef286146107705780634f558e791461078357806352d1902d146107a257806354efdcf6146107b6575f80fd5b806343ffa64e146106b4578063440e806e146106e757806345cc05a01461071357806347aa3a2e14610732575f80fd5b8063248a9ca3116103985780632f2ff15d116103685780632f2ff15d146105f457806336568abe146106135780633f47e662146106325780633f4ba83a14610681578063426a849314610695575f80fd5b8063248a9ca31461056457806327276d9814610583578063282c51f3146105a25780632d99179e146105d5575f80fd5b8063022d63fb116103de578063022d63fb146104c9578063095bcdb6146104f15780630aa6220b14610510578063156e29f614610526578063162094c414610545575f80fd5b8062ad800c1461040c578062e6449d14610441578062fdd58e1461046d57806301ffc9a71461049a575b5f80fd5b348015610417575f80fd5b5061042b610426366004614a30565b610db4565b6040516104389190614a69565b60405180910390f35b34801561044c575f80fd5b5061046061045b366004614aaf565b610e64565b6040516104389190614ad9565b348015610478575f80fd5b5061048c610487366004614aaf565b610f00565b604051908152602001610438565b3480156104a5575f80fd5b506104b96104b4366004614b27565b610f12565b6040519015158152602001610438565b3480156104d4575f80fd5b50620697805b60405165ffffffffffff9091168152602001610438565b3480156104fc575f80fd5b506104b961050b366004614b4e565b610f1c565b34801561051b575f80fd5b50610524610f33565b005b348015610531575f80fd5b50610524610540366004614b4e565b610f48565b348015610550575f80fd5b5061052461055f366004614c24565b610f83565b34801561056f575f80fd5b5061048c61057e366004614a30565b610fa9565b34801561058e575f80fd5b5061048c61059d366004614c77565b610fc9565b3480156105ad575f80fd5b5061048c7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84881565b3480156105e0575f80fd5b506105246105ef366004614cc2565b610ff3565b3480156105ff575f80fd5b5061052461060e366004614d87565b6110f4565b34801561061e575f80fd5b5061052461062d366004614d87565b611120565b34801561063d575f80fd5b5061066f61064c366004614a30565b5f9081525f805160206154f2833981519152602052604090206002015460ff1690565b60405160ff9091168152602001610438565b34801561068c575f80fd5b506105246111e2565b3480156106a0575f80fd5b506104b96106af366004614b4e565b611201565b3480156106bf575f80fd5b5061048c7fa76ace73a908083d89af9ff88e5b4f7cadb3591a80631063f68b695fda726db581565b3480156106f2575f80fd5b50610706610701366004614a30565b61120e565b6040516104389190614e03565b34801561071e575f80fd5b5061052461072d366004614e5b565b61129c565b34801561073d575f80fd5b5061052461074c366004614e9e565b6112c0565b34801561075c575f80fd5b5061042b61076b366004614a30565b6112e1565b61052461077e366004614ed7565b611310565b34801561078e575f80fd5b506104b961079d366004614a30565b61132b565b3480156107ad575f80fd5b5061048c61134d565b3480156107c1575f80fd5b506105246107d0366004614aaf565b611368565b3480156107e0575f80fd5b506104b96107ef366004614f3b565b6115f8565b3480156107ff575f80fd5b5061048c61080e366004614f6e565b61160d565b34801561081e575f80fd5b505f805160206156528339815191525460ff166104b9565b348015610841575f80fd5b505f80516020615692833981519152546001600160a01b03165b6040516001600160a01b039091168152602001610438565b34801561087e575f80fd5b5061052461088d366004614fac565b61165d565b34801561089d575f80fd5b506105246108ac366004614fc7565b611670565b6105246108bf366004614b4e565b611683565b6105246108d2366004614fe0565b6116a6565b3480156108e2575f80fd5b506105246108f1366004614fac565b6116c9565b348015610901575f80fd5b5061048c7f6f58fc3760b5743cf76087dfed697597f39c204c204718113b3ee0e4d995fc3b81565b348015610934575f80fd5b506105246116e9565b348015610948575f80fd5b5061085b611708565b34801561095c575f80fd5b5061085b611723565b348015610970575f80fd5b506104b961097f366004614d87565b611731565b34801561098f575f80fd5b5061052461099e366004615000565b611767565b3480156109ae575f80fd5b5061048c606481565b3480156109c2575f80fd5b506109d66109d1366004614a30565b611787565b6040516104389190615031565b3480156109ee575f80fd5b506109f76117bc565b6040805165ffffffffffff938416815292909116602083015201610438565b348015610a21575f80fd5b5061048c5f81565b348015610a34575f80fd5b5061048c5f8051602061563283398151915281565b348015610a54575f80fd5b5061048c610a63366004614a30565b61182b565b348015610a73575f80fd5b5061042b604051806040016040528060058152602001640352e302e360dc1b81525081565b348015610aa3575f80fd5b506104b9610ab2366004614a30565b611888565b348015610ac2575f80fd5b506104b9610ad1366004615043565b6118e8565b348015610ae1575f80fd5b5061048c7f7d2be5e40a0d45d9af5c7db1fc1fa7822674e1d5f550082d32be1b8bf80c015f81565b348015610b14575f80fd5b5061048c5f8051602061551283398151915281565b348015610b34575f80fd5b50610524610b43366004614b4e565b611934565b348015610b53575f80fd5b5061042b610b62366004614a30565b611950565b348015610b72575f80fd5b506104da611999565b348015610b86575f80fd5b50610524611a14565b348015610b9a575f80fd5b50610ba3611a53565b604080516001600160a01b03909316835265ffffffffffff909116602083015201610438565b348015610bd4575f80fd5b50610bdd611a80565b604051610438919061506f565b348015610bf5575f80fd5b5061048c610c04366004614a30565b611aef565b348015610c14575f80fd5b5061048c7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b348015610c47575f80fd5b50610524610c56366004614d87565b611b23565b348015610c66575f80fd5b50610524611b4b565b348015610c7a575f80fd5b50610524610c893660046150af565b611b5d565b348015610c99575f80fd5b506104b9610ca8366004614fac565b6001600160a01b03165f9081525f80516020615572833981519152602052604090205460ff1690565b348015610cdc575f80fd5b5061042b611b99565b348015610cf0575f80fd5b5061048c7f3496e2e73c4d42b75d702e60d9e48102720b8691234415963a5a857b86425d0781565b348015610d23575f80fd5b50610524610d32366004614fac565b611c31565b348015610d42575f80fd5b505f805160206155b28339815191525461048c565b348015610d62575f80fd5b50610524610d71366004614fac565b611c64565b348015610d81575f80fd5b50610524610d90366004614b4e565b611c84565b348015610da0575f80fd5b506104b9610daf366004614e5b565b611cb9565b5f8181525f805160206154f28339815191526020819052604090912080546060929190610de09061512e565b80601f0160208091040260200160405190810160405280929190818152602001828054610e0c9061512e565b8015610e575780601f10610e2e57610100808354040283529160200191610e57565b820191905f5260205f20905b815481529060010190602001808311610e3a57829003601f168201915b5050505050915050919050565b6001600160a01b0382165f9081525f80516020615532833981519152602081815260408084208585528252808420805482518185028101850190935280835260609592939192909184015b82821015610ef2578382905f5260205f2090600202016040518060400160405290815f820154815260200160018201548152505081526020019060010190610eaf565b505050509150505b92915050565b5f610f0b8383611d04565b9392505050565b5f610efa82611dac565b5f610f2933858585611dd0565b5060019392505050565b5f610f3d81611e2e565b610f45611e38565b50565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6610f7281611e2e565b610f7d848484611e44565b50505050565b5f80516020615512833981519152610f9a81611e2e565b610fa48383611e79565b505050565b5f9081525f80516020615612833981519152602052604090206001015490565b5f5f80516020615512833981519152610fe181611e2e565b610fea83611efc565b91505b50919050565b5f610ffc611ff2565b805490915060ff600160401b82041615906001600160401b03165f811580156110225750825b90505f826001600160401b0316600114801561103d5750303b155b90508115801561104b575080155b156110695760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561109357845460ff60401b1916600160401b1785555b6110a18b8b8b8b8b8b61201a565b83156110e757845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050505050565b8161111257604051631fe1e13d60e11b815260040160405180910390fd5b61111c8282612040565b5050565b5f805160206155f283398151915282158015611154575061113f611708565b6001600160a01b0316826001600160a01b0316145b156111d8575f80611163611a53565b90925090506001600160a01b038216151580611185575065ffffffffffff8116155b8061119857504265ffffffffffff821610155b156111c5576040516319ca5ebb60e01b815265ffffffffffff821660048201526024015b60405180910390fd5b5050805465ffffffffffff60a01b191681555b610fa4838361205c565b5f805160206156328339815191526111f981611e2e565b610f4561208f565b5f610f29338585856120ee565b6112166149f0565b816112208161132b565b6112405760405163b7c882eb60e01b8152600481018290526024016111bc565b6040518060400160405280848152602001604051806080016040528061126587611aef565b815260200161127387611787565b81526020016112818761182b565b815260200161128f87611888565b1515905290529392505050565b6112a46121be565b6112ac6121ee565b6112b88484848461225b565b610f7d61247e565b5f805160206155128339815191526112d781611e2e565b610fa483836124a8565b5f8181525f805160206154f28339815191526020819052604090912060010180546060929190610de09061512e565b61131861256b565b6113218261260f565b61111c8282612639565b5f5f805160206155b28339815191528215801590610fea575054909110919050565b5f6113566126f5565b505f805160206155d283398151915290565b6001600160a01b0382165f9081525f8051602061553283398151915260208181526040808420858552909152822080549192909142919081805b82811015611498578581815481106113bc576113bc615160565b5f9182526020909120600290910201541561149057848682815481106113e4576113e4615160565b905f5260205f2090600202016001015411156114615783811461144f5785818154811061141357611413615160565b905f5260205f20906002020186858154811061143157611431615160565b5f918252602090912082546002909202019081556001918201549101555b8361145981615188565b945050611490565b85818154811061147357611473615160565b905f5260205f2090600202015f01548261148d91906151a0565b91505b6001016113a2565b50825b828110156114ee5760405180604001604052805f81526020015f8152508682815481106114ca576114ca615160565b5f91825260209182902083516002909202019081559101516001918201550161149b565b50821580156114fc57505f82115b1561153f575b84541561153a5784805480611519576115196151b3565b5f8281526020812060025f1990930192830201818155600101559055611502565b611598565b61154a8360026151c7565b821180156115585750600a82115b15611598575b84548310156115985784805480611577576115776151b3565b5f8281526020812060025f199093019283020181815560010155905561155e565b80156115ee576115a988888361273e565b86886001600160a01b03167f6dd845d42097bcb5bd43605815b8ea0407e0022cd38d0a278d336bd0a5643f9d836040516115e591815260200190565b60405180910390a35b5050505050505050565b5f61160433848461274a565b50600192915050565b6001600160a01b039283165f9081527f9e75074fe7582401cc58901f6bda367c4d687c51437956963a7c06ef5cfaf902602090815260408083209490951682529283528381209181529152205490565b5f61166781611e2e565b61111c8261281a565b5f61167a81611e2e565b61111c8261288d565b61168b6121be565b6116936121ee565b61169e8383836128fc565b610fa461247e565b6116ae6121be565b6116b66121ee565b6116c13383836128fc565b61111c61247e565b5f805160206156328339815191526116e081611e2e565b61111c82612a15565b5f8051602061563283398151915261170081611e2e565b610f45612bbf565b5f80516020615672833981519152546001600160a01b031690565b5f61172c611708565b905090565b5f9182525f80516020615612833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b5f8051602061551283398151915261177e81611e2e565b61111c82612c07565b6060816117938161132b565b6117b35760405163b7c882eb60e01b8152600481018290526024016111bc565b610fea83612c4d565b5f80516020615672833981519152545f90600160d01b900465ffffffffffff165f805160206155f2833981519152811580159061180157504265ffffffffffff831610155b61180c575f80611822565b6001810154600160a01b900465ffffffffffff16825b92509250509091565b5f816118368161132b565b6118565760405163b7c882eb60e01b8152600481018290526024016111bc565b5f8381527fec3c1253ecdf88a29ff53024f0721fc3faa1b42abcff612deb5b22d1f94e2d016020526040902054610fea565b5f816118938161132b565b6118b35760405163b7c882eb60e01b8152600481018290526024016111bc565b5f8381527fdaa3d1cf82c71b982a9e24ff7dadd71a10e8c3e82a219c0e60ca5c6b8e617700602052604090205460ff16610fea565b6001600160a01b039182165f9081527f9e75074fe7582401cc58901f6bda367c4d687c51437956963a7c06ef5cfaf9016020908152604080832093909416825291909152205460ff1690565b61193c6121be565b6119446121ee565b61169e3384848461225b565b5f8181527f2ada2772a8c4d40c4be8741992e423a9f97d5f4ef76852e5c17a40aa7fb9e5016020526040902080546060915f8051602061559283398151915291610de09061512e565b5f80516020615672833981519152545f905f805160206155f283398151915290600160d01b900465ffffffffffff1680158015906119de57504265ffffffffffff8216105b6119f8578154600160d01b900465ffffffffffff16611a0d565b6001820154600160a01b900465ffffffffffff165b9250505090565b5f611a1d611a53565b509050336001600160a01b03821614611a4b57604051636116401160e11b81523360048201526024016111bc565b610f45612d82565b5f805160206155f2833981519152546001600160a01b03811691600160a01b90910465ffffffffffff1690565b60605f5f8051602061557283398151915260018101805460408051602080840282018101909252828152939450830182828015611ae457602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311611ac6575b505050505091505090565b5f81611afa8161132b565b611b1a5760405163b7c882eb60e01b8152600481018290526024016111bc565b610fea83612e1b565b81611b4157604051631fe1e13d60e11b815260040160405180910390fd5b61111c8282612e7b565b5f611b5581611e2e565b610f45612e97565b5f80516020615512833981519152611b7481611e2e565b611b7e8585612ea1565b611b888584612ef8565b611b928583612f52565b5050505050565b5f805160206155928339815191528054606091908190611bb89061512e565b80601f0160208091040260200160405190810160405280929190818152602001828054611be49061512e565b8015611ae45780601f10611c0657610100808354040283529160200191611ae4565b820191905f5260205f20905b815481529060010190602001808311611c125750939695505050505050565b7f3496e2e73c4d42b75d702e60d9e48102720b8691234415963a5a857b86425d07611c5b81611e2e565b61111c82612fb3565b5f80516020615632833981519152611c7b81611e2e565b61111c8261303e565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848611cae81611e2e565b610f7d848484613136565b5f336001600160a01b0386168114801590611cdb5750611cd986826118e8565b155b15611cec57611cec8682868661316b565b611cf886868686611dd0565b50600195945050505050565b6001600160a01b0382165f9081525f8051602061553283398151915260208181526040808420858552909152822080548390815b81811015611da05742848281548110611d5357611d53615160565b905f5260205f209060020201600101541115611d9857838181548110611d7b57611d7b615160565b905f5260205f2090600202015f015483611d9591906151a0565b92505b600101611d38565b50909695505050505050565b5f6001600160e01b031982166318a4c3c360e11b1480610efa5750610efa826131f4565b6001600160a01b038416611df9576040516301486a4160e71b81525f60048201526024016111bc565b6001600160a01b038316611e2257604051630b8bbd6160e41b81525f60048201526024016111bc565b610f7d84848484613218565b610f4581336133f9565b611e425f80613432565b565b6001600160a01b038316611e6d57604051630b8bbd6160e41b81525f60048201526024016111bc565b610fa45f848484613218565b5f8281527f2ada2772a8c4d40c4be8741992e423a9f97d5f4ef76852e5c17a40aa7fb9e501602052604090205f8051602061559283398151915290611ebe8382615222565b50827f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b83604051611eef9190614a69565b60405180910390a2505050565b5f611f0561350a565b9050611f12818335613530565b611f2881611f2360208501856152dd565b6135a1565b611f618183604001355f9182527fec3c1253ecdf88a29ff53024f0721fc3faa1b42abcff612deb5b22d1f94e2d01602052604090912055565b611fb581611f756080850160608601615329565b5f7fdaa3d1cf82c71b982a9e24ff7dadd71a10e8c3e82a219c0e60ca5c6b8e6177005f938452602052506040909120805460ff1916911515919091179055565b807f76e35084bc84f178215c72d32676286f16ca2d3a80d3e80e317c858d61eb5a3783604051611fe59190615388565b60405180910390a2919050565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00610efa565b612022613600565b61202f8686868686613625565b61203881613652565b505050505050565b61204982610fa9565b61205281611e2e565b610f7d8383613663565b6001600160a01b03811633146120855760405163334bd91960e11b815260040160405180910390fd5b610fa482826136d7565b61209761372e565b5f80516020615652833981519152805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b5f805160206155528339815191526001600160a01b0385166121255760405163198ecd5360e31b81525f60048201526024016111bc565b6001600160a01b03841661214e57604051636f65f46560e01b81525f60048201526024016111bc565b6001600160a01b038581165f81815260028401602090815260408083209489168084529482528083208884528252918290208690559051858152869392917fb3fd5071835887567a0671151121894ddccc2842f1d10bedad13e0d17cace9a7910160405180910390a45050505050565b5f805160206156528339815191525460ff1615611e425760405163d93c066560e01b815260040160405180910390fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c1561222e57604051633ee5aeb560e01b815260040160405180910390fd5b611e4260017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b9061375d565b5f8051602061569283398151915261227285613764565b61227b82613796565b5f83815260028201602090815260408083206001600160a01b0388168452909152812054908190036122d25760405163ec40a7ab60e01b8152600481018590526001600160a01b03861660248201526044016111bc565b5f6122dd84836151c7565b9050855f6001600160a01b03821663dd62ed3e336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa158015612339573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061235d9190615414565b905082811015612399576040516303dfb80d60e11b81526001600160a01b038916600482015260248101849052604481018290526064016111bc565b5f6001600160a01b0383166370a08231336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156123ec573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124109190615414565b90508381101561244c57604051633514dc2360e21b81526001600160a01b038a16600482015260248101859052604481018290526064016111bc565b6124663387546001600160a01b03868116929116876137b9565b6124728a898987613813565b50505050505050505050565b611e425f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00612255565b816124b28161132b565b6124d25760405163b7c882eb60e01b8152600481018290526024016111bc565b6124dd838335613530565b6124ee83611f2360208501856152dd565b6125278383604001355f9182527fec3c1253ecdf88a29ff53024f0721fc3faa1b42abcff612deb5b22d1f94e2d01602052604090912055565b61253b83611f756080850160608601615329565b827f76e35084bc84f178215c72d32676286f16ca2d3a80d3e80e317c858d61eb5a3783604051611eef9190615388565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806125f157507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166125e55f805160206155d2833981519152546001600160a01b031690565b6001600160a01b031614155b15611e425760405163703e46dd60e11b815260040160405180910390fd5b7fa76ace73a908083d89af9ff88e5b4f7cadb3591a80631063f68b695fda726db561111c81611e2e565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612693575060408051601f3d908101601f1916820190925261269091810190615414565b60015b6126bb57604051634c9c8ce360e01b81526001600160a01b03831660048201526024016111bc565b5f805160206155d283398151915281146126eb57604051632a87526960e21b8152600481018290526024016111bc565b610fa48383613870565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611e425760405163703e46dd60e11b815260040160405180910390fd5b610fa4835f84846138c5565b5f805160206155528339815191526001600160a01b0384166127815760405163198ecd5360e31b81525f60048201526024016111bc565b6001600160a01b0383166127aa57604051636f65f46560e01b81525f60048201526024016111bc565b6001600160a01b038481165f818152600184016020908152604080832094881680845294825291829020805460ff191687151590811790915591519182527fceb576d9f15e4e200fdb5096d64d5dfd667e16def20c1eefd14256d8e3faa26791015b60405180910390a350505050565b5f612823611999565b61282c426139ee565b612836919061542b565b90506128428282613a24565b60405165ffffffffffff821681526001600160a01b038316907f3377dc44241e779dd06afab5b788a35ca5f3b778836e2990bdb26a2a4b2e5ed6906020015b60405180910390a25050565b5f61289782613aae565b6128a0426139ee565b6128aa919061542b565b90506128b68282613432565b6040805165ffffffffffff8085168252831660208201527ff1038c18cf84a56e432fdbfaf746924b7ea511dfe03a6506a0ceba4888788d9b910160405180910390a15050565b5f8051602061569283398151915261291384613764565b61291c82613796565b5f83815260018201602052604081205490819003612950576040516384e7368960e01b8152600481018590526024016111bc565b5f61295b84836151c7565b905080341015612995576040516301b1e28360e21b81526004810186905260248101859052604481018290523460648201526084016111bc565b803411156129d257336108fc6129ab833461544a565b6040518115909202915f818181858888f193505050501580156129d0573d5f803e3d5ffd5b505b82546040516001600160a01b039091169082156108fc029083905f818181858888f19350505050158015612a08573d5f803e3d5ffd5b5061203886868684613813565b6001600160a01b0381165f9081525f80516020615572833981519152602081905260409091205460ff16612a47575050565b6001600160a01b0382165f908152602082905260408120805460ff191690555b6001820154811015612b6557826001600160a01b0316826001018281548110612a9257612a92615160565b5f918252602090912001546001600160a01b031603612b5d57600180830180549091612abd9161544a565b81548110612acd57612acd615160565b5f918252602090912001546001830180546001600160a01b039092169183908110612afa57612afa615160565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555081600101805480612b3857612b386151b3565b5f8281526020902081015f1990810180546001600160a01b0319169055019055612b65565b600101612a67565b506040517f7d2be5e40a0d45d9af5c7db1fc1fa7822674e1d5f550082d32be1b8bf80c015f906001600160a01b038416907f233494033cad48d751b00c55d58da5f087d21031a3859563c7b6a7f3a2ccf04d905f90a35050565b612bc76121be565b5f80516020615652833981519152805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258336120d0565b5f8051602061559283398151915280612c208382615222565b506040517fa5d4097edda6d87cb9329af83fb3712ef77eeb13738ffe43cc35a4ce305ad962905f90a15050565b5f8181527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff6036020526040902080546060915f80516020615692833981519152916001600160401b03811115612ca457612ca4614b80565b604051908082528060200260200182016040528015612ce857816020015b604080518082019091525f8082526020820152815260200190600190039081612cc25790505b5092505f5b8154811015612d7a575f828281548110612d0957612d09615160565b5f91825260208083209091015488835260028701825260408084206001600160a01b03909216808552918352928390205483518085019094528184529183018290528751909350909190879085908110612d6557612d65615160565b60209081029190910101525050600101612ced565b505050919050565b5f805160206155f28339815191525f80612d9a611a53565b91509150612daf8165ffffffffffff16151590565b1580612dc357504265ffffffffffff821610155b15612deb576040516319ca5ebb60e01b815265ffffffffffff821660048201526024016111bc565b612dfc5f612df7611708565b6136d7565b50612e075f83613663565b505081546001600160d01b03191690915550565b5f8181527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff6016020526040812054905f8051602061569283398151915290829003610fed576040516384e7368960e01b8152600481018490526024016111bc565b612e8482610fa9565b612e8d81611e2e565b610f7d83836136d7565b611e425f80613a24565b5f8281525f805160206154f283398151915260208190526040909120612ec78382615222565b50827f6846707b16f55a3623d38bf118700af63d0784698270a53ce28b116dbaa8b79483604051611eef9190614a69565b5f8281525f805160206154f283398151915260208190526040909120600101612f218382615222565b50827f8fabcb7b4fbdde605303a7339bc80fb6956cd01a42e9cdf2d15d0f2fdd3b06fa83604051611eef9190614a69565b5f8281525f805160206154f28339815191526020818152604092839020600201805460ff191660ff86169081179091559251928352909184917fc7435874568017e6134c851002a405d733521c0f4c63f9f25f3a32a4d595b7299101611eef565b5f805160206156928339815191526001600160a01b038216612ff3576040516334d5d27d60e21b81526001600160a01b03831660048201526024016111bc565b80546001600160a01b0319166001600160a01b03831690811782556040513381527f4ab5be82436d353e61ca18726e984e561f5c1cc7c6d38b29d2553c790434705a90602001612881565b6001600160a01b03811661307057604051634726455360e11b81526001600160a01b03821660048201526024016111bc565b6001600160a01b0381165f9081525f80516020615572833981519152602081905260409091205460ff16156130a3575050565b6001600160a01b0382165f81815260208381526040808320805460ff1916600190811790915585810180549182018155845291832090910180546001600160a01b03191684179055517f6f58fc3760b5743cf76087dfed697597f39c204c204718113b3ee0e4d995fc3b92917f233494033cad48d751b00c55d58da5f087d21031a3859563c7b6a7f3a2ccf04d91a35050565b6001600160a01b03831661315f576040516301486a4160e71b81525f60048201526024016111bc565b610fa4835f8484613218565b5f805160206155528339815191525f61318586868661160d565b90505f1981101561203857828110156131b95784818486604051632c51fead60e11b81526004016111bc949392919061545d565b6001600160a01b038087165f908152600284016020908152604080832093891683529281528282208783529052208382039055505050505050565b5f6001600160e01b03198216637965db0b60e01b1480610efa5750610efa82613af5565b6132206121be565b6001600160a01b0384165f9081525f80516020615572833981519152602081905260409091205485919060ff1615613276576040516327951b3f60e11b81526001600160a01b03831660048201526024016111bc565b6001600160a01b0385165f9081525f80516020615572833981519152602081905260409091205486919060ff16156132cc576040516327951b3f60e11b81526001600160a01b03831660048201526024016111bc565b856132d68161132b565b6132f65760405163b7c882eb60e01b8152600481018290526024016111bc565b8888887fdaa3d1cf82c71b982a9e24ff7dadd71a10e8c3e82a219c0e60ca5c6b8e6177006001600160a01b0384161580159061333a57506001600160a01b03831615155b801561335457505f8281526020829052604090205460ff16155b15613375576040516368ee0b2f60e11b8152600481018390526024016111bc565b8b6001600160a01b03168d6001600160a01b0316036133b257604051633ef2228f60e21b81526001600160a01b038e1660048201526024016111bc565b895f036133d2576040516323cf7d7d60e01b815260040160405180910390fd5b6133de8d8d8d8d613b29565b6133ea8d8d8d8d6138c5565b50505050505050505050505050565b6134038282611731565b61111c5760405163e2517d3f60e01b81526001600160a01b0382166004820152602481018390526044016111bc565b5f80516020615672833981519152545f805160206155f283398151915290600160d01b900465ffffffffffff1680156134cc574265ffffffffffff821610156134a357600182015482546001600160d01b0316600160a01b90910465ffffffffffff16600160d01b021782556134cc565b6040517f2b1fa2edafe6f7b9e97c1a9e0c3660e645beb2dcaa2d45bdbf9beaf5472e1ec5905f90a15b5060010180546001600160a01b0316600160a01b65ffffffffffff948516026001600160d01b031617600160d01b9290931691909102919091179055565b5f805160206155b283398151915280549081815f61352783615188565b91905055505090565b5f8281527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff601602090815260409182902083905590518281525f805160206156928339815191529184917fa12c47d56c27d127f5f74f842a31dcfca20ecb155635a6ec6cb060a39cac2b339101611eef565b5f5b81811015610f7d576135f8848484848181106135c1576135c1615160565b6135d79260206040909202019081019150614fac565b8585858181106135e9576135e9615160565b90506040020160200135613b9d565b6001016135a3565b613608613e02565b611e4257604051631afcd79f60e31b815260040160405180910390fd5b61362d613600565b6136378585613e1b565b61363f613e3d565b61364883613e55565b611b928282613e66565b61365a613600565b610f4581612c07565b5f5f805160206155f2833981519152836136c5575f613680611708565b6001600160a01b0316146136a757604051631fe1e13d60e11b815260040160405180910390fd5b6001810180546001600160a01b0319166001600160a01b0385161790555b6136cf8484613ece565b949350505050565b5f5f805160206155f28339815191528315801561370c57506136f7611708565b6001600160a01b0316836001600160a01b0316145b15613724576001810180546001600160a01b03191690555b6136cf8484613f76565b5f805160206156528339815191525460ff16611e4257604051638dfc202b60e01b815260040160405180910390fd5b80825d5050565b6001600160a01b038116610f455760405163094293a160e31b81526001600160a01b03821660048201526024016111bc565b805f03610f455760405163023d875560e41b8152600481018290526024016111bc565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052610f7d908590613fef565b61381e84848461405b565b826001600160a01b0385167f0a9521815fb3c5bc7dd6f4c9f89dc270322e46b945b104c18981f81c3f2cd1aa33604080516001600160a01b03909216825260208201879052810185905260600161280c565b61387982614066565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156138bd57610fa482826140c9565b61111c61413b565b5f80516020615552833981519152336001600160a01b03861615613954576001600160a01b0386165f908152602083815260408083208784529091529020548381101561392d57868185876040516302c6d3fb60e61b81526004016111bc949392919061545d565b6001600160a01b0387165f9081526020848152604080832088845290915290209084900390555b6001600160a01b03851615613999576001600160a01b0385165f90815260208381526040808320878452909152812080548592906139939084906151a0565b90915550505b604080516001600160a01b03838116825260208201869052869281891692918a16917f1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac728859910160405180910390a4505050505050565b5f65ffffffffffff821115613a20576040516306dfcc6560e41b815260306004820152602481018390526044016111bc565b5090565b5f805160206155f28339815191525f613a3b611a53565b835465ffffffffffff8616600160a01b026001600160d01b03199091166001600160a01b038816171784559150613a7b90508165ffffffffffff16151590565b15610f7d576040517f8886ebfc4259abdbc16601dd8fb5678e54878f47b3c34836cfc51154a9605109905f90a150505050565b5f80613ab8611999565b90508065ffffffffffff168365ffffffffffff1611613ae057613adb8382615483565b610fea565b610fea65ffffffffffff84166206978061415a565b5f6001600160e01b03198216630f632fb360e01b1480610efa57506301ffc9a760e01b6001600160e01b0319831614610efa565b6001600160a01b038416613b5a57613b418383611368565b613b55838383613b5086614169565b6141e4565b610f7d565b6001600160a01b038316613b7d57613b7384838361450d565b613b558483611368565b613b878383611368565b613b93848484846146a7565b610f7d8483611368565b6001600160a01b038216613bcf5760405163aac3232160e01b81526001600160a01b03831660048201526024016111bc565b5f8381527f54c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff602602090815260408083206001600160a01b038616845290915290208190555f805160206156928339815191528115613cbf575f848152600382016020526040812090805b8254811015613c8757856001600160a01b0316838281548110613c5d57613c5d615160565b5f918252602090912001546001600160a01b031603613c7f5760019150613c87565b600101613c38565b5080613cb85781546001810183555f838152602090200180546001600160a01b0319166001600160a01b0387161790555b5050613dc6565b5f8481526003820160205260408120905b8154811015613dc357846001600160a01b0316828281548110613cf557613cf5615160565b5f918252602090912001546001600160a01b031603613dbb5781548290613d1e9060019061544a565b81548110613d2e57613d2e615160565b905f5260205f20015f9054906101000a90046001600160a01b0316828281548110613d5b57613d5b615160565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555081805480613d9657613d966151b3565b5f8281526020902081015f1990810180546001600160a01b0319169055019055613dc3565b600101613cd0565b50505b826001600160a01b0316847ffb08de1e404ab196167a5843d6f4552a93056ed1da04e2f6c958dc6c63f1e4b48460405161280c91815260200190565b5f613e0b611ff2565b54600160401b900460ff16919050565b613e23613600565b613e2d82826148b4565b613e356148c6565b61111c6148d2565b613e45613600565b613e4d6148d2565b611e426148da565b613e5d613600565b610f45816148f5565b613e6e613600565b5f5b81811015610fa457613ec5838383818110613e8d57613e8d615160565b9050604002015f0135848484818110613ea857613ea8615160565b9050604002016020016020810190613ec09190614fac565b613663565b50600101613e70565b5f5f80516020615612833981519152613ee78484611731565b613f66575f848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055613f1c3390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a46001915050610efa565b5f915050610efa565b5092915050565b5f5f80516020615612833981519152613f8f8484611731565b15613f66575f848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a46001915050610efa565b5f8060205f8451602086015f885af18061400e576040513d5f823e3d81fd5b50505f513d91508115614025578060011415614032565b6001600160a01b0384163b155b15610f7d57604051635274afe760e01b81526001600160a01b03851660048201526024016111bc565b610fa4838383611e44565b806001600160a01b03163b5f0361409b57604051634c9c8ce360e01b81526001600160a01b03821660048201526024016111bc565b5f805160206155d283398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80846001600160a01b0316846040516140e591906154a2565b5f60405180830381855af49150503d805f811461411d576040519150601f19603f3d011682016040523d82523d5f602084013e614122565b606091505b5091509150614132858383614906565b95945050505050565b3415611e425760405163b398979f60e01b815260040160405180910390fd5b5f828218828410028218610f0b565b5f806141748361182b565b9050805f0361418657505f1992915050565b5f61419182426151a0565b90505f61419f6064846154bd565b9050805f036141ac575060015b5f8160016141ba82866151a0565b6141c4919061544a565b6141ce91906154bd565b90506141da82826151c7565b9695505050505050565b6001600160a01b0384165f9081525f805160206155328339815191526020818152604080842087855290915282208054919290919081905b828110156143205783818154811061423657614236615160565b905f5260205f2090600202015f01545f148015614273575083818154811061426057614260615160565b905f5260205f209060020201600101545f145b1561428057809150614320565b8584828154811061429357614293615160565b905f5260205f20906002020160010154036142e757868482815481106142bb576142bb615160565b905f5260205f2090600202015f015f8282546142d791906151a0565b90915550610f7d95505050505050565b858482815481106142fa576142fa615160565b905f5260205f20906002020160010154111561431857809150614320565b60010161421c565b50818110614364576040805180820190915286815260208082018781528554600181810188555f8881529390932093516002909102909301928355519101556115ee565b82818154811061437657614376615160565b905f5260205f2090600202015f01545f1480156143b357508281815481106143a0576143a0615160565b905f5260205f209060020201600101545f145b15614402576040518060400160405280878152602001868152508382815481106143df576143df615160565b5f91825260209182902083516002909202019081559101516001909101556115ee565b604080518082019091525f8082526020808301828152865460018181018955888552928420945160029091029094019384555192810192909255845490916144499161544a565b90505b818111156144bd578361446060018361544a565b8154811061447057614470615160565b905f5260205f20906002020184828154811061448e5761448e615160565b5f91825260209091208254600290920201908155600191820154910155806144b5816154dc565b91505061444c565b506040518060400160405280878152602001868152508382815481106144e5576144e5615160565b5f91825260209182902083516002909202019081559101516001909101555050505050505050565b6001600160a01b0383165f9081525f8051602061553283398151915260208181526040808420868552909152822080549192909184914291905b818110801561455557505f84115b15614676578285828154811061456d5761456d615160565b905f5260205f209060020201600101541115806145a9575084818154811061459757614597615160565b905f5260205f2090600202015f01545f145b61466457838582815481106145c0576145c0615160565b905f5260205f2090600202015f0154111561461257838582815481106145e8576145e8615160565b905f5260205f2090600202015f015f828254614604919061544a565b909155505f94506146649050565b84818154811061462457614624615160565b905f5260205f2090600202015f01548461463e919061544a565b93505f85828154811061465357614653615160565b5f9182526020909120600290910201555b8061466e81615188565b915050614547565b5082156115ee5787614688848861544a565b878960405163670f004560e01b81526004016111bc949392919061545d565b826001600160a01b0316846001600160a01b031614806146c5575080155b610f7d576001600160a01b0384165f9081525f8051602061553283398151915260208181526040808420868552909152822080549192909184914291905b818110801561471157505f84115b15614897578285828154811061472957614729615160565b905f5260205f20906002020160010154111580614765575084818154811061475357614753615160565b905f5260205f2090600202015f01545f145b614885578385828154811061477c5761477c615160565b905f5260205f2090600202015f015411156147fb576147be8989868885815481106147a9576147a9615160565b905f5260205f209060020201600101546141e4565b838582815481106147d1576147d1615160565b905f5260205f2090600202015f015f8282546147ed919061544a565b909155505f94506148859050565b614833898987848154811061481257614812615160565b905f5260205f2090600202015f01548885815481106147a9576147a9615160565b84818154811061484557614845615160565b905f5260205f2090600202015f01548461485f919061544a565b93505f85828154811061487457614874615160565b5f9182526020909120600290910201555b8061488f81615188565b915050614703565b5082156148a95788614688848861544a565b505050505050505050565b6148bc613600565b61111c8282614962565b6148ce613600565b611e425b611e42613600565b6148e2613600565b60015f805160206155b283398151915255565b6148fd613600565b610f4581612fb3565b60608261491b57614916826149c8565b610f0b565b815115801561493257506001600160a01b0384163b155b1561495b57604051639996b31560e01b81526001600160a01b03851660048201526024016111bc565b5080610f0b565b61496a613600565b5f805160206155f28339815191526001600160a01b0382166149a157604051636116401160e11b81525f60048201526024016111bc565b80546001600160d01b0316600160d01b65ffffffffffff851602178155610f7d5f83613663565b8051156149d757805160208201fd5b60405163d6bda27560e01b815260040160405180910390fd5b60405180604001604052805f8152602001614a2b60405180608001604052805f8152602001606081526020015f81526020015f151581525090565b905290565b5f60208284031215614a40575f80fd5b5035919050565b5f5b83811015614a61578181015183820152602001614a49565b50505f910152565b602081525f8251806020840152614a87816040850160208701614a47565b601f01601f19169190910160400192915050565b6001600160a01b0381168114610f45575f80fd5b5f8060408385031215614ac0575f80fd5b8235614acb81614a9b565b946020939093013593505050565b602080825282518282018190525f919060409081850190868401855b82811015614b1a57815180518552860151868501529284019290850190600101614af5565b5091979650505050505050565b5f60208284031215614b37575f80fd5b81356001600160e01b031981168114610f0b575f80fd5b5f805f60608486031215614b60575f80fd5b8335614b6b81614a9b565b95602085013595506040909401359392505050565b634e487b7160e01b5f52604160045260245ffd5b5f6001600160401b0380841115614bad57614bad614b80565b604051601f8501601f19908116603f01168101908282118183101715614bd557614bd5614b80565b81604052809350858152868686011115614bed575f80fd5b858560208301375f602087830101525050509392505050565b5f82601f830112614c15575f80fd5b610f0b83833560208501614b94565b5f8060408385031215614c35575f80fd5b8235915060208301356001600160401b03811115614c51575f80fd5b614c5d85828601614c06565b9150509250929050565b5f60808284031215610fed575f80fd5b5f60208284031215614c87575f80fd5b81356001600160401b03811115614c9c575f80fd5b6136cf84828501614c67565b803565ffffffffffff81168114614cbd575f80fd5b919050565b5f805f805f8060a08789031215614cd7575f80fd5b614ce087614ca8565b95506020870135614cf081614a9b565b94506040870135614d0081614a9b565b935060608701356001600160401b0380821115614d1b575f80fd5b818901915089601f830112614d2e575f80fd5b813581811115614d3c575f80fd5b8a60208260061b8501011115614d50575f80fd5b602083019550809450506080890135915080821115614d6d575f80fd5b50614d7a89828a01614c06565b9150509295509295509295565b5f8060408385031215614d98575f80fd5b823591506020830135614daa81614a9b565b809150509250929050565b5f815180845260208085019450602084015f5b83811015614df857815180516001600160a01b031688528301518388015260409096019590820190600101614dc8565b509495945050505050565b60208152815160208201525f6020830151604080840152805160608401526020810151608080850152614e3960e0850182614db5565b604083015160a0860152606090920151151560c0909401939093529392505050565b5f805f8060808587031215614e6e575f80fd5b8435614e7981614a9b565b93506020850135614e8981614a9b565b93969395505050506040820135916060013590565b5f8060408385031215614eaf575f80fd5b8235915060208301356001600160401b03811115614ecb575f80fd5b614c5d85828601614c67565b5f8060408385031215614ee8575f80fd5b8235614ef381614a9b565b915060208301356001600160401b03811115614f0d575f80fd5b8301601f81018513614f1d575f80fd5b614c5d85823560208401614b94565b80358015158114614cbd575f80fd5b5f8060408385031215614f4c575f80fd5b8235614f5781614a9b565b9150614f6560208401614f2c565b90509250929050565b5f805f60608486031215614f80575f80fd5b8335614f8b81614a9b565b92506020840135614f9b81614a9b565b929592945050506040919091013590565b5f60208284031215614fbc575f80fd5b8135610f0b81614a9b565b5f60208284031215614fd7575f80fd5b610f0b82614ca8565b5f8060408385031215614ff1575f80fd5b50508035926020909101359150565b5f60208284031215615010575f80fd5b81356001600160401b03811115615025575f80fd5b6136cf84828501614c06565b602081525f610f0b6020830184614db5565b5f8060408385031215615054575f80fd5b823561505f81614a9b565b91506020830135614daa81614a9b565b602080825282518282018190525f9190848201906040850190845b81811015611da05783516001600160a01b03168352928401929184019160010161508a565b5f805f80608085870312156150c2575f80fd5b8435935060208501356001600160401b03808211156150df575f80fd5b6150eb88838901614c06565b94506040870135915080821115615100575f80fd5b5061510d87828801614c06565b925050606085013560ff81168114615123575f80fd5b939692955090935050565b600181811c9082168061514257607f821691505b602082108103610fed57634e487b7160e01b5f52602260045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f6001820161519957615199615174565b5060010190565b80820180821115610efa57610efa615174565b634e487b7160e01b5f52603160045260245ffd5b8082028115828204841417610efa57610efa615174565b601f821115610fa457805f5260205f20601f840160051c810160208510156152035750805b601f840160051c820191505b81811015611b92575f815560010161520f565b81516001600160401b0381111561523b5761523b614b80565b61524f81615249845461512e565b846151de565b602080601f831160018114615282575f841561526b5750858301515b5f19600386901b1c1916600185901b178555612038565b5f85815260208120601f198616915b828110156152b057888601518255948401946001909101908401615291565b50858210156152cd57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f808335601e198436030181126152f2575f80fd5b8301803591506001600160401b0382111561530b575f80fd5b6020019150600681901b3603821315615322575f80fd5b9250929050565b5f60208284031215615339575f80fd5b610f0b82614f2c565b8183525f60208085019450825f5b85811015614df857813561536381614a9b565b6001600160a01b03168752818301358388015260409687019690910190600101615350565b60208152813560208201525f6020830135601e198436030181126153aa575f80fd5b83016020810190356001600160401b038111156153c5575f80fd5b8060061b36038213156153d6575f80fd5b608060408501526153eb60a085018284615342565b9150506040840135606084015261540460608501614f2c565b8015156080850152509392505050565b5f60208284031215615424575f80fd5b5051919050565b65ffffffffffff818116838216019080821115613f6f57613f6f615174565b81810381811115610efa57610efa615174565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b65ffffffffffff828116828216039080821115613f6f57613f6f615174565b5f82516154b3818460208701614a47565b9190910192915050565b5f826154d757634e487b7160e01b5f52601260045260245ffd5b500490565b5f816154ea576154ea615174565b505f19019056fea0651e3d105d335a33d7d04897e080112be09c416f44637d6543e5b47885f80074f7a545c65c11839a48d7453738b30c295408df2d944516167556759ddc6d06ec3c1253ecdf88a29ff53024f0721fc3faa1b42abcff612deb5b22d1f94e2d009e75074fe7582401cc58901f6bda367c4d687c51437956963a7c06ef5cfaf900a095fe5a3c31691ae0832631cef3701285d36b2af1972f4c23463476b0353a002ada2772a8c4d40c4be8741992e423a9f97d5f4ef76852e5c17a40aa7fb9e500591f2d2df77efc80b9969dfd51dd4fc103fe490745902503f7c21df07a35d600360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbceef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840002dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680046f3eccdd88dd62792ae8eed1be7b9b658477566c49fd85b0d08cf44261c9208cd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300eef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840154c84cf2875b53587e3bd1a41cdb4ae126fe9184d0b1bd9183d4f9005d2ff600a26469706673582212208080f9bf44f8535e057a3c1ce9fc15fd88bc16ad72ce5b1c94b4513a8d4e834864736f6c63430008180033 diff --git a/src/EVMAuth6909.sol b/src/EVMAuth6909.sol index 6ffaa37..df46891 100644 --- a/src/EVMAuth6909.sol +++ b/src/EVMAuth6909.sol @@ -152,6 +152,11 @@ contract EVMAuth6909 is ERC6909MetadataUpgradeable, ERC6909ContentURIUpgradeable _setDecimals(id, decimals); } + /// @inheritdoc TokenEphemeral + function _burnPrunedTokens(address account, uint256 id, uint256 amount) internal virtual override { + super._update(account, address(0), id, amount); + } + /// @inheritdoc TokenPurchasable function _mintPurchasedTokens(address to, uint256 id, uint256 amount) internal virtual override { _mint(to, id, amount); diff --git a/src/base/EVMAuth.sol b/src/base/EVMAuth.sol index 656838f..3ff5c00 100644 --- a/src/base/EVMAuth.sol +++ b/src/base/EVMAuth.sol @@ -222,10 +222,10 @@ abstract contract EVMAuth is function _createToken(EVMAuthTokenConfig calldata config) internal virtual returns (uint256 id) { id = _claimNextTokenID(); - _setPrice(id, config.price); - _setERC20Prices(id, config.erc20Prices); - _setTTL(id, config.ttl); - _setTransferable(id, config.transferable); + TokenPurchasable._setPrice(id, config.price); + TokenPurchasable._setERC20Prices(id, config.erc20Prices); + TokenEphemeral._setTTL(id, config.ttl); + TokenTransferable._setTransferable(id, config.transferable); emit EVMAuthTokenConfigured(id, config); @@ -240,39 +240,14 @@ abstract contract EVMAuth is * @custom:emits EVMAuthTokenConfigured */ function _updateToken(uint256 id, EVMAuthTokenConfig calldata config) internal virtual tokenExists(id) { - _setPrice(id, config.price); - _setERC20Prices(id, config.erc20Prices); - _setTTL(id, config.ttl); - _setTransferable(id, config.transferable); + TokenPurchasable._setPrice(id, config.price); + TokenPurchasable._setERC20Prices(id, config.erc20Prices); + TokenEphemeral._setTTL(id, config.ttl); + TokenTransferable._setTransferable(id, config.transferable); emit EVMAuthTokenConfigured(id, config); } - /// @inheritdoc TokenPurchasable - function _setPrice(uint256 id, uint256 price) internal virtual override tokenExists(id) { - TokenPurchasable._setPrice(id, price); - } - - /// @inheritdoc TokenPurchasable - function _setERC20Price(uint256 id, address token, uint256 price) internal virtual override tokenExists(id) { - TokenPurchasable._setERC20Price(id, token, price); - } - - /// @inheritdoc TokenPurchasable - function _setERC20Prices(uint256 id, PaymentToken[] calldata prices) internal virtual override tokenExists(id) { - TokenPurchasable._setERC20Prices(id, prices); - } - - /// @inheritdoc TokenEphemeral - function _setTTL(uint256 id, uint256 ttl) internal virtual override tokenExists(id) { - TokenEphemeral._setTTL(id, ttl); - } - - /// @inheritdoc TokenTransferable - function _setTransferable(uint256 id, bool transferable) internal virtual override tokenExists(id) { - super._setTransferable(id, transferable); - } - /// @inheritdoc UUPSUpgradeable function _authorizeUpgrade(address newImplementation) internal virtual override onlyRole(UPGRADE_MANAGER_ROLE) { // This will revert if the caller is not authorized. diff --git a/src/base/TokenAccessControl.sol b/src/base/TokenAccessControl.sol index a83cb95..b9a6404 100644 --- a/src/base/TokenAccessControl.sol +++ b/src/base/TokenAccessControl.sol @@ -11,7 +11,7 @@ import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/P * @title TokenAccessControl * @author EVMAuth * @notice Provides comprehensive role-based access control for token management. - * @dev Abstract contract implementing six distinct roles for granular permission control:. + * @dev Abstract contract implementing six distinct roles for granular permission control: * upgrade management, access management, token management, minting, burning, and treasury operations. * Includes account freezing via AccountFreezable and contract pausing via PausableUpgradeable. */ diff --git a/src/base/TokenEphemeral.sol b/src/base/TokenEphemeral.sol index a5b51a0..6d18b36 100644 --- a/src/base/TokenEphemeral.sol +++ b/src/base/TokenEphemeral.sol @@ -43,6 +43,14 @@ abstract contract TokenEphemeral is ContextUpgradeable { mapping(uint256 => uint256) ttls; } + /** + * @notice Emitted when pruned tokens are burned. + * @param from Address from which tokens were pruned + * @param id Token type identifier + * @param amount Quantity of tokens that were pruned (expired) + */ + event ExpiredTokensPruned(address indexed from, uint256 indexed id, uint256 amount); + /** * @notice EIP-7201 storage slot for TokenEphemeral state. * @dev Computed as: keccak256(abi.encode(uint256(keccak256("tokenephemeral.storage.TokenEphemeral")) - 1)) @@ -133,6 +141,7 @@ abstract contract TokenEphemeral is ContextUpgradeable { * @dev Public function for manual storage cleanup. Automatically called during transfers. * @param account Address to prune records for * @param id Token type identifier + * @custom:emits ExpiredTokensPruned if any tokens were pruned. */ function pruneBalanceRecords(address account, uint256 id) public virtual { TokenEphemeralStorage storage $ = _getTokenEphemeralStorage(); @@ -140,15 +149,23 @@ abstract contract TokenEphemeral is ContextUpgradeable { uint256 currentTime = block.timestamp; uint256 writeIndex = 0; uint256 currentLength = records.length; + uint256 expiredAmount = 0; // This amount must be burned using the token standard's burn method // Compact valid records to the front for (uint256 i = 0; i < currentLength; i++) { - bool isValid = records[i].amount > 0 && records[i].expiresAt > currentTime; - if (isValid) { + if (records[i].amount == 0) { + continue; // Skip empty records + } + + if (records[i].expiresAt > currentTime) { + // Record is still valid; move it to the write index if needed if (i != writeIndex) { records[writeIndex] = records[i]; } writeIndex++; + } else { + // Record is expired; accumulate expired amount + expiredAmount += records[i].amount; } } @@ -170,8 +187,24 @@ abstract contract TokenEphemeral is ContextUpgradeable { records.pop(); } } + + // If any tokens were pruned (expired), call the _burnPrunedTokens hook and emit event + if (expiredAmount > 0) { + _burnPrunedTokens(account, id, expiredAmount); + emit ExpiredTokensPruned(account, id, expiredAmount); + } } + /** + * @notice Internal hook to handle burning of pruned tokens. + * @dev Override this function to integrate with the token standard's burn mechanism. + * Called automatically during pruning if expired tokens are found. + * @param account Address from which tokens were pruned + * @param id Token type identifier + * @param amount Quantity of tokens that were pruned (expired) + */ + function _burnPrunedTokens(address account, uint256 id, uint256 amount) internal virtual; + /** * @notice Internal function to configure token TTL. * @dev Sets expiration duration for new tokens of this type. diff --git a/src/base/TokenPurchasable.sol b/src/base/TokenPurchasable.sol index 6f8d8db..74e1475 100644 --- a/src/base/TokenPurchasable.sol +++ b/src/base/TokenPurchasable.sol @@ -221,18 +221,6 @@ abstract contract TokenPurchasable is PausableUpgradeable, ReentrancyGuardTransi } } - /** - * @notice Checks if ERC-20 token is accepted for payment. - * @dev Returns true if price > 0. - * @param id Token type identifier - * @param paymentToken ERC-20 contract address to check - * @return True if accepted, false otherwise - */ - function isAcceptedERC20PaymentToken(uint256 id, address paymentToken) public view virtual returns (bool) { - TokenPurchasableStorage storage $ = _getTokenPurchasableStorage(); - return $.erc20Prices[id][paymentToken] > 0; - } - /** * @notice Gets current treasury address. * @dev All purchase revenues are sent to this address. diff --git a/test/EVMAuth1155.t.sol b/test/EVMAuth1155.t.sol index f16510b..d0a0c43 100644 --- a/test/EVMAuth1155.t.sol +++ b/test/EVMAuth1155.t.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.24; import { EVMAuth } from "src/base/EVMAuth.sol"; +import { TokenEphemeral } from "src/base/TokenEphemeral.sol"; import { TokenPurchasable } from "src/base/TokenPurchasable.sol"; import { EVMAuth1155 } from "src/EVMAuth1155.sol"; import { BaseTestWithAccessControlAndERC20s } from "test/_helpers/BaseTest.sol"; @@ -930,6 +931,62 @@ contract EVMAuth1155Test is BaseTestWithAccessControlAndERC20s { assertEq(v1.balanceOf(alice, tokenId), 100); } + function test_ephemeralToken_balanceRecords() public { + // Create ephemeral token + uint256 ttl = 7200; // 2 hours + vm.prank(tokenManager); + uint256 tokenId = v1.createToken( + EVMAuth.EVMAuthTokenConfig({ + price: 1 ether, + erc20Prices: new TokenPurchasable.PaymentToken[](0), + ttl: ttl, + transferable: true + }) + ); + + // Mint tokens at different times + vm.prank(minter); + v1.mint(alice, tokenId, 50, ""); + + vm.warp(block.timestamp + 3600); // 1 hour later + vm.prank(minter); + v1.mint(alice, tokenId, 75, ""); + + // Check balance records + TokenEphemeral.BalanceRecord[] memory records = v1.balanceRecordsOf(alice, tokenId); + assertEq(records.length, 2); + assertEq(v1.balanceOf(alice, tokenId), 125); + } + + function test_ephemeralToken_pruning() public { + // Create ephemeral token + uint256 ttl = 60; // 1 minute + vm.prank(tokenManager); + uint256 tokenId = v1.createToken( + EVMAuth.EVMAuthTokenConfig({ + price: 1 ether, + erc20Prices: new TokenPurchasable.PaymentToken[](0), + ttl: ttl, + transferable: true + }) + ); + + // Mint tokens + vm.prank(minter); + v1.mint(alice, tokenId, 5, ""); + assertEq(v1.balanceOf(alice, tokenId), 5); + + // Let tokens expire + vm.warp(block.timestamp + ttl * 2); + assertEq(v1.balanceOf(alice, tokenId), 0); + + // Prune expired records + v1.pruneBalanceRecords(alice, tokenId); + + TokenEphemeral.BalanceRecord[] memory records = v1.balanceRecordsOf(alice, tokenId); + assertEq(records.length, 0); + } + // ============ Transfer Restrictions Tests ============= // function testRevert_transfer_TokenIsNonTransferable() public { diff --git a/test/EVMAuth6909.t.sol b/test/EVMAuth6909.t.sol index ba1a237..83f3dbe 100644 --- a/test/EVMAuth6909.t.sol +++ b/test/EVMAuth6909.t.sol @@ -2,13 +2,13 @@ pragma solidity ^0.8.24; +import { AccountFreezable } from "src/base/AccountFreezable.sol"; import { EVMAuth } from "src/base/EVMAuth.sol"; import { EVMAuth6909 } from "src/EVMAuth6909.sol"; -import { TokenPurchasable } from "src/base/TokenPurchasable.sol"; import { TokenEphemeral } from "src/base/TokenEphemeral.sol"; import { TokenEnumerable } from "src/base/TokenEnumerable.sol"; +import { TokenPurchasable } from "src/base/TokenPurchasable.sol"; import { TokenTransferable } from "src/base/TokenTransferable.sol"; -import { AccountFreezable } from "src/base/AccountFreezable.sol"; import { BaseTestWithAccessControlAndERC20s } from "test/_helpers/BaseTest.sol"; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; import { IERC6909 } from "@openzeppelin/contracts/interfaces/draft-IERC6909.sol"; @@ -243,7 +243,7 @@ contract EVMAuth6909Test is BaseTestWithAccessControlAndERC20s { }); vm.expectEmit(true, false, false, true); - emit EVMAuthTokenConfigured(1, config); + emit EVMAuth.EVMAuthTokenConfigured(1, config); vm.prank(tokenManager); uint256 tokenId = v1.createToken(config); @@ -309,7 +309,7 @@ contract EVMAuth6909Test is BaseTestWithAccessControlAndERC20s { }); vm.expectEmit(true, false, false, true); - emit EVMAuthTokenConfigured(tokenId, newConfig); + emit EVMAuth.EVMAuthTokenConfigured(tokenId, newConfig); vm.prank(tokenManager); v1.updateToken(tokenId, newConfig); @@ -434,6 +434,7 @@ contract EVMAuth6909Test is BaseTestWithAccessControlAndERC20s { // ============ Ephemeral Token Behavior Tests ============= // function test_ephemeralToken_expiration() public { + // Create ephemeral token uint256 ttl = 3600; // 1 hour vm.prank(tokenManager); uint256 tokenId = v1.createToken( @@ -445,6 +446,7 @@ contract EVMAuth6909Test is BaseTestWithAccessControlAndERC20s { }) ); + // Mint tokens to Alice vm.prank(minter); v1.mint(alice, tokenId, 100); @@ -460,7 +462,79 @@ contract EVMAuth6909Test is BaseTestWithAccessControlAndERC20s { assertEq(v1.balanceOf(alice, tokenId), 0); } + function test_ephemeralToken_multipleExpirations() public { + uint48 ttl1 = 1800; // 30 minutes + uint48 ttl2 = 3600; // 1 hour + uint256 bucketSize1 = ttl1 / 100; // DEFAULT_MAX_BALANCE_RECORDS = 100 + uint256 bucketSize2 = ttl2 / 100; // DEFAULT_MAX_BALANCE_RECORDS = 100 + + // Create two ephemeral tokens with different TTLs + vm.startPrank(tokenManager); + uint256 tokenId1 = v1.createToken( + EVMAuth.EVMAuthTokenConfig({ + price: 0, + erc20Prices: new TokenPurchasable.PaymentToken[](0), + ttl: ttl1, + transferable: true + }) + ); + uint256 tokenId2 = v1.createToken( + EVMAuth.EVMAuthTokenConfig({ + price: 0, + erc20Prices: new TokenPurchasable.PaymentToken[](0), + ttl: ttl2, + transferable: true + }) + ); + vm.stopPrank(); + + // Mint tokens + vm.startPrank(minter); + v1.mint(alice, tokenId1, 50); + v1.mint(alice, tokenId2, 100); + vm.stopPrank(); + + // Initially both should have full balance + assertEq(v1.balanceOf(alice, tokenId1), 50); + assertEq(v1.balanceOf(alice, tokenId2), 100); + + // Fast forward past first expiration but before second + vm.warp(block.timestamp + ttl1 + bucketSize1); + assertEq(v1.balanceOf(alice, tokenId1), 0); // Expired + assertEq(v1.balanceOf(alice, tokenId2), 100); // Still valid + + // Fast forward past second expiration + vm.warp(block.timestamp + (ttl2 - ttl1 + bucketSize2)); + assertEq(v1.balanceOf(alice, tokenId1), 0); // Still expired + assertEq(v1.balanceOf(alice, tokenId2), 0); // Now expired + } + + function test_permanentToken_noExpiration() public { + // Create permanent token (TTL = 0) + vm.prank(tokenManager); + uint256 tokenId = v1.createToken( + EVMAuth.EVMAuthTokenConfig({ + price: 0, + erc20Prices: new TokenPurchasable.PaymentToken[](0), + ttl: 0, // Permanent + transferable: true + }) + ); + + // Mint tokens + vm.prank(minter); + v1.mint(alice, tokenId, 100); + + // Initially alice should have full balance + assertEq(v1.balanceOf(alice, tokenId), 100); + + // Fast forward a very long time - tokens should still be valid + vm.warp(block.timestamp + 365 days); + assertEq(v1.balanceOf(alice, tokenId), 100); + } + function test_ephemeralToken_balanceRecords() public { + // Create ephemeral token uint256 ttl = 7200; // 2 hours vm.prank(tokenManager); uint256 tokenId = v1.createToken( @@ -487,6 +561,7 @@ contract EVMAuth6909Test is BaseTestWithAccessControlAndERC20s { } function test_ephemeralToken_pruning() public { + // Create token with short TTL uint256 ttl = 60; // 1 minute vm.prank(tokenManager); uint256 tokenId = v1.createToken( @@ -498,11 +573,14 @@ contract EVMAuth6909Test is BaseTestWithAccessControlAndERC20s { }) ); + // Mint tokens vm.prank(minter); v1.mint(alice, tokenId, 100); + assertEq(v1.balanceOf(alice, tokenId), 100); // Let tokens expire - vm.warp(block.timestamp + ttl + 1); + vm.warp(block.timestamp + ttl * 2); + assertEq(v1.balanceOf(alice, tokenId), 0); // Prune expired records v1.pruneBalanceRecords(alice, tokenId); @@ -705,6 +783,17 @@ contract EVMAuth6909Test is BaseTestWithAccessControlAndERC20s { v1.setTreasury(newTreasury); } + function test_supportsInterface() public view { + // Test that the contract supports required interfaces + bytes4 erc6909InterfaceId = 0x0f632fb3; // IERC6909 + bytes4 erc165InterfaceId = 0x01ffc9a7; // IERC165 + bytes4 accessControlInterfaceId = 0x7965db0b; // IAccessControl + + assertTrue(v1.supportsInterface(erc6909InterfaceId), "Should support IERC6909"); + assertTrue(v1.supportsInterface(erc165InterfaceId), "Should support IERC165"); + assertTrue(v1.supportsInterface(accessControlInterfaceId), "Should support IAccessControl"); + } + // ============ Helper Functions ============= // function _createPurchasableToken(uint256 price) internal returns (uint256) { @@ -725,8 +814,4 @@ contract EVMAuth6909Test is BaseTestWithAccessControlAndERC20s { v1.mint(to, tokenId, amount); return tokenId; } - - // ============ Event Definitions ============= // - - event EVMAuthTokenConfigured(uint256 indexed id, EVMAuth.EVMAuthTokenConfig config); } diff --git a/test/base/EVMAuth.t.sol b/test/base/EVMAuth.t.sol index fc6762d..301b4c2 100644 --- a/test/base/EVMAuth.t.sol +++ b/test/base/EVMAuth.t.sol @@ -3,13 +3,14 @@ pragma solidity ^0.8.24; import { EVMAuth } from "src/base/EVMAuth.sol"; -import { TokenPurchasable } from "src/base/TokenPurchasable.sol"; import { TokenEnumerable } from "src/base/TokenEnumerable.sol"; +import { TokenEphemeral } from "src/base/TokenEphemeral.sol"; +import { TokenPurchasable } from "src/base/TokenPurchasable.sol"; import { BaseTestWithAccessControlAndERC20s } from "test/_helpers/BaseTest.sol"; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; contract MockEVMAuthV1 is EVMAuth { - // For testing only; in a real implementation, use a token standard like ERC-1155 or ERC-6909. + // Mapping of address to token ID to balance, simulating an ERC-1155 or ERC-6909 implementation mapping(address => mapping(uint256 => uint256)) public balances; /** @@ -54,8 +55,15 @@ contract MockEVMAuthV1 is EVMAuth { /// @inheritdoc TokenPurchasable function _mintPurchasedTokens(address to, uint256 id, uint256 amount) internal virtual override { + _updateBalanceRecords(address(0), to, id, amount); balances[to][id] += amount; } + + /// @inheritdoc TokenEphemeral + function _burnPrunedTokens(address account, uint256 id, uint256 amount) internal virtual override { + // This is only called by pruneBalanceRecords, so we don't need to update balance records again + balances[account][id] -= amount; + } } contract EVMAuthTest is BaseTestWithAccessControlAndERC20s { @@ -122,7 +130,7 @@ contract EVMAuthTest is BaseTestWithAccessControlAndERC20s { // Create token vm.prank(tokenManager); vm.expectEmit(true, false, false, true); - emit EVMAuthTokenConfigured(1, config); + emit EVMAuth.EVMAuthTokenConfigured(1, config); uint256 tokenId = v1.createToken(config); // Verify token was created @@ -243,7 +251,7 @@ contract EVMAuthTest is BaseTestWithAccessControlAndERC20s { vm.prank(tokenManager); vm.expectEmit(true, false, false, true); - emit EVMAuthTokenConfigured(tokenId, newConfig); + emit EVMAuth.EVMAuthTokenConfigured(tokenId, newConfig); v1.updateToken(tokenId, newConfig); // Verify updated configuration @@ -342,7 +350,7 @@ contract EVMAuthTest is BaseTestWithAccessControlAndERC20s { // Update treasury vm.prank(treasurer); vm.expectEmit(false, true, false, true); - emit TreasuryUpdated(treasurer, newTreasury); + emit TokenPurchasable.TreasuryUpdated(treasurer, newTreasury); v1.setTreasury(newTreasury); // Verify treasury was updated @@ -586,8 +594,49 @@ contract EVMAuthTest is BaseTestWithAccessControlAndERC20s { assertFalse(v1.isFrozen(alice)); } - // ============ Event Tests ============= // + // ============ Pruning Tests ============= // + + function test_pruneBalanceRecords() public { + uint48 ttl = 10; - event EVMAuthTokenConfigured(uint256 indexed id, EVMAuth.EVMAuthTokenConfig config); - event TreasuryUpdated(address caller, address indexed account); + // Create token + vm.prank(tokenManager); + uint256 tokenId = v1.createToken( + EVMAuth.EVMAuthTokenConfig({ + price: 1 ether, + erc20Prices: new TokenPurchasable.PaymentToken[](0), + ttl: ttl, + transferable: true + }) + ); + + // Fund Alice + vm.deal(alice, 10 ether); + + // Mint tokens + vm.prank(alice); + v1.purchase{ value: 5 ether }(tokenId, 5); + assertEq(v1.balanceOf(alice, tokenId), 5); + assertEq(v1.balances(alice, tokenId), 5); + + // Let tokens expire + vm.warp(block.timestamp + ttl * 2); + + // Verify balanceOf does not show a balance, but the underlying balance still exists + assertEq(v1.balanceOf(alice, tokenId), 0); + assertEq(v1.balances(alice, tokenId), 5); + + // Expect the PrunedTokensBurned event to be emitted when pruning + vm.expectEmit(true, true, false, true); + emit TokenEphemeral.ExpiredTokensPruned(alice, tokenId, 5); + v1.pruneBalanceRecords(alice, tokenId); + + // Verify the underlying balance has been updated + assertEq(v1.balanceOf(alice, tokenId), 0); + assertEq(v1.balances(alice, tokenId), 0); + + // Verify all records are pruned + TokenEphemeral.BalanceRecord[] memory records = v1.balanceRecordsOf(alice, tokenId); + assertEq(records.length, 0); + } } diff --git a/test/base/TokenAccessControl.t.sol b/test/base/TokenAccessControl.t.sol index 9701663..1140c89 100644 --- a/test/base/TokenAccessControl.t.sol +++ b/test/base/TokenAccessControl.t.sol @@ -5,6 +5,8 @@ pragma solidity ^0.8.24; import { TokenAccessControl } from "src/base/TokenAccessControl.sol"; import { BaseTestWithAccessControl } from "test/_helpers/BaseTest.sol"; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; +import { IAccessControlDefaultAdminRules } from + "@openzeppelin/contracts/access/extensions/IAccessControlDefaultAdminRules.sol"; import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; contract MockTokenAccessControlV1 is TokenAccessControl, UUPSUpgradeable { @@ -213,4 +215,73 @@ contract TokenAccessControlTest is BaseTestWithAccessControl { v1.unpause(); vm.stopPrank(); } + + // ============ Default Admin Tests ============= // + + function test_beginDefaultAdminTransfer() public { + // Verify that owner has the DEFAULT_ADMIN_ROLE + assertTrue(v1.hasRole(DEFAULT_ADMIN_ROLE, owner)); + + // Begin transfer of default admin role to Alice + vm.prank(owner); + v1.beginDefaultAdminTransfer(alice); + + // Get transfer delay + uint48 delay = v1.defaultAdminDelay(); + + // Verify that Alice is the pending default admin + (address pendingAdmin, uint48 schedule) = v1.pendingDefaultAdmin(); + assertEq(pendingAdmin, alice); + assertEq(schedule, uint48(block.timestamp + delay)); + + // Verify that the transfer cannot be completed immediately + vm.expectRevert( + abi.encodeWithSelector( + IAccessControlDefaultAdminRules.AccessControlEnforcedDefaultAdminDelay.selector, schedule + ) + ); + vm.prank(alice); + v1.acceptDefaultAdminTransfer(); + + // Fast forward time + vm.warp(block.timestamp + delay + 1); + + // Now accept the transfer + vm.prank(alice); + v1.acceptDefaultAdminTransfer(); + + // Verify that Alice is now the default admin + assertTrue(v1.hasRole(DEFAULT_ADMIN_ROLE, alice)); + assertFalse(v1.hasRole(DEFAULT_ADMIN_ROLE, owner)); + } + + function test_changeDefaultAdminDelay() public { + // Verify that owner has the DEFAULT_ADMIN_ROLE + assertTrue(v1.hasRole(DEFAULT_ADMIN_ROLE, owner)); + + // Begin change of default admin delay + uint48 oldDelay = v1.defaultAdminDelay(); // 172800 + vm.prank(owner); + v1.changeDefaultAdminDelay(oldDelay + 1 days); + + // Verify that the delay change is pending + (uint48 pendingDelay, uint48 schedule) = v1.pendingDefaultAdminDelay(); + assertEq(pendingDelay, oldDelay + 1 days); + + // Expected delay change schedule depends on whether the delay was increased or decreased + uint48 expectedSchedule; + if (pendingDelay > oldDelay) { + expectedSchedule = uint48(block.timestamp + pendingDelay); + } else { + expectedSchedule = uint48(block.timestamp + oldDelay - pendingDelay); + } + assertEq(schedule, expectedSchedule); + + // Fast forward time + vm.warp(expectedSchedule + 1); + + // Now the delay change should be in effect + uint48 newDelay = v1.defaultAdminDelay(); + assertEq(newDelay, pendingDelay); + } } diff --git a/test/base/TokenEnumerable.t.sol b/test/base/TokenEnumerable.t.sol index 6ba12f0..99df0af 100644 --- a/test/base/TokenEnumerable.t.sol +++ b/test/base/TokenEnumerable.t.sol @@ -23,8 +23,8 @@ contract MockTokenEnumerableV1 is TokenEnumerable, OwnableUpgradeable, UUPSUpgra * @param initialOwner The address to be set as the owner of the contract. */ function __MockTokenEnumerableV1_init(address initialOwner) internal onlyInitializing { - __Ownable_init(initialOwner); __TokenEnumerable_init(); + __Ownable_init(initialOwner); __MockTokenEnumerableV1_init_unchained(); } diff --git a/test/base/TokenEphemeral.t.sol b/test/base/TokenEphemeral.t.sol index 1df3148..1aae5d2 100644 --- a/test/base/TokenEphemeral.t.sol +++ b/test/base/TokenEphemeral.t.sol @@ -11,6 +11,9 @@ contract MockTokenEphemeralV1 is TokenEphemeral, OwnableUpgradeable, UUPSUpgrade // Used for testing different max balance records uint256 public customMaxBalanceRecords; + // Mapping of address to token ID to balance, simulating an ERC-1155 or ERC-6909 implementation + mapping(address => mapping(uint256 => uint256)) public balances; + /** * @dev Initializer used when deployed directly as an upgradeable contract. * @@ -36,11 +39,6 @@ contract MockTokenEphemeralV1 is TokenEphemeral, OwnableUpgradeable, UUPSUpgrade */ function __MockTokenEphemeralV1_init_unchained() internal onlyInitializing { } - /// @inheritdoc UUPSUpgradeable - function _authorizeUpgrade(address newImplementation) internal virtual override onlyOwner { - // This will revert if the caller is not authorized. - } - // @dev Expose internal function for testing function setTTL(uint256 id, uint48 ttl) public onlyOwner { _setTTL(id, ttl); @@ -53,17 +51,24 @@ contract MockTokenEphemeralV1 is TokenEphemeral, OwnableUpgradeable, UUPSUpgrade // @dev Helper function to mint tokens for testing. function mint(address to, uint256 id, uint256 amount) external onlyOwner { + // Call _updateBalanceRecords first, because that is what we're testing _updateBalanceRecords(address(0), to, id, amount); + balances[to][id] += amount; } // @dev Helper function to burn tokens for testing. function burn(address from, uint256 id, uint256 amount) external onlyOwner { + // Call _updateBalanceRecords first, because that is what we're testing _updateBalanceRecords(from, address(0), id, amount); + balances[from][id] -= amount; } // @dev Helper function to transfer tokens for testing. function transfer(address to, uint256 id, uint256 amount) external { + // Call _updateBalanceRecords first, because that is what we're testing _updateBalanceRecords(_msgSender(), to, id, amount); + balances[to][id] += amount; + balances[_msgSender()][id] -= amount; } // @dev Override to allow custom max balance records for testing. @@ -78,6 +83,16 @@ contract MockTokenEphemeralV1 is TokenEphemeral, OwnableUpgradeable, UUPSUpgrade function setCustomMaxBalanceRecords(uint256 newMax) external onlyOwner { customMaxBalanceRecords = newMax; } + + /// @inheritdoc UUPSUpgradeable + function _authorizeUpgrade(address newImplementation) internal virtual override onlyOwner { + // This will revert if the caller is not authorized. + } + + /// @inheritdoc TokenEphemeral + function _burnPrunedTokens(address from, uint256 id, uint256 amount) internal virtual override { + balances[from][id] -= amount; + } } contract TokenEphemeralTest is BaseTest { @@ -704,6 +719,29 @@ contract TokenEphemeralTest is BaseTest { assertEq(records.length, 0); } + function test_pruneBalanceRecords_callsBurnPrunedTokens() public { + // Set TTL + uint48 ttl = 10; + vm.prank(owner); + v1.setTTL(1, ttl); + + // Mint tokens + vm.prank(owner); + v1.mint(alice, 1, 5); + + // Let tokens expire + vm.warp(block.timestamp + ttl * 2); + + // Expect the PrunedTokensBurned event to be emitted when pruning + vm.expectEmit(true, true, false, true); + emit TokenEphemeral.ExpiredTokensPruned(alice, 1, 5); + v1.pruneBalanceRecords(alice, 1); + + // Verify all records are pruned + TokenEphemeral.BalanceRecord[] memory records = v1.balanceRecordsOf(alice, 1); + assertEq(records.length, 0); + } + // ============ Griefing Attack Mitigation Tests ============= // struct TestCase { diff --git a/test/base/TokenPurchasable.t.sol b/test/base/TokenPurchasable.t.sol index 4bafc59..8482ad1 100644 --- a/test/base/TokenPurchasable.t.sol +++ b/test/base/TokenPurchasable.t.sol @@ -54,6 +54,16 @@ contract MockTokenPurchasableV1 is TokenPurchasable, OwnableUpgradeable, UUPSUpg // ========== Helper Functions for Testing ========== + function isAcceptedERC20PaymentToken(uint256 id, address token) public view returns (bool) { + TokenPurchasable.PaymentToken[] memory prices = tokenERC20Prices(id); + for (uint256 i = 0; i < prices.length; i++) { + if (prices[i].token == token && prices[i].price > 0) { + return true; + } + } + return false; + } + /// @dev Expose internal function for testing function setPrice(uint256 id, uint256 price) external onlyOwner { _setPrice(id, price); @@ -179,12 +189,13 @@ contract TokenPurchasableTest is BaseTestWithERC20s { uint256 tokenId = 1; uint256 price = 100e6; // 100 USDC + // Set ERC-20 token price vm.expectEmit(true, true, false, true); emit TokenPurchasable.ERC20PriceSet(tokenId, address(usdc), price); - vm.prank(owner); v1.setERC20Price(tokenId, address(usdc), price); + // Check price was set assertTrue(v1.isAcceptedERC20PaymentToken(tokenId, address(usdc))); } @@ -199,7 +210,7 @@ contract TokenPurchasableTest is BaseTestWithERC20s { vm.prank(owner); v1.setERC20Price(tokenId, address(usdc), 100e6); - // Check it was added + // Check USDC is now accepted prices = v1.tokenERC20Prices(tokenId); assertEq(prices.length, 1); assertEq(prices[0].token, address(usdc));