From c010a679c0bb83aab0a7ab96bcd8e414edb9a4e6 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 9 Sep 2024 22:00:47 +0100 Subject: [PATCH 01/21] feat: receive ether in claim function --- src/periphery/SablierMerkleFactory.sol | 61 ++++++++++++++++--- src/periphery/SablierMerkleInstant.sol | 7 ++- src/periphery/SablierMerkleLL.sol | 5 +- src/periphery/SablierMerkleLT.sol | 5 +- src/periphery/abstracts/SablierMerkleBase.sol | 32 +++++++++- .../interfaces/ISablierMerkleBase.sol | 21 ++++++- .../interfaces/ISablierMerkleFactory.sol | 39 +++++++++++- src/periphery/libraries/Errors.sol | 9 +++ 8 files changed, 164 insertions(+), 15 deletions(-) diff --git a/src/periphery/SablierMerkleFactory.sol b/src/periphery/SablierMerkleFactory.sol index d75d3df06..d37900bf3 100644 --- a/src/periphery/SablierMerkleFactory.sol +++ b/src/periphery/SablierMerkleFactory.sol @@ -3,9 +3,11 @@ pragma solidity >=0.8.22; import { uUNIT } from "@prb/math/src/UD2x18.sol"; +import { Adminable } from "../core/abstracts/Adminable.sol"; import { ISablierLockupLinear } from "../core/interfaces/ISablierLockupLinear.sol"; import { ISablierLockupTranched } from "../core/interfaces/ISablierLockupTranched.sol"; +import { ISablierMerkleBase } from "./interfaces/ISablierMerkleBase.sol"; import { ISablierMerkleFactory } from "./interfaces/ISablierMerkleFactory.sol"; import { ISablierMerkleInstant } from "./interfaces/ISablierMerkleInstant.sol"; import { ISablierMerkleLL } from "./interfaces/ISablierMerkleLL.sol"; @@ -17,7 +19,28 @@ import { MerkleBase, MerkleLL, MerkleLT } from "./types/DataTypes.sol"; /// @title SablierMerkleFactory /// @notice See the documentation in {ISablierMerkleFactory}. -contract SablierMerkleFactory is ISablierMerkleFactory { +contract SablierMerkleFactory is + ISablierMerkleFactory, // 2 inherited components + Adminable // 1 inherited component +{ + /*////////////////////////////////////////////////////////////////////////// + STATE VARIABLES + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierMerkleFactory + uint256 public sablierFee; + + /*////////////////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Emits a {TransferAdmin} event. + /// @param initialAdmin The address of the initial contract admin. + constructor(address initialAdmin) { + admin = initialAdmin; + emit TransferAdmin({ oldAdmin: address(0), newAdmin: initialAdmin }); + } + /*////////////////////////////////////////////////////////////////////////// USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ @@ -36,11 +59,34 @@ contract SablierMerkleFactory is ISablierMerkleFactory { return totalPercentage == uUNIT; } + /*////////////////////////////////////////////////////////////////////////// + ADMIN-FACING NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierMerkleFactory + function setSablierFee(uint256 fee) external onlyAdmin { + // Effect: update the Sablier fee. + sablierFee = fee; + + emit SetSablierFee(msg.sender, fee); + } + + /// @inheritdoc ISablierMerkleFactory + function withdrawFees(address payable to, ISablierMerkleBase merkleLockup) external onlyAdmin { + uint256 feesAccrued = address(merkleLockup).balance; + + // Effect: call `withdrawFees` on the MerkleLockup contract. + merkleLockup.withdrawFees(to, feesAccrued); + + // Log the withdrawal. + emit WithdrawSablierFees(msg.sender, to, feesAccrued); + } + /*////////////////////////////////////////////////////////////////////////// USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @notice inheritdoc ISablierMerkleFactory + /// @inheritdoc ISablierMerkleFactory function createMerkleInstant( MerkleBase.ConstructorParams memory baseParams, uint256 aggregateAmount, @@ -63,13 +109,13 @@ contract SablierMerkleFactory is ISablierMerkleFactory { ); // Deploy the MerkleInstant contract with CREATE2. - merkleInstant = new SablierMerkleInstant{ salt: salt }(baseParams); + merkleInstant = new SablierMerkleInstant{ salt: salt }(baseParams, sablierFee); // Log the creation of the MerkleInstant contract, including some metadata that is not stored on-chain. emit CreateMerkleInstant(merkleInstant, baseParams, aggregateAmount, recipientCount); } - /// @notice inheritdoc ISablierMerkleFactory + /// @inheritdoc ISablierMerkleFactory function createMerkleLL( MerkleBase.ConstructorParams memory baseParams, ISablierLockupLinear lockupLinear, @@ -100,7 +146,8 @@ contract SablierMerkleFactory is ISablierMerkleFactory { ); // Deploy the MerkleLL contract with CREATE2. - merkleLL = new SablierMerkleLL{ salt: salt }(baseParams, lockupLinear, cancelable, transferable, schedule); + merkleLL = + new SablierMerkleLL{ salt: salt }(baseParams, lockupLinear, cancelable, transferable, schedule, sablierFee); // Log the creation of the MerkleLL contract, including some metadata that is not stored on-chain. emit CreateMerkleLL( @@ -108,7 +155,7 @@ contract SablierMerkleFactory is ISablierMerkleFactory { ); } - /// @notice inheritdoc ISablierMerkleFactory + /// @inheritdoc ISablierMerkleFactory function createMerkleLT( MerkleBase.ConstructorParams memory baseParams, ISablierLockupTranched lockupTranched, @@ -189,7 +236,7 @@ contract SablierMerkleFactory is ISablierMerkleFactory { // Deploy the MerkleLT contract with CREATE2. merkleLT = new SablierMerkleLT{ salt: salt }( - baseParams, lockupTranched, cancelable, transferable, streamStartTime, tranchesWithPercentages + baseParams, lockupTranched, cancelable, transferable, streamStartTime, tranchesWithPercentages, sablierFee ); } } diff --git a/src/periphery/SablierMerkleInstant.sol b/src/periphery/SablierMerkleInstant.sol index c6bccb328..844b8459b 100644 --- a/src/periphery/SablierMerkleInstant.sol +++ b/src/periphery/SablierMerkleInstant.sol @@ -21,7 +21,12 @@ contract SablierMerkleInstant is //////////////////////////////////////////////////////////////////////////*/ /// @dev Constructs the contract by initializing the immutable state variables. - constructor(MerkleBase.ConstructorParams memory baseParams) SablierMerkleBase(baseParams) { } + constructor( + MerkleBase.ConstructorParams memory baseParams, + uint256 sablierFee + ) + SablierMerkleBase(baseParams, sablierFee) + { } /*////////////////////////////////////////////////////////////////////////// INTERNAL NON-CONSTANT FUNCTIONS diff --git a/src/periphery/SablierMerkleLL.sol b/src/periphery/SablierMerkleLL.sol index bb8c8ce1b..be4433e4c 100644 --- a/src/periphery/SablierMerkleLL.sol +++ b/src/periphery/SablierMerkleLL.sol @@ -47,9 +47,10 @@ contract SablierMerkleLL is ISablierLockupLinear lockupLinear, bool cancelable, bool transferable, - MerkleLL.Schedule memory schedule_ + MerkleLL.Schedule memory schedule_, + uint256 sablierFee ) - SablierMerkleBase(baseParams) + SablierMerkleBase(baseParams, sablierFee) { CANCELABLE = cancelable; LOCKUP_LINEAR = lockupLinear; diff --git a/src/periphery/SablierMerkleLT.sol b/src/periphery/SablierMerkleLT.sol index 733bb1c9d..f851e2706 100644 --- a/src/periphery/SablierMerkleLT.sol +++ b/src/periphery/SablierMerkleLT.sol @@ -56,9 +56,10 @@ contract SablierMerkleLT is bool cancelable, bool transferable, uint40 streamStartTime, - MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages + MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages, + uint256 sablierFee ) - SablierMerkleBase(baseParams) + SablierMerkleBase(baseParams, sablierFee) { CANCELABLE = cancelable; LOCKUP_TRANCHED = lockupTranched; diff --git a/src/periphery/abstracts/SablierMerkleBase.sol b/src/periphery/abstracts/SablierMerkleBase.sol index efa0da9a6..c2dc9d82d 100644 --- a/src/periphery/abstracts/SablierMerkleBase.sol +++ b/src/periphery/abstracts/SablierMerkleBase.sol @@ -29,12 +29,18 @@ abstract contract SablierMerkleBase is /// @inheritdoc ISablierMerkleBase uint40 public immutable override EXPIRATION; + /// @inheritdoc ISablierMerkleBase + address public immutable FACTORY; + /// @inheritdoc ISablierMerkleBase bytes32 public immutable override MERKLE_ROOT; /// @dev The name of the campaign stored as bytes32. bytes32 internal immutable NAME; + /// @inheritdoc ISablierMerkleBase + uint256 public immutable SABLIER_FEE; + /// @inheritdoc ISablierMerkleBase string public ipfsCID; @@ -49,7 +55,7 @@ abstract contract SablierMerkleBase is //////////////////////////////////////////////////////////////////////////*/ /// @dev Constructs the contract by initializing the immutable state variables. - constructor(MerkleBase.ConstructorParams memory params) { + constructor(MerkleBase.ConstructorParams memory params, uint256 sablierFee) { // Check: the campaign name is not greater than 32 bytes if (bytes(params.name).length > 32) { revert Errors.SablierMerkleBase_CampaignNameTooLong({ nameLength: bytes(params.name).length, maxLength: 32 }); @@ -61,6 +67,8 @@ abstract contract SablierMerkleBase is ipfsCID = params.ipfsCID; MERKLE_ROOT = params.merkleRoot; NAME = bytes32(abi.encodePacked(params.name)); + FACTORY = msg.sender; + SABLIER_FEE = sablierFee; } /*////////////////////////////////////////////////////////////////////////// @@ -99,6 +107,7 @@ abstract contract SablierMerkleBase is bytes32[] calldata merkleProof ) external + payable override { // Check: the campaign has not expired. @@ -106,6 +115,11 @@ abstract contract SablierMerkleBase is revert Errors.SablierMerkleBase_CampaignExpired({ blockTimestamp: block.timestamp, expiration: EXPIRATION }); } + // Check: `msg.value` is not less than the sablier fee. + if (msg.value < SABLIER_FEE) { + revert Errors.SablierMerkleBase_InsufficientFeePayment(msg.value, SABLIER_FEE); + } + // Check: the index has not been claimed. if (_claimedBitMap.get(index)) { revert Errors.SablierMerkleBase_StreamClaimed(index); @@ -150,6 +164,22 @@ abstract contract SablierMerkleBase is emit Clawback(admin, to, amount); } + /// @inheritdoc ISablierMerkleBase + function withdrawFees(address payable to, uint256 feeAmount) external { + // Check: the caller is the factory. + if (msg.sender != FACTORY) { + revert Errors.SablierMerkleBase_CallerNotFactory(FACTORY, msg.sender); + } + + // Effect: transfer the fees to the provided address. + (bool success,) = to.call{ value: feeAmount }(""); + + // Revert if the call failed. + if (!success) { + revert Errors.SablierMerkleBase_FeeWithdrawFailed(to, feeAmount); + } + } + /*////////////////////////////////////////////////////////////////////////// INTERNAL CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/periphery/interfaces/ISablierMerkleBase.sol b/src/periphery/interfaces/ISablierMerkleBase.sol index 4e76d8e8c..96062f7a5 100644 --- a/src/periphery/interfaces/ISablierMerkleBase.sol +++ b/src/periphery/interfaces/ISablierMerkleBase.sol @@ -27,10 +27,16 @@ interface ISablierMerkleBase is IAdminable { /// @dev This is an immutable state variable. function EXPIRATION() external returns (uint40); + /// @notice Retrieves the address of the factory contract. + function FACTORY() external view returns (address); + /// @notice The root of the Merkle tree used to validate the proofs of inclusion. /// @dev This is an immutable state variable. function MERKLE_ROOT() external returns (bytes32); + /// @notice Retrieves the minimum fee required to claim Airstream, paid in ETH. + function SABLIER_FEE() external view returns (uint256); + /// @notice Returns the timestamp when the first claim is made. function getFirstClaimTime() external view returns (uint40); @@ -61,12 +67,13 @@ interface ISablierMerkleBase is IAdminable { /// - The campaign must not have expired. /// - The stream must not have been claimed already. /// - The Merkle proof must be valid. + /// - The `msg.value` must not be less than `SABLIER_FEE`. /// /// @param index The index of the recipient in the Merkle tree. /// @param recipient The address of the airdrop recipient. /// @param amount The amount of ERC-20 assets to be transferred to the recipient. /// @param merkleProof The proof of inclusion in the Merkle tree. - function claim(uint256 index, address recipient, uint128 amount, bytes32[] calldata merkleProof) external; + function claim(uint256 index, address recipient, uint128 amount, bytes32[] calldata merkleProof) external payable; /// @notice Claws back the unclaimed tokens from the campaign. /// @@ -81,4 +88,16 @@ interface ISablierMerkleBase is IAdminable { /// @param to The address to receive the tokens. /// @param amount The amount of tokens to claw back. function clawback(address to, uint128 amount) external; + + /// @notice Withdraws the Sablier fees accrued to the provided address. + /// + /// @dev This function transfers ETH to the provided address. If the receiver is a contract, it must be able to + /// receive ETH. + /// + /// Requirements: + /// - The caller must be the Factory contract. + /// + /// @param to The address to receive the Sablier fees. + /// @param feeAmount The fee amount to withdraw from the contract. + function withdrawFees(address payable to, uint256 feeAmount) external; } diff --git a/src/periphery/interfaces/ISablierMerkleFactory.sol b/src/periphery/interfaces/ISablierMerkleFactory.sol index 6eed0ae5a..f6179c245 100644 --- a/src/periphery/interfaces/ISablierMerkleFactory.sol +++ b/src/periphery/interfaces/ISablierMerkleFactory.sol @@ -1,9 +1,11 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; +import { IAdminable } from "../../core/interfaces/IAdminable.sol"; import { ISablierLockupLinear } from "../../core/interfaces/ISablierLockupLinear.sol"; import { ISablierLockupTranched } from "../../core/interfaces/ISablierLockupTranched.sol"; +import { ISablierMerkleBase } from "../interfaces/ISablierMerkleBase.sol"; import { MerkleBase, MerkleLL, MerkleLT } from "../types/DataTypes.sol"; import { ISablierMerkleInstant } from "./ISablierMerkleInstant.sol"; import { ISablierMerkleLL } from "./ISablierMerkleLL.sol"; @@ -16,7 +18,7 @@ import { ISablierMerkleLT } from "./ISablierMerkleLT.sol"; /// enables instant airdrops where tokens are unlocked and distributed immediately. See the Sablier docs for more /// guidance: https://docs.sablier.com /// @dev Deploys Merkle Lockup and Merkle Instant campaigns with CREATE2. -interface ISablierMerkleFactory { +interface ISablierMerkleFactory is IAdminable { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ @@ -55,6 +57,12 @@ interface ISablierMerkleFactory { uint256 recipientCount ); + /// @notice Emitted when the Sablier fee is set by the admin. + event SetSablierFee(address indexed admin, uint256 sablierFee); + + /// @notice Emitted when the sablier fees are claimed by the sablier admin. + event WithdrawSablierFees(address indexed admin, address indexed to, uint256 sablierFees); + /*////////////////////////////////////////////////////////////////////////// CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ @@ -68,6 +76,10 @@ interface ISablierMerkleFactory { pure returns (bool result); + /// @notice Retrieves the sablier fee required to claim an airstream. + /// @dev A minimum of this fee must be paid in ETH during `claim`. + function sablierFee() external view returns (uint256); + /*////////////////////////////////////////////////////////////////////////// NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ @@ -135,4 +147,29 @@ interface ISablierMerkleFactory { ) external returns (ISablierMerkleLT merkleLT); + + /// @notice Sets the Sablier fee for claiming an airstream. + /// @dev Emits a {SetSablierFee} event. + /// + /// Notes: + /// - The new fee will only be applied to the future campaigns. + /// + /// Requiurements: + /// - The caller must be the admin. + /// + /// @param fee The new fee to be set. + function setSablierFee(uint256 fee) external; + + /// @notice Withdraws the Sablier fees accrued on `merkleLockup` to the provided address. + /// @dev Emits a {WithdrawSablierFees} event. + /// + /// Notes: + /// - This function transfers ETH to the provided address. If the receiver is a contract, it must be able to receive + /// ETH. + /// + /// Requirements: + /// - The caller must be the admin. + /// + /// @param to The address to receive the Sablier fees. + function withdrawFees(address payable to, ISablierMerkleBase merkleLockup) external; } diff --git a/src/periphery/libraries/Errors.sol b/src/periphery/libraries/Errors.sol index e5bcf24ed..a0f010e37 100644 --- a/src/periphery/libraries/Errors.sol +++ b/src/periphery/libraries/Errors.sol @@ -14,6 +14,9 @@ library Errors { SABLIER-MERKLE-BASE //////////////////////////////////////////////////////////////////////////*/ + /// @notice Thrown when caller is not the factory contract. + error SablierMerkleBase_CallerNotFactory(address factory, address caller); + /// @notice Thrown when trying to claim after the campaign has expired. error SablierMerkleBase_CampaignExpired(uint256 blockTimestamp, uint40 expiration); @@ -24,6 +27,12 @@ library Errors { /// not expired. error SablierMerkleBase_ClawbackNotAllowed(uint256 blockTimestamp, uint40 expiration, uint40 firstClaimTime); + /// @notice Thrown if the Sablier fees withdraw failed. + error SablierMerkleBase_FeeWithdrawFailed(address to, uint256 amount); + + /// @notice Thrown when trying to claim with an insufficient fee payment. + error SablierMerkleBase_InsufficientFeePayment(uint256 feePaid, uint256 sablierFee); + /// @notice Thrown when trying to claim with an invalid Merkle proof. error SablierMerkleBase_InvalidProof(); From 357e720eb6269bff3920d86c2f4c400f60ff07f7 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 10 Sep 2024 00:22:58 +0100 Subject: [PATCH 02/21] test: msg.value in claim function test: setSablierFee --- precompiles/Precompiles.sol | 13 +++-- .../DeployDeterministicPeriphery.s.sol | 4 +- script/periphery/DeployMerkleFactory.s.sol | 4 +- script/periphery/DeployPeriphery.s.sol | 4 +- .../DeployDeterministicProtocol.s.sol | 2 +- script/protocol/DeployProtocol.s.sol | 2 +- src/periphery/abstracts/SablierMerkleBase.sol | 3 ++ test/Base.t.sol | 22 +++++++- test/periphery/Periphery.t.sol | 34 +++++++----- .../fork/merkle-campaign/MerkleInstant.t.sol | 9 ++-- .../fork/merkle-campaign/MerkleLL.t.sol | 9 ++-- .../fork/merkle-campaign/MerkleLT.t.sol | 9 ++-- .../merkle-campaign/MerkleCampaign.t.sol | 43 ++++++++------- .../merkle-campaign/factory/constructor.t.sol | 18 +++++++ .../set-sablier-fee/setSablierFee.t.sol | 29 ++++++++++ .../set-sablier-fee/setSablierFee.tree | 6 +++ .../merkle-campaign/instant/claim/claim.t.sol | 10 +++- .../merkle-campaign/instant/constructor.t.sol | 22 ++++++-- .../merkle-campaign/ll/claim/claim.t.sol | 11 +++- .../merkle-campaign/ll/constructor.t.sol | 30 +++++++++-- .../merkle-campaign/lt/claim/claim.t.sol | 29 ++++++++-- .../merkle-campaign/lt/constructor.t.sol | 52 +++++++++++------- .../shared/MerkleCampaign.t.sol | 7 ++- .../merkle-campaign/shared/claim/claim.t.sol | 53 +++++++++++++++---- .../merkle-campaign/shared/claim/claim.tree | 28 +++++----- test/utils/Defaults.sol | 1 + test/utils/Events.sol | 4 ++ test/utils/Precompiles.t.sol | 4 +- 28 files changed, 353 insertions(+), 109 deletions(-) create mode 100644 test/periphery/integration/merkle-campaign/factory/constructor.t.sol create mode 100644 test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.t.sol create mode 100644 test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.tree diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 69a1d083f..301a581af 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -213,8 +213,8 @@ contract Precompiles { } /// @notice Deploys {SablierMerkleFactory} from precompiled bytecode. - function deployMerkleFactory() public returns (ISablierMerkleFactory factory) { - bytes memory creationBytecode = BYTECODE_MERKLE_FACTORY; + function deployMerkleFactory(address initialAdmin) public returns (ISablierMerkleFactory factory) { + bytes memory creationBytecode = bytes.concat(BYTECODE_MERKLE_FACTORY, abi.encode(initialAdmin)); assembly { factory := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) } @@ -225,9 +225,12 @@ contract Precompiles { /// /// 1. {SablierBatchLockup} /// 2. {SablierMerkleFactory} - function deployPeriphery() public returns (ISablierBatchLockup batchLockup, ISablierMerkleFactory merkleFactory) { + function deployPeriphery(address initialAdmin) + public + returns (ISablierBatchLockup batchLockup, ISablierMerkleFactory merkleFactory) + { batchLockup = deployBatchLockup(); - merkleFactory = deployMerkleFactory(); + merkleFactory = deployMerkleFactory(initialAdmin); } /// @notice Deploys the entire Lockup Protocol from precompiled bytecode. @@ -255,6 +258,6 @@ contract Precompiles { (nftDescriptor, lockupDynamic, lockupLinear, lockupTranched) = deployCore(initialAdmin); // Deploy Periphery. - (batchLockup, merkleFactory) = deployPeriphery(); + (batchLockup, merkleFactory) = deployPeriphery(initialAdmin); } } diff --git a/script/periphery/DeployDeterministicPeriphery.s.sol b/script/periphery/DeployDeterministicPeriphery.s.sol index 40c8bf2ac..79122e01d 100644 --- a/script/periphery/DeployDeterministicPeriphery.s.sol +++ b/script/periphery/DeployDeterministicPeriphery.s.sol @@ -14,7 +14,7 @@ import { BaseScript } from "../Base.s.sol"; /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicPeriphery is BaseScript { /// @dev Deploy via Forge. - function run() + function run(address initialAdmin) public virtual broadcast @@ -22,6 +22,6 @@ contract DeployDeterministicPeriphery is BaseScript { { bytes32 salt = constructCreate2Salt(); batchLockup = new SablierBatchLockup{ salt: salt }(); - merkleFactory = new SablierMerkleFactory{ salt: salt }(); + merkleFactory = new SablierMerkleFactory{ salt: salt }(initialAdmin); } } diff --git a/script/periphery/DeployMerkleFactory.s.sol b/script/periphery/DeployMerkleFactory.s.sol index c44cea888..decfbf0cb 100644 --- a/script/periphery/DeployMerkleFactory.s.sol +++ b/script/periphery/DeployMerkleFactory.s.sol @@ -7,7 +7,7 @@ import { BaseScript } from "../Base.s.sol"; contract DeployMerkleFactory is BaseScript { /// @dev Deploy via Forge. - function run() public virtual broadcast returns (SablierMerkleFactory merkleFactory) { - merkleFactory = new SablierMerkleFactory(); + function run(address initialAdmin) public virtual broadcast returns (SablierMerkleFactory merkleFactory) { + merkleFactory = new SablierMerkleFactory(initialAdmin); } } diff --git a/script/periphery/DeployPeriphery.s.sol b/script/periphery/DeployPeriphery.s.sol index 17940a4d6..c2dfe9100 100644 --- a/script/periphery/DeployPeriphery.s.sol +++ b/script/periphery/DeployPeriphery.s.sol @@ -11,13 +11,13 @@ import { BaseScript } from "./../Base.s.sol"; /// 2. {SablierMerkleFactory} contract DeployPeriphery is BaseScript { /// @dev Deploy via Forge. - function run() + function run(address initialAdmin) public virtual broadcast returns (SablierBatchLockup batchLockup, SablierMerkleFactory merkleFactory) { batchLockup = new SablierBatchLockup(); - merkleFactory = new SablierMerkleFactory(); + merkleFactory = new SablierMerkleFactory(initialAdmin); } } diff --git a/script/protocol/DeployDeterministicProtocol.s.sol b/script/protocol/DeployDeterministicProtocol.s.sol index e110b8ecc..75744af23 100644 --- a/script/protocol/DeployDeterministicProtocol.s.sol +++ b/script/protocol/DeployDeterministicProtocol.s.sol @@ -72,7 +72,7 @@ contract DeployDeterministicProtocol is DeploymentLogger("deterministic") { // Deploy Periphery. batchLockup = new SablierBatchLockup{ salt: salt }(); - merkleLockupFactory = new SablierMerkleFactory{ salt: salt }(); + merkleLockupFactory = new SablierMerkleFactory{ salt: salt }(initialAdmin); appendToFileDeployedAddresses( address(lockupDynamic), diff --git a/script/protocol/DeployProtocol.s.sol b/script/protocol/DeployProtocol.s.sol index 7a8a6384d..0419d1f94 100644 --- a/script/protocol/DeployProtocol.s.sol +++ b/script/protocol/DeployProtocol.s.sol @@ -65,7 +65,7 @@ contract DeployProtocol is DeploymentLogger("non_deterministic") { lockupLinear = new SablierLockupLinear(initialAdmin, nftDescriptor); lockupTranched = new SablierLockupTranched(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); batchLockup = new SablierBatchLockup(); - merkleLockupFactory = new SablierMerkleFactory(); + merkleLockupFactory = new SablierMerkleFactory(initialAdmin); appendToFileDeployedAddresses( address(lockupDynamic), diff --git a/src/periphery/abstracts/SablierMerkleBase.sol b/src/periphery/abstracts/SablierMerkleBase.sol index c2dc9d82d..1057a642d 100644 --- a/src/periphery/abstracts/SablierMerkleBase.sol +++ b/src/periphery/abstracts/SablierMerkleBase.sol @@ -71,6 +71,9 @@ abstract contract SablierMerkleBase is SABLIER_FEE = sablierFee; } + /// @dev Implements the receive Ether function to be able to receive sablier fee during claim. + receive() external payable { } + /*////////////////////////////////////////////////////////////////////////// USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ diff --git a/test/Base.t.sol b/test/Base.t.sol index b8b18e883..ed86bc682 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -12,6 +12,7 @@ import { SablierLockupLinear } from "src/core/SablierLockupLinear.sol"; import { SablierLockupTranched } from "src/core/SablierLockupTranched.sol"; import { LockupDynamic, LockupLinear, LockupTranched } from "src/core/types/DataTypes.sol"; import { ISablierBatchLockup } from "src/periphery/interfaces/ISablierBatchLockup.sol"; +import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; import { ISablierMerkleFactory } from "src/periphery/interfaces/ISablierMerkleFactory.sol"; import { ISablierMerkleInstant } from "src/periphery/interfaces/ISablierMerkleInstant.sol"; import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; @@ -86,6 +87,9 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi // Deploy the protocol. deployProtocolConditionally(); + // Set the Sablier fee on the Merkle factory. + merkleFactory.setSablierFee(defaults.SABLIER_FEE()); + // Create users for testing. users.alice = createUser("Alice"); users.broker = createUser("Broker"); @@ -153,7 +157,7 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi lockupDynamic = new SablierLockupDynamic(users.admin, nftDescriptor, defaults.MAX_SEGMENT_COUNT()); lockupLinear = new SablierLockupLinear(users.admin, nftDescriptor); lockupTranched = new SablierLockupTranched(users.admin, nftDescriptor, defaults.MAX_TRANCHE_COUNT()); - merkleFactory = new SablierMerkleFactory(); + merkleFactory = new SablierMerkleFactory(users.admin); } else { (nftDescriptor, lockupDynamic, lockupLinear, lockupTranched, batchLockup, merkleFactory) = deployOptimizedProtocol(users.admin, defaults.MAX_SEGMENT_COUNT(), defaults.MAX_TRANCHE_COUNT()); @@ -218,6 +222,22 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi }); } + /*////////////////////////////////////////////////////////////////////////// + CALL EXPECTS - MERKLE LOCKUP + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Expects a call to {ISablierMerkleBase.claim} with msgValue as `msg.value`. + function expectCallToClaimWithMsgValue(address merkleLockup, uint256 msgValue) internal { + vm.expectCall( + merkleLockup, + msgValue, + abi.encodeCall( + ISablierMerkleBase.claim, + (defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), defaults.index1Proof()) + ) + ); + } + /*////////////////////////////////////////////////////////////////////////// CALL EXPECTS - LOCKUP //////////////////////////////////////////////////////////////////////////*/ diff --git a/test/periphery/Periphery.t.sol b/test/periphery/Periphery.t.sol index ba722a6ba..05281a3b2 100644 --- a/test/periphery/Periphery.t.sol +++ b/test/periphery/Periphery.t.sol @@ -23,7 +23,8 @@ contract Periphery_Test is Base_Test { address admin, IERC20 asset_, bytes32 merkleRoot, - uint40 expiration + uint40 expiration, + uint256 sablierFee ) internal view @@ -40,7 +41,8 @@ contract Periphery_Test is Base_Test { defaults.NAME_BYTES32() ) ); - bytes32 creationBytecodeHash = keccak256(getMerkleInstantBytecode(admin, asset_, merkleRoot, expiration)); + bytes32 creationBytecodeHash = + keccak256(getMerkleInstantBytecode(admin, asset_, merkleRoot, expiration, sablierFee)); return vm.computeCreate2Address({ salt: salt, initCodeHash: creationBytecodeHash, @@ -53,7 +55,8 @@ contract Periphery_Test is Base_Test { address admin, IERC20 asset_, bytes32 merkleRoot, - uint40 expiration + uint40 expiration, + uint256 sablierFee ) internal view @@ -74,7 +77,7 @@ contract Periphery_Test is Base_Test { abi.encode(defaults.schedule()) ) ); - bytes32 creationBytecodeHash = keccak256(getMerkleLLBytecode(admin, asset_, merkleRoot, expiration)); + bytes32 creationBytecodeHash = keccak256(getMerkleLLBytecode(admin, asset_, merkleRoot, expiration, sablierFee)); return vm.computeCreate2Address({ salt: salt, initCodeHash: creationBytecodeHash, @@ -87,7 +90,8 @@ contract Periphery_Test is Base_Test { address admin, IERC20 asset_, bytes32 merkleRoot, - uint40 expiration + uint40 expiration, + uint256 sablierFee ) internal view @@ -109,7 +113,7 @@ contract Periphery_Test is Base_Test { abi.encode(defaults.tranchesWithPercentages()) ) ); - bytes32 creationBytecodeHash = keccak256(getMerkleLTBytecode(admin, asset_, merkleRoot, expiration)); + bytes32 creationBytecodeHash = keccak256(getMerkleLTBytecode(admin, asset_, merkleRoot, expiration, sablierFee)); return vm.computeCreate2Address({ salt: salt, initCodeHash: creationBytecodeHash, @@ -121,13 +125,15 @@ contract Periphery_Test is Base_Test { address admin, IERC20 asset_, bytes32 merkleRoot, - uint40 expiration + uint40 expiration, + uint256 sablierFee ) internal view returns (bytes memory) { - bytes memory constructorArgs = abi.encode(defaults.baseParams(admin, asset_, expiration, merkleRoot)); + bytes memory constructorArgs = + abi.encode(defaults.baseParams(admin, asset_, expiration, merkleRoot), sablierFee); if (!isTestOptimizedProfile()) { return bytes.concat(type(SablierMerkleInstant).creationCode, constructorArgs); } else { @@ -141,7 +147,8 @@ contract Periphery_Test is Base_Test { address admin, IERC20 asset_, bytes32 merkleRoot, - uint40 expiration + uint40 expiration, + uint256 sablierFee ) internal view @@ -152,7 +159,8 @@ contract Periphery_Test is Base_Test { lockupLinear, defaults.CANCELABLE(), defaults.TRANSFERABLE(), - defaults.schedule() + defaults.schedule(), + sablierFee ); if (!isTestOptimizedProfile()) { return bytes.concat(type(SablierMerkleLL).creationCode, constructorArgs); @@ -165,7 +173,8 @@ contract Periphery_Test is Base_Test { address admin, IERC20 asset_, bytes32 merkleRoot, - uint40 expiration + uint40 expiration, + uint256 sablierFee ) internal view @@ -177,7 +186,8 @@ contract Periphery_Test is Base_Test { defaults.CANCELABLE(), defaults.TRANSFERABLE(), defaults.STREAM_START_TIME_ZERO(), - defaults.tranchesWithPercentages() + defaults.tranchesWithPercentages(), + sablierFee ); if (!isTestOptimizedProfile()) { return bytes.concat(type(SablierMerkleLT).creationCode, constructorArgs); diff --git a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol index 81cdb9c76..304bfa921 100644 --- a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol @@ -95,8 +95,11 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test { // Make the caller the admin. resetPrank({ msgSender: params.admin }); - vars.expectedMerkleInstant = - computeMerkleInstantAddress(params.admin, params.admin, FORK_ASSET, vars.merkleRoot, params.expiration); + uint256 sablierFee = defaults.SABLIER_FEE(); + + vars.expectedMerkleInstant = computeMerkleInstantAddress( + params.admin, params.admin, FORK_ASSET, vars.merkleRoot, params.expiration, sablierFee + ); vars.baseParams = defaults.baseParams({ admin: params.admin, @@ -163,7 +166,7 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test { value: vars.amounts[params.posBeforeSort] }); - vars.merkleInstant.claim({ + vars.merkleInstant.claim{ value: sablierFee }({ index: vars.indexes[params.posBeforeSort], recipient: vars.recipients[params.posBeforeSort], amount: vars.amounts[params.posBeforeSort], diff --git a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol index 471b5e5ec..1a9f417a0 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol @@ -99,8 +99,11 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { // Make the caller the admin. resetPrank({ msgSender: params.admin }); - vars.expectedLL = - computeMerkleLLAddress(params.admin, params.admin, FORK_ASSET, vars.merkleRoot, params.expiration); + uint256 sablierFee = defaults.SABLIER_FEE(); + + vars.expectedLL = computeMerkleLLAddress( + params.admin, params.admin, FORK_ASSET, vars.merkleRoot, params.expiration, sablierFee + ); vars.baseParams = defaults.baseParams({ admin: params.admin, @@ -168,7 +171,7 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); } - vars.merkleLL.claim({ + vars.merkleLL.claim{ value: sablierFee }({ index: vars.indexes[params.posBeforeSort], recipient: vars.recipients[params.posBeforeSort], amount: vars.amounts[params.posBeforeSort], diff --git a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol index bd945cdcf..27a5bf92b 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol @@ -100,8 +100,11 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { // Make the caller the admin. resetPrank({ msgSender: params.admin }); - vars.expectedLT = - computeMerkleLTAddress(params.admin, params.admin, FORK_ASSET, vars.merkleRoot, params.expiration); + uint256 sablierFee = defaults.SABLIER_FEE(); + + vars.expectedLT = computeMerkleLTAddress( + params.admin, params.admin, FORK_ASSET, vars.merkleRoot, params.expiration, sablierFee + ); vars.baseParams = defaults.baseParams({ admin: params.admin, @@ -171,7 +174,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); } - vars.merkleLT.claim({ + vars.merkleLT.claim{ value: sablierFee }({ index: vars.indexes[params.posBeforeSort], recipient: vars.recipients[params.posBeforeSort], amount: vars.amounts[params.posBeforeSort], diff --git a/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol index ca3465ab6..5156ef65c 100644 --- a/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol +++ b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol @@ -34,31 +34,34 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { //////////////////////////////////////////////////////////////////////////*/ function computeMerkleInstantAddress() internal view returns (address) { - return computeMerkleInstantAddress(users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); + return computeMerkleInstantAddress( + users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.SABLIER_FEE() + ); } function computeMerkleInstantAddress(address admin) internal view returns (address) { - return computeMerkleInstantAddress(admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); + return computeMerkleInstantAddress(admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.SABLIER_FEE()); } function computeMerkleInstantAddress(address admin, uint40 expiration) internal view returns (address) { - return computeMerkleInstantAddress(admin, defaults.MERKLE_ROOT(), expiration); + return computeMerkleInstantAddress(admin, defaults.MERKLE_ROOT(), expiration, defaults.SABLIER_FEE()); } function computeMerkleInstantAddress(address admin, bytes32 merkleRoot) internal view returns (address) { - return computeMerkleInstantAddress(admin, merkleRoot, defaults.EXPIRATION()); + return computeMerkleInstantAddress(admin, merkleRoot, defaults.EXPIRATION(), defaults.SABLIER_FEE()); } function computeMerkleInstantAddress( address admin, bytes32 merkleRoot, - uint40 expiration + uint40 expiration, + uint256 sablierFee ) internal view returns (address) { - return computeMerkleInstantAddress(users.alice, admin, dai, merkleRoot, expiration); + return computeMerkleInstantAddress(users.alice, admin, dai, merkleRoot, expiration, sablierFee); } function createMerkleInstant() internal returns (ISablierMerkleInstant) { @@ -86,31 +89,33 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { //////////////////////////////////////////////////////////////////////////*/ function computeMerkleLLAddress() internal view returns (address) { - return computeMerkleLLAddress(users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); + return + computeMerkleLLAddress(users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.SABLIER_FEE()); } function computeMerkleLLAddress(address admin) internal view returns (address) { - return computeMerkleLLAddress(admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); + return computeMerkleLLAddress(admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.SABLIER_FEE()); } function computeMerkleLLAddress(address admin, uint40 expiration) internal view returns (address) { - return computeMerkleLLAddress(admin, defaults.MERKLE_ROOT(), expiration); + return computeMerkleLLAddress(admin, defaults.MERKLE_ROOT(), expiration, defaults.SABLIER_FEE()); } function computeMerkleLLAddress(address admin, bytes32 merkleRoot) internal view returns (address) { - return computeMerkleLLAddress(admin, merkleRoot, defaults.EXPIRATION()); + return computeMerkleLLAddress(admin, merkleRoot, defaults.EXPIRATION(), defaults.SABLIER_FEE()); } function computeMerkleLLAddress( address admin, bytes32 merkleRoot, - uint40 expiration + uint40 expiration, + uint256 sablierFee ) internal view returns (address) { - return computeMerkleLLAddress(users.alice, admin, dai, merkleRoot, expiration); + return computeMerkleLLAddress(users.alice, admin, dai, merkleRoot, expiration, sablierFee); } function createMerkleLL() internal returns (ISablierMerkleLL) { @@ -142,31 +147,33 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { //////////////////////////////////////////////////////////////////////////*/ function computeMerkleLTAddress() internal view returns (address) { - return computeMerkleLTAddress(users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); + return + computeMerkleLTAddress(users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.SABLIER_FEE()); } function computeMerkleLTAddress(address admin) internal view returns (address) { - return computeMerkleLTAddress(admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); + return computeMerkleLTAddress(admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.SABLIER_FEE()); } function computeMerkleLTAddress(address admin, uint40 expiration) internal view returns (address) { - return computeMerkleLTAddress(admin, defaults.MERKLE_ROOT(), expiration); + return computeMerkleLTAddress(admin, defaults.MERKLE_ROOT(), expiration, defaults.SABLIER_FEE()); } function computeMerkleLTAddress(address admin, bytes32 merkleRoot) internal view returns (address) { - return computeMerkleLTAddress(admin, merkleRoot, defaults.EXPIRATION()); + return computeMerkleLTAddress(admin, merkleRoot, defaults.EXPIRATION(), defaults.SABLIER_FEE()); } function computeMerkleLTAddress( address admin, bytes32 merkleRoot, - uint40 expiration + uint40 expiration, + uint256 sablierFee ) internal view returns (address) { - return computeMerkleLTAddress(users.alice, admin, dai, merkleRoot, expiration); + return computeMerkleLTAddress(users.alice, admin, dai, merkleRoot, expiration, sablierFee); } function createMerkleLT() internal returns (ISablierMerkleLT) { diff --git a/test/periphery/integration/merkle-campaign/factory/constructor.t.sol b/test/periphery/integration/merkle-campaign/factory/constructor.t.sol new file mode 100644 index 000000000..c09c9f0ab --- /dev/null +++ b/test/periphery/integration/merkle-campaign/factory/constructor.t.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { SablierMerkleFactory } from "src/periphery/SablierMerkleFactory.sol"; + +import { MerkleCampaign_Integration_Test } from "../MerkleCampaign.t.sol"; + +contract Constructor_MerkleFactory_Integration_Test is MerkleCampaign_Integration_Test { + function test_Constructor() external { + SablierMerkleFactory constructedFactory = new SablierMerkleFactory(users.admin); + + address actualAdmin = constructedFactory.admin(); + assertEq(actualAdmin, users.admin, "factory admin"); + + uint256 actualSablierFee = constructedFactory.sablierFee(); + assertEq(actualSablierFee, 0, "sablier fee"); + } +} diff --git a/test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.t.sol b/test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.t.sol new file mode 100644 index 000000000..e7dc25390 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.t.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; + +import { MerkleCampaign_Integration_Shared_Test } from "../../shared/MerkleCampaign.t.sol"; + +contract SetSablierFee_Integration_Test is MerkleCampaign_Integration_Shared_Test { + function test_RevertWhen_CallerNotAdmin() external { + uint256 sablierFee = defaults.SABLIER_FEE(); + resetPrank({ msgSender: users.eve }); + vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); + merkleFactory.setSablierFee({ fee: sablierFee }); + } + + function test_WhenCallerAdmin() external { + resetPrank({ msgSender: users.admin }); + + // It should emit a {SetSablierFee} event. + vm.expectEmit({ emitter: address(merkleFactory) }); + emit SetSablierFee({ admin: users.admin, sablierFee: defaults.SABLIER_FEE() }); + + merkleFactory.setSablierFee({ fee: defaults.SABLIER_FEE() }); + + // It should set the Sablier fee. + assertEq(merkleFactory.sablierFee(), defaults.SABLIER_FEE(), "sablier fee"); + } +} diff --git a/test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.tree b/test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.tree new file mode 100644 index 000000000..71420c45b --- /dev/null +++ b/test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.tree @@ -0,0 +1,6 @@ +SetSablierFee_Integration_Test +├── when caller not admin +│ └── it should revert +└── when caller admin + ├── it should set the Sablier fee + └── it should emit a {SetSablierFee} event diff --git a/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol index b3e192339..bdfebd3c6 100644 --- a/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol @@ -12,18 +12,24 @@ contract Claim_MerkleInstant_Integration_Test is Claim_Integration_Test, MerkleI function test_Claim() external givenCampaignNotExpired + givenMsgValueNotLessThanSablierFee givenRecipientNotClaimed whenIndexValid whenRecipientValid whenAmountValid whenMerkleProofValid { - vm.expectEmit({ emitter: address(merkleBase) }); + uint256 previousFeeAccrued = address(merkleInstant).balance; + + vm.expectEmit({ emitter: address(merkleInstant) }); emit Claim(defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT()); expectCallToTransfer({ to: users.recipient1, value: defaults.CLAIM_AMOUNT() }); + expectCallToClaimWithMsgValue(address(merkleInstant), defaults.SABLIER_FEE()); claim(); - assertTrue(merkleBase.hasClaimed(defaults.INDEX1()), "not claimed"); + assertTrue(merkleInstant.hasClaimed(defaults.INDEX1()), "not claimed"); + + assertEq(address(merkleInstant).balance, previousFeeAccrued + defaults.SABLIER_FEE(), "fee collected"); } } diff --git a/test/periphery/integration/merkle-campaign/instant/constructor.t.sol b/test/periphery/integration/merkle-campaign/instant/constructor.t.sol index 535dba4c0..e53c974df 100644 --- a/test/periphery/integration/merkle-campaign/instant/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/instant/constructor.t.sol @@ -10,20 +10,28 @@ contract Constructor_MerkleInstant_Integration_Test is MerkleCampaign_Integratio struct Vars { address actualAdmin; address actualAsset; - string actualIpfsCID; - string actualName; uint40 actualExpiration; + address actualFactory; + string actualIpfsCID; bytes32 actualMerkleRoot; + string actualName; + uint256 actualSablierFee; address expectedAdmin; address expectedAsset; uint40 expectedExpiration; + address expectedFactory; string expectedIpfsCID; bytes32 expectedMerkleRoot; bytes32 expectedName; + uint256 expectedSablierFee; } function test_Constructor() external { - SablierMerkleInstant constructedInstant = new SablierMerkleInstant(defaults.baseParams()); + // Make Factory the caller for the constructor test. + resetPrank(address(merkleFactory)); + + SablierMerkleInstant constructedInstant = + new SablierMerkleInstant(defaults.baseParams(), defaults.SABLIER_FEE()); Vars memory vars; @@ -39,6 +47,10 @@ contract Constructor_MerkleInstant_Integration_Test is MerkleCampaign_Integratio vars.expectedExpiration = defaults.EXPIRATION(); assertEq(vars.actualExpiration, vars.expectedExpiration, "expiration"); + vars.actualFactory = constructedInstant.FACTORY(); + vars.expectedFactory = address(merkleFactory); + assertEq(vars.actualFactory, vars.expectedFactory, "factory"); + vars.actualIpfsCID = constructedInstant.ipfsCID(); vars.expectedIpfsCID = defaults.IPFS_CID(); assertEq(vars.actualIpfsCID, vars.expectedIpfsCID, "ipfsCID"); @@ -50,5 +62,9 @@ contract Constructor_MerkleInstant_Integration_Test is MerkleCampaign_Integratio vars.actualName = constructedInstant.name(); vars.expectedName = defaults.NAME_BYTES32(); assertEq(bytes32(abi.encodePacked(vars.actualName)), vars.expectedName, "name"); + + vars.actualSablierFee = constructedInstant.SABLIER_FEE(); + vars.expectedSablierFee = defaults.SABLIER_FEE(); + assertEq(vars.actualSablierFee, vars.expectedSablierFee, "sablierFee"); } } diff --git a/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol index b22592524..4fd751ed0 100644 --- a/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol @@ -65,16 +65,23 @@ contract Claim_MerkleLL_Integration_Test is Claim_Integration_Test, MerkleLL_Int /// @dev Helper function to test claim. function _test_Claim(uint40 startTime, uint40 cliffTime) private { + uint256 sablierFee = defaults.SABLIER_FEE(); deal({ token: address(dai), to: address(merkleLL), give: defaults.AGGREGATE_AMOUNT() }); uint256 expectedStreamId = lockupLinear.nextStreamId(); + uint256 previousFeeAccrued = address(merkleLL).balance; // It should emit a {Claim} event. vm.expectEmit({ emitter: address(merkleLL) }); emit Claim(defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), expectedStreamId); + expectCallToTransferFrom({ from: address(merkleLL), to: address(lockupLinear), value: defaults.CLAIM_AMOUNT() }); + expectCallToClaimWithMsgValue(address(merkleLL), sablierFee); + // Claim the airstream. - merkleLL.claim(defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), defaults.index1Proof()); + merkleLL.claim{ value: sablierFee }( + defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), defaults.index1Proof() + ); LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(expectedStreamId); LockupLinear.StreamLL memory expectedStream = LockupLinear.StreamLL({ @@ -94,5 +101,7 @@ contract Claim_MerkleLL_Integration_Test is Claim_Integration_Test, MerkleLL_Int assertEq(actualStream, expectedStream); assertTrue(merkleLL.hasClaimed(defaults.INDEX1()), "not claimed"); + + assertEq(address(merkleLL).balance, previousFeeAccrued + defaults.SABLIER_FEE(), "fee collected"); } } diff --git a/test/periphery/integration/merkle-campaign/ll/constructor.t.sol b/test/periphery/integration/merkle-campaign/ll/constructor.t.sol index ee33e111d..9f3187da4 100644 --- a/test/periphery/integration/merkle-campaign/ll/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/constructor.t.sol @@ -12,30 +12,42 @@ contract Constructor_MerkleLL_Integration_Test is MerkleCampaign_Integration_Tes address actualAdmin; uint256 actualAllowance; address actualAsset; - string actualIpfsCID; - string actualName; bool actualCancelable; - MerkleLL.Schedule actualSchedule; uint40 actualExpiration; + address actualFactory; + string actualIpfsCID; address actualLockupLinear; bytes32 actualMerkleRoot; + string actualName; + uint256 actualSablierFee; + MerkleLL.Schedule actualSchedule; bool actualTransferable; address expectedAdmin; uint256 expectedAllowance; address expectedAsset; bool expectedCancelable; - MerkleLL.Schedule expectedSchedule; uint40 expectedExpiration; + address expectedFactory; string expectedIpfsCID; address expectedLockupLinear; bytes32 expectedMerkleRoot; bytes32 expectedName; + uint256 expectedSablierFee; + MerkleLL.Schedule expectedSchedule; bool expectedTransferable; } function test_Constructor() external { + // Make Factory the caller for the constructor test. + resetPrank(address(merkleFactory)); + SablierMerkleLL constructedLL = new SablierMerkleLL( - defaults.baseParams(), lockupLinear, defaults.CANCELABLE(), defaults.TRANSFERABLE(), defaults.schedule() + defaults.baseParams(), + lockupLinear, + defaults.CANCELABLE(), + defaults.TRANSFERABLE(), + defaults.schedule(), + defaults.SABLIER_FEE() ); Vars memory vars; @@ -60,6 +72,10 @@ contract Constructor_MerkleLL_Integration_Test is MerkleCampaign_Integration_Tes vars.expectedExpiration = defaults.EXPIRATION(); assertEq(vars.actualExpiration, vars.expectedExpiration, "expiration"); + vars.actualFactory = constructedLL.FACTORY(); + vars.expectedFactory = address(merkleFactory); + assertEq(vars.actualFactory, vars.expectedFactory, "factory"); + vars.actualIpfsCID = constructedLL.ipfsCID(); vars.expectedIpfsCID = defaults.IPFS_CID(); assertEq(vars.actualIpfsCID, vars.expectedIpfsCID, "ipfsCID"); @@ -86,5 +102,9 @@ contract Constructor_MerkleLL_Integration_Test is MerkleCampaign_Integration_Tes vars.actualTransferable = constructedLL.TRANSFERABLE(); vars.expectedTransferable = defaults.TRANSFERABLE(); assertEq(vars.actualTransferable, vars.expectedTransferable, "transferable"); + + vars.actualSablierFee = constructedLL.SABLIER_FEE(); + vars.expectedSablierFee = defaults.SABLIER_FEE(); + assertEq(vars.actualSablierFee, vars.expectedSablierFee, "sablierFee"); } } diff --git a/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol index bc808de8c..c4e0d3623 100644 --- a/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol @@ -20,6 +20,8 @@ contract Claim_MerkleLT_Integration_Test is Claim_Integration_Test, MerkleLT_Int } function test_RevertWhen_TotalPercentageLessThan100() external whenMerkleProofValid whenTotalPercentageNot100 { + uint256 sablierFee = defaults.SABLIER_FEE(); + // Create a MerkleLT campaign with a total percentage less than 100. MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = defaults.tranchesWithPercentages(); tranchesWithPercentages[0].unlockPercentage = ud2x18(0.05e18); @@ -46,10 +48,16 @@ contract Claim_MerkleLT_Integration_Test is Claim_Integration_Test, MerkleLT_Int abi.encodeWithSelector(Errors.SablierMerkleLT_TotalPercentageNotOneHundred.selector, totalPercentage) ); - merkleLT.claim({ index: 1, recipient: users.recipient1, amount: 10_000e18, merkleProof: merkleProof }); + merkleLT.claim{ value: sablierFee }({ + index: 1, + recipient: users.recipient1, + amount: 10_000e18, + merkleProof: merkleProof + }); } function test_RevertWhen_TotalPercentageGreaterThan100() external whenMerkleProofValid whenTotalPercentageNot100 { + uint256 sablierFee = defaults.SABLIER_FEE(); // Create a MerkleLT campaign with a total percentage less than 100. MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = defaults.tranchesWithPercentages(); tranchesWithPercentages[0].unlockPercentage = ud2x18(0.75e18); @@ -76,7 +84,12 @@ contract Claim_MerkleLT_Integration_Test is Claim_Integration_Test, MerkleLT_Int abi.encodeWithSelector(Errors.SablierMerkleLT_TotalPercentageNotOneHundred.selector, totalPercentage) ); - merkleLT.claim({ index: 1, recipient: users.recipient1, amount: 10_000e18, merkleProof: merkleProof }); + merkleLT.claim{ value: sablierFee }({ + index: 1, + recipient: users.recipient1, + amount: 10_000e18, + merkleProof: merkleProof + }); } modifier whenTotalPercentage100() { @@ -109,16 +122,24 @@ contract Claim_MerkleLT_Integration_Test is Claim_Integration_Test, MerkleLT_Int /// @dev Helper function to test claim. function _test_Claim(uint40 streamStartTime, uint40 startTime) private { + uint256 sablierFee = defaults.SABLIER_FEE(); + deal({ token: address(dai), to: address(merkleLT), give: defaults.AGGREGATE_AMOUNT() }); uint256 expectedStreamId = lockupTranched.nextStreamId(); + uint256 previousFeeAccrued = address(merkleLL).balance; // It should emit a {Claim} event. vm.expectEmit({ emitter: address(merkleLT) }); emit Claim(defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), expectedStreamId); + expectCallToTransferFrom({ from: address(merkleLT), to: address(lockupTranched), value: defaults.CLAIM_AMOUNT() }); + expectCallToClaimWithMsgValue(address(merkleLT), sablierFee); + // Claim the airstream. - merkleLT.claim(defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), defaults.index1Proof()); + merkleLT.claim{ value: sablierFee }( + defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), defaults.index1Proof() + ); // It should create a stream with `STREAM_START_TIME` as start time. LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(expectedStreamId); @@ -139,5 +160,7 @@ contract Claim_MerkleLT_Integration_Test is Claim_Integration_Test, MerkleLT_Int assertEq(actualStream, expectedStream); assertTrue(merkleLT.hasClaimed(defaults.INDEX1()), "not claimed"); + + assertEq(address(merkleLT).balance, previousFeeAccrued + defaults.SABLIER_FEE(), "fee collected"); } } diff --git a/test/periphery/integration/merkle-campaign/lt/constructor.t.sol b/test/periphery/integration/merkle-campaign/lt/constructor.t.sol index bf9f3dfbc..e712a603b 100644 --- a/test/periphery/integration/merkle-campaign/lt/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/constructor.t.sol @@ -12,12 +12,14 @@ contract Constructor_MerkleLT_Integration_Test is MerkleCampaign_Integration_Tes address actualAdmin; uint256 actualAllowance; address actualAsset; - string actualIpfsCID; - string actualName; bool actualCancelable; uint40 actualExpiration; + address actualFactory; + string actualIpfsCID; address actualLockupTranched; bytes32 actualMerkleRoot; + string actualName; + uint256 actualSablierFee; uint40 actualStreamStartTime; uint64 actualTotalPercentage; MerkleLT.TrancheWithPercentage[] actualTranchesWithPercentages; @@ -26,11 +28,13 @@ contract Constructor_MerkleLT_Integration_Test is MerkleCampaign_Integration_Tes uint256 expectedAllowance; address expectedAsset; bool expectedCancelable; - string expectedIpfsCID; uint40 expectedExpiration; + address expectedFactory; + string expectedIpfsCID; address expectedLockupTranched; bytes32 expectedMerkleRoot; bytes32 expectedName; + uint256 expectedSablierFee; uint40 expectedStreamStartTime; uint64 expectedTotalPercentage; MerkleLT.TrancheWithPercentage[] expectedTranchesWithPercentages; @@ -38,33 +42,53 @@ contract Constructor_MerkleLT_Integration_Test is MerkleCampaign_Integration_Tes } function test_Constructor() external { + // Make Factory the caller for the constructor test. + resetPrank(address(merkleFactory)); + SablierMerkleLT constructedLT = new SablierMerkleLT( defaults.baseParams(), lockupTranched, defaults.CANCELABLE(), defaults.TRANSFERABLE(), defaults.STREAM_START_TIME_ZERO(), - defaults.tranchesWithPercentages() + defaults.tranchesWithPercentages(), + defaults.SABLIER_FEE() ); Vars memory vars; + vars.actualAdmin = constructedLT.admin(); + vars.expectedAdmin = users.admin; + assertEq(vars.actualAdmin, vars.expectedAdmin, "admin"); + + vars.actualAllowance = dai.allowance(address(constructedLT), address(lockupTranched)); + vars.expectedAllowance = MAX_UINT256; + assertEq(vars.actualAllowance, vars.expectedAllowance, "allowance"); + vars.actualAsset = address(constructedLT.ASSET()); vars.expectedAsset = address(dai); assertEq(vars.actualAsset, vars.expectedAsset, "asset"); + vars.actualCancelable = constructedLT.CANCELABLE(); + vars.expectedCancelable = defaults.CANCELABLE(); + assertEq(vars.actualCancelable, vars.expectedCancelable, "cancelable"); + vars.actualExpiration = constructedLT.EXPIRATION(); vars.expectedExpiration = defaults.EXPIRATION(); assertEq(vars.actualExpiration, vars.expectedExpiration, "expiration"); - vars.actualAdmin = constructedLT.admin(); - vars.expectedAdmin = users.admin; - assertEq(vars.actualAdmin, vars.expectedAdmin, "admin"); + vars.actualFactory = constructedLT.FACTORY(); + vars.expectedFactory = address(merkleFactory); + assertEq(vars.actualFactory, vars.expectedFactory, "factory"); vars.actualIpfsCID = constructedLT.ipfsCID(); vars.expectedIpfsCID = defaults.IPFS_CID(); assertEq(vars.actualIpfsCID, vars.expectedIpfsCID, "ipfsCID"); + vars.actualLockupTranched = address(constructedLT.LOCKUP_TRANCHED()); + vars.expectedLockupTranched = address(lockupTranched); + assertEq(vars.actualLockupTranched, vars.expectedLockupTranched, "lockupTranched"); + vars.actualMerkleRoot = constructedLT.MERKLE_ROOT(); vars.expectedMerkleRoot = defaults.MERKLE_ROOT(); assertEq(vars.actualMerkleRoot, vars.expectedMerkleRoot, "merkleRoot"); @@ -73,13 +97,9 @@ contract Constructor_MerkleLT_Integration_Test is MerkleCampaign_Integration_Tes vars.expectedName = defaults.NAME_BYTES32(); assertEq(bytes32(abi.encodePacked(vars.actualName)), vars.expectedName, "name"); - vars.actualCancelable = constructedLT.CANCELABLE(); - vars.expectedCancelable = defaults.CANCELABLE(); - assertEq(vars.actualCancelable, vars.expectedCancelable, "cancelable"); - - vars.actualLockupTranched = address(constructedLT.LOCKUP_TRANCHED()); - vars.expectedLockupTranched = address(lockupTranched); - assertEq(vars.actualLockupTranched, vars.expectedLockupTranched, "lockupTranched"); + vars.actualSablierFee = constructedLT.SABLIER_FEE(); + vars.expectedSablierFee = defaults.SABLIER_FEE(); + assertEq(vars.actualSablierFee, vars.expectedSablierFee, "sablierFee"); vars.actualStreamStartTime = constructedLT.STREAM_START_TIME(); vars.expectedStreamStartTime = defaults.STREAM_START_TIME_ZERO(); @@ -96,9 +116,5 @@ contract Constructor_MerkleLT_Integration_Test is MerkleCampaign_Integration_Tes vars.actualTranchesWithPercentages = constructedLT.getTranchesWithPercentages(); vars.expectedTranchesWithPercentages = defaults.tranchesWithPercentages(); assertEq(vars.actualTranchesWithPercentages, vars.expectedTranchesWithPercentages, "tranchesWithPercentages"); - - vars.actualAllowance = dai.allowance(address(constructedLT), address(lockupTranched)); - vars.expectedAllowance = MAX_UINT256; - assertEq(vars.actualAllowance, vars.expectedAllowance, "allowance"); } } diff --git a/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol b/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol index 2ba71977a..c3ba552c2 100644 --- a/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol +++ b/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol @@ -19,7 +19,7 @@ abstract contract MerkleCampaign_Integration_Shared_Test is MerkleCampaign_Integ //////////////////////////////////////////////////////////////////////////*/ function claim() internal { - merkleBase.claim({ + merkleBase.claim{ value: defaults.SABLIER_FEE() }({ index: defaults.INDEX1(), recipient: users.recipient1, amount: defaults.CLAIM_AMOUNT(), @@ -50,8 +50,13 @@ abstract contract MerkleCampaign_Integration_Shared_Test is MerkleCampaign_Integ } modifier whenFirstClaimMade() { + // Reset the prank to the recipient to make the first claim. + resetPrank({ msgSender: users.recipient }); // Make the first claim to set `_firstClaimTime`. claim(); + + // Reset the prank back to the users.admin. + resetPrank(users.admin); _; } diff --git a/test/periphery/integration/merkle-campaign/shared/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/shared/claim/claim.t.sol index 441bddac1..80f4e4b75 100644 --- a/test/periphery/integration/merkle-campaign/shared/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/shared/claim/claim.t.sol @@ -12,32 +12,59 @@ abstract contract Claim_Integration_Test is MerkleCampaign_Integration_Shared_Te function test_RevertGiven_CampaignExpired() external { uint40 expiration = defaults.EXPIRATION(); + uint256 sablierFee = defaults.SABLIER_FEE(); uint256 warpTime = expiration + 1 seconds; bytes32[] memory merkleProof; vm.warp({ newTimestamp: warpTime }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_CampaignExpired.selector, warpTime, expiration)); - merkleBase.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); + merkleBase.claim{ value: sablierFee }({ + index: 1, + recipient: users.recipient1, + amount: 1, + merkleProof: merkleProof + }); } - function test_RevertGiven_RecipientClaimed() external givenCampaignNotExpired { + function test_RevertGiven_MsgValueLessThanSablierFee() external givenCampaignNotExpired { + uint256 index1 = defaults.INDEX1(); + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory merkleProof = defaults.index1Proof(); + uint256 sablierFee = defaults.SABLIER_FEE(); + + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InsufficientFeePayment.selector, 0, sablierFee)); + merkleBase.claim{ value: 0 }(index1, users.recipient1, amount, merkleProof); + } + + modifier givenMsgValueNotLessThanSablierFee() { + _; + } + + function test_RevertGiven_RecipientClaimed() external givenCampaignNotExpired givenMsgValueNotLessThanSablierFee { claim(); uint256 index1 = defaults.INDEX1(); uint128 amount = defaults.CLAIM_AMOUNT(); + uint256 sablierFee = defaults.SABLIER_FEE(); bytes32[] memory merkleProof = defaults.index1Proof(); vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_StreamClaimed.selector, index1)); - merkleBase.claim(index1, users.recipient1, amount, merkleProof); + merkleBase.claim{ value: sablierFee }(index1, users.recipient1, amount, merkleProof); } modifier givenRecipientNotClaimed() { _; } - function test_RevertWhen_IndexNotValid() external givenCampaignNotExpired givenRecipientNotClaimed { + function test_RevertWhen_IndexNotValid() + external + givenCampaignNotExpired + givenMsgValueNotLessThanSablierFee + givenRecipientNotClaimed + { uint256 invalidIndex = 1337; uint128 amount = defaults.CLAIM_AMOUNT(); + uint256 sablierFee = defaults.SABLIER_FEE(); bytes32[] memory merkleProof = defaults.index1Proof(); vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); - merkleBase.claim(invalidIndex, users.recipient1, amount, merkleProof); + merkleBase.claim{ value: sablierFee }(invalidIndex, users.recipient1, amount, merkleProof); } modifier whenIndexValid() { @@ -47,15 +74,17 @@ abstract contract Claim_Integration_Test is MerkleCampaign_Integration_Shared_Te function test_RevertWhen_RecipientNotValid() external givenCampaignNotExpired + givenMsgValueNotLessThanSablierFee givenRecipientNotClaimed whenIndexValid { uint256 index1 = defaults.INDEX1(); address invalidRecipient = address(1337); uint128 amount = defaults.CLAIM_AMOUNT(); + uint256 sablierFee = defaults.SABLIER_FEE(); bytes32[] memory merkleProof = defaults.index1Proof(); vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); - merkleBase.claim(index1, invalidRecipient, amount, merkleProof); + merkleBase.claim{ value: sablierFee }(index1, invalidRecipient, amount, merkleProof); } modifier whenRecipientValid() { @@ -65,15 +94,17 @@ abstract contract Claim_Integration_Test is MerkleCampaign_Integration_Shared_Te function test_RevertWhen_AmountNotValid() external givenCampaignNotExpired + givenMsgValueNotLessThanSablierFee givenRecipientNotClaimed whenIndexValid whenRecipientValid { uint256 index1 = defaults.INDEX1(); uint128 invalidAmount = 1337; + uint256 sablierFee = defaults.SABLIER_FEE(); bytes32[] memory merkleProof = defaults.index1Proof(); vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); - merkleBase.claim(index1, users.recipient1, invalidAmount, merkleProof); + merkleBase.claim{ value: sablierFee }(index1, users.recipient1, invalidAmount, merkleProof); } modifier whenAmountValid() { @@ -83,6 +114,7 @@ abstract contract Claim_Integration_Test is MerkleCampaign_Integration_Shared_Te function test_RevertWhen_MerkleProofNotValid() external givenCampaignNotExpired + givenMsgValueNotLessThanSablierFee givenRecipientNotClaimed whenIndexValid whenRecipientValid @@ -90,9 +122,10 @@ abstract contract Claim_Integration_Test is MerkleCampaign_Integration_Shared_Te { uint256 index1 = defaults.INDEX1(); uint128 amount = defaults.CLAIM_AMOUNT(); + uint256 sablierFee = defaults.SABLIER_FEE(); bytes32[] memory invalidMerkleProof = defaults.index2Proof(); vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); - merkleBase.claim(index1, users.recipient1, amount, invalidMerkleProof); + merkleBase.claim{ value: sablierFee }(index1, users.recipient1, amount, invalidMerkleProof); } /// @dev Since the implementation of `_claim()` differs in each Merkle campaign, we declare this dummy test and @@ -100,12 +133,14 @@ abstract contract Claim_Integration_Test is MerkleCampaign_Integration_Shared_Te function test_WhenMerkleProofValid() external givenCampaignNotExpired + givenMsgValueNotLessThanSablierFee givenRecipientNotClaimed whenIndexValid whenRecipientValid whenAmountValid { // The child contract must check that the claim event is emitted. - // It should also mark the index as claimed. + // It should mark the index as claimed. + // It should transfer the sablier fee from the caller address to the merkle lockup. } } diff --git a/test/periphery/integration/merkle-campaign/shared/claim/claim.tree b/test/periphery/integration/merkle-campaign/shared/claim/claim.tree index 6bde417e7..849cf9e49 100644 --- a/test/periphery/integration/merkle-campaign/shared/claim/claim.tree +++ b/test/periphery/integration/merkle-campaign/shared/claim/claim.tree @@ -2,20 +2,24 @@ Claim_Integration_Test ├── given campaign expired │ └── it should revert └── given campaign not expired - ├── given recipient claimed + ├── given msg value less than sablier fee │ └── it should revert - └── given recipient not claimed - ├── when index not valid + └── given msg value not less than sablier fee + ├── given recipient claimed │ └── it should revert - └── when index valid - ├── when recipient not valid + └── given recipient not claimed + ├── when index not valid │ └── it should revert - └── when recipient valid - ├── when amount not valid + └── when index valid + ├── when recipient not valid │ └── it should revert - └── when amount valid - ├── when Merkle proof not valid + └── when recipient valid + ├── when amount not valid │ └── it should revert - └── when Merkle proof valid - ├── it should mark the index as Claimed - └── it should emit {Claim} event + └── when amount valid + ├── when Merkle proof not valid + │ └── it should revert + └── when Merkle proof valid + ├── it should mark the index as Claimed + ├── it should transfer the ETH to the merkle lockup + └── it should emit {Claim} event diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 12ac731db..095b09b62 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -64,6 +64,7 @@ contract Defaults is Constants, Merkle { bytes32 public MERKLE_ROOT; string public constant NAME = "Airdrop Campaign"; bytes32 public constant NAME_BYTES32 = bytes32(abi.encodePacked("Airdrop Campaign")); + uint256 public constant SABLIER_FEE = 0.005e18; uint40 public immutable STREAM_START_TIME_NON_ZERO = JULY_1_2024 - 2 days; uint40 public immutable STREAM_START_TIME_ZERO = 0; uint64 public constant TOTAL_PERCENTAGE = uUNIT; diff --git a/test/utils/Events.sol b/test/utils/Events.sol index 63b86f766..c5b18c686 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -137,4 +137,8 @@ abstract contract Events { uint256 aggregateAmount, uint256 recipientCount ); + + event SetSablierFee(address indexed admin, uint256 sablierFee); + + event WithdrawSablierFees(address indexed admin, address indexed to, uint256 sablierFees); } diff --git a/test/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol index 3588d67b2..31b9fa6ee 100644 --- a/test/utils/Precompiles.t.sol +++ b/test/utils/Precompiles.t.sol @@ -102,14 +102,14 @@ contract Precompiles_Test is Base_Test { } function test_DeployMerkleFactory() external onlyTestOptimizedProfile { - address actualFactory = address(precompiles.deployMerkleFactory()); + address actualFactory = address(precompiles.deployMerkleFactory(users.admin)); address expectedFactory = address(deployOptimizedMerkleFactory()); assertEq(actualFactory.code, expectedFactory.code, "bytecodes mismatch"); } function test_DeployPeriphery() external onlyTestOptimizedProfile { (ISablierBatchLockup actualBatchLockup, ISablierMerkleFactory actualMerkleFactory) = - precompiles.deployPeriphery(); + precompiles.deployPeriphery(users.admin); (ISablierBatchLockup expectedBatchLockup, ISablierMerkleFactory expectedMerkleFactory) = deployOptimizedPeriphery(); From d90bd2c2c367c9bbb10d2a839a48c0b86bd8f9fd Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 10 Sep 2024 00:31:27 +0100 Subject: [PATCH 03/21] test: fix claim in fork tests --- test/periphery/fork/merkle-campaign/MerkleInstant.t.sol | 9 ++++++++- test/periphery/fork/merkle-campaign/MerkleLL.t.sol | 9 ++++++++- test/periphery/fork/merkle-campaign/MerkleLT.t.sol | 9 ++++++++- .../factory/set-sablier-fee/setSablierFee.t.sol | 1 - 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol index 304bfa921..5693a49d6 100644 --- a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol @@ -92,7 +92,7 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test { vars.merkleRoot = getRoot(leaves.toBytes32()); } - // Make the caller the admin. + // Make the admin as the caller. resetPrank({ msgSender: params.admin }); uint256 sablierFee = defaults.SABLIER_FEE(); @@ -136,6 +136,10 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test { CLAIM //////////////////////////////////////////////////////////////////////////*/ + // Make the recipient as the caller. + resetPrank({ msgSender: vars.recipients[params.posBeforeSort] }); + vm.deal(vars.recipients[params.posBeforeSort], 1 ether); + assertFalse(vars.merkleInstant.hasClaimed(vars.indexes[params.posBeforeSort])); vars.leafToClaim = MerkleBuilder.computeLeaf( @@ -179,6 +183,9 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test { CLAWBACK //////////////////////////////////////////////////////////////////////////*/ + // Make the admin as the caller. + resetPrank({ msgSender: params.admin }); + if (params.expiration > 0) { vars.clawbackAmount = uint128(FORK_ASSET.balanceOf(address(vars.merkleInstant))); vm.warp({ newTimestamp: uint256(params.expiration) + 1 seconds }); diff --git a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol index 1a9f417a0..cb11afdc0 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol @@ -96,7 +96,7 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { vars.merkleRoot = getRoot(leaves.toBytes32()); } - // Make the caller the admin. + // Make the admin as the caller. resetPrank({ msgSender: params.admin }); uint256 sablierFee = defaults.SABLIER_FEE(); @@ -144,6 +144,10 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { CLAIM //////////////////////////////////////////////////////////////////////////*/ + // Make the recipient as the caller. + resetPrank({ msgSender: vars.recipients[params.posBeforeSort] }); + vm.deal(vars.recipients[params.posBeforeSort], 1 ether); + assertFalse(vars.merkleLL.hasClaimed(vars.indexes[params.posBeforeSort])); vars.leafToClaim = MerkleBuilder.computeLeaf( @@ -201,6 +205,9 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { CLAWBACK //////////////////////////////////////////////////////////////////////////*/ + // Make the admin as the caller. + resetPrank({ msgSender: params.admin }); + if (params.expiration > 0) { vars.clawbackAmount = uint128(FORK_ASSET.balanceOf(address(vars.merkleLL))); vm.warp({ newTimestamp: uint256(params.expiration) + 1 seconds }); diff --git a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol index 27a5bf92b..b1bc5dc7d 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol @@ -97,7 +97,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { vars.merkleRoot = getRoot(leaves.toBytes32()); } - // Make the caller the admin. + // Make the admin as the caller. resetPrank({ msgSender: params.admin }); uint256 sablierFee = defaults.SABLIER_FEE(); @@ -148,6 +148,10 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { CLAIM //////////////////////////////////////////////////////////////////////////*/ + // Make the recipient as the caller. + resetPrank({ msgSender: vars.recipients[params.posBeforeSort] }); + vm.deal(vars.recipients[params.posBeforeSort], 1 ether); + assertFalse(vars.merkleLT.hasClaimed(vars.indexes[params.posBeforeSort])); vars.leafToClaim = MerkleBuilder.computeLeaf( @@ -207,6 +211,9 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { CLAWBACK //////////////////////////////////////////////////////////////////////////*/ + // Make the admin as the caller. + resetPrank({ msgSender: params.admin }); + if (params.expiration > 0) { vars.clawbackAmount = uint128(FORK_ASSET.balanceOf(address(vars.merkleLT))); vm.warp({ newTimestamp: uint256(params.expiration) + 1 seconds }); diff --git a/test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.t.sol b/test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.t.sol index e7dc25390..c988778dd 100644 --- a/test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.t.sol @@ -2,7 +2,6 @@ pragma solidity >=0.8.22 <0.9.0; import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; -import { Errors } from "src/periphery/libraries/Errors.sol"; import { MerkleCampaign_Integration_Shared_Test } from "../../shared/MerkleCampaign.t.sol"; From 0f2985a73d30c11daa65c84193dee96684fa37ab Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 10 Sep 2024 00:33:51 +0100 Subject: [PATCH 04/21] refactor: remove redundant receive function --- src/periphery/abstracts/SablierMerkleBase.sol | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/periphery/abstracts/SablierMerkleBase.sol b/src/periphery/abstracts/SablierMerkleBase.sol index 1057a642d..c2dc9d82d 100644 --- a/src/periphery/abstracts/SablierMerkleBase.sol +++ b/src/periphery/abstracts/SablierMerkleBase.sol @@ -71,9 +71,6 @@ abstract contract SablierMerkleBase is SABLIER_FEE = sablierFee; } - /// @dev Implements the receive Ether function to be able to receive sablier fee during claim. - receive() external payable { } - /*////////////////////////////////////////////////////////////////////////// USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ From d135b8b2e4ba99b466a552966f56305014576012 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 10 Sep 2024 11:55:44 +0100 Subject: [PATCH 05/21] test: withdrawFees in Factory and MerkleBase test: ReceiveEth mock contract test: update precompiles refactor: add missing override modifier refactor: return feeAmount in withdrawFees in MerkleBase --- precompiles/Precompiles.sol | 10 +-- src/periphery/SablierMerkleFactory.sol | 13 +-- src/periphery/abstracts/SablierMerkleBase.sol | 4 +- .../interfaces/ISablierMerkleBase.sol | 4 +- test/mocks/ReceiveEth.sol | 10 +++ test/periphery/Periphery.t.sol | 17 ++++ .../factory/withdraw-fees/withdrawFees.t.sol | 83 +++++++++++++++++++ .../factory/withdraw-fees/withdrawFees.tree | 16 ++++ .../instant/MerkleInstant.t.sol | 22 +++-- .../merkle-campaign/ll/MerkleLL.t.sol | 8 ++ .../merkle-campaign/lt/MerkleLT.t.sol | 8 ++ .../shared/withdraw-fees/withdrawFees.t.sol | 71 ++++++++++++++++ .../shared/withdraw-fees/withdrawFees.tree | 13 +++ test/utils/DeployOptimized.sol | 15 ++-- test/utils/Precompiles.t.sol | 4 +- 15 files changed, 270 insertions(+), 28 deletions(-) create mode 100644 test/mocks/ReceiveEth.sol create mode 100644 test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.t.sol create mode 100644 test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.tree create mode 100644 test/periphery/integration/merkle-campaign/shared/withdraw-fees/withdrawFees.t.sol create mode 100644 test/periphery/integration/merkle-campaign/shared/withdraw-fees/withdrawFees.tree diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 301a581af..f0faabfbf 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -23,15 +23,15 @@ contract Precompiles { bytes public constant BYTECODE_BATCH_LOCKUP = hex"60808060405234601557611b67908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c806337266dd31461108957806349a32c4014610d7b578063606ef87514610a635780639e743f291461072b578063a514f83e146103e85763f7ca34eb1461005b575f80fd5b3461032a57610069366113d4565b91909282156103c0575f905f5b84811061039557506001600160a01b036100939116918383611827565b61009c83611584565b926001600160a01b035f9316925b8181106100c357604051806100bf878261142b565b0390f35b6100ce8183886117e1565b6100d7906115b6565b90826100e482828a6117e1565b6020016100f0906115b6565b6100fb83838b6117e1565b604001610107906114b0565b93896101148585836117e1565b606001610120906115ca565b61012b8686846117e1565b608001610137906115ca565b6101428787856117e1565b60a00161014e90611804565b918761015b8189876117e1565b60c081016101689161170e565b986101749291966117e1565b60e001936040519561018587611511565b6001600160a01b0316865260208601966001600160a01b0316875260408601996001600160801b03168a5260608601978d895260808701921515835260a08701931515845260c087019464ffffffffff16855236906101e392611744565b9360e08601948552366101f5916116b0565b966101008601978852604051998a977f31df3d480000000000000000000000000000000000000000000000000000000089526004890160209052610164890197516001600160a01b031660248a0152516001600160a01b03166044890152516001600160801b03166064880152516001600160a01b0316608487015251151560a486015251151560c48501525164ffffffffff1660e48401525190610104830161014090528151809152610184830191602001905f905b808210610341575050925180516001600160a01b03166101248401526020908101516101448401529250819003815f885af18015610336575f90610300575b600192506102f982886116e9565b52016100aa565b506020823d821161032e575b816103196020938361154a565b8101031261032a57600191516102eb565b5f80fd5b3d915061030c565b6040513d5f823e3d90fd5b91949350916020606082610386600194895164ffffffffff604080926001600160801b03815116855267ffffffffffffffff6020820151166020860152015116910152565b019501920186939492916102ac565b916001906001600160801b036103b760406103b1878a8c6117e1565b016114b0565b16019201610076565b7f36186274000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461032a57606036600319011261032a57610401611464565b61040961138d565b906044359167ffffffffffffffff831161032a573660238401121561032a5782600401359267ffffffffffffffff841161032a57602481019060243691610140870201011161032a5783156103c05790915f9190825b85811061070257506001600160a01b0361047c9116928484611827565b61048584611584565b926001600160a01b03165f5b8581106104a657604051806100bf878261142b565b6104b96104b4828886611816565b6115b6565b906104d060206104ca838a88611816565b016115b6565b87856104e260406103b1868585611816565b6104f860606104f2878686611816565b016115ca565b906101006105228761051b818861051560806104f284848d611816565b98611816565b968c611816565b01906001600160a01b03604051986105398a6114c4565b1688526001600160a01b0360208901961686526001600160801b036040890191168152606088019189835260808901931515845260a0890194151585526060609f19873603011261032a57604051956105918761152e565b61059d60a08201611621565b87526105ab60c08201611621565b602088015260e0016105bc90611621565b604087015260c08901958652366105d2916116b0565b9560e08901968752604051987f53b15727000000000000000000000000000000000000000000000000000000008a52516001600160a01b031660048a0152516001600160a01b03166024890152516001600160801b03166044880152516001600160a01b03166064870152511515608486015251151560a485015251805164ffffffffff1660c4850152602081015164ffffffffff1660e48501526040015164ffffffffff166101048401525161012483016106a091602080916001600160a01b0381511684520151910152565b8180865a925f61016492602095f18015610336575f906106d0575b600192506106c982886116e9565b5201610491565b506020823d82116106fa575b816106e96020938361154a565b8101031261032a57600191516106bb565b3d91506106dc565b93926001906001600160801b0361071f60406103b1898b89611816565b1601940193929361045f565b3461032a57610739366113d4565b91909282156103c0575f905f5b848110610a3e57506001600160a01b036107639116918383611827565b61076c83611584565b926001600160a01b035f9316925b81811061078f57604051806100bf878261142b565b61079a8183886117e1565b6107a3906115b6565b90826107b082828a6117e1565b6020016107bc906115b6565b6107c783838b6117e1565b6040016107d3906114b0565b93896107e08585836117e1565b6060016107ec906115ca565b6107f78686846117e1565b608001610803906115ca565b61080e8787856117e1565b60a00161081a90611804565b91876108278189876117e1565b60c08101610834916115d7565b986108409291966117e1565b60e001936040519561085187611511565b6001600160a01b0316865260208601966001600160a01b0316875260408601996001600160801b03168a5260608601978d895260808701921515835260a08701931515845260c087019464ffffffffff16855236906108af92611633565b9360e08601948552366108c1916116b0565b966101008601978852604051998a977f32fbe22b0000000000000000000000000000000000000000000000000000000089526004890160209052610164890197516001600160a01b031660248a0152516001600160a01b03166044890152516001600160801b03166064880152516001600160a01b0316608487015251151560a486015251151560c48501525164ffffffffff1660e48401525190610104830161014090528151809152610184830191602001905f905b8082106109fe575050925180516001600160a01b03166101248401526020908101516101448401529250819003815f885af18015610336575f906109cc575b600192506109c582886116e9565b520161077a565b506020823d82116109f6575b816109e56020938361154a565b8101031261032a57600191516109b7565b3d91506109d8565b91949350916020604082610a2f600194895164ffffffffff602080926001600160801b038151168552015116910152565b01950192018693949291610978565b916001906001600160801b03610a5a60406103b1878a8c6117e1565b16019201610746565b3461032a57610a71366113d4565b91909282156103c0575f905f5b848110610d5657506001600160a01b03610a9b9116918383611827565b610aa483611584565b926001600160a01b035f9316925b818110610ac757604051806100bf878261142b565b610ad281838861147a565b610adb906115b6565b9082610ae882828a61147a565b602001610af4906115b6565b610aff83838b61147a565b604001610b0b906114b0565b9389610b1885858361147a565b606001610b24906115ca565b610b2f86868461147a565b608001610b3b906115ca565b9086610b4881888661147a565b60a08101610b559161170e565b97610b6192919561147a565b60c0019260405194610b72866114c4565b6001600160a01b0316855260208501956001600160a01b0316865260408501986001600160801b0316895260608501968c885260808601921515835260a0860193151584523690610bc292611744565b9260c0850193845236610bd4916116b0565b9560e085019687526040519889967f54c022920000000000000000000000000000000000000000000000000000000088526004880160209052610144880196516001600160a01b03166024890152516001600160a01b03166044880152516001600160801b03166064870152516001600160a01b0316608486015251151560a485015251151560c4840152519060e4830161012090528151809152610164830191602001905f905b808210610d02575050925180516001600160a01b03166101048401526020908101516101248401529250819003815f885af18015610336575f90610cd0575b60019250610cc982886116e9565b5201610ab2565b506020823d8211610cfa575b81610ce96020938361154a565b8101031261032a5760019151610cbb565b3d9150610cdc565b91949350916020606082610d47600194895164ffffffffff604080926001600160801b03815116855267ffffffffffffffff6020820151166020860152015116910152565b01950192018693949291610c7c565b916001906001600160801b03610d7260406103b1878a8c61147a565b16019201610a7e565b3461032a57606036600319011261032a57610d94611464565b610d9c61138d565b906044359167ffffffffffffffff831161032a573660238401121561032a5782600401359267ffffffffffffffff841161032a57602481019060243691610120870201011161032a5783156103c05790915f9190825b85811061106057506001600160a01b03610e0f9116928484611827565b610e1884611584565b926001600160a01b03165f5b858110610e3957604051806100bf878261142b565b610e476104b48288866116fd565b90610e5860206104ca838a886116fd565b8785610e6a60406103b18685856116fd565b610e7a60606104f28786866116fd565b9060e0610ea387610e9c8188610e9660806104f284848d6116fd565b986116fd565b968c6116fd565b01906001600160a01b0360405198610eba8a6114c4565b1688526001600160a01b0360208901961686526001600160801b036040890191168152606088019189835260808901931515845260a0890194151585526040609f19873603011261032a5760405195610f12876114f5565b610f1e60a08201611621565b875260c001610f2c90611621565b602087015260c0890195865236610f42916116b0565b9560e08901968752604051987fab167ccc000000000000000000000000000000000000000000000000000000008a52516001600160a01b031660048a0152516001600160a01b03166024890152516001600160801b03166044880152516001600160a01b03166064870152511515608486015251151560a485015251805164ffffffffff1660c48501526020015164ffffffffff1660e4840152516101048301610ffe91602080916001600160a01b0381511684520151910152565b8180865a925f61014492602095f18015610336575f9061102e575b6001925061102782886116e9565b5201610e24565b506020823d8211611058575b816110476020938361154a565b8101031261032a5760019151611019565b3d915061103a565b93926001906001600160801b0361107d60406103b1898b896116fd565b16019401939293610df2565b3461032a57611097366113d4565b91909282156103c0575f905f5b84811061136857506001600160a01b036110c19116918383611827565b6110ca83611584565b926001600160a01b035f9316925b8181106110ed57604051806100bf878261142b565b6110f881838861147a565b611101906115b6565b908261110e82828a61147a565b60200161111a906115b6565b61112583838b61147a565b604001611131906114b0565b938961113e85858361147a565b60600161114a906115ca565b61115586868461147a565b608001611161906115ca565b908661116e81888661147a565b60a0810161117b916115d7565b9761118792919561147a565b60c0019260405194611198866114c4565b6001600160a01b0316855260208501956001600160a01b0316865260408501986001600160801b0316895260608501968c885260808601921515835260a08601931515845236906111e892611633565b9260c08501938452366111fa916116b0565b9560e085019687526040519889967f897f362b0000000000000000000000000000000000000000000000000000000088526004880160209052610144880196516001600160a01b03166024890152516001600160a01b03166044880152516001600160801b03166064870152516001600160a01b0316608486015251151560a485015251151560c4840152519060e4830161012090528151809152610164830191602001905f905b808210611328575050925180516001600160a01b03166101048401526020908101516101248401529250819003815f885af18015610336575f906112f6575b600192506112ef82886116e9565b52016110d8565b506020823d8211611320575b8161130f6020938361154a565b8101031261032a57600191516112e1565b3d9150611302565b91949350916020604082611359600194895164ffffffffff602080926001600160801b038151168552015116910152565b019501920186939492916112a2565b916001906001600160801b0361138460406103b1878a8c61147a565b160192016110a4565b602435906001600160a01b038216820361032a57565b9181601f8401121561032a5782359167ffffffffffffffff831161032a576020808501948460051b01011161032a57565b606060031982011261032a576004356001600160a01b038116810361032a57916024356001600160a01b038116810361032a57916044359067ffffffffffffffff821161032a57611427916004016113a3565b9091565b60206040818301928281528451809452019201905f5b81811061144e5750505090565b8251845260209384019390920191600101611441565b600435906001600160a01b038216820361032a57565b919081101561149c5760051b8101359060fe198136030182121561032a570190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b038116810361032a5790565b610100810190811067ffffffffffffffff8211176114e157604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff8211176114e157604052565b610120810190811067ffffffffffffffff8211176114e157604052565b6060810190811067ffffffffffffffff8211176114e157604052565b90601f8019910116810190811067ffffffffffffffff8211176114e157604052565b67ffffffffffffffff81116114e15760051b60200190565b9061158e8261156c565b61159b604051918261154a565b82815280926115ac601f199161156c565b0190602036910137565b356001600160a01b038116810361032a5790565b35801515810361032a5790565b903590601e198136030182121561032a570180359067ffffffffffffffff821161032a57602001918160061b3603831361032a57565b35906001600160801b038216820361032a57565b359064ffffffffff8216820361032a57565b92919261163f8261156c565b9361164d604051958661154a565b602085848152019260061b82019181831161032a57925b8284106116715750505050565b60408483031261032a576020604091825161168b816114f5565b6116948761160d565b81526116a1838801611621565b83820152815201930192611664565b919082604091031261032a576040516116c8816114f5565b809280356001600160a01b038116810361032a578252602090810135910152565b805182101561149c5760209160051b010190565b919081101561149c57610120020190565b903590601e198136030182121561032a570180359067ffffffffffffffff821161032a5760200191606082023603831361032a57565b9291926117508261156c565b9361175e604051958661154a565b606060208685815201930282019181831161032a57925b8284106117825750505050565b60608483031261032a57604051906117998261152e565b6117a28561160d565b825260208501359067ffffffffffffffff8216820361032a57826020928360609501526117d160408801611621565b6040820152815201930192611775565b919081101561149c5760051b8101359061011e198136030182121561032a570190565b3564ffffffffff8116810361032a5790565b919081101561149c57610140020190565b919061187c6040517f23b872dd0000000000000000000000000000000000000000000000000000000060208201523360248201523060448201528360648201526064815261187660848261154a565b82611a0a565b6001600160a01b0381166001600160a01b03604051947fdd62ed3e0000000000000000000000000000000000000000000000000000000086523060048701521693846024820152602081604481855afa80156103365784915f916119bd575b50106118e8575b50505050565b5f8060405194602086019063095ea7b360e01b825287602488015260448701526044865261191760648761154a565b85519082855af190611927611a8f565b8261198b575b5081611980575b5015611941575b806118e2565b611973611978936040519063095ea7b360e01b602083015260248201525f60448201526044815261187660648261154a565b611a0a565b5f808061193b565b90503b15155f611934565b805191925081159182156119a3575b5050905f61192d565b6119b692506020809183010191016119f2565b5f8061199a565b9150506020813d6020116119ea575b816119d96020938361154a565b8101031261032a578390515f6118db565b3d91506119cc565b9081602091031261032a5751801515810361032a5790565b5f806001600160a01b03611a3393169360208151910182865af1611a2c611a8f565b9083611ace565b8051908115159182611a74575b5050611a495750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b611a8792506020809183010191016119f2565b155f80611a40565b3d15611ac9573d9067ffffffffffffffff82116114e15760405191611abe601f8201601f19166020018461154a565b82523d5f602084013e565b606090565b90611b0b5750805115611ae357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611b51575b611b1c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15611b1456fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c0604052346103e157615a506060813803918261001c816103e5565b9384928339810103126103e15780516001600160a01b038116908190036103e15760208201516001600160a01b03811692908390036103e1576040015161006360406103e5565b92601a84527f5361626c696572204c6f636b75702044796e616d6963204e4654000000000000602085015261009860406103e5565b600e81526d29a0a116a627a1a5aaa816a22ca760911b602082015230608052845190946001600160401b0382116102e45760015490600182811c921680156103d7575b60208310146102c65781601f849311610369575b50602090601f8311600114610303575f926102f8575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e457600254600181811c911680156102da575b60208210146102c657601f8111610263575b50602094601f8211600114610200579481929394955f926101f5575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755615645908161040b823960805181613938015260a051818181610bcc0152613a020152f35b015190505f80610169565b601f1982169560025f52805f20915f5b88811061024b57508360019596979810610233575b505050811b0160025561017e565b01515f1960f88460031b161c191690555f8080610225565b91926020600181928685015181550194019201610210565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bc575b601f0160051c01905b8181106102b1575061014d565b5f81556001016102a4565b909150819061029b565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013b565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610105565b60015f9081528281209350601f198516905b8181106103515750908460019594939210610339575b505050811b0160015561011a565b01515f1960f88460031b161c191690555f808061032b565b92936020600181928786015181550195019301610315565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103cd575b90601f859493920160051c01905b8181106103bf57506100ef565b5f81558493506001016103b2565b90915081906103a4565b91607f16916100db565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e45760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146127c957508063027b6744146127a757806306fdde03146126ec578063081812fc146126ce578063095ea7b3146125c95780631400ecec146125185780631c1cdd4c146124b45780631e99d5691461249757806323b872dd14612480578063303acc851461244357806331df3d4814612330578063406887cb146121c157806340e58ee514611ea8578063425d30dd14611e5857806342842e0e14611e2f57806342966c6814611c6b5780634426757014611c455780634857501f14611bd45780634869e12d14611b9a5780634cc55e1114611aa257806354c02292146117f157806357404b12146117635780636352211e146117345780636d0cee751461173457806370a08231146116ca57806375829def1461165c5780637cad6cd11461156b5780637de6b1db146113ec5780638659c27014610fed578063894e9a0d14610cbe5780638f69b99314610c3e5780639067b67714610bef5780639188ec8414610bb557806395d89b4114610aad578063a22cb465146109f9578063a80fc071146109a8578063ad35efd414610949578063b2564569146108f9578063b637b865146108a0578063b88d4fde14610818578063b8a3be66146107e3578063b971302a14610795578063bc2be1be14610746578063c156a11d1461060f578063c87b56dd146104f9578063d4dbd20b146104a8578063d511609f1461045d578063d975dfed14610423578063e985e9c5146103ca578063ea5ead1914610386578063eac8f5b814610335578063f590c176146102d9578063f851a440146102b45763fdd46d601461026e575f80fd5b346102b05760603660031901126102b0576102876128f6565b6044356001600160801b03811681036102b0576102ae916102a661392e565b6004356133e2565b005b5f80fd5b346102b0575f3660031901126102b05760206001600160a01b035f5416604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346102b05760403660031901126102b05760206004356103b96103a76128f6565b916103b181614209565b928391613085565b6001600160801b0360405191168152f35b346102b05760403660031901126102b0576103e36128e0565b6001600160a01b036103f36128f6565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b9602091614209565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a6020526020600260405f20015460801c604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346102b05760203660031901126102b057600435610516816136b0565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa8015610604575f90610587575b610583906040519182916020835260208301906128bb565b0390f35b503d805f833e6105978183612a79565b8101906020818303126102b05780519067ffffffffffffffff82116102b057019080601f830112156102b0578151916105cf83612a9b565b916105dd6040519384612a79565b838352602084830101116102b057610583926105ff916020808501910161289a565b61056b565b6040513d5f823e3d90fd5b346102b05760403660031901126102b05760043561062b6128f6565b61063361392e565b815f52600a60205260ff600160405f20015460a81c161561073357815f5260036020526001600160a01b0360405f205416908133036107135761067583614209565b6001600160801b0381169182610703575b6001600160a01b038116156106f0576106a7856001600160a01b03926137f4565b1692836106c15784637e27328960e01b5f5260045260245ffd5b80859185036106d557602084604051908152f35b8492506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b61070e828587613085565b610686565b82632082501160e01b5f526004526001600160a01b03331660245260445ffd5b5063699d2de960e01b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b0360405f205416604051908152f35b346102b05760203660031901126102b0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346102b05760803660031901126102b0576108316128e0565b6108396128f6565b6064359167ffffffffffffffff83116102b057366023840112156102b05782600401359161086683612a9b565b926108746040519485612a79565b80845236602482870101116102b0576020815f9260246102ae9801838801378501015260443591612f95565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600b6020526105836108e560405f20612f0e565b60405191829160208352602083019061298b565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c16156103235761098190613760565b6040516005821015610994576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346102b05760403660031901126102b057610a126128e0565b602435908115158092036102b0576001600160a01b0316908115610a8157335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0575f3660031901126102b0576040515f6002548060011c90600181168015610bab575b602083108114610b9757828552908115610b735750600114610b15575b61058383610b0181850382612a79565b6040519182916020835260208301906128bb565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210610b5957509091508101602001610b01610af1565b919260018160209254838588010152019101909291610b41565b60ff191660208086019190915291151560051b84019091019150610b019050610af1565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ad4565b346102b0575f3660031901126102b05760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610c7690613760565b6005811015806109945760028214908115610cb2575b8115610ca0575b6020826040519015158152f35b90506109945760046020911482610c93565b5050600381145f610c8c565b346102b05760203660031901126102b057600435604051610180810181811067ffffffffffffffff821117610fd957606091610160916040525f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152610d39612ebe565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260405f20604051610d7481612a5c565b8154906001600160a01b0382168152602081019264ffffffffff8360a01c1684526040820164ffffffffff8460c81c168152606083019160ff8560f01c1615158352608084019460f81c1515855260018101549160a08501946001600160a01b038416865260c0810160ff8560a01c1615158152610e13600260e084019560ff8860a81c161515875260ff61010086019860b01c161515885201612edc565b61012083019081526002610e268c613760565b610e2f816129fd565b14610fd1575b5196516001600160a01b0316925164ffffffffff1695511515905115159351151594511515958a5f52600360205260405f20546001600160a01b03169a5f52600b60205260405f2092516001600160a01b0316995164ffffffffff1698511515926040519a610ea66101808d612a79565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610efa90612f0e565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e082016105839161298b565b5f8752610e35565b634e487b7160e01b5f52604160045260245ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761101e90369060040161295a565b9061102761392e565b5f915b80831061103357005b61103e838284612e4d565b359261104861392e565b835f52600a60205260ff600160405f20015460a81c16156113d857835f52600a60205260ff600160405f20015460a01c165f1461109257836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c6113c6576110c7815f52600a6020526001600160a01b0360405f205416331490565b156113b0576110d5816136d1565b90805f52600a6020526110ed600260405f2001612edc565b916001600160801b038351166001600160801b038216101561139c57815f52600a60205260ff60405f205460f01c161561138857806001600160801b03602081611141948188511603169501511690612aed565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611363575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061125c6001600160a01b03600160405f2001541694611234888588614663565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a160ff6112a6866001600160a01b03165f52600960205260405f2090565b54166112bc575b5050505050600101919061102a565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060457630d4af11f60e31b916001600160e01b0319915f91611335575b50160361131957808080806112ad565b636ade251160e01b5f526001600160a01b03602491166004525ffd5b611356915060203d811161135c575b61134e8183612a79565b810190613690565b87611309565b503d611344565b825f52600a602052600160405f2001600160a01b60ff60a01b1982541617905561118b565b50635dd950cb60e11b5f526024906004525ffd5b506308aca53f60e21b5f526024906004525ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f526024906004525ffd5b346102b05760203660031901126102b05760043561140861392e565b805f52600a60205260ff600160405f20015460a81c16156103235761142c81613760565b611435816129fd565b6004810361145057506315efa0f360e11b5f5260045260245ffd5b611459816129fd565b60038103611474575063d0a172b360e01b5f5260045260245ffd5b600290611480816129fd565b14611559576114a3815f52600a6020526001600160a01b0360405f205416331490565b1561153a57805f52600a60205260ff60405f205460f01c1615611528576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b632082501160e01b5f526004526001600160a01b03331660245260445ffd5b6308aca53f60e21b5f5260045260245ffd5b346102b05760203660031901126102b0576004356001600160a01b0381168091036102b0576001600160a01b035f5416338103611646575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116325760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b0576116756128e0565b5f546001600160a01b03811633810361164657506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346102b05760203660031901126102b0576001600160a01b036116eb6128e0565b168015611708575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346102b05760203660031901126102b05760206117526004356136b0565b6001600160a01b0360405191168152f35b346102b05760203660031901126102b05760043561177f612ea6565b50805f52600a60205260ff600160405f20015460a81c1615610323575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166117c983612a40565b825260208201526117ef8251809264ffffffffff60208092828151168552015116910152565bf35b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b0578036036101206003198201126102b05761182c61392e565b60c482013590602219018112156102b057810160048101359067ffffffffffffffff82116102b05760240160608202360381136102b05761186e913691612d69565b9081519161187b83612d51565b926118896040519485612a79565b808452601f1961189882612d51565b015f5b818110611a8b57505064ffffffffff4216916001600160801b036118be82613988565b51511667ffffffffffffffff60206118d584613988565b5101511664ffffffffff8060406118eb86613988565b51015116860116906040519261190084612a24565b83526020830152604082015261191586613988565b5261191f85613988565b5060015b8281106119f75750505061193982600401612e85565b9261194660248401612e85565b9261195360448201612e71565b916064820135936001600160a01b0385168095036102b0576020966119ef966119af966001600160801b036119e4976001600160a01b0361199660848a01612e99565b94816119a460a48c01612e99565b976040519d8e612a07565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612e06565b6101008201526139a9565b604051908152f35b806001600160801b03611a0c60019385613995565b51511667ffffffffffffffff6020611a248487613995565b5101511664ffffffffff806040611a3e5f1987018d613995565b51015116816040611a4f878a613995565b5101511601169060405192611a6384612a24565b835260208301526040820152611a798289613995565b52611a848188613995565b5001611923565b602090611a96612ebe565b8282890101520161189b565b346102b05760403660031901126102b05760043567ffffffffffffffff81116102b057611ad390369060040161295a565b9060243567ffffffffffffffff81116102b057611af490369060040161295a565b9091611afe61392e565b818403611b6a575f5b848110611b1057005b80611b64611b216001938886612e4d565b35611b2d838987612e4d565b355f5260036020526001600160a01b0360405f205416611b56611b5185898b612e4d565b612e71565b91611b5f61392e565b6133e2565b01611b07565b50827fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b9602091614159565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f611c0d82613760565b600581101561099457600203611c2b575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16611c1e565b346102b0575f3660031901126102b05760206001600160a01b0360085416604051908152f35b346102b05760203660031901126102b057600435611c8761392e565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c1615611e0457611cc6816140e7565b156113b057805f5260036020526001600160a01b0360405f205416151580611dfd575b80611de0575b611dce577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115611d97575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611d8557005b637e27328960e01b5f5260045260245ffd5b611db6835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055611d3d565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615611cef565b505f611ce9565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0576102ae611e4036612920565b9060405192611e50602085612a79565b5f8452612f95565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346102b05760203660031901126102b057600435611ec461392e565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c165f14611f0d576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c6113c657611f3f815f52600a6020526001600160a01b0360405f205416331490565b1561153a57611f4d816136d1565b90805f52600a602052611f65600260405f2001612edc565b916001600160801b038351166001600160801b03821610156121ae57815f52600a60205260ff60405f205460f01c161561219b57806001600160801b03602081611fb9948188511603169501511690612aed565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612176575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506120ac6001600160a01b03600160405f2001541694611234888588614663565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f2054166120ef57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060457630d4af11f60e31b916001600160e01b0319915f91612157575b50160361214557005b636ade251160e01b5f5260045260245ffd5b612170915060203d60201161135c5761134e8183612a79565b8461213c565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612003565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b346102b05760203660031901126102b0576121da6128e0565b6001600160a01b035f54169033820361231957806001600160a01b03913b156122ed57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa908115610604575f916122be575b501561229357805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6122e0915060203d6020116122e6575b6122d88183612a79565b810190612e35565b82612248565b503d6122ce565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761014060031982360301126102b05761236a61392e565b6040519061237782612a07565b6123838160040161290c565b82526123916024820161290c565b60208301526123a260448201612ab7565b604083015260648101356001600160a01b03811681036102b05760608301526123cd608482016129f0565b60808301526123de60a482016129f0565b60a08301526123ef60c48201612d3f565b60c083015260e481013567ffffffffffffffff81116102b057810191366023840112156102b0576119e46119ef926124336020953690602460048201359101612d69565b60e0840152610104369101612e06565b346102b05760203660031901126102b0576001600160a01b036124646128e0565b165f526009602052602060ff60405f2054166040519015158152f35b346102b0576102ae61249136612920565b91612b0d565b346102b0575f3660031901126102b0576020600754604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576124ec90613760565b600581101561099457806020911590811561250d575b506040519015158152f35b600191501482612502565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576020905f90805f52600a835260ff60405f205460f01c16806125ad575b61257b575b506001600160801b0360405191168152f35b6125a79150805f52600a83526125a16001600160801b03600260405f20015416916136d1565b90612aed565b82612569565b50805f52600a835260ff600160405f20015460a01c1615612564565b346102b05760403660031901126102b0576125e26128e0565b6024356125ee816136b0565b331515806126bb575b80612688575b61265c5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156125fd565b50336001600160a01b03821614156125f7565b346102b05760203660031901126102b0576020611752600435612acb565b346102b0575f3660031901126102b0576040515f6001548060011c9060018116801561279d575b602083108114610b9757828552908115610b73575060011461273f5761058383610b0181850382612a79565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061278357509091508101602001610b01610af1565b91926001816020925483858801015201910190929161276b565b91607f1691612713565b346102b0575f3660031901126102b057602060405167016345785d8a00008152f35b346102b05760203660031901126102b057600435906001600160e01b031982168092036102b057817f490649060000000000000000000000000000000000000000000000000000000060209314908115612825575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115612870575b811561285f575b508361281e565b6301ffc9a760e01b91501483612858565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612851565b5f5b8381106128ab5750505f910152565b818101518382015260200161289c565b906020916128d48151809281855285808601910161289a565b601f01601f1916010190565b600435906001600160a01b03821682036102b057565b602435906001600160a01b03821682036102b057565b35906001600160a01b03821682036102b057565b60609060031901126102b0576004356001600160a01b03811681036102b057906024356001600160a01b03811681036102b0579060443590565b9181601f840112156102b05782359167ffffffffffffffff83116102b0576020808501948460051b0101116102b057565b90602080835192838152019201905f5b8181106129a85750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff8682015116868501520151166040820152019401910191909161299b565b359081151582036102b057565b6005111561099457565b610120810190811067ffffffffffffffff821117610fd957604052565b6060810190811067ffffffffffffffff821117610fd957604052565b6040810190811067ffffffffffffffff821117610fd957604052565b610140810190811067ffffffffffffffff821117610fd957604052565b90601f8019910116810190811067ffffffffffffffff821117610fd957604052565b67ffffffffffffffff8111610fd957601f01601f191660200190565b35906001600160801b03821682036102b057565b612ad4816136b0565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161163257565b91906001600160a01b031680156106f057815f5260036020526001600160a01b0360405f205416151580612d37575b80612d1a575b612d07577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612c52575b6001600160a01b03935085612c1b575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303612c0357505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b612c3a825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612ba2565b9192905080612cb0575b15612c6957828291612b92565b8284612c8157637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612cde575b80612c5c5750825f526005602052336001600160a01b0360405f20541614612c5c565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612cbb565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615612b42565b506001612b3c565b359064ffffffffff821682036102b057565b67ffffffffffffffff8111610fd95760051b60200190565b929192612d7582612d51565b93612d836040519586612a79565b60606020868581520193028201918183116102b057925b828410612da75750505050565b6060848303126102b05760405190612dbe82612a24565b612dc785612ab7565b825260208501359067ffffffffffffffff821682036102b05782602092836060950152612df660408801612d3f565b6040820152815201930192612d9a565b91908260409103126102b057604051612e1e81612a40565b6020808294612e2c8161290c565b84520135910152565b908160209103126102b0575180151581036102b05790565b9190811015612e5d5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036102b05790565b356001600160a01b03811681036102b05790565b3580151581036102b05790565b60405190612eb382612a40565b5f6020838281520152565b60405190612ecb82612a24565b5f6040838281528260208201520152565b90604051612ee981612a24565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612f1a81612d51565b92612f286040519485612a79565b81845260208401905f5260205f205f915b838310612f465750505050565b600160208192604051612f5881612a24565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612f39565b90612fa1838284612b0d565b803b612fae575b50505050565b602091612ff46001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906128bb565b03815f865af15f9181613064575b5061303057506130106141da565b8051908161302b5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361305257505f808080612fa8565b633250574960e11b5f5260045260245ffd5b61307e91925060203d60201161135c5761134e8183612a79565b905f613002565b9061308e61392e565b815f52600a60205260ff600160405f20015460a81c161561073357815f52600a60205260ff600160405f20015460a01c166133cf576001600160a01b03811680156133a3576001600160801b03841691821561337757835f5260036020526001600160a01b0360405f205416948583141580613367575b613333576001600160801b0361311a86614209565b16808511613300575061313f90855f52600a602052600260405f20015460801c61422f565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff191691909117815561318290612edc565b6001600160801b036131a68160208401511692826040818351169201511690612aed565b1611156132ce575b835f52600a6020526131d2836001600160a01b03600160405f200154169283614663565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806132b8575b61323c5750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610604576392b9102b60e01b916001600160e01b0319915f91613299575b50160361214557808080612fa8565b6132b2915060203d60201161135c5761134e8183612a79565b5f61328a565b50835f52600960205260ff60405f205416613232565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556131ae565b84867f066920d7000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b82857f6a166406000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b50613371856140e7565b15613105565b837fb2ae7633000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b827f2da33e5b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b506315efa0f360e11b5f5260045260245ffd5b90815f52600a60205260ff600160405f20015460a81c161561073357815f52600a60205260ff600160405f20015460a01c166133cf576001600160a01b03811680156133a3576001600160801b03841691821561337757835f5260036020526001600160a01b0360405f205416948583141580613680575b613333576001600160801b0361346f86614209565b16808511613300575061349490855f52600a602052600260405f20015460801c61422f565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff19169190911781556134d790612edc565b6001600160801b036134fb8160208401511692826040818351169201511690612aed565b16111561364e575b835f52600a602052613527836001600160a01b03600160405f200154169283614663565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613629575b6135915750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610604576392b9102b60e01b916001600160e01b0319915f9161360a575b5016036135ee57808080612fa8565b6001600160a01b0390636ade251160e01b5f521660045260245ffd5b613623915060203d60201161135c5761134e8183612a79565b5f6135df565b5060ff613647856001600160a01b03165f52600960205260405f2090565b5416613587565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055613503565b5061368a856140e7565b1561345a565b908160209103126102b057516001600160e01b0319811681036102b05790565b805f5260036020526001600160a01b0360405f205416908115611d85575090565b64ffffffffff4216815f52600a6020528064ffffffffff60405f205460a01c16101561375a57815f52600a60205264ffffffffff60405f205460c81c16111561373f57805f52600b602052600160405f2054115f14613736576137339061430f565b90565b6137339061424f565b5f52600a6020526001600160801b03600260405f2001541690565b50505f90565b805f52600a60205260ff600160405f20015460a01c165f146137825750600490565b805f52600a60205260405f205460f81c6137ee57805f52600a60205264ffffffffff60405f205460a01c1642106137e9576137bc816136d1565b905f52600a6020526001600160801b0380600260405f200154169116105f146137e457600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f20541615158061391c575b806138ff575b611dce577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836138c8575b16806138b0575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f206001815401905561386c565b6138e7835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613865565b50805f52600a60205260ff600160405f20015460b01c1615613819565b506001600160a01b0382161515613813565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361396057565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612e5d5760200190565b8051821015612e5d5760209160051b010190565b906139cb6001600160801b036040840151166020610100850151015190614525565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156140bf578015614097578151801561406f577f00000000000000000000000000000000000000000000000000000000000000008111614044575064ffffffffff6040613a3984613988565b5101511681101561400057505f905f905f81515f905b808210613f78575050505064ffffffffff80421691169081811015613f4a5750506001600160801b031690818103613f1c57505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c248751975f19890190613995565b51015160c81b169360a01b169116171785555f5b818110613e0e575050600187016007556001600160a01b0360208301511680156106f057613c6e886001600160a01b03926137f4565b16613de2578682613cbc6001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b038551169030903390614602565b6001600160801b0360208401511680613db2575b506001600160a01b0381511694613da7613d896001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613d2e8b612a40565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c087015261014086019061298b565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613ddc906001600160a01b036060840151166001600160a01b036101008501515116903390614602565b5f613cd0565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f2090613e298160e0870151613995565b51825468010000000000000000811015610fd95760018101808555811015612e5d576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613c38565b7f0fa99c11000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f879842de000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193613f9c906001600160801b03613f938588613995565b5151169061422f565b9364ffffffffff806040613fb08685613995565b51015116941680851115613fcc57506001849301909291613a4f565b8490847f4b90504d000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff604061401184613988565b51015116907f93c315e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f099c714b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f5fbab612000000000000000000000000000000000000000000000000000000005f5260045ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561412d575b508115614114575090565b90506001600160a01b036141283392612acb565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614109565b805f52600a602052614170600260405f2001612edc565b90805f52600a60205260ff600160405f20015460a01c165f1461419e5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6141bd5750613733906136d1565b61373391506001600160801b036040818351169201511690612aed565b3d15614204573d906141eb82612a9b565b916141f96040519384612a79565b82523d5f602084013e565b606090565b6137339061421681614159565b905f52600a602052600260405f20015460801c90612aed565b906001600160801b03809116911601906001600160801b03821161163257565b5f818152600a60205260409020546142869064ffffffffff60a082901c811660c89290921c811682900381169142821603166146b3565b90805f52600b60205260405f20805415612e5d575f526142db67ffffffffffffffff60205f205460801c1692825f52600a6020526142d66001600160801b03600260405f20015416948592614793565b614806565b9182136142f857506142f46001600160801b03916148e1565b1690565b90505f52600a602052600260405f20015460801c90565b9064ffffffffff421691805f52600a60205260405f20906040519061433382612a5c565b6101206143c660028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612edc565b92019182525f52600b6020526143de60405f20612f0e565b915f9264ffffffffff60406143f283613988565b510151168664ffffffffff5f925b16106144e6578161447764ffffffffff9697988784816001600160801b0361442f6142d69861447c9b9a613995565b5151169a8b9867ffffffffffffffff602061444a868b613995565b510151169782604061445c8784613995565b5101511694806144c9575050511680925b03169203166146b3565b614793565b91821361449d5750906001600160801b0361449781936148e1565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f146144c4575090565b905090565b60409250906144db915f190190613995565b51015116809261446d565b936001600160801b03600191816144fd8886613995565b51511601169401958064ffffffffff8060406145198b87613995565b51015116989298614400565b91909160405161453481612a40565b5f81525f6020820152926001600160801b0382169081156145e55767016345785d8a000081116145ae576145706001600160801b0391836154fe565b166020850191818352111561459a576001600160801b03918261459592511690612aed565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516145f681612a40565b5f81525f602082015290565b9091926001600160a01b036146619481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261465c608483612a79565b614916565b565b614661926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261465c606483612a79565b600160ff1b81148015614786575b61475e575f811215614755576146e5815f035b5f84121561474e57835f039061499b565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161471f575f199118131561471a5790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b839061499b565b6146e5816146d4565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b82146146c1565b806147ad57506147a957670de0b6b3a764000090565b5f90565b90670de0b6b3a764000082146147f857806147d0575050670de0b6b3a764000090565b670de0b6b3a764000081146147f4576147ef906142d661373393614aa1565b614bf8565b5090565b5050670de0b6b3a764000090565b600160ff1b811480156148d4575b6148ac575f8112156148a357614838815f035b5f84121561489c57835f03906154fe565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161486d575f199118131561471a5790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b83906154fe565b61483881614827565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b8214614814565b5f81126148eb5790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b0361493f93169360208151910182865af16149386141da565b90836155ac565b8051908115159182614980575b50506149555750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6149939250602080918301019101612e35565b155f8061494c565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614a665781841015614a2c57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614a73570490565b634e487b7160e01b5f52601260045260245ffd5b8015614a73576ec097ce7bc90715b34b9f10000000000590565b805f811315614bcd57670de0b6b3a76400008112614bad57506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614b9a57506706f05b59d3b20000905b5f8213614b645750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614b8c575b60011d90614b57565b809192019160011d90614b83565b9050670de0b6b3a7640000929150020290565b5f1991508015614a73576ec097ce7bc90715b34b9f100000000005614abe565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614c255768033dd1780914b971141981126137e957614c1c905f03614bf8565b61373390614a87565b680a688906bd8affffff81136154d357670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff00000000000000821661539e575b670de0b6b3a76400009066ff000000000000831661528e575b65ff00000000008316615186575b64ff000000008316615086575b63ff0000008316614f8e575b62ff00008316614e9e575b61ff008316614db6575b60ff8316614cd6575b029060401c60bf031c90565b60808316614da3575b60408316614d90575b60208316614d7d575b60108316614d6a575b60088316614d57575b60048316614d44575b60028316614d31575b6001831615614cca57680100000000000000010260401c614cca565b680100000000000000010260401c614d15565b680100000000000000030260401c614d0c565b680100000000000000060260401c614d03565b6801000000000000000b0260401c614cfa565b680100000000000000160260401c614cf1565b6801000000000000002c0260401c614ce8565b680100000000000000590260401c614cdf565b6180008316614e8b575b6140008316614e78575b6120008316614e65575b6110008316614e52575b6108008316614e3f575b6104008316614e2c575b6102008316614e19575b610100831615614cc157680100000000000000b10260401c614cc1565b680100000000000001630260401c614dfc565b680100000000000002c60260401c614df2565b6801000000000000058c0260401c614de8565b68010000000000000b170260401c614dde565b6801000000000000162e0260401c614dd4565b68010000000000002c5d0260401c614dca565b680100000000000058b90260401c614dc0565b628000008316614f7b575b624000008316614f68575b622000008316614f55575b621000008316614f42575b620800008316614f2f575b620400008316614f1c575b620200008316614f09575b62010000831615614cb7576801000000000000b1720260401c614cb7565b680100000000000162e40260401c614eeb565b6801000000000002c5c80260401c614ee0565b68010000000000058b910260401c614ed5565b680100000000000b17210260401c614eca565b68010000000000162e430260401c614ebf565b680100000000002c5c860260401c614eb4565b6801000000000058b90c0260401c614ea9565b63800000008316615073575b63400000008316615060575b6320000000831661504d575b6310000000831661503a575b63080000008316615027575b63040000008316615014575b63020000008316615001575b6301000000831615614cac5768010000000000b172180260401c614cac565b6801000000000162e4300260401c614fe2565b68010000000002c5c8600260401c614fd6565b680100000000058b90c00260401c614fca565b6801000000000b17217f0260401c614fbe565b680100000000162e42ff0260401c614fb2565b6801000000002c5c85fe0260401c614fa6565b68010000000058b90bfc0260401c614f9a565b6480000000008316615173575b6440000000008316615160575b642000000000831661514d575b641000000000831661513a575b6408000000008316615127575b6404000000008316615114575b6402000000008316615101575b640100000000831615614ca057680100000000b17217f80260401c614ca0565b68010000000162e42ff10260401c6150e1565b680100000002c5c85fe30260401c6150d4565b6801000000058b90bfce0260401c6150c7565b68010000000b17217fbb0260401c6150ba565b6801000000162e42fff00260401c6150ad565b68010000002c5c8601cc0260401c6150a0565b680100000058b90c0b490260401c615093565b65800000000000831661527b575b654000000000008316615268575b652000000000008316615255575b651000000000008316615242575b65080000000000831661522f575b65040000000000831661521c575b650200000000008316615209575b65010000000000831615614c93576801000000b1721835510260401c614c93565b680100000162e430e5a20260401c6151e8565b6801000002c5c863b73f0260401c6151da565b68010000058b90cf1e6e0260401c6151cc565b680100000b1721bcfc9a0260401c6151be565b68010000162e43f4f8310260401c6151b0565b680100002c5c89d5ec6d0260401c6151a2565b6801000058b91b5bc9ae0260401c615194565b6680000000000000831661538b575b66400000000000008316615378575b66200000000000008316615365575b66100000000000008316615352575b6608000000000000831661533f575b6604000000000000831661532c575b66020000000000008316615319575b6601000000000000831615614c855768010000b17255775c040260401c614c85565b6801000162e525ee05470260401c6152f7565b68010002c5cc37da94920260401c6152e8565b680100058ba01fb9f96d0260401c6152d9565b6801000b175effdc76ba0260401c6152ca565b680100162f3904051fa10260401c6152bb565b6801002c605e2e8cec500260401c6152ac565b68010058c86da1c09ea20260401c61529d565b67800000000000000082166154b4575b670de0b6b3a76400009067400000000000000083166154a1575b672000000000000000831661548e575b671000000000000000831661547b575b6708000000000000008316615468575b6704000000000000008316615455575b6702000000000000008316615442575b670100000000000000831661542f575b9050614c6c565b680100b1afa5abcbed610260401c615428565b68010163da9fb33356d80260401c615418565b680102c9a3e778060ee70260401c615408565b6801059b0d31585743ae0260401c6153f8565b68010b5586cf9890f62a0260401c6153e8565b6801172b83c7d517adce0260401c6153d8565b6801306fe0a31b7152df0260401c6153c8565b5077b504f333f9de6484800000000000000000000000000000006153ae565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461559b57670de0b6b3a764000082101561556b577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906155e957508051156155c157805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061562f575b6155fa575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156155f256fea164736f6c634300081a000a"; + hex"60c0604052346103e157615a406060813803918261001c816103e5565b9384928339810103126103e15780516001600160a01b038116908190036103e15760208201516001600160a01b03811692908390036103e1576040015161006360406103e5565b92601a84527f5361626c696572204c6f636b75702044796e616d6963204e4654000000000000602085015261009860406103e5565b600e81526d29a0a116a627a1a5aaa816a22ca760911b602082015230608052845190946001600160401b0382116102e45760015490600182811c921680156103d7575b60208310146102c65781601f849311610369575b50602090601f8311600114610303575f926102f8575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e457600254600181811c911680156102da575b60208210146102c657601f8111610263575b50602094601f8211600114610200579481929394955f926101f5575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755615635908161040b82396080518161393a015260a051818181610bcc0152613a140152f35b015190505f80610169565b601f1982169560025f52805f20915f5b88811061024b57508360019596979810610233575b505050811b0160025561017e565b01515f1960f88460031b161c191690555f8080610225565b91926020600181928685015181550194019201610210565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bc575b601f0160051c01905b8181106102b1575061014d565b5f81556001016102a4565b909150819061029b565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013b565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610105565b60015f9081528281209350601f198516905b8181106103515750908460019594939210610339575b505050811b0160015561011a565b01515f1960f88460031b161c191690555f808061032b565b92936020600181928786015181550195019301610315565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103cd575b90601f859493920160051c01905b8181106103bf57506100ef565b5f81558493506001016103b2565b90915081906103a4565b91607f16916100db565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e45760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146127c957508063027b6744146127a757806306fdde03146126ec578063081812fc146126ce578063095ea7b3146125c95780631400ecec146125185780631c1cdd4c146124b45780631e99d5691461249757806323b872dd14612480578063303acc851461244357806331df3d4814612330578063406887cb146121c157806340e58ee514611ea8578063425d30dd14611e5857806342842e0e14611e2f57806342966c6814611c6b5780634426757014611c455780634857501f14611bd45780634869e12d14611b9a5780634cc55e1114611aa257806354c02292146117f157806357404b12146117635780636352211e146117345780636d0cee751461173457806370a08231146116ca57806375829def1461165c5780637cad6cd11461156b5780637de6b1db146113ec5780638659c27014610fed578063894e9a0d14610cbe5780638f69b99314610c3e5780639067b67714610bef5780639188ec8414610bb557806395d89b4114610aad578063a22cb465146109f9578063a80fc071146109a8578063ad35efd414610949578063b2564569146108f9578063b637b865146108a0578063b88d4fde14610818578063b8a3be66146107e3578063b971302a14610795578063bc2be1be14610746578063c156a11d1461060f578063c87b56dd146104f9578063d4dbd20b146104a8578063d511609f1461045d578063d975dfed14610423578063e985e9c5146103ca578063ea5ead1914610386578063eac8f5b814610335578063f590c176146102d9578063f851a440146102b45763fdd46d601461026e575f80fd5b346102b05760603660031901126102b0576102876128f6565b6044356001600160801b03811681036102b0576102ae916102a6613930565b6004356133e3565b005b5f80fd5b346102b0575f3660031901126102b05760206001600160a01b035f5416604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346102b05760403660031901126102b05760206004356103b96103a76128f6565b916103b1816141f9565b928391613085565b6001600160801b0360405191168152f35b346102b05760403660031901126102b0576103e36128e0565b6001600160a01b036103f36128f6565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b96020916141f9565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a6020526020600260405f20015460801c604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346102b05760203660031901126102b057600435610516816136b2565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa8015610604575f90610587575b610583906040519182916020835260208301906128bb565b0390f35b503d805f833e6105978183612a79565b8101906020818303126102b05780519067ffffffffffffffff82116102b057019080601f830112156102b0578151916105cf83612a9b565b916105dd6040519384612a79565b838352602084830101116102b057610583926105ff916020808501910161289a565b61056b565b6040513d5f823e3d90fd5b346102b05760403660031901126102b05760043561062b6128f6565b610633613930565b815f52600a60205260ff600160405f20015460a81c161561073357815f5260036020526001600160a01b0360405f2054169081330361071357610675836141f9565b6001600160801b0381169182610703575b6001600160a01b038116156106f0576106a7856001600160a01b03926137f6565b1692836106c15784637e27328960e01b5f5260045260245ffd5b80859185036106d557602084604051908152f35b8492506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b61070e828587613085565b610686565b82632082501160e01b5f526004526001600160a01b03331660245260445ffd5b5063699d2de960e01b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b0360405f205416604051908152f35b346102b05760203660031901126102b0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346102b05760803660031901126102b0576108316128e0565b6108396128f6565b6064359167ffffffffffffffff83116102b057366023840112156102b05782600401359161086683612a9b565b926108746040519485612a79565b80845236602482870101116102b0576020815f9260246102ae9801838801378501015260443591612f95565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600b6020526105836108e560405f20612f0e565b60405191829160208352602083019061298b565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c16156103235761098190613762565b6040516005821015610994576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346102b05760403660031901126102b057610a126128e0565b602435908115158092036102b0576001600160a01b0316908115610a8157335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0575f3660031901126102b0576040515f6002548060011c90600181168015610bab575b602083108114610b9757828552908115610b735750600114610b15575b61058383610b0181850382612a79565b6040519182916020835260208301906128bb565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210610b5957509091508101602001610b01610af1565b919260018160209254838588010152019101909291610b41565b60ff191660208086019190915291151560051b84019091019150610b019050610af1565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ad4565b346102b0575f3660031901126102b05760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610c7690613762565b6005811015806109945760028214908115610cb2575b8115610ca0575b6020826040519015158152f35b90506109945760046020911482610c93565b5050600381145f610c8c565b346102b05760203660031901126102b057600435604051610180810181811067ffffffffffffffff821117610fd957606091610160916040525f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152610d39612ebe565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260405f20604051610d7481612a5c565b8154906001600160a01b0382168152602081019264ffffffffff8360a01c1684526040820164ffffffffff8460c81c168152606083019160ff8560f01c1615158352608084019460f81c1515855260018101549160a08501946001600160a01b038416865260c0810160ff8560a01c1615158152610e13600260e084019560ff8860a81c161515875260ff61010086019860b01c161515885201612edc565b61012083019081526002610e268c613762565b610e2f816129fd565b14610fd1575b5196516001600160a01b0316925164ffffffffff1695511515905115159351151594511515958a5f52600360205260405f20546001600160a01b03169a5f52600b60205260405f2092516001600160a01b0316995164ffffffffff1698511515926040519a610ea66101808d612a79565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610efa90612f0e565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e082016105839161298b565b5f8752610e35565b634e487b7160e01b5f52604160045260245ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761101e90369060040161295a565b90611027613930565b5f915b80831061103357005b61103e838284612e4d565b3592611048613930565b835f52600a60205260ff600160405f20015460a81c16156113d857835f52600a60205260ff600160405f20015460a01c165f1461109257836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c6113c6576110c7815f52600a6020526001600160a01b0360405f205416331490565b156113b0576110d5816136d3565b90805f52600a6020526110ed600260405f2001612edc565b916001600160801b038351166001600160801b038216101561139c57815f52600a60205260ff60405f205460f01c161561138857806001600160801b03602081611141948188511603169501511690612aed565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611363575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061125c6001600160a01b03600160405f2001541694611234888588614653565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a160ff6112a6866001600160a01b03165f52600960205260405f2090565b54166112bc575b5050505050600101919061102a565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060457630d4af11f60e31b916001600160e01b0319915f91611335575b50160361131957808080806112ad565b636ade251160e01b5f526001600160a01b03602491166004525ffd5b611356915060203d811161135c575b61134e8183612a79565b810190613692565b87611309565b503d611344565b825f52600a602052600160405f2001600160a01b60ff60a01b1982541617905561118b565b50635dd950cb60e11b5f526024906004525ffd5b506308aca53f60e21b5f526024906004525ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f526024906004525ffd5b346102b05760203660031901126102b057600435611408613930565b805f52600a60205260ff600160405f20015460a81c16156103235761142c81613762565b611435816129fd565b6004810361145057506315efa0f360e11b5f5260045260245ffd5b611459816129fd565b60038103611474575063d0a172b360e01b5f5260045260245ffd5b600290611480816129fd565b14611559576114a3815f52600a6020526001600160a01b0360405f205416331490565b1561153a57805f52600a60205260ff60405f205460f01c1615611528576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b632082501160e01b5f526004526001600160a01b03331660245260445ffd5b6308aca53f60e21b5f5260045260245ffd5b346102b05760203660031901126102b0576004356001600160a01b0381168091036102b0576001600160a01b035f5416338103611646575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116325760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b0576116756128e0565b5f546001600160a01b03811633810361164657506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346102b05760203660031901126102b0576001600160a01b036116eb6128e0565b168015611708575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346102b05760203660031901126102b05760206117526004356136b2565b6001600160a01b0360405191168152f35b346102b05760203660031901126102b05760043561177f612ea6565b50805f52600a60205260ff600160405f20015460a81c1615610323575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166117c983612a40565b825260208201526117ef8251809264ffffffffff60208092828151168552015116910152565bf35b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b0578036036101206003198201126102b05761182c613930565b60c482013590602219018112156102b057810160048101359067ffffffffffffffff82116102b05760240160608202360381136102b05761186e913691612d69565b9081519161187b83612d51565b926118896040519485612a79565b808452601f1961189882612d51565b015f5b818110611a8b57505064ffffffffff4216916001600160801b036118be8261398a565b51511667ffffffffffffffff60206118d58461398a565b5101511664ffffffffff8060406118eb8661398a565b51015116860116906040519261190084612a24565b8352602083015260408201526119158661398a565b5261191f8561398a565b5060015b8281106119f75750505061193982600401612e85565b9261194660248401612e85565b9261195360448201612e71565b916064820135936001600160a01b0385168095036102b0576020966119ef966119af966001600160801b036119e4976001600160a01b0361199660848a01612e99565b94816119a460a48c01612e99565b976040519d8e612a07565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612e06565b6101008201526139ab565b604051908152f35b806001600160801b03611a0c60019385613997565b51511667ffffffffffffffff6020611a248487613997565b5101511664ffffffffff806040611a3e5f1987018d613997565b51015116816040611a4f878a613997565b5101511601169060405192611a6384612a24565b835260208301526040820152611a798289613997565b52611a848188613997565b5001611923565b602090611a96612ebe565b8282890101520161189b565b346102b05760403660031901126102b05760043567ffffffffffffffff81116102b057611ad390369060040161295a565b9060243567ffffffffffffffff81116102b057611af490369060040161295a565b9091611afe613930565b818403611b6a575f5b848110611b1057005b80611b64611b216001938886612e4d565b35611b2d838987612e4d565b355f5260036020526001600160a01b0360405f205416611b56611b5185898b612e4d565b612e71565b91611b5f613930565b6133e3565b01611b07565b50827fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b9602091614149565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f611c0d82613762565b600581101561099457600203611c2b575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16611c1e565b346102b0575f3660031901126102b05760206001600160a01b0360085416604051908152f35b346102b05760203660031901126102b057600435611c87613930565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c1615611e0457611cc6816140d7565b156113b057805f5260036020526001600160a01b0360405f205416151580611dfd575b80611de0575b611dce577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115611d97575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611d8557005b637e27328960e01b5f5260045260245ffd5b611db6835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055611d3d565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615611cef565b505f611ce9565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0576102ae611e4036612920565b9060405192611e50602085612a79565b5f8452612f95565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346102b05760203660031901126102b057600435611ec4613930565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c165f14611f0d576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c6113c657611f3f815f52600a6020526001600160a01b0360405f205416331490565b1561153a57611f4d816136d3565b90805f52600a602052611f65600260405f2001612edc565b916001600160801b038351166001600160801b03821610156121ae57815f52600a60205260ff60405f205460f01c161561219b57806001600160801b03602081611fb9948188511603169501511690612aed565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612176575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506120ac6001600160a01b03600160405f2001541694611234888588614653565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f2054166120ef57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060457630d4af11f60e31b916001600160e01b0319915f91612157575b50160361214557005b636ade251160e01b5f5260045260245ffd5b612170915060203d60201161135c5761134e8183612a79565b8461213c565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612003565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b346102b05760203660031901126102b0576121da6128e0565b6001600160a01b035f54169033820361231957806001600160a01b03913b156122ed57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa908115610604575f916122be575b501561229357805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6122e0915060203d6020116122e6575b6122d88183612a79565b810190612e35565b82612248565b503d6122ce565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761014060031982360301126102b05761236a613930565b6040519061237782612a07565b6123838160040161290c565b82526123916024820161290c565b60208301526123a260448201612ab7565b604083015260648101356001600160a01b03811681036102b05760608301526123cd608482016129f0565b60808301526123de60a482016129f0565b60a08301526123ef60c48201612d3f565b60c083015260e481013567ffffffffffffffff81116102b057810191366023840112156102b0576119e46119ef926124336020953690602460048201359101612d69565b60e0840152610104369101612e06565b346102b05760203660031901126102b0576001600160a01b036124646128e0565b165f526009602052602060ff60405f2054166040519015158152f35b346102b0576102ae61249136612920565b91612b0d565b346102b0575f3660031901126102b0576020600754604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576124ec90613762565b600581101561099457806020911590811561250d575b506040519015158152f35b600191501482612502565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576020905f90805f52600a835260ff60405f205460f01c16806125ad575b61257b575b506001600160801b0360405191168152f35b6125a79150805f52600a83526125a16001600160801b03600260405f20015416916136d3565b90612aed565b82612569565b50805f52600a835260ff600160405f20015460a01c1615612564565b346102b05760403660031901126102b0576125e26128e0565b6024356125ee816136b2565b331515806126bb575b80612688575b61265c5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156125fd565b50336001600160a01b03821614156125f7565b346102b05760203660031901126102b0576020611752600435612acb565b346102b0575f3660031901126102b0576040515f6001548060011c9060018116801561279d575b602083108114610b9757828552908115610b73575060011461273f5761058383610b0181850382612a79565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061278357509091508101602001610b01610af1565b91926001816020925483858801015201910190929161276b565b91607f1691612713565b346102b0575f3660031901126102b057602060405167016345785d8a00008152f35b346102b05760203660031901126102b057600435906001600160e01b031982168092036102b057817f490649060000000000000000000000000000000000000000000000000000000060209314908115612825575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115612870575b811561285f575b508361281e565b6301ffc9a760e01b91501483612858565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612851565b5f5b8381106128ab5750505f910152565b818101518382015260200161289c565b906020916128d48151809281855285808601910161289a565b601f01601f1916010190565b600435906001600160a01b03821682036102b057565b602435906001600160a01b03821682036102b057565b35906001600160a01b03821682036102b057565b60609060031901126102b0576004356001600160a01b03811681036102b057906024356001600160a01b03811681036102b0579060443590565b9181601f840112156102b05782359167ffffffffffffffff83116102b0576020808501948460051b0101116102b057565b90602080835192838152019201905f5b8181106129a85750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff8682015116868501520151166040820152019401910191909161299b565b359081151582036102b057565b6005111561099457565b610120810190811067ffffffffffffffff821117610fd957604052565b6060810190811067ffffffffffffffff821117610fd957604052565b6040810190811067ffffffffffffffff821117610fd957604052565b610140810190811067ffffffffffffffff821117610fd957604052565b90601f8019910116810190811067ffffffffffffffff821117610fd957604052565b67ffffffffffffffff8111610fd957601f01601f191660200190565b35906001600160801b03821682036102b057565b612ad4816136b2565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161163257565b91906001600160a01b031680156106f057815f5260036020526001600160a01b0360405f205416151580612d37575b80612d1a575b612d07577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612c52575b6001600160a01b03935085612c1b575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303612c0357505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b612c3a825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612ba2565b9192905080612cb0575b15612c6957828291612b92565b8284612c8157637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612cde575b80612c5c5750825f526005602052336001600160a01b0360405f20541614612c5c565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612cbb565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615612b42565b506001612b3c565b359064ffffffffff821682036102b057565b67ffffffffffffffff8111610fd95760051b60200190565b929192612d7582612d51565b93612d836040519586612a79565b60606020868581520193028201918183116102b057925b828410612da75750505050565b6060848303126102b05760405190612dbe82612a24565b612dc785612ab7565b825260208501359067ffffffffffffffff821682036102b05782602092836060950152612df660408801612d3f565b6040820152815201930192612d9a565b91908260409103126102b057604051612e1e81612a40565b6020808294612e2c8161290c565b84520135910152565b908160209103126102b0575180151581036102b05790565b9190811015612e5d5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036102b05790565b356001600160a01b03811681036102b05790565b3580151581036102b05790565b60405190612eb382612a40565b5f6020838281520152565b60405190612ecb82612a24565b5f6040838281528260208201520152565b90604051612ee981612a24565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612f1a81612d51565b92612f286040519485612a79565b81845260208401905f5260205f205f915b838310612f465750505050565b600160208192604051612f5881612a24565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612f39565b90612fa1838284612b0d565b803b612fae575b50505050565b602091612ff46001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906128bb565b03815f865af15f9181613064575b5061303057506130106141ca565b8051908161302b5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361305257505f808080612fa8565b633250574960e11b5f5260045260245ffd5b61307e91925060203d60201161135c5761134e8183612a79565b905f613002565b909161308f613930565b815f52600a60205260ff600160405f20015460a81c161561073357815f52600a60205260ff600160405f20015460a01c166133d0576001600160a01b03831680156133a457825f5260036020526001600160a01b0360405f205416938482141580613394575b613360576001600160801b038316928315613334576001600160801b0361311b866141f9565b16808511613301575061314090855f52600a602052600260405f20015460801c61421f565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff191691909117815561318390612edc565b6001600160801b036131a78160208401511692826040818351169201511690612aed565b1611156132cf575b835f52600a6020526131d3836001600160a01b03600160405f200154169283614653565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806132b9575b61323d5750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610604576392b9102b60e01b916001600160e01b0319915f9161329a575b50160361214557808080612fa8565b6132b3915060203d60201161135c5761134e8183612a79565b5f61328b565b50835f52600960205260ff60405f205416613233565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556131af565b84867f066920d7000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b847fb2ae7633000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50827f6a166406000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b5061339e846140d7565b156130f5565b827f2da33e5b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b506315efa0f360e11b5f5260045260245ffd5b9091815f52600a60205260ff600160405f20015460a81c161561073357815f52600a60205260ff600160405f20015460a01c166133d0576001600160a01b03831680156133a457825f5260036020526001600160a01b0360405f205416938482141580613682575b613360576001600160801b038316928315613334576001600160801b03613471866141f9565b16808511613301575061349690855f52600a602052600260405f20015460801c61421f565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff19169190911781556134d990612edc565b6001600160801b036134fd8160208401511692826040818351169201511690612aed565b161115613650575b835f52600a602052613529836001600160a01b03600160405f200154169283614653565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a1833314158061362b575b6135935750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610604576392b9102b60e01b916001600160e01b0319915f9161360c575b5016036135f057808080612fa8565b6001600160a01b0390636ade251160e01b5f521660045260245ffd5b613625915060203d60201161135c5761134e8183612a79565b5f6135e1565b5060ff613649856001600160a01b03165f52600960205260405f2090565b5416613589565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055613505565b5061368c846140d7565b1561344b565b908160209103126102b057516001600160e01b0319811681036102b05790565b805f5260036020526001600160a01b0360405f205416908115611d85575090565b64ffffffffff4216815f52600a6020528064ffffffffff60405f205460a01c16101561375c57815f52600a60205264ffffffffff60405f205460c81c16111561374157805f52600b602052600160405f2054115f1461373857613735906142ff565b90565b6137359061423f565b5f52600a6020526001600160801b03600260405f2001541690565b50505f90565b805f52600a60205260ff600160405f20015460a01c165f146137845750600490565b805f52600a60205260405f205460f81c6137f057805f52600a60205264ffffffffff60405f205460a01c1642106137eb576137be816136d3565b905f52600a6020526001600160801b0380600260405f200154169116105f146137e657600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f20541615158061391e575b80613901575b611dce577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836138ca575b16806138b2575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f206001815401905561386e565b6138e9835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613867565b50805f52600a60205260ff600160405f20015460b01c161561381b565b506001600160a01b0382161515613815565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361396257565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612e5d5760200190565b8051821015612e5d5760209160051b010190565b906139cd6001600160801b036040840151166020610100850151015190614515565b916001600160a01b03815116906001600160801b0384511660e082015160c083019364ffffffffff85511690156140af57821561408757801561405f5781518015614037577f0000000000000000000000000000000000000000000000000000000000000000811161400c575064ffffffffff6040613a4b8461398a565b51015116811015613fc857505f809180515f915b818310613f45575050506001600160801b0391501690818103613f1757505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c1f8751975f19890190613997565b51015160c81b169360a01b169116171785555f5b818110613e09575050600187016007556001600160a01b0360208301511680156106f057613c69886001600160a01b03926137f6565b16613ddd578682613cb76001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b0385511690309033906145f2565b6001600160801b0360208401511680613dad575b506001600160a01b0381511694613da2613d846001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613d298b612a40565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c087015261014086019061298b565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613dd7906001600160a01b036060840151166001600160a01b0361010085015151169033906145f2565b5f613ccb565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f2090613e248160e0870151613997565b51825468010000000000000000811015610fd95760018101808555811015612e5d576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613c33565b7f0fa99c11000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b909192613f67906001600160801b03613f5e8685613997565b5151169061421f565b9364ffffffffff806040613f7b8786613997565b51015116911680821115613f96575093926001019190613a5f565b847f4b90504d000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff6040613fd98461398a565b51015116907f93c315e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f099c714b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f5fbab612000000000000000000000000000000000000000000000000000000005f5260045ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6d004a9e000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561411d575b508115614104575090565b90506001600160a01b036141183392612acb565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f6140f9565b805f52600a602052614160600260405f2001612edc565b90805f52600a60205260ff600160405f20015460a01c165f1461418e5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6141ad5750613735906136d3565b61373591506001600160801b036040818351169201511690612aed565b3d156141f4573d906141db82612a9b565b916141e96040519384612a79565b82523d5f602084013e565b606090565b6137359061420681614149565b905f52600a602052600260405f20015460801c90612aed565b906001600160801b03809116911601906001600160801b03821161163257565b5f818152600a60205260409020546142769064ffffffffff60a082901c811660c89290921c811682900381169142821603166146a3565b90805f52600b60205260405f20805415612e5d575f526142cb67ffffffffffffffff60205f205460801c1692825f52600a6020526142c66001600160801b03600260405f20015416948592614783565b6147f6565b9182136142e857506142e46001600160801b03916148d1565b1690565b90505f52600a602052600260405f20015460801c90565b9064ffffffffff421691805f52600a60205260405f20906040519061432382612a5c565b6101206143b660028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612edc565b92019182525f52600b6020526143ce60405f20612f0e565b915f9264ffffffffff60406143e28361398a565b510151168664ffffffffff5f925b16106144d6578161446764ffffffffff9697988784816001600160801b0361441f6142c69861446c9b9a613997565b5151169a8b9867ffffffffffffffff602061443a868b613997565b510151169782604061444c8784613997565b5101511694806144b9575050511680925b03169203166146a3565b614783565b91821361448d5750906001600160801b0361448781936148d1565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f146144b4575090565b905090565b60409250906144cb915f190190613997565b51015116809261445d565b936001600160801b03600191816144ed8886613997565b51511601169401958064ffffffffff8060406145098b87613997565b510151169892986143f0565b91909160405161452481612a40565b5f81525f6020820152926001600160801b0382169081156145d55767016345785d8a0000811161459e576145606001600160801b0391836154ee565b166020850191818352111561458a576001600160801b03918261458592511690612aed565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516145e681612a40565b5f81525f602082015290565b9091926001600160a01b036146519481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261464c608483612a79565b614906565b565b614651926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261464c606483612a79565b600160ff1b81148015614776575b61474e575f811215614745576146d5815f035b5f84121561473e57835f039061498b565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161470f575f199118131561470a5790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b839061498b565b6146d5816146c4565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b82146146b1565b8061479d575061479957670de0b6b3a764000090565b5f90565b90670de0b6b3a764000082146147e857806147c0575050670de0b6b3a764000090565b670de0b6b3a764000081146147e4576147df906142c661373593614a91565b614be8565b5090565b5050670de0b6b3a764000090565b600160ff1b811480156148c4575b61489c575f81121561489357614828815f035b5f84121561488c57835f03906154ee565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161485d575f199118131561470a5790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b83906154ee565b61482881614817565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b8214614804565b5f81126148db5790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b0361492f93169360208151910182865af16149286141ca565b908361559c565b8051908115159182614970575b50506149455750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6149839250602080918301019101612e35565b155f8061493c565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614a565781841015614a1c57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614a63570490565b634e487b7160e01b5f52601260045260245ffd5b8015614a63576ec097ce7bc90715b34b9f10000000000590565b805f811315614bbd57670de0b6b3a76400008112614b9d57506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614b8a57506706f05b59d3b20000905b5f8213614b545750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614b7c575b60011d90614b47565b809192019160011d90614b73565b9050670de0b6b3a7640000929150020290565b5f1991508015614a63576ec097ce7bc90715b34b9f100000000005614aae565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614c155768033dd1780914b971141981126137eb57614c0c905f03614be8565b61373590614a77565b680a688906bd8affffff81136154c357670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff00000000000000821661538e575b670de0b6b3a76400009066ff000000000000831661527e575b65ff00000000008316615176575b64ff000000008316615076575b63ff0000008316614f7e575b62ff00008316614e8e575b61ff008316614da6575b60ff8316614cc6575b029060401c60bf031c90565b60808316614d93575b60408316614d80575b60208316614d6d575b60108316614d5a575b60088316614d47575b60048316614d34575b60028316614d21575b6001831615614cba57680100000000000000010260401c614cba565b680100000000000000010260401c614d05565b680100000000000000030260401c614cfc565b680100000000000000060260401c614cf3565b6801000000000000000b0260401c614cea565b680100000000000000160260401c614ce1565b6801000000000000002c0260401c614cd8565b680100000000000000590260401c614ccf565b6180008316614e7b575b6140008316614e68575b6120008316614e55575b6110008316614e42575b6108008316614e2f575b6104008316614e1c575b6102008316614e09575b610100831615614cb157680100000000000000b10260401c614cb1565b680100000000000001630260401c614dec565b680100000000000002c60260401c614de2565b6801000000000000058c0260401c614dd8565b68010000000000000b170260401c614dce565b6801000000000000162e0260401c614dc4565b68010000000000002c5d0260401c614dba565b680100000000000058b90260401c614db0565b628000008316614f6b575b624000008316614f58575b622000008316614f45575b621000008316614f32575b620800008316614f1f575b620400008316614f0c575b620200008316614ef9575b62010000831615614ca7576801000000000000b1720260401c614ca7565b680100000000000162e40260401c614edb565b6801000000000002c5c80260401c614ed0565b68010000000000058b910260401c614ec5565b680100000000000b17210260401c614eba565b68010000000000162e430260401c614eaf565b680100000000002c5c860260401c614ea4565b6801000000000058b90c0260401c614e99565b63800000008316615063575b63400000008316615050575b6320000000831661503d575b6310000000831661502a575b63080000008316615017575b63040000008316615004575b63020000008316614ff1575b6301000000831615614c9c5768010000000000b172180260401c614c9c565b6801000000000162e4300260401c614fd2565b68010000000002c5c8600260401c614fc6565b680100000000058b90c00260401c614fba565b6801000000000b17217f0260401c614fae565b680100000000162e42ff0260401c614fa2565b6801000000002c5c85fe0260401c614f96565b68010000000058b90bfc0260401c614f8a565b6480000000008316615163575b6440000000008316615150575b642000000000831661513d575b641000000000831661512a575b6408000000008316615117575b6404000000008316615104575b64020000000083166150f1575b640100000000831615614c9057680100000000b17217f80260401c614c90565b68010000000162e42ff10260401c6150d1565b680100000002c5c85fe30260401c6150c4565b6801000000058b90bfce0260401c6150b7565b68010000000b17217fbb0260401c6150aa565b6801000000162e42fff00260401c61509d565b68010000002c5c8601cc0260401c615090565b680100000058b90c0b490260401c615083565b65800000000000831661526b575b654000000000008316615258575b652000000000008316615245575b651000000000008316615232575b65080000000000831661521f575b65040000000000831661520c575b6502000000000083166151f9575b65010000000000831615614c83576801000000b1721835510260401c614c83565b680100000162e430e5a20260401c6151d8565b6801000002c5c863b73f0260401c6151ca565b68010000058b90cf1e6e0260401c6151bc565b680100000b1721bcfc9a0260401c6151ae565b68010000162e43f4f8310260401c6151a0565b680100002c5c89d5ec6d0260401c615192565b6801000058b91b5bc9ae0260401c615184565b6680000000000000831661537b575b66400000000000008316615368575b66200000000000008316615355575b66100000000000008316615342575b6608000000000000831661532f575b6604000000000000831661531c575b66020000000000008316615309575b6601000000000000831615614c755768010000b17255775c040260401c614c75565b6801000162e525ee05470260401c6152e7565b68010002c5cc37da94920260401c6152d8565b680100058ba01fb9f96d0260401c6152c9565b6801000b175effdc76ba0260401c6152ba565b680100162f3904051fa10260401c6152ab565b6801002c605e2e8cec500260401c61529c565b68010058c86da1c09ea20260401c61528d565b67800000000000000082166154a4575b670de0b6b3a7640000906740000000000000008316615491575b672000000000000000831661547e575b671000000000000000831661546b575b6708000000000000008316615458575b6704000000000000008316615445575b6702000000000000008316615432575b670100000000000000831661541f575b9050614c5c565b680100b1afa5abcbed610260401c615418565b68010163da9fb33356d80260401c615408565b680102c9a3e778060ee70260401c6153f8565b6801059b0d31585743ae0260401c6153e8565b68010b5586cf9890f62a0260401c6153d8565b6801172b83c7d517adce0260401c6153c8565b6801306fe0a31b7152df0260401c6153b8565b5077b504f333f9de64848000000000000000000000000000000061539e565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461558b57670de0b6b3a764000082101561555b577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906155d957508051156155b157805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061561f575b6155ea575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156155e256fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a0604052346103bc57614b716040813803918261001c816103c0565b9384928339810103126103bc5780516001600160a01b03811691908290036103bc57602001516001600160a01b038116908190036103bc5761005e60406103c0565b91601983527f5361626c696572204c6f636b7570204c696e656172204e465400000000000000602084015261009360406103c0565b600e81526d29a0a116a627a1a5aaa816a624a760911b60208201523060805283519092906001600160401b0381116102cd57600154600181811c911680156103b2575b60208210146102af57601f811161034f575b50602094601f82116001146102ec579481929394955f926102e1575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102cd57600254600181811c911680156102c3575b60208210146102af57601f811161024c575b506020601f82116001146101e957819293945f926101de575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3600160075561478b90816103e6823960805181613adf0152f35b015190505f80610165565b601f1982169060025f52805f20915f5b8181106102345750958360019596971061021c575b505050811b0160025561017a565b01515f1960f88460031b161c191690555f808061020e565b9192602060018192868b0151815501940192016101f9565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a5575b601f0160051c01905b81811061029a575061014c565b5f815560010161028d565b9091508190610284565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013a565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610104565b601f1982169560015f52805f20915f5b8881106103375750836001959697981061031f575b505050811b01600155610119565b01515f1960f88460031b161c191690555f8080610311565b919260206001819286850151815501940192016102fc565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103a8575b601f0160051c01905b81811061039d57506100e8565b5f8155600101610390565b9091508190610387565b90607f16906100d6565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102cd5760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461313b57508063027b67441461311957806306fdde031461305e578063081812fc14613040578063095ea7b314612f3b5780631400ecec14612e8a5780631c1cdd4c14612e265780631e99d56914612e0957806323b872dd14612df2578063303acc8514612db5578063406887cb14612c4657806340e58ee51461296f578063425d30dd1461291f57806342842e0e146128f657806342966c6814612732578063442675701461270c5780634857501f1461269b5780634869e12d146126615780634cc55e11146122ba57806353b157271461218f57806357404b12146120c95780636352211e1461209a5780636d0cee751461209a57806370a082311461203057806375829def14611fc2578063780a82c814611f765780637cad6cd114611e995780637de6b1db14611d4c5780638659c27014611994578063894e9a0d146116ac5780638f69b9931461162c5780639067b677146115dd57806395d89b41146114d5578063a22cb46514611421578063a80fc071146113d0578063ab167ccc1461125f578063ad35efd414611200578063b2564569146111b0578063b88d4fde14611126578063b8a3be66146110f1578063b971302a146110a3578063bc2be1be14611054578063c156a11d14610c3e578063c87b56dd14610b33578063d4dbd20b14610ae2578063d511609f14610a97578063d975dfed14610a4c578063e985e9c5146109f3578063ea5ead19146106ae578063eac8f5b81461065d578063f590c17614610601578063f851a440146105dc5763fdd46d6014610263575f80fd5b346105d85760603660031901126105d85760043561027f613268565b906102886133ca565b610290613ad5565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b2576001600160a01b03831690811561059f576001600160801b031690811561058c57825f5260036020526001600160a01b0360405f20541693848214158061057c575b610561576001600160801b0361031c8561431f565b168084116105475750835f52600a60205282600260405f20015460801c016001600160801b0381116105335761037b90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610392600260405f20016136ae565b6001600160801b036103b68160208401511692826040818351169201511690613402565b161115610501575b835f52600a6020526103e2836001600160a01b03600160405f200154169283614345565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104eb575b61044857005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f916104b1575b50160361049f57005b636ade251160e01b5f5260045260245ffd5b6104d3915060203d6020116104d9575b6104cb818361338c565b8101906137e4565b5f610496565b503d6104c1565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f205416610442565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103be565b634e487b7160e01b5f52601160045260245ffd5b838563066920d760e01b5f5260045260245260445260645ffd5b508263350b320360e11b5f526004523360245260445260645ffd5b5061058684613b2f565b15610307565b8263b2ae763360e01b5f5260045260245ffd5b82632da33e5b60e01b5f5260045260245ffd5b506315efa0f360e11b5f5260045260245ffd5b5063699d2de960e01b5f5260045260245ffd5b5f80fd5b346105d8575f3660031901126105d85760206001600160a01b035f5416604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105d85760403660031901126105d8576004356106ca613268565b906106d48161431f565b906106dd613ad5565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c166109e1576001600160a01b0383169182156109ce576001600160801b03169182156109bb57815f5260036020526001600160a01b0360405f2054169384821415806109ab575b610990576001600160801b036107698461431f565b168085116109765750825f52600a60205283600260405f20015460801c016001600160801b038111610533576107c890845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526107df600260405f20016136ae565b6001600160801b036108038160208401511692826040818351169201511690613402565b161115610944575b825f52600a60205261082f846001600160a01b03600160405f200154169283614345565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1833314158061092e575b61089f575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104e0576392b9102b60e01b916001600160e01b0319915f9161090f575b5016036108fc578180610894565b50636ade251160e01b5f5260045260245ffd5b610928915060203d6020116104d9576104cb818361338c565b856108ee565b50835f52600960205260ff60405f20541661088f565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b1916905561080b565b848463066920d760e01b5f5260045260245260445260645ffd5b509063350b320360e11b5f526004523360245260445260645ffd5b506109b583613b2f565b15610754565b5063b2ae763360e01b5f5260045260245ffd5b50632da33e5b60e01b5f5260045260245ffd5b6315efa0f360e11b5f5260045260245ffd5b346105d85760403660031901126105d857610a0c613252565b6001600160a01b03610a1c613268565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57610a8660209161431f565b6001600160801b0360405191168152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a6020526020600260405f20015460801c604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105d85760203660031901126105d857600435610b5081613804565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104e0575f90610bc1575b610bbd9060405191829160208352602083019061322d565b0390f35b503d805f833e610bd1818361338c565b8101906020818303126105d85780519067ffffffffffffffff82116105d857019080601f830112156105d857815191610c09836133ae565b91610c17604051938461338c565b838352602084830101116105d857610bbd92610c39916020808501910161320c565b610ba5565b346105d85760403660031901126105d857600435610c5a613268565b610c62613ad5565b815f52600a60205260ff600160405f20015460a81c16156105c557815f5260036020526001600160a01b0360405f2054169081330361103d576001600160801b03610cac8461431f565b169081158015610d35575b506001600160a01b03811615610d2257610cd9846001600160a01b039261399b565b169182610cf35783637e27328960e01b5f5260045260245ffd5b8084918403610d0757602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d3d613ad5565b845f52600a60205260ff600160405f20015460a81c161561102a57845f52600a60205260ff600160405f20015460a01c1661101757831561100457610ff157835f5260036020526001600160a01b0360405f2054168084141580610fe1575b610fc6576001600160801b03610db18661431f565b16808411610fac5750845f52600a60205282600260405f20015460801c016001600160801b03811161053357610e1090865f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b845f52600a602052610e27600260405f20016136ae565b6001600160801b03610e4b8160208401511692826040818351169201511690613402565b161115610f7a575b845f52600a6020526001600160a01b03600160405f20015416610e77848683614345565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f64575b15610cb7576040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91610f45575b501614610cb757636ade251160e01b5f5260045260245ffd5b610f5e915060203d6020116104d9576104cb818361338c565b88610f2c565b50805f52600960205260ff60405f205416610ed7565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e53565b838663066920d760e01b5f5260045260245260445260645ffd5b838563350b320360e11b5f526004523360245260445260645ffd5b50610feb85613b2f565b15610d9c565b8363b2ae763360e01b5f5260045260245ffd5b84632da33e5b60e01b5f5260045260245ffd5b846315efa0f360e11b5f5260045260245ffd5b8463699d2de960e01b5f5260045260245ffd5b82632082501160e01b5f526004523360245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105d85760203660031901126105d8576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105d85760803660031901126105d85761113f613252565b611147613268565b6064359167ffffffffffffffff83116105d857366023840112156105d857826004013591611174836133ae565b92611182604051948561338c565b80845236602482870101116105d8576020815f9260246111ae98018388013785010152604435916136f4565b005b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b5761123890613907565b604051600582101561124b576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105d8576101403660031901126105d857611279613ad5565b611281613690565b64ffffffffff421680825264ffffffffff61129a6136e0565b166113b5575b60e43564ffffffffff811681036105d85764ffffffffff9101166040820152600435906001600160a01b038216918281036105d857506024356001600160a01b038116908181036105d857506044356001600160801b038116908181036105d857506064356001600160a01b0381168091036105d85760843591821515928381036105d8575060a43593841515948581036105d8575060405196611343886132e9565b8752602087015260408601526060850152608084015260a083015260c08201526040610103193601126105d8576040519061137d82613370565b61010435906001600160a01b03821682036105d857826113ad9260209452610124358482015260e0820152613c25565b604051908152f35b64ffffffffff6113c36136e0565b82011660208301526112a0565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105d85760403660031901126105d85761143a613252565b602435908115158092036105d8576001600160a01b03169081156114a957335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d8575f3660031901126105d8576040515f6002548060011c906001811680156115d3575b6020831081146115bf5782855290811561159b575060011461153d575b610bbd836115298185038261338c565b60405191829160208352602083019061322d565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b80821061158157509091508101602001611529611519565b919260018160209254838588010152019101909291611569565b60ff191660208086019190915291151560051b840190910191506115299050611519565b634e487b7160e01b5f52602260045260245ffd5b91607f16916114fc565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b5761166490613907565b60058110158061124b57600282149081156116a0575b811561168e575b6020826040519015158152f35b905061124b5760046020911482611681565b5050600381145f61167a565b346105d85760203660031901126105d8576004355f6101606040516116d081613336565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152611713613690565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260405f2060405161174e81613353565b81546001600160a01b0381168252602082019364ffffffffff8260a01c168552604083019364ffffffffff8360c81c1685526060840160ff8460f01c1615158152608085019360f81c1515845260018201549360a08601956001600160a01b038616875260c081019560ff8160a01c16151587526117ed600260e084019660ff8460a81c161515885260ff61010086019460b01c1615158452016136ae565b61012083019081526117fe87613907565b600581101561124b5760021461198c575b5197516001600160a01b031692865f52600b60205260405f205464ffffffffff16995164ffffffffff1694511515915115159751151595511515965f52600360205260405f20546001600160a01b031692516001600160a01b03169a5164ffffffffff16905115159260405161188481613336565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b5f855261180f565b346105d85760203660031901126105d85760043567ffffffffffffffff81116105d8576119c59036906004016132b8565b906119ce613ad5565b5f915b8083106119da57005b6119e583828461366c565b35926119ef613ad5565b835f52600a60205260ff600160405f20015460a81c1615611d3957835f52600a60205260ff600160405f20015460a01c165f14611a3957836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611d2757611a6e815f52600a6020526001600160a01b0360405f205416331490565b15611d1157611a7c81613825565b90805f52600a602052611a94600260405f20016136ae565b916001600160801b038351166001600160801b0382161015611cfe57815f52600a60205260ff60405f205460f01c1615611ceb57806001600160801b03602081611ae8948188511603169501511690613402565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611cc6575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611bfa6001600160a01b03600160405f2001541694611bd2888588614345565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611c4b575b505050505060010191906119d1565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91611ca8575b50160361049f5780808080611c3c565b611cc0915060203d81116104d9576104cb818361338c565b87611c98565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611b32565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f5260045260245ffd5b346105d85760203660031901126105d857600435611d68613ad5565b805f52600a60205260ff600160405f20015460a81c161561064b57611d8c81613907565b600581101561124b5760048103611db057506315efa0f360e11b5f5260045260245ffd5b60038103611dcb575063d0a172b360e01b5f5260045260245ffd5b600214611e8757611df0815f52600a6020526001600160a01b0360405f205416331490565b15611d1157805f52600a60205260ff60405f205460f01c1615611e75576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b6308aca53f60e21b5f5260045260245ffd5b346105d85760203660031901126105d8576004356001600160a01b0381168091036105d8576001600160a01b035f5416338103611f60575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116105335760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600b602052602064ffffffffff60405f205416604051908152f35b346105d85760203660031901126105d857611fdb613252565b5f546001600160a01b038116338103611f6057506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105d85760203660031901126105d8576001600160a01b03612051613252565b16801561206e575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105d85760203660031901126105d85760206120b8600435613804565b6001600160a01b0360405191168152f35b346105d85760203660031901126105d8576004356120e5613690565b50805f52600a60205260ff600160405f20015460a81c161561064b57806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c1690604051926121558461331a565b83526020830152604082015261218d604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b346105d8576101603660031901126105d8576121a9613ad5565b6040516121b5816132e9565b6121bd613252565b81526121c7613268565b60208201526121d46133ca565b60408201526064356001600160a01b03811681036105d857606082015260843580151581036105d857608082015260a43580151581036105d85760a082015260603660c31901126105d85760405161222b8161331a565b60c43564ffffffffff811681036105d857815260e43564ffffffffff811681036105d85760208201526101043564ffffffffff811681036105d857604082015260c08201526040610123193601126105d8576040519061228a82613370565b61012435906001600160a01b03821682036105d857826113ad9260209452610144358482015260e0820152613c25565b346105d85760403660031901126105d85760043567ffffffffffffffff81116105d8576122eb9036906004016132b8565b60243567ffffffffffffffff81116105d85761230b9036906004016132b8565b612316939193613ad5565b808303612632575f5b83811061232857005b61233381858561366c565b3561233f82868661366c565b355f5260036020526001600160a01b0360405f2054169061236183858961366c565b356001600160801b038116908181036105d8575061237d613ad5565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b25782156109ce5780156109bb57815f5260036020526001600160a01b0360405f205416928381141580612622575b612608576001600160801b036123f48461431f565b168083116125ee5750825f52600a60205281600260405f20015460801c016001600160801b0381116105335761245390845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a60205261246a600260405f20016136ae565b6001600160801b0361248e8160208401511692826040818351169201511690613402565b1611156125bc575b825f52600a6020526001600160a01b03600160405f200154166124ba838383614345565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125a6575b61252b575b5050505060010161231f565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91612588575b50160361049f5780808061251f565b6125a0915060203d81116104d9576104cb818361338c565b89612579565b50835f52600960205260ff60405f20541661251a565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612496565b828463066920d760e01b5f5260045260245260445260645ffd5b8263350b320360e11b5f526004523360245260445260645ffd5b5061262c83613b2f565b156123df565b827fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57610a86602091613ba1565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f6126d482613907565b600581101561124b576002036126f2575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c166126e5565b346105d8575f3660031901126105d85760206001600160a01b0360085416604051908152f35b346105d85760203660031901126105d85760043561274e613ad5565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c16156128cb5761278d81613b2f565b15611d1157805f5260036020526001600160a01b0360405f2054161515806128c4575b806128a7575b612895577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f205416801590811561285e575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061284c57005b637e27328960e01b5f5260045260245ffd5b61287d835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612804565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127b6565b505f6127b0565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d8576111ae6129073661327e565b906040519261291760208561338c565b5f84526136f4565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105d85760203660031901126105d85760043561298b613ad5565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c165f146129d4576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c611d2757612a06815f52600a6020526001600160a01b0360405f205416331490565b15611d1157612a1481613825565b90805f52600a602052612a2c600260405f20016136ae565b916001600160801b038351166001600160801b0382161015611cfe57815f52600a60205260ff60405f205460f01c1615611ceb57806001600160801b03602081612a80948188511603169501511690613402565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c21575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612b6a6001600160a01b03600160405f2001541694611bd2888588614345565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612bad57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91612c025750160361049f57005b612c1b915060203d6020116104d9576104cb818361338c565b84610496565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612aca565b346105d85760203660031901126105d857612c5f613252565b6001600160a01b035f541690338203612d9e57806001600160a01b03913b15612d7257166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104e0575f91612d43575b5015612d1857805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612d65915060203d602011612d6b575b612d5d818361338c565b810190613654565b82612ccd565b503d612d53565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105d85760203660031901126105d8576001600160a01b03612dd6613252565b165f526009602052602060ff60405f2054166040519015158152f35b346105d8576111ae612e033661327e565b91613422565b346105d8575f3660031901126105d8576020600754604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57612e5e90613907565b600581101561124b578060209115908115612e7f575b506040519015158152f35b600191501482612e74565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b576020905f90805f52600a835260ff60405f205460f01c1680612f1f575b612eed575b506001600160801b0360405191168152f35b612f199150805f52600a8352612f136001600160801b03600260405f2001541691613825565b90613402565b82612edb565b50805f52600a835260ff600160405f20015460a01c1615612ed6565b346105d85760403660031901126105d857612f54613252565b602435612f6081613804565b3315158061302d575b80612ffa575b612fce5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612f6f565b50336001600160a01b0382161415612f69565b346105d85760203660031901126105d85760206120b86004356133e0565b346105d8575f3660031901126105d8576040515f6001548060011c9060018116801561310f575b6020831081146115bf5782855290811561159b57506001146130b157610bbd836115298185038261338c565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106130f557509091508101602001611529611519565b9192600181602092548385880101520191019092916130dd565b91607f1691613085565b346105d8575f3660031901126105d857602060405167016345785d8a00008152f35b346105d85760203660031901126105d857600435906001600160e01b031982168092036105d857817f490649060000000000000000000000000000000000000000000000000000000060209314908115613197575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156131e2575b81156131d1575b5083613190565b6301ffc9a760e01b915014836131ca565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506131c3565b5f5b83811061321d5750505f910152565b818101518382015260200161320e565b906020916132468151809281855285808601910161320c565b601f01601f1916010190565b600435906001600160a01b03821682036105d857565b602435906001600160a01b03821682036105d857565b60609060031901126105d8576004356001600160a01b03811681036105d857906024356001600160a01b03811681036105d8579060443590565b9181601f840112156105d85782359167ffffffffffffffff83116105d8576020808501948460051b0101116105d857565b610100810190811067ffffffffffffffff82111761330657604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761330657604052565b610180810190811067ffffffffffffffff82111761330657604052565b610140810190811067ffffffffffffffff82111761330657604052565b6040810190811067ffffffffffffffff82111761330657604052565b90601f8019910116810190811067ffffffffffffffff82111761330657604052565b67ffffffffffffffff811161330657601f01601f191660200190565b604435906001600160801b03821682036105d857565b6133e981613804565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161053357565b91906001600160a01b03168015610d2257815f5260036020526001600160a01b0360405f20541615158061364c575b8061362f575b61361c577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613567575b6001600160a01b03935085613530575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361351857505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b61354f825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556134b7565b91929050806135c5575b1561357e578282916134a7565b828461359657637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b5033841480156135f3575b806135715750825f526005602052336001600160a01b0360405f20541614613571565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166135d0565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615613457565b506001613451565b908160209103126105d8575180151581036105d85790565b919081101561367c5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b6040519061369d8261331a565b5f6040838281528260208201520152565b906040516136bb8161331a565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff811681036105d85790565b90613700838284613422565b803b61370d575b50505050565b6020916137536001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061322d565b03815f865af15f91816137c3575b5061378f575061376f6142f0565b8051908161378a5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b9116036137b157505f808080613707565b633250574960e11b5f5260045260245ffd5b6137dd91925060203d6020116104d9576104cb818361338c565b905f613761565b908160209103126105d857516001600160e01b0319811681036105d85790565b805f5260036020526001600160a01b0360405f20541690811561284c575090565b805f52600b60205264ffffffffff60405f205416815f52600a60205264ffffffffff60405f205460a01c1690421080156138fd575b6138f757815f52600a60205264ffffffffff60405f205460c81c1690814210156138da578061388c92039042036144d3565b815f52600a6020526138af6001600160801b03600260405f2001541680926145bf565b9081116138c4576001600160801b0391501690565b505f52600a602052600260405f20015460801c90565b50505f52600a6020526001600160801b03600260405f2001541690565b50505f90565b504281101561385a565b805f52600a60205260ff600160405f20015460a01c165f146139295750600490565b805f52600a60205260405f205460f81c61399557805f52600a60205264ffffffffff60405f205460a01c1642106139905761396381613825565b905f52600a6020526001600160801b0380600260405f200154169116105f1461398b57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613ac3575b80613aa6575b612895577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613a6f575b1680613a57575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613a13565b613a8e835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613a0c565b50805f52600a60205260ff600160405f20015460b01c16156139c0565b506001600160a01b03821615156139ba565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613b0757565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613b75575b508115613b5c575090565b90506001600160a01b03613b7033926133e0565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613b51565b805f52600a602052613bb8600260405f20016136ae565b90805f52600a60205260ff600160405f20015460a01c165f14613be65750602001516001600160801b031690565b90815f52600a60205260405f205460f81c613c085750613c0590613825565b90565b613c0591506001600160801b036040818351169201511690613402565b90613c466001600160801b03604084015116602060e085015101519061439c565b916001600160801b0383511660c082015190156142c85764ffffffffff815116156142a0576020810164ffffffffff81511680614214575b5050604064ffffffffff82511691019064ffffffffff82511690818110156141e657505064ffffffffff80421691511690818110156141b85750506007549280516001600160801b03169160405192613cd68461331a565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613d3c89613353565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600a60205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613fbc91906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff1680614198575b50600185016007556001600160a01b036020820151168015610d225761402a866001600160a01b039261399b565b1661416c576140556001600160a01b036060830151166001600160801b038451169030903390614479565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b038651168061413d575b506141346001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b614166906001600160a01b036060880151166001600160a01b0360e08901515116903390614479565b5f614090565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600b60205260405f209064ffffffffff198254161790555f613ffc565b7f879842de000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f9e7fd91f000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff8351168181101561427257505064ffffffffff90511664ffffffffff60408301511690818110613c7e577f87d966a0000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f84fe0623000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d1561431a573d90614301826133ae565b9161430f604051938461338c565b82523d5f602084013e565b606090565b613c059061432c81613ba1565b905f52600a602052600260405f20015460801c90613402565b61439a926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261439560648361338c565b61466d565b565b9190916040516143ab81613370565b5f81525f6020820152926001600160801b03821690811561445c5767016345785d8a00008111614425576143e76001600160801b0391836145bf565b1660208501918183521115614411576001600160801b03918261440c92511690613402565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161446d81613370565b5f81525f602082015290565b9091926001600160a01b0361439a9481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261439560848361338c565b5f19670de0b6b3a7640000820991670de0b6b3a764000082029182808510940393808503941461459e578184101561456457670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156145ab570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f198382098382029182808310920391808303921461465c57670de0b6b3a764000082101561462c577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b0361469693169360208151910182865af161468f6142f0565b90836146f2565b80519081151591826146d7575b50506146ac5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6146ea9250602080918301019101613654565b155f806146a3565b9061472f575080511561470757805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614775575b614740575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561473856fea164736f6c634300081a000a"; + hex"60a0604052346103bc57614b5c6040813803918261001c816103c0565b9384928339810103126103bc5780516001600160a01b03811691908290036103bc57602001516001600160a01b038116908190036103bc5761005e60406103c0565b91601983527f5361626c696572204c6f636b7570204c696e656172204e465400000000000000602084015261009360406103c0565b600e81526d29a0a116a627a1a5aaa816a624a760911b60208201523060805283519092906001600160401b0381116102cd57600154600181811c911680156103b2575b60208210146102af57601f811161034f575b50602094601f82116001146102ec579481929394955f926102e1575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102cd57600254600181811c911680156102c3575b60208210146102af57601f811161024c575b506020601f82116001146101e957819293945f926101de575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3600160075561477690816103e6823960805181613ade0152f35b015190505f80610165565b601f1982169060025f52805f20915f5b8181106102345750958360019596971061021c575b505050811b0160025561017a565b01515f1960f88460031b161c191690555f808061020e565b9192602060018192868b0151815501940192016101f9565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a5575b601f0160051c01905b81811061029a575061014c565b5f815560010161028d565b9091508190610284565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013a565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610104565b601f1982169560015f52805f20915f5b8881106103375750836001959697981061031f575b505050811b01600155610119565b01515f1960f88460031b161c191690555f8080610311565b919260206001819286850151815501940192016102fc565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103a8575b601f0160051c01905b81811061039d57506100e8565b5f8155600101610390565b9091508190610387565b90607f16906100d6565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102cd5760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461313a57508063027b67441461311857806306fdde031461305d578063081812fc1461303f578063095ea7b314612f3a5780631400ecec14612e895780631c1cdd4c14612e255780631e99d56914612e0857806323b872dd14612df1578063303acc8514612db4578063406887cb14612c4557806340e58ee51461296e578063425d30dd1461291e57806342842e0e146128f557806342966c6814612731578063442675701461270b5780634857501f1461269a5780634869e12d146126605780634cc55e11146122b957806353b157271461218e57806357404b12146120c85780636352211e146120995780636d0cee751461209957806370a082311461202f57806375829def14611fc1578063780a82c814611f755780637cad6cd114611e985780637de6b1db14611d4b5780638659c27014611993578063894e9a0d146116ab5780638f69b9931461162b5780639067b677146115dc57806395d89b41146114d4578063a22cb46514611420578063a80fc071146113cf578063ab167ccc1461125e578063ad35efd4146111ff578063b2564569146111af578063b88d4fde14611125578063b8a3be66146110f0578063b971302a146110a2578063bc2be1be14611053578063c156a11d14610c3c578063c87b56dd14610b31578063d4dbd20b14610ae0578063d511609f14610a95578063d975dfed14610a4a578063e985e9c5146109f1578063ea5ead19146106ae578063eac8f5b81461065d578063f590c17614610601578063f851a440146105dc5763fdd46d6014610263575f80fd5b346105d85760603660031901126105d85760043561027f613267565b906102886133c9565b91610291613ad4565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b2576001600160a01b038116801561059f57825f5260036020526001600160a01b0360405f20541693848214158061058f575b610574576001600160801b0316918215610561576001600160801b0361031c8561430a565b168084116105475750835f52600a60205282600260405f20015460801c016001600160801b0381116105335761037b90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610392600260405f20016136ad565b6001600160801b036103b68160208401511692826040818351169201511690613401565b161115610501575b835f52600a6020526103e2836001600160a01b03600160405f200154169283614330565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104eb575b61044857005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f916104b1575b50160361049f57005b636ade251160e01b5f5260045260245ffd5b6104d3915060203d6020116104d9575b6104cb818361338b565b8101906137e3565b5f610496565b503d6104c1565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f205416610442565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103be565b634e487b7160e01b5f52601160045260245ffd5b838563066920d760e01b5f5260045260245260445260645ffd5b8363b2ae763360e01b5f5260045260245ffd5b508263350b320360e11b5f526004523360245260445260645ffd5b5061059984613b2e565b156102f7565b82632da33e5b60e01b5f5260045260245ffd5b506315efa0f360e11b5f5260045260245ffd5b5063699d2de960e01b5f5260045260245ffd5b5f80fd5b346105d8575f3660031901126105d85760206001600160a01b035f5416604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105d85760403660031901126105d8576004356106ca613267565b6106d38261430a565b916106dc613ad4565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c166109df576001600160a01b03821680156109cc57815f5260036020526001600160a01b0360405f2054169384821415806109bc575b6109a1576001600160801b031692831561098e576001600160801b036107678461430a565b168085116109745750825f52600a60205283600260405f20015460801c016001600160801b038111610533576107c690845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526107dd600260405f20016136ad565b6001600160801b036108018160208401511692826040818351169201511690613401565b161115610942575b825f52600a60205261082d846001600160a01b03600160405f200154169283614330565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1833314158061092c575b61089d575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104e0576392b9102b60e01b916001600160e01b0319915f9161090d575b5016036108fa578180610892565b50636ade251160e01b5f5260045260245ffd5b610926915060203d6020116104d9576104cb818361338b565b856108ec565b50835f52600960205260ff60405f20541661088d565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610809565b848463066920d760e01b5f5260045260245260445260645ffd5b8263b2ae763360e01b5f5260045260245ffd5b509063350b320360e11b5f526004523360245260445260645ffd5b506109c683613b2e565b15610742565b50632da33e5b60e01b5f5260045260245ffd5b6315efa0f360e11b5f5260045260245ffd5b346105d85760403660031901126105d857610a0a613251565b6001600160a01b03610a1a613267565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57610a8460209161430a565b6001600160801b0360405191168152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a6020526020600260405f20015460801c604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105d85760203660031901126105d857600435610b4e81613803565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104e0575f90610bbf575b610bbb9060405191829160208352602083019061322c565b0390f35b503d805f833e610bcf818361338b565b8101906020818303126105d85780519067ffffffffffffffff82116105d857019080601f830112156105d857815191610c07836133ad565b91610c15604051938461338b565b838352602084830101116105d857610bbb92610c37916020808501910161320b565b610ba3565b346105d85760403660031901126105d857600435610c58613267565b610c60613ad4565b815f52600a60205260ff600160405f20015460a81c16156105c557815f5260036020526001600160a01b0360405f2054169081330361103c576001600160801b03610caa8461430a565b169081158015610d33575b506001600160a01b03811615610d2057610cd7846001600160a01b039261399a565b169182610cf15783637e27328960e01b5f5260045260245ffd5b8084918403610d0557602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d3b613ad4565b845f52600a60205260ff600160405f20015460a81c161561102957845f52600a60205260ff600160405f20015460a01c1661101657831561100357845f5260036020526001600160a01b0360405f205416908185141580610ff3575b610fd857610fc5576001600160801b03610db08661430a565b16808411610fab5750845f52600a60205282600260405f20015460801c016001600160801b03811161053357610e0f90865f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b845f52600a602052610e26600260405f20016136ad565b6001600160801b03610e4a8160208401511692826040818351169201511690613401565b161115610f79575b845f52600a6020526001600160a01b03600160405f20015416610e76848683614330565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f63575b15610cb5576040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91610f44575b501614610cb557636ade251160e01b5f5260045260245ffd5b610f5d915060203d6020116104d9576104cb818361338b565b88610f2b565b50805f52600960205260ff60405f205416610ed6565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e52565b838663066920d760e01b5f5260045260245260445260645ffd5b8463b2ae763360e01b5f5260045260245ffd5b848663350b320360e11b5f526004523360245260445260645ffd5b50610ffd86613b2e565b15610d97565b84632da33e5b60e01b5f5260045260245ffd5b846315efa0f360e11b5f5260045260245ffd5b8463699d2de960e01b5f5260045260245ffd5b82632082501160e01b5f526004523360245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105d85760203660031901126105d8576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105d85760803660031901126105d85761113e613251565b611146613267565b6064359167ffffffffffffffff83116105d857366023840112156105d857826004013591611173836133ad565b92611181604051948561338b565b80845236602482870101116105d8576020815f9260246111ad98018388013785010152604435916136f3565b005b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b5761123790613906565b604051600582101561124a576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105d8576101403660031901126105d857611278613ad4565b61128061368f565b64ffffffffff421680825264ffffffffff6112996136df565b166113b4575b60e43564ffffffffff811681036105d85764ffffffffff9101166040820152600435906001600160a01b038216918281036105d857506024356001600160a01b038116908181036105d857506044356001600160801b038116908181036105d857506064356001600160a01b0381168091036105d85760843591821515928381036105d8575060a43593841515948581036105d8575060405196611342886132e8565b8752602087015260408601526060850152608084015260a083015260c08201526040610103193601126105d8576040519061137c8261336f565b61010435906001600160a01b03821682036105d857826113ac9260209452610124358482015260e0820152613c24565b604051908152f35b64ffffffffff6113c26136df565b820116602083015261129f565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105d85760403660031901126105d857611439613251565b602435908115158092036105d8576001600160a01b03169081156114a857335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d8575f3660031901126105d8576040515f6002548060011c906001811680156115d2575b6020831081146115be5782855290811561159a575060011461153c575b610bbb836115288185038261338b565b60405191829160208352602083019061322c565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b80821061158057509091508101602001611528611518565b919260018160209254838588010152019101909291611568565b60ff191660208086019190915291151560051b840190910191506115289050611518565b634e487b7160e01b5f52602260045260245ffd5b91607f16916114fb565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b5761166390613906565b60058110158061124a576002821490811561169f575b811561168d575b6020826040519015158152f35b905061124a5760046020911482611680565b5050600381145f611679565b346105d85760203660031901126105d8576004355f6101606040516116cf81613335565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201528261012082015261171261368f565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260405f2060405161174d81613352565b81546001600160a01b0381168252602082019364ffffffffff8260a01c168552604083019364ffffffffff8360c81c1685526060840160ff8460f01c1615158152608085019360f81c1515845260018201549360a08601956001600160a01b038616875260c081019560ff8160a01c16151587526117ec600260e084019660ff8460a81c161515885260ff61010086019460b01c1615158452016136ad565b61012083019081526117fd87613906565b600581101561124a5760021461198b575b5197516001600160a01b031692865f52600b60205260405f205464ffffffffff16995164ffffffffff1694511515915115159751151595511515965f52600360205260405f20546001600160a01b031692516001600160a01b03169a5164ffffffffff16905115159260405161188381613335565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b5f855261180e565b346105d85760203660031901126105d85760043567ffffffffffffffff81116105d8576119c49036906004016132b7565b906119cd613ad4565b5f915b8083106119d957005b6119e483828461366b565b35926119ee613ad4565b835f52600a60205260ff600160405f20015460a81c1615611d3857835f52600a60205260ff600160405f20015460a01c165f14611a3857836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611d2657611a6d815f52600a6020526001600160a01b0360405f205416331490565b15611d1057611a7b81613824565b90805f52600a602052611a93600260405f20016136ad565b916001600160801b038351166001600160801b0382161015611cfd57815f52600a60205260ff60405f205460f01c1615611cea57806001600160801b03602081611ae7948188511603169501511690613401565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611cc5575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611bf96001600160a01b03600160405f2001541694611bd1888588614330565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611c4a575b505050505060010191906119d0565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91611ca7575b50160361049f5780808080611c3b565b611cbf915060203d81116104d9576104cb818361338b565b87611c97565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611b31565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f5260045260245ffd5b346105d85760203660031901126105d857600435611d67613ad4565b805f52600a60205260ff600160405f20015460a81c161561064b57611d8b81613906565b600581101561124a5760048103611daf57506315efa0f360e11b5f5260045260245ffd5b60038103611dca575063d0a172b360e01b5f5260045260245ffd5b600214611e8657611def815f52600a6020526001600160a01b0360405f205416331490565b15611d1057805f52600a60205260ff60405f205460f01c1615611e74576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b6308aca53f60e21b5f5260045260245ffd5b346105d85760203660031901126105d8576004356001600160a01b0381168091036105d8576001600160a01b035f5416338103611f5f575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116105335760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600b602052602064ffffffffff60405f205416604051908152f35b346105d85760203660031901126105d857611fda613251565b5f546001600160a01b038116338103611f5f57506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105d85760203660031901126105d8576001600160a01b03612050613251565b16801561206d575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105d85760203660031901126105d85760206120b7600435613803565b6001600160a01b0360405191168152f35b346105d85760203660031901126105d8576004356120e461368f565b50805f52600a60205260ff600160405f20015460a81c161561064b57806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c16906040519261215484613319565b83526020830152604082015261218c604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b346105d8576101603660031901126105d8576121a8613ad4565b6040516121b4816132e8565b6121bc613251565b81526121c6613267565b60208201526121d36133c9565b60408201526064356001600160a01b03811681036105d857606082015260843580151581036105d857608082015260a43580151581036105d85760a082015260603660c31901126105d85760405161222a81613319565b60c43564ffffffffff811681036105d857815260e43564ffffffffff811681036105d85760208201526101043564ffffffffff811681036105d857604082015260c08201526040610123193601126105d857604051906122898261336f565b61012435906001600160a01b03821682036105d857826113ac9260209452610144358482015260e0820152613c24565b346105d85760403660031901126105d85760043567ffffffffffffffff81116105d8576122ea9036906004016132b7565b60243567ffffffffffffffff81116105d85761230a9036906004016132b7565b612315939193613ad4565b808303612631575f5b83811061232757005b61233281858561366b565b3561233e82868661366b565b355f5260036020526001600160a01b0360405f2054169061236083858961366b565b356001600160801b038116908181036105d8575061237c613ad4565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b25782156109cc57815f5260036020526001600160a01b0360405f205416928381141580612621575b61260757811561098e576001600160801b036123f38461430a565b168083116125ed5750825f52600a60205281600260405f20015460801c016001600160801b0381116105335761245290845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a602052612469600260405f20016136ad565b6001600160801b0361248d8160208401511692826040818351169201511690613401565b1611156125bb575b825f52600a6020526001600160a01b03600160405f200154166124b9838383614330565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125a5575b61252a575b5050505060010161231e565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91612587575b50160361049f5780808061251e565b61259f915060203d81116104d9576104cb818361338b565b89612578565b50835f52600960205260ff60405f205416612519565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612495565b828463066920d760e01b5f5260045260245260445260645ffd5b8263350b320360e11b5f526004523360245260445260645ffd5b5061262b83613b2e565b156123d8565b827fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57610a84602091613ba0565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f6126d382613906565b600581101561124a576002036126f1575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c166126e4565b346105d8575f3660031901126105d85760206001600160a01b0360085416604051908152f35b346105d85760203660031901126105d85760043561274d613ad4565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c16156128ca5761278c81613b2e565b15611d1057805f5260036020526001600160a01b0360405f2054161515806128c3575b806128a6575b612894577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f205416801590811561285d575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061284b57005b637e27328960e01b5f5260045260245ffd5b61287c835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612803565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127b5565b505f6127af565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d8576111ad6129063661327d565b906040519261291660208561338b565b5f84526136f3565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105d85760203660031901126105d85760043561298a613ad4565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c165f146129d3576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c611d2657612a05815f52600a6020526001600160a01b0360405f205416331490565b15611d1057612a1381613824565b90805f52600a602052612a2b600260405f20016136ad565b916001600160801b038351166001600160801b0382161015611cfd57815f52600a60205260ff60405f205460f01c1615611cea57806001600160801b03602081612a7f948188511603169501511690613401565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c20575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612b696001600160a01b03600160405f2001541694611bd1888588614330565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612bac57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91612c015750160361049f57005b612c1a915060203d6020116104d9576104cb818361338b565b84610496565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612ac9565b346105d85760203660031901126105d857612c5e613251565b6001600160a01b035f541690338203612d9d57806001600160a01b03913b15612d7157166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104e0575f91612d42575b5015612d1757805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612d64915060203d602011612d6a575b612d5c818361338b565b810190613653565b82612ccc565b503d612d52565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105d85760203660031901126105d8576001600160a01b03612dd5613251565b165f526009602052602060ff60405f2054166040519015158152f35b346105d8576111ad612e023661327d565b91613421565b346105d8575f3660031901126105d8576020600754604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57612e5d90613906565b600581101561124a578060209115908115612e7e575b506040519015158152f35b600191501482612e73565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b576020905f90805f52600a835260ff60405f205460f01c1680612f1e575b612eec575b506001600160801b0360405191168152f35b612f189150805f52600a8352612f126001600160801b03600260405f2001541691613824565b90613401565b82612eda565b50805f52600a835260ff600160405f20015460a01c1615612ed5565b346105d85760403660031901126105d857612f53613251565b602435612f5f81613803565b3315158061302c575b80612ff9575b612fcd5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612f6e565b50336001600160a01b0382161415612f68565b346105d85760203660031901126105d85760206120b76004356133df565b346105d8575f3660031901126105d8576040515f6001548060011c9060018116801561310e575b6020831081146115be5782855290811561159a57506001146130b057610bbb836115288185038261338b565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106130f457509091508101602001611528611518565b9192600181602092548385880101520191019092916130dc565b91607f1691613084565b346105d8575f3660031901126105d857602060405167016345785d8a00008152f35b346105d85760203660031901126105d857600435906001600160e01b031982168092036105d857817f490649060000000000000000000000000000000000000000000000000000000060209314908115613196575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156131e1575b81156131d0575b508361318f565b6301ffc9a760e01b915014836131c9565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506131c2565b5f5b83811061321c5750505f910152565b818101518382015260200161320d565b906020916132458151809281855285808601910161320b565b601f01601f1916010190565b600435906001600160a01b03821682036105d857565b602435906001600160a01b03821682036105d857565b60609060031901126105d8576004356001600160a01b03811681036105d857906024356001600160a01b03811681036105d8579060443590565b9181601f840112156105d85782359167ffffffffffffffff83116105d8576020808501948460051b0101116105d857565b610100810190811067ffffffffffffffff82111761330557604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761330557604052565b610180810190811067ffffffffffffffff82111761330557604052565b610140810190811067ffffffffffffffff82111761330557604052565b6040810190811067ffffffffffffffff82111761330557604052565b90601f8019910116810190811067ffffffffffffffff82111761330557604052565b67ffffffffffffffff811161330557601f01601f191660200190565b604435906001600160801b03821682036105d857565b6133e881613803565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161053357565b91906001600160a01b03168015610d2057815f5260036020526001600160a01b0360405f20541615158061364b575b8061362e575b61361b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613566575b6001600160a01b0393508561352f575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361351757505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b61354e825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556134b6565b91929050806135c4575b1561357d578282916134a6565b828461359557637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b5033841480156135f2575b806135705750825f526005602052336001600160a01b0360405f20541614613570565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166135cf565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615613456565b506001613450565b908160209103126105d8575180151581036105d85790565b919081101561367b5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b6040519061369c82613319565b5f6040838281528260208201520152565b906040516136ba81613319565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff811681036105d85790565b906136ff838284613421565b803b61370c575b50505050565b6020916137526001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061322c565b03815f865af15f91816137c2575b5061378e575061376e6142db565b805190816137895782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b9116036137b057505f808080613706565b633250574960e11b5f5260045260245ffd5b6137dc91925060203d6020116104d9576104cb818361338b565b905f613760565b908160209103126105d857516001600160e01b0319811681036105d85790565b805f5260036020526001600160a01b0360405f20541690811561284b575090565b805f52600b60205264ffffffffff60405f205416815f52600a60205264ffffffffff60405f205460a01c1690421080156138fc575b6138f657815f52600a60205264ffffffffff60405f205460c81c1690814210156138d9578061388b92039042036144be565b815f52600a6020526138ae6001600160801b03600260405f2001541680926145aa565b9081116138c3576001600160801b0391501690565b505f52600a602052600260405f20015460801c90565b50505f52600a6020526001600160801b03600260405f2001541690565b50505f90565b5042811015613859565b805f52600a60205260ff600160405f20015460a01c165f146139285750600490565b805f52600a60205260405f205460f81c61399457805f52600a60205264ffffffffff60405f205460a01c16421061398f5761396281613824565b905f52600a6020526001600160801b0380600260405f200154169116105f1461398a57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613ac2575b80613aa5575b612894577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613a6e575b1680613a56575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613a12565b613a8d835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613a0b565b50805f52600a60205260ff600160405f20015460b01c16156139bf565b506001600160a01b03821615156139b9565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613b0657565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613b74575b508115613b5b575090565b90506001600160a01b03613b6f33926133df565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613b50565b805f52600a602052613bb7600260405f20016136ad565b90805f52600a60205260ff600160405f20015460a01c165f14613be55750602001516001600160801b031690565b90815f52600a60205260405f205460f81c613c075750613c0490613824565b90565b613c0491506001600160801b036040818351169201511690613401565b90613c456001600160801b03604084015116602060e0850151015190614387565b916001600160a01b038151166001600160801b0384511660c083015191156142b3571561428b5764ffffffffff81511615614263576020810164ffffffffff815116806141d7575b505064ffffffffff6040818351169201511690818110156141a95750506007549280516001600160801b03169160405192613cc784613319565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613d2d89613352565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600a60205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613fad91906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff1680614189575b50600185016007556001600160a01b036020820151168015610d205761401b866001600160a01b039261399a565b1661415d576140466001600160a01b036060830151166001600160801b038451169030903390614464565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b038651168061412e575b506141256001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b614157906001600160a01b036060880151166001600160a01b0360e08901515116903390614464565b5f614081565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600b60205260405f209064ffffffffff198254161790555f613fed565b7f9e7fd91f000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff8351168181101561423557505064ffffffffff90511664ffffffffff60408301511690818110613c8d577f87d966a0000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f84fe0623000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6d004a9e000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d15614305573d906142ec826133ad565b916142fa604051938461338b565b82523d5f602084013e565b606090565b613c049061431781613ba0565b905f52600a602052600260405f20015460801c90613401565b614385926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261438060648361338b565b614658565b565b9190916040516143968161336f565b5f81525f6020820152926001600160801b0382169081156144475767016345785d8a00008111614410576143d26001600160801b0391836145aa565b16602085019181835211156143fc576001600160801b0391826143f792511690613401565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516144588161336f565b5f81525f602082015290565b9091926001600160a01b036143859481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261438060848361338b565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614589578184101561454f57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614596570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f198382098382029182808310920391808303921461464757670de0b6b3a7640000821015614617577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b0361468193169360208151910182865af161467a6142db565b90836146dd565b80519081151591826146c2575b50506146975750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6146d59250602080918301019101613653565b155f8061468e565b9061471a57508051156146f257805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614760575b61472b575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561472356fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = - hex"60c0604052346103e157614e306060813803918261001c816103e5565b9384928339810103126103e15780516001600160a01b038116908190036103e15760208201516001600160a01b03811692908390036103e1576040015161006360406103e5565b92601b84527f5361626c696572204c6f636b7570205472616e63686564204e46540000000000602085015261009860406103e5565b600e81526d5341422d4c4f434b55502d54524160901b602082015230608052845190946001600160401b0382116102e45760015490600182811c921680156103d7575b60208310146102c65781601f849311610369575b50602090601f8311600114610303575f926102f8575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e457600254600181811c911680156102da575b60208210146102c657601f8111610263575b50602094601f8211600114610200579481929394955f926101f5575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614a25908161040b823960805181613e37015260a051818181612fa60152613ee00152f35b015190505f80610169565b601f1982169560025f52805f20915f5b88811061024b57508360019596979810610233575b505050811b0160025561017e565b01515f1960f88460031b161c191690555f8080610225565b91926020600181928685015181550194019201610210565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bc575b601f0160051c01905b8181106102b1575061014d565b5f81556001016102a4565b909150819061029b565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013b565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610105565b60015f9081528281209350601f198516905b8181106103515750908460019594939210610339575b505050811b0160015561011a565b01515f1960f88460031b161c191690555f808061032b565b92936020600181928786015181550195019301610315565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103cd575b90601f859493920160051c01905b8181106103bf57506100ef565b5f81558493506001016103b2565b90915081906103a4565b91607f16916100db565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e45760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461331257508063027b6744146132f057806306fdde0314613235578063081812fc14613217578063095ea7b3146131125780631400ecec146130615780631c1cdd4c14612ffd5780631e99d56914612fe057806323b872dd14612fc95780632fe4304114612f8f578063303acc8514612f5257806332fbe22b14612df5578063406887cb14612c8657806340e58ee5146129af578063425d30dd1461295f57806342842e0e1461293657806342966c6814612772578063442675701461274c5780634857501f146126db5780634869e12d146126a15780634cc55e11146122fb57806357404b121461226d5780636352211e1461223e5780636d0cee751461223e57806370a08231146121d457806375829def146121665780637cad6cd1146120755780637de6b1db14611f285780637f5799f914611ecf5780638659c27014611b17578063894e9a0d146117d8578063897f362b1461150d5780638f69b9931461148d5780639067b6771461143e57806395d89b4114611336578063a22cb46514611282578063a80fc07114611231578063ad35efd4146111d2578063b256456914611182578063b88d4fde146110f8578063b8a3be66146110c3578063b971302a14611075578063bc2be1be14611026578063c156a11d14610c0a578063c87b56dd14610aff578063d4dbd20b14610aae578063d511609f14610a63578063d975dfed14610a18578063e985e9c5146109bf578063ea5ead1914610692578063eac8f5b814610641578063f590c176146105e5578063f851a440146105c05763fdd46d601461026e575f80fd5b346105bc5760603660031901126105bc5760043561028a61343f565b90604435916001600160801b038316908184036105bc576102a9613e2d565b825f52600a60205260ff600160405f20015460a81c16156105a957825f52600a60205260ff600160405f20015460a01c16610596576001600160a01b03811690811561058357821561057057835f5260036020526001600160a01b0360405f205416948583141580610560575b610545576001600160801b0361032b86614685565b1680851161052b575061035090855f52600a602052600260405f20015460801c6146ab565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561038a906139d3565b6001600160801b036103ae8160208401511692826040818351169201511690613616565b1611156104f9575b835f52600a6020526103da836001600160a01b03600160405f200154169283614809565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104e3575b61044057005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916104a9575b50160361049757005b636ade251160e01b5f5260045260245ffd5b6104cb915060203d6020116104d1575b6104c381836135a2565b810190613b16565b5f61048e565b503d6104b9565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f20541661043a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103b6565b848663066920d760e01b5f5260045260245260445260645ffd5b828563350b320360e11b5f526004523360245260445260645ffd5b5061056a85614560565b15610316565b8363b2ae763360e01b5f5260045260245ffd5b83632da33e5b60e01b5f5260045260245ffd5b826315efa0f360e11b5f5260045260245ffd5b8263699d2de960e01b5f5260045260245ffd5b5f80fd5b346105bc575f3660031901126105bc5760206001600160a01b035f5416604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105bc5760403660031901126105bc576004356106ae61343f565b6106b782614685565b916106c0613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c166109ad576001600160a01b038216801561099a576001600160801b03841692831561098757825f5260036020526001600160a01b0360405f205416948583141580610977575b61095c576001600160801b0361074c85614685565b16808611610942575061077190845f52600a602052600260405f20015460801c6146ab565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b0319169190911781556107ab906139d3565b6001600160801b036107cf8160208401511692826040818351169201511690613616565b161115610910575b825f52600a6020526107fb846001600160a01b03600160405f200154169283614809565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a183331415806108fa575b61086b575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104d8576392b9102b60e01b916001600160e01b0319915f916108db575b5016036108c8578180610860565b50636ade251160e01b5f5260045260245ffd5b6108f4915060203d6020116104d1576104c381836135a2565b856108ba565b50835f52600960205260ff60405f20541661085b565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556107d7565b858563066920d760e01b5f5260045260245260445260645ffd5b828463350b320360e11b5f526004523360245260445260645ffd5b5061098184614560565b15610737565b8263b2ae763360e01b5f5260045260245ffd5b50632da33e5b60e01b5f5260045260245ffd5b6315efa0f360e11b5f5260045260245ffd5b346105bc5760403660031901126105bc576109d8613429565b6001600160a01b036109e861343f565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f57610a52602091614685565b6001600160801b0360405191168152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a6020526020600260405f20015460801c604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105bc5760203660031901126105bc57600435610b1c81613b36565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104d8575f90610b8d575b610b8990604051918291602083526020830190613404565b0390f35b503d805f833e610b9d81836135a2565b8101906020818303126105bc5780519067ffffffffffffffff82116105bc57019080601f830112156105bc57815191610bd5836135c4565b91610be360405193846135a2565b838352602084830101116105bc57610b8992610c0591602080850191016133e3565b610b71565b346105bc5760403660031901126105bc57600435610c2661343f565b610c2e613e2d565b815f52600a60205260ff600160405f20015460a81c161561101357815f5260036020526001600160a01b0360405f20541690813303610ffc57610c7083614685565b906001600160801b0382169182158015610d04575b50506001600160a01b03811615610cf157610ca8846001600160a01b0392613cf3565b169182610cc25783637e27328960e01b5f5260045260245ffd5b8084918403610cd657602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d0c613e2d565b855f52600a60205260ff600160405f20015460a81c1615610fe957855f52600a60205260ff600160405f20015460a01c16610fd6578415610fc357610fb057845f5260036020526001600160a01b0360405f205416908185141580610fa0575b610f85576001600160801b03610d8187614685565b16808511610f6b5750610da690865f52600a602052600260405f20015460801c6146ab565b5f868152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155610de0906139d3565b6001600160801b03610e048160208401511692826040818351169201511690613616565b161115610f39575b845f52600a6020526001600160a01b03600160405f20015416610e30848683614809565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f23575b610e9b575b80610c85565b6040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f91610f04575b501614610e9557636ade251160e01b5f5260045260245ffd5b610f1d915060203d6020116104d1576104c381836135a2565b88610eeb565b50805f52600960205260ff60405f205416610e90565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e0c565b848763066920d760e01b5f5260045260245260445260645ffd5b848663350b320360e11b5f526004523360245260445260645ffd5b50610faa86614560565b15610d6c565b8463b2ae763360e01b5f5260045260245ffd5b85632da33e5b60e01b5f5260045260245ffd5b856315efa0f360e11b5f5260045260245ffd5b8563699d2de960e01b5f5260045260245ffd5b82632082501160e01b5f526004523360245260445ffd5b5063699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105bc5760203660031901126105bc576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105bc5760803660031901126105bc57611111613429565b61111961343f565b6064359167ffffffffffffffff83116105bc57366023840112156105bc57826004013591611146836135c4565b9261115460405194856135a2565b80845236602482870101116105bc576020815f9260246111809801838801378501015260443591613a26565b005b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f5761120a90613c5f565b604051600582101561121d576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105bc5760403660031901126105bc5761129b613429565b602435908115158092036105bc576001600160a01b031690811561130a57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bc575f3660031901126105bc576040515f6002548060011c90600181168015611434575b602083108114611420578285529081156113fc575060011461139e575b610b898361138a818503826135a2565b604051918291602083526020830190613404565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106113e25750909150810160200161138a61137a565b9192600181602092548385880101520191019092916113ca565b60ff191660208086019190915291151560051b8401909101915061138a905061137a565b634e487b7160e01b5f52602260045260245ffd5b91607f169161135d565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f576114c590613c5f565b60058110158061121d5760028214908115611501575b81156114ef575b6020826040519015158152f35b905061121d57600460209114826114e2565b5050600381145f6114db565b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc578036036101206003198201126105bc57611548613e2d565b60c482013590602219018112156105bc5781019060048201359167ffffffffffffffff83116105bc5760248101908360061b80360383136105bc5760046020916115918761387a565b9661159f60405198896135a2565b875282870193010101913683116105bc57905b8282106117be575050508151916115c88361387a565b926115d660405194856135a2565b808452601f196115e58261387a565b015f5b81811061179b57505064ffffffffff4216916001600160801b0361160b82613b57565b51511664ffffffffff80602061162085613b57565b51015116850116604051916116348361354d565b8252602082015261164486613b57565b5261164e85613b57565b5060015b8281106117265750505061166882600401613a05565b9261167560248401613a05565b9261168260448201613933565b916064820135936001600160a01b0385168095036105bc5760209661171e966116de966001600160801b03611713976001600160a01b036116c560848a01613a19565b94816116d360a48c01613a19565b976040519d8e613530565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e43691016138c8565b610100820152613e87565b604051908152f35b806001600160801b0361173b60019385613b64565b51511664ffffffffff8060206117545f1986018c613b64565b510151168160206117658689613b64565b510151160116604051916117788361354d565b825260208201526117898289613b64565b526117948188613b64565b5001611652565b6020906040516117aa8161354d565b5f81525f83820152828289010152016115e8565b60206040916117cd3685613892565b8152019101906115b2565b346105bc5760203660031901126105bc5760043560606101606040516117fd81613569565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f61012082015260405161184381613586565b5f81525f60208201525f60408201526101408201520152805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260405f2060405191610140830183811067ffffffffffffffff821117611b03576040528154916001600160a01b0383168452602084019264ffffffffff8160a01c168452604085019064ffffffffff8160c81c16825285606081019260ff8360f01c1615158452608082019260f81c1515835260018501549260a08301956001600160a01b0385168752611940600260c086019260ff8860a01c161515845260ff61010060e0890198828b60a81c1615158a52019860b01c1615158852016139d3565b6101208b0190815261195189613c5f565b600581101561121d57600214611afb575b5196516001600160a01b0316925164ffffffffff169551151590511515935115159451151595885f52600360205260405f20546001600160a01b03169a516001600160a01b0316995164ffffffffff16985f52600b60205260405f2092511515926040519a6119d08c613569565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952611a249061395f565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e08201610b89916134d4565b5f8752611962565b634e487b7160e01b5f52604160045260245ffd5b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc57611b489036906004016134a3565b90611b51613e2d565b5f915b808310611b5d57005b611b6883828461390f565b3592611b72613e2d565b835f52600a60205260ff600160405f20015460a81c1615611ebc57835f52600a60205260ff600160405f20015460a01c165f14611bbc57836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611eaa57611bf1815f52600a6020526001600160a01b0360405f205416331490565b15611e9457611bff81613b78565b90805f52600a602052611c17600260405f20016139d3565b916001600160801b038351166001600160801b0382161015611e8157815f52600a60205260ff60405f205460f01c1615611e6e57806001600160801b03602081611c6b948188511603169501511690613616565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611e49575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611d7d6001600160a01b03600160405f2001541694611d55888588614809565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611dce575b50505050506001019190611b54565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91611e2b575b5016036104975780808080611dbf565b611e43915060203d81116104d1576104c381836135a2565b87611e1b565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611cb5565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600b602052610b89611f1460405f2061395f565b6040519182916020835260208301906134d4565b346105bc5760203660031901126105bc57600435611f44613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57611f6881613c5f565b600581101561121d5760048103611f8c57506315efa0f360e11b5f5260045260245ffd5b60038103611fa7575063d0a172b360e01b5f5260045260245ffd5b60021461206357611fcc815f52600a6020526001600160a01b0360405f205416331490565b15611e9457805f52600a60205260ff60405f205460f01c1615612051576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b6308aca53f60e21b5f5260045260245ffd5b346105bc5760203660031901126105bc576004356001600160a01b0381168091036105bc576001600160a01b035f5416338103612150575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161213c5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346105bc5760203660031901126105bc5761217f613429565b5f546001600160a01b03811633810361215057506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105bc5760203660031901126105bc576001600160a01b036121f5613429565b168015612212575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105bc5760203660031901126105bc57602061225c600435613b36565b6001600160a01b0360405191168152f35b346105bc5760203660031901126105bc57600435612289613947565b50805f52600a60205260ff600160405f20015460a81c161561062f575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166122d38361354d565b825260208201526122f98251809264ffffffffff60208092828151168552015116910152565bf35b346105bc5760403660031901126105bc5760043567ffffffffffffffff81116105bc5761232c9036906004016134a3565b9060243567ffffffffffffffff81116105bc5761234d9036906004016134a3565b919092612358613e2d565b828103612671575f5b81811061236a57005b61237581838561390f565b3561238182848661390f565b355f5260036020526001600160a01b0360405f205416906123ab6123a684888a61390f565b613933565b916123b4613e2d565b815f52600a60205260ff600160405f20015460a81c161561101357815f52600a60205260ff600160405f20015460a01c1661265e57801561099a576001600160801b03831690811561098757825f5260036020526001600160a01b0360405f20541693848214158061264e575b612633576001600160801b0361243685614685565b16808411612619575061245b90845f52600a602052600260405f20015460801c6146ab565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155612495906139d3565b6001600160801b036124b98160208401511692826040818351169201511690613616565b1611156125e7575b825f52600a6020526001600160a01b03600160405f200154166124e5838383614809565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125d1575b612556575b50505050600101612361565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916125b3575b5016036104975780808061254a565b6125cb915060203d81116104d1576104c381836135a2565b896125a4565b50835f52600960205260ff60405f205416612545565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556124c1565b838563066920d760e01b5f5260045260245260445260645ffd5b508263350b320360e11b5f526004523360245260445260645ffd5b5061265884614560565b15612421565b506315efa0f360e11b5f5260045260245ffd5b90507fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f57610a526020916145d2565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f61271482613c5f565b600581101561121d57600203612732575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16612725565b346105bc575f3660031901126105bc5760206001600160a01b0360085416604051908152f35b346105bc5760203660031901126105bc5760043561278e613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c161561290b576127cd81614560565b15611e9457805f5260036020526001600160a01b0360405f205416151580612904575b806128e7575b6128d5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f205416801590811561289e575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061288c57005b637e27328960e01b5f5260045260245ffd5b6128bd835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612844565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127f6565b505f6127f0565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bc5761118061294736613469565b90604051926129576020856135a2565b5f8452613a26565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105bc5760203660031901126105bc576004356129cb613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c165f14612a14576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c611eaa57612a46815f52600a6020526001600160a01b0360405f205416331490565b15611e9457612a5481613b78565b90805f52600a602052612a6c600260405f20016139d3565b916001600160801b038351166001600160801b0382161015611e8157815f52600a60205260ff60405f205460f01c1615611e6e57806001600160801b03602081612ac0948188511603169501511690613616565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c61575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612baa6001600160a01b03600160405f2001541694611d55888588614809565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612bed57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91612c425750160361049757005b612c5b915060203d6020116104d1576104c381836135a2565b8461048e565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612b0a565b346105bc5760203660031901126105bc57612c9f613429565b6001600160a01b035f541690338203612dde57806001600160a01b03913b15612db257166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104d8575f91612d83575b5015612d5857805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612da5915060203d602011612dab575b612d9d81836135a2565b8101906138f7565b82612d0d565b503d612d93565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc5761014060031982360301126105bc57612e2f613e2d565b604051612e3b81613530565b612e4782600401613455565b8152612e5560248301613455565b6020820152612e66604483016135e0565b604082015260648201356001600160a01b03811681036105bc576060820152612e9160848301613523565b6080820152612ea260a48301613523565b60a0820152612eb360c48301613868565b60c082015260e482013567ffffffffffffffff81116105bc57820191366023840112156105bc57600483013592612ee98461387a565b90612ef760405192836135a2565b848252602060048184019660061b83010101903682116105bc57602401945b818610612f3857602061171e86611713878760e08401526101043691016138c8565b6020604091612f473689613892565b815201950194612f16565b346105bc5760203660031901126105bc576001600160a01b03612f73613429565b165f526009602052602060ff60405f2054166040519015158152f35b346105bc575f3660031901126105bc5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346105bc57611180612fda36613469565b91613636565b346105bc575f3660031901126105bc576020600754604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f5761303590613c5f565b600581101561121d578060209115908115613056575b506040519015158152f35b60019150148261304b565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f576020905f90805f52600a835260ff60405f205460f01c16806130f6575b6130c4575b506001600160801b0360405191168152f35b6130f09150805f52600a83526130ea6001600160801b03600260405f2001541691613b78565b90613616565b826130b2565b50805f52600a835260ff600160405f20015460a01c16156130ad565b346105bc5760403660031901126105bc5761312b613429565b60243561313781613b36565b33151580613204575b806131d1575b6131a55781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615613146565b50336001600160a01b0382161415613140565b346105bc5760203660031901126105bc57602061225c6004356135f4565b346105bc575f3660031901126105bc576040515f6001548060011c906001811680156132e6575b602083108114611420578285529081156113fc575060011461328857610b898361138a818503826135a2565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106132cc5750909150810160200161138a61137a565b9192600181602092548385880101520191019092916132b4565b91607f169161325c565b346105bc575f3660031901126105bc57602060405167016345785d8a00008152f35b346105bc5760203660031901126105bc57600435906001600160e01b031982168092036105bc57817f49064906000000000000000000000000000000000000000000000000000000006020931490811561336e575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156133b9575b81156133a8575b5083613367565b6301ffc9a760e01b915014836133a1565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061339a565b5f5b8381106133f45750505f910152565b81810151838201526020016133e5565b9060209161341d815180928185528580860191016133e3565b601f01601f1916010190565b600435906001600160a01b03821682036105bc57565b602435906001600160a01b03821682036105bc57565b35906001600160a01b03821682036105bc57565b60609060031901126105bc576004356001600160a01b03811681036105bc57906024356001600160a01b03811681036105bc579060443590565b9181601f840112156105bc5782359167ffffffffffffffff83116105bc576020808501948460051b0101116105bc57565b90602080835192838152019201905f5b8181106134f15750505090565b825180516001600160801b0316855260209081015164ffffffffff1681860152604090940193909201916001016134e4565b359081151582036105bc57565b610120810190811067ffffffffffffffff821117611b0357604052565b6040810190811067ffffffffffffffff821117611b0357604052565b610180810190811067ffffffffffffffff821117611b0357604052565b6060810190811067ffffffffffffffff821117611b0357604052565b90601f8019910116810190811067ffffffffffffffff821117611b0357604052565b67ffffffffffffffff8111611b0357601f01601f191660200190565b35906001600160801b03821682036105bc57565b6135fd81613b36565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161213c57565b91906001600160a01b03168015610cf157815f5260036020526001600160a01b0360405f205416151580613860575b80613843575b613830577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f2054169282331515928361377b575b6001600160a01b03935085613744575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361372c57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b613763825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556136cb565b91929050806137d9575b15613792578282916136bb565b82846137aa57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613807575b806137855750825f526005602052336001600160a01b0360405f20541614613785565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166137e4565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c161561366b565b506001613665565b359064ffffffffff821682036105bc57565b67ffffffffffffffff8111611b035760051b60200190565b91908260409103126105bc576040516138aa8161354d565b60206138c38183956138bb816135e0565b855201613868565b910152565b91908260409103126105bc576040516138e08161354d565b60208082946138ee81613455565b84520135910152565b908160209103126105bc575180151581036105bc5790565b919081101561391f5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036105bc5790565b604051906139548261354d565b5f6020838281520152565b90815461396b8161387a565b9261397960405194856135a2565b81845260208401905f5260205f205f915b8383106139975750505050565b6001602081926040516139a98161354d565b64ffffffffff86546001600160801b038116835260801c168382015281520192019201919061398a565b906040516139e081613586565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b03811681036105bc5790565b3580151581036105bc5790565b90613a32838284613636565b803b613a3f575b50505050565b602091613a856001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613404565b03815f865af15f9181613af5575b50613ac15750613aa1614656565b80519081613abc5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b911603613ae357505f808080613a39565b633250574960e11b5f5260045260245ffd5b613b0f91925060203d6020116104d1576104c381836135a2565b905f613a93565b908160209103126105bc57516001600160e01b0319811681036105bc5790565b805f5260036020526001600160a01b0360405f20541690811561288c575090565b80511561391f5760200190565b805182101561391f5760209160051b010190565b9064ffffffffff421691805f52600b602052613b9660405f2061395f565b908364ffffffffff6020613ba985613b57565b5101511611613c5857805f52600a6020528364ffffffffff60405f205460c81c161115613c3957506001600160801b03613be282613b57565b515116916001925b8251841015613c32578464ffffffffff6020613c068787613b64565b5101511611613c32576001600160801b0360019181613c258787613b64565b5151160116930192613bea565b9350915050565b919250505f52600a6020526001600160801b03600260405f2001541690565b505f925050565b805f52600a60205260ff600160405f20015460a01c165f14613c815750600490565b805f52600a60205260405f205460f81c613ced57805f52600a60205264ffffffffff60405f205460a01c164210613ce857613cbb81613b78565b905f52600a6020526001600160801b0380600260405f200154169116105f14613ce357600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613e1b575b80613dfe575b6128d5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613dc7575b1680613daf575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613d6b565b613de6835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613d64565b50805f52600a60205260ff600160405f20015460b01c1615613d18565b506001600160a01b0382161515613d12565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e5f57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613ea96001600160801b0360408401511660206101008501510151906146cb565b916001600160801b038351169060e08101519160c082019264ffffffffff845116821561453857801561451057815180156144e8577f000000000000000000000000000000000000000000000000000000000000000081116144bd575064ffffffffff6020613f1784613b57565b5101511681101561447957505f905f905f81515f905b8082106143f1575050505064ffffffffff804216911690818110156143c35750506001600160801b03169081810361439557505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140f98751975f19890190613b64565b51015160c81b169360a01b169116171785555f5b8181106142e3575050600187016007556001600160a01b036020830151168015610cf157614143886001600160a01b0392613cf3565b166142b75786826141916001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b0385511690309033906147a8565b6001600160801b0360208401511680614287575b506001600160a01b038151169461427c61425e6001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996142038b61354d565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c08701526101408601906134d4565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b6142b1906001600160a01b036060840151166001600160a01b0361010085015151169033906147a8565b5f6141a5565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f20906142fe8160e0870151613b64565b5182549268010000000000000000841015611b03576001840180825584101561391f576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b1691161790550161410d565b7fa4cdf853000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f879842de000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193614415906001600160801b0361440c8588613b64565b515116906146ab565b9364ffffffffff8060206144298685613b64565b5101511694168085111561444557506001849301909291613f2d565b8490847fbfc5f2fa000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff602061448a84613b57565b51015116907fab900963000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f76d9c284000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f814426ed000000000000000000000000000000000000000000000000000000005f5260045ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f205416908133149182156145a6575b50811561458d575090565b90506001600160a01b036145a133926135f4565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614582565b805f52600a6020526145e9600260405f20016139d3565b90805f52600a60205260ff600160405f20015460a01c165f146146175750602001516001600160801b031690565b90815f52600a60205260405f205460f81c614639575061463690613b78565b90565b61463691506001600160801b036040818351169201511690613616565b3d15614680573d90614667826135c4565b9161467560405193846135a2565b82523d5f602084013e565b606090565b61463690614692816145d2565b905f52600a602052600260405f20015460801c90613616565b906001600160801b03809116911601906001600160801b03821161213c57565b9190916040516146da8161354d565b5f81525f6020820152926001600160801b03821690811561478b5767016345785d8a00008111614754576147166001600160801b0391836148de565b1660208501918183521115614740576001600160801b03918261473b92511690613616565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161479c8161354d565b5f81525f602082015290565b9091926001600160a01b036148079481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526148026084836135a2565b614859565b565b614807926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526148026064836135a2565b5f806001600160a01b0361488293169360208151910182865af161487b614656565b908361498c565b80519081151591826148c3575b50506148985750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6148d692506020809183010191016138f7565b155f8061488f565b9091905f198382098382029182808310920391808303921461497b57670de0b6b3a764000082101561494b577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906149c957508051156149a157805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614a0f575b6149da575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156149d256fea164736f6c634300081a000a"; + hex"60c0604052346103e157614e1e6060813803918261001c816103e5565b9384928339810103126103e15780516001600160a01b038116908190036103e15760208201516001600160a01b03811692908390036103e1576040015161006360406103e5565b92601b84527f5361626c696572204c6f636b7570205472616e63686564204e46540000000000602085015261009860406103e5565b600e81526d5341422d4c4f434b55502d54524160901b602082015230608052845190946001600160401b0382116102e45760015490600182811c921680156103d7575b60208310146102c65781601f849311610369575b50602090601f8311600114610303575f926102f8575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e457600254600181811c911680156102da575b60208210146102c657601f8111610263575b50602094601f8211600114610200579481929394955f926101f5575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614a13908161040b823960805181613e37015260a051818181612fa60152613ef00152f35b015190505f80610169565b601f1982169560025f52805f20915f5b88811061024b57508360019596979810610233575b505050811b0160025561017e565b01515f1960f88460031b161c191690555f8080610225565b91926020600181928685015181550194019201610210565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bc575b601f0160051c01905b8181106102b1575061014d565b5f81556001016102a4565b909150819061029b565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013b565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610105565b60015f9081528281209350601f198516905b8181106103515750908460019594939210610339575b505050811b0160015561011a565b01515f1960f88460031b161c191690555f808061032b565b92936020600181928786015181550195019301610315565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103cd575b90601f859493920160051c01905b8181106103bf57506100ef565b5f81558493506001016103b2565b90915081906103a4565b91607f16916100db565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e45760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461331257508063027b6744146132f057806306fdde0314613235578063081812fc14613217578063095ea7b3146131125780631400ecec146130615780631c1cdd4c14612ffd5780631e99d56914612fe057806323b872dd14612fc95780632fe4304114612f8f578063303acc8514612f5257806332fbe22b14612df5578063406887cb14612c8657806340e58ee5146129af578063425d30dd1461295f57806342842e0e1461293657806342966c6814612772578063442675701461274c5780634857501f146126db5780634869e12d146126a15780634cc55e11146122fd57806357404b121461226f5780636352211e146122405780636d0cee751461224057806370a08231146121d657806375829def146121685780637cad6cd1146120775780637de6b1db14611f2a5780637f5799f914611ed15780638659c27014611b19578063894e9a0d146117da578063897f362b1461150f5780638f69b9931461148f5780639067b6771461144057806395d89b4114611338578063a22cb46514611284578063a80fc07114611233578063ad35efd4146111d4578063b256456914611184578063b88d4fde146110fa578063b8a3be66146110c5578063b971302a14611077578063bc2be1be14611028578063c156a11d14610c0b578063c87b56dd14610b00578063d4dbd20b14610aaf578063d511609f14610a64578063d975dfed14610a19578063e985e9c5146109c0578063ea5ead1914610692578063eac8f5b814610641578063f590c176146105e5578063f851a440146105c05763fdd46d601461026e575f80fd5b346105bc5760603660031901126105bc5760043561028a61343f565b90604435916001600160801b038316908184036105bc576102a9613e2d565b825f52600a60205260ff600160405f20015460a81c16156105a957825f52600a60205260ff600160405f20015460a01c16610596576001600160a01b03811690811561058357835f5260036020526001600160a01b0360405f205416948583141580610573575b610558578315610545576001600160801b0361032b86614673565b1680851161052b575061035090855f52600a602052600260405f20015460801c614699565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561038a906139d3565b6001600160801b036103ae8160208401511692826040818351169201511690613616565b1611156104f9575b835f52600a6020526103da836001600160a01b03600160405f2001541692836147f7565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104e3575b61044057005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916104a9575b50160361049757005b636ade251160e01b5f5260045260245ffd5b6104cb915060203d6020116104d1575b6104c381836135a2565b810190613b16565b5f61048e565b503d6104b9565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f20541661043a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103b6565b848663066920d760e01b5f5260045260245260445260645ffd5b8463b2ae763360e01b5f5260045260245ffd5b828563350b320360e11b5f526004523360245260445260645ffd5b5061057d8561454e565b15610310565b83632da33e5b60e01b5f5260045260245ffd5b826315efa0f360e11b5f5260045260245ffd5b8263699d2de960e01b5f5260045260245ffd5b5f80fd5b346105bc575f3660031901126105bc5760206001600160a01b035f5416604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105bc5760403660031901126105bc576004356106ae61343f565b906106b881614673565b906106c1613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c166109ae576001600160a01b038316801561099b57815f5260036020526001600160a01b0360405f20541693848214158061098b575b610970576001600160801b03841693841561095d576001600160801b0361074d85614673565b16808611610943575061077290845f52600a602052600260405f20015460801c614699565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b0319169190911781556107ac906139d3565b6001600160801b036107d08160208401511692826040818351169201511690613616565b161115610911575b825f52600a6020526107fc846001600160a01b03600160405f2001541692836147f7565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a183331415806108fb575b61086c575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104d8576392b9102b60e01b916001600160e01b0319915f916108dc575b5016036108c9578180610861565b50636ade251160e01b5f5260045260245ffd5b6108f5915060203d6020116104d1576104c381836135a2565b856108bb565b50835f52600960205260ff60405f20541661085c565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556107d8565b858563066920d760e01b5f5260045260245260445260645ffd5b8363b2ae763360e01b5f5260045260245ffd5b509063350b320360e11b5f526004523360245260445260645ffd5b506109958361454e565b15610727565b50632da33e5b60e01b5f5260045260245ffd5b6315efa0f360e11b5f5260045260245ffd5b346105bc5760403660031901126105bc576109d9613429565b6001600160a01b036109e961343f565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f57610a53602091614673565b6001600160801b0360405191168152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a6020526020600260405f20015460801c604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105bc5760203660031901126105bc57600435610b1d81613b36565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104d8575f90610b8e575b610b8a90604051918291602083526020830190613404565b0390f35b503d805f833e610b9e81836135a2565b8101906020818303126105bc5780519067ffffffffffffffff82116105bc57019080601f830112156105bc57815191610bd6836135c4565b91610be460405193846135a2565b838352602084830101116105bc57610b8a92610c0691602080850191016133e3565b610b72565b346105bc5760403660031901126105bc57600435610c2761343f565b610c2f613e2d565b815f52600a60205260ff600160405f20015460a81c161561101557815f5260036020526001600160a01b0360405f20541690813303610ffe57610c7183614673565b906001600160801b038216918215908115610d06575b50506001600160a01b03811615610cf357610caa846001600160a01b0392613cf3565b169182610cc45783637e27328960e01b5f5260045260245ffd5b8084918403610cd857602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d0e613e2d565b855f52600a60205260ff600160405f20015460a81c1615610feb57855f52600a60205260ff600160405f20015460a01c16610fd8578415610fc557855f5260036020526001600160a01b0360405f205416918286141580610fb5575b610f9a57610f87576001600160801b03610d8387614673565b16808511610f6d5750610da890865f52600a602052600260405f20015460801c614699565b5f868152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155610de2906139d3565b6001600160801b03610e068160208401511692826040818351169201511690613616565b161115610f3b575b845f52600a6020526001600160a01b03600160405f20015416610e328486836147f7565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f25575b610e9d575b80610c87565b6040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f91610f06575b501614610e9757636ade251160e01b5f5260045260245ffd5b610f1f915060203d6020116104d1576104c381836135a2565b88610eed565b50805f52600960205260ff60405f205416610e92565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e0e565b848763066920d760e01b5f5260045260245260445260645ffd5b8563b2ae763360e01b5f5260045260245ffd5b858763350b320360e11b5f526004523360245260445260645ffd5b50610fbf8761454e565b15610d6a565b85632da33e5b60e01b5f5260045260245ffd5b856315efa0f360e11b5f5260045260245ffd5b8563699d2de960e01b5f5260045260245ffd5b82632082501160e01b5f526004523360245260445ffd5b5063699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105bc5760203660031901126105bc576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105bc5760803660031901126105bc57611113613429565b61111b61343f565b6064359167ffffffffffffffff83116105bc57366023840112156105bc57826004013591611148836135c4565b9261115660405194856135a2565b80845236602482870101116105bc576020815f9260246111829801838801378501015260443591613a26565b005b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f5761120c90613c5f565b604051600582101561121f576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105bc5760403660031901126105bc5761129d613429565b602435908115158092036105bc576001600160a01b031690811561130c57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bc575f3660031901126105bc576040515f6002548060011c90600181168015611436575b602083108114611422578285529081156113fe57506001146113a0575b610b8a8361138c818503826135a2565b604051918291602083526020830190613404565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106113e45750909150810160200161138c61137c565b9192600181602092548385880101520191019092916113cc565b60ff191660208086019190915291151560051b8401909101915061138c905061137c565b634e487b7160e01b5f52602260045260245ffd5b91607f169161135f565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f576114c790613c5f565b60058110158061121f5760028214908115611503575b81156114f1575b6020826040519015158152f35b905061121f57600460209114826114e4565b5050600381145f6114dd565b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc578036036101206003198201126105bc5761154a613e2d565b60c482013590602219018112156105bc5781019060048201359167ffffffffffffffff83116105bc5760248101908360061b80360383136105bc5760046020916115938761387a565b966115a160405198896135a2565b875282870193010101913683116105bc57905b8282106117c0575050508151916115ca8361387a565b926115d860405194856135a2565b808452601f196115e78261387a565b015f5b81811061179d57505064ffffffffff4216916001600160801b0361160d82613b57565b51511664ffffffffff80602061162285613b57565b51015116850116604051916116368361354d565b8252602082015261164686613b57565b5261165085613b57565b5060015b8281106117285750505061166a82600401613a05565b9261167760248401613a05565b9261168460448201613933565b916064820135936001600160a01b0385168095036105bc57602096611720966116e0966001600160801b03611715976001600160a01b036116c760848a01613a19565b94816116d560a48c01613a19565b976040519d8e613530565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e43691016138c8565b610100820152613e87565b604051908152f35b806001600160801b0361173d60019385613b64565b51511664ffffffffff8060206117565f1986018c613b64565b510151168160206117678689613b64565b5101511601166040519161177a8361354d565b8252602082015261178b8289613b64565b526117968188613b64565b5001611654565b6020906040516117ac8161354d565b5f81525f83820152828289010152016115ea565b60206040916117cf3685613892565b8152019101906115b4565b346105bc5760203660031901126105bc5760043560606101606040516117ff81613569565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f61012082015260405161184581613586565b5f81525f60208201525f60408201526101408201520152805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260405f2060405191610140830183811067ffffffffffffffff821117611b05576040528154916001600160a01b0383168452602084019264ffffffffff8160a01c168452604085019064ffffffffff8160c81c16825285606081019260ff8360f01c1615158452608082019260f81c1515835260018501549260a08301956001600160a01b0385168752611942600260c086019260ff8860a01c161515845260ff61010060e0890198828b60a81c1615158a52019860b01c1615158852016139d3565b6101208b0190815261195389613c5f565b600581101561121f57600214611afd575b5196516001600160a01b0316925164ffffffffff169551151590511515935115159451151595885f52600360205260405f20546001600160a01b03169a516001600160a01b0316995164ffffffffff16985f52600b60205260405f2092511515926040519a6119d28c613569565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952611a269061395f565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e08201610b8a916134d4565b5f8752611964565b634e487b7160e01b5f52604160045260245ffd5b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc57611b4a9036906004016134a3565b90611b53613e2d565b5f915b808310611b5f57005b611b6a83828461390f565b3592611b74613e2d565b835f52600a60205260ff600160405f20015460a81c1615611ebe57835f52600a60205260ff600160405f20015460a01c165f14611bbe57836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611eac57611bf3815f52600a6020526001600160a01b0360405f205416331490565b15611e9657611c0181613b78565b90805f52600a602052611c19600260405f20016139d3565b916001600160801b038351166001600160801b0382161015611e8357815f52600a60205260ff60405f205460f01c1615611e7057806001600160801b03602081611c6d948188511603169501511690613616565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611e4b575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611d7f6001600160a01b03600160405f2001541694611d578885886147f7565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611dd0575b50505050506001019190611b56565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91611e2d575b5016036104975780808080611dc1565b611e45915060203d81116104d1576104c381836135a2565b87611e1d565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611cb7565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600b602052610b8a611f1660405f2061395f565b6040519182916020835260208301906134d4565b346105bc5760203660031901126105bc57600435611f46613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57611f6a81613c5f565b600581101561121f5760048103611f8e57506315efa0f360e11b5f5260045260245ffd5b60038103611fa9575063d0a172b360e01b5f5260045260245ffd5b60021461206557611fce815f52600a6020526001600160a01b0360405f205416331490565b15611e9657805f52600a60205260ff60405f205460f01c1615612053576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b6308aca53f60e21b5f5260045260245ffd5b346105bc5760203660031901126105bc576004356001600160a01b0381168091036105bc576001600160a01b035f5416338103612152575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161213e5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346105bc5760203660031901126105bc57612181613429565b5f546001600160a01b03811633810361215257506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105bc5760203660031901126105bc576001600160a01b036121f7613429565b168015612214575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105bc5760203660031901126105bc57602061225e600435613b36565b6001600160a01b0360405191168152f35b346105bc5760203660031901126105bc5760043561228b613947565b50805f52600a60205260ff600160405f20015460a81c161561062f575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166122d58361354d565b825260208201526122fb8251809264ffffffffff60208092828151168552015116910152565bf35b346105bc5760403660031901126105bc5760043567ffffffffffffffff81116105bc5761232e9036906004016134a3565b9060243567ffffffffffffffff81116105bc5761234f9036906004016134a3565b91909261235a613e2d565b828103612671575f5b81811061236c57005b61237781838561390f565b3561238382848661390f565b355f5260036020526001600160a01b0360405f205416906123ad6123a884888a61390f565b613933565b6123b5613e2d565b815f52600a60205260ff600160405f20015460a81c161561101557815f52600a60205260ff600160405f20015460a01c1661265e57821561099b57815f5260036020526001600160a01b0360405f20541692838114158061264e575b612634576001600160801b03821691821561095d576001600160801b0361243785614673565b1680841161261a575061245c90845f52600a602052600260405f20015460801c614699565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155612496906139d3565b6001600160801b036124ba8160208401511692826040818351169201511690613616565b1611156125e8575b825f52600a6020526001600160a01b03600160405f200154166124e68383836147f7565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125d2575b612557575b50505050600101612363565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916125b4575b5016036104975780808061254b565b6125cc915060203d81116104d1576104c381836135a2565b896125a5565b50835f52600960205260ff60405f205416612546565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556124c2565b838563066920d760e01b5f5260045260245260445260645ffd5b8263350b320360e11b5f526004523360245260445260645ffd5b506126588361454e565b15612411565b506315efa0f360e11b5f5260045260245ffd5b90507fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f57610a536020916145c0565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f61271482613c5f565b600581101561121f57600203612732575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16612725565b346105bc575f3660031901126105bc5760206001600160a01b0360085416604051908152f35b346105bc5760203660031901126105bc5760043561278e613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c161561290b576127cd8161454e565b15611e9657805f5260036020526001600160a01b0360405f205416151580612904575b806128e7575b6128d5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f205416801590811561289e575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061288c57005b637e27328960e01b5f5260045260245ffd5b6128bd835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612844565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127f6565b505f6127f0565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bc5761118261294736613469565b90604051926129576020856135a2565b5f8452613a26565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105bc5760203660031901126105bc576004356129cb613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c165f14612a14576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c611eac57612a46815f52600a6020526001600160a01b0360405f205416331490565b15611e9657612a5481613b78565b90805f52600a602052612a6c600260405f20016139d3565b916001600160801b038351166001600160801b0382161015611e8357815f52600a60205260ff60405f205460f01c1615611e7057806001600160801b03602081612ac0948188511603169501511690613616565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c61575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612baa6001600160a01b03600160405f2001541694611d578885886147f7565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612bed57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91612c425750160361049757005b612c5b915060203d6020116104d1576104c381836135a2565b8461048e565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612b0a565b346105bc5760203660031901126105bc57612c9f613429565b6001600160a01b035f541690338203612dde57806001600160a01b03913b15612db257166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104d8575f91612d83575b5015612d5857805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612da5915060203d602011612dab575b612d9d81836135a2565b8101906138f7565b82612d0d565b503d612d93565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc5761014060031982360301126105bc57612e2f613e2d565b604051612e3b81613530565b612e4782600401613455565b8152612e5560248301613455565b6020820152612e66604483016135e0565b604082015260648201356001600160a01b03811681036105bc576060820152612e9160848301613523565b6080820152612ea260a48301613523565b60a0820152612eb360c48301613868565b60c082015260e482013567ffffffffffffffff81116105bc57820191366023840112156105bc57600483013592612ee98461387a565b90612ef760405192836135a2565b848252602060048184019660061b83010101903682116105bc57602401945b818610612f3857602061172086611715878760e08401526101043691016138c8565b6020604091612f473689613892565b815201950194612f16565b346105bc5760203660031901126105bc576001600160a01b03612f73613429565b165f526009602052602060ff60405f2054166040519015158152f35b346105bc575f3660031901126105bc5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346105bc57611182612fda36613469565b91613636565b346105bc575f3660031901126105bc576020600754604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f5761303590613c5f565b600581101561121f578060209115908115613056575b506040519015158152f35b60019150148261304b565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f576020905f90805f52600a835260ff60405f205460f01c16806130f6575b6130c4575b506001600160801b0360405191168152f35b6130f09150805f52600a83526130ea6001600160801b03600260405f2001541691613b78565b90613616565b826130b2565b50805f52600a835260ff600160405f20015460a01c16156130ad565b346105bc5760403660031901126105bc5761312b613429565b60243561313781613b36565b33151580613204575b806131d1575b6131a55781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615613146565b50336001600160a01b0382161415613140565b346105bc5760203660031901126105bc57602061225e6004356135f4565b346105bc575f3660031901126105bc576040515f6001548060011c906001811680156132e6575b602083108114611422578285529081156113fe575060011461328857610b8a8361138c818503826135a2565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106132cc5750909150810160200161138c61137c565b9192600181602092548385880101520191019092916132b4565b91607f169161325c565b346105bc575f3660031901126105bc57602060405167016345785d8a00008152f35b346105bc5760203660031901126105bc57600435906001600160e01b031982168092036105bc57817f49064906000000000000000000000000000000000000000000000000000000006020931490811561336e575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156133b9575b81156133a8575b5083613367565b6301ffc9a760e01b915014836133a1565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061339a565b5f5b8381106133f45750505f910152565b81810151838201526020016133e5565b9060209161341d815180928185528580860191016133e3565b601f01601f1916010190565b600435906001600160a01b03821682036105bc57565b602435906001600160a01b03821682036105bc57565b35906001600160a01b03821682036105bc57565b60609060031901126105bc576004356001600160a01b03811681036105bc57906024356001600160a01b03811681036105bc579060443590565b9181601f840112156105bc5782359167ffffffffffffffff83116105bc576020808501948460051b0101116105bc57565b90602080835192838152019201905f5b8181106134f15750505090565b825180516001600160801b0316855260209081015164ffffffffff1681860152604090940193909201916001016134e4565b359081151582036105bc57565b610120810190811067ffffffffffffffff821117611b0557604052565b6040810190811067ffffffffffffffff821117611b0557604052565b610180810190811067ffffffffffffffff821117611b0557604052565b6060810190811067ffffffffffffffff821117611b0557604052565b90601f8019910116810190811067ffffffffffffffff821117611b0557604052565b67ffffffffffffffff8111611b0557601f01601f191660200190565b35906001600160801b03821682036105bc57565b6135fd81613b36565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161213e57565b91906001600160a01b03168015610cf357815f5260036020526001600160a01b0360405f205416151580613860575b80613843575b613830577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f2054169282331515928361377b575b6001600160a01b03935085613744575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361372c57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b613763825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556136cb565b91929050806137d9575b15613792578282916136bb565b82846137aa57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613807575b806137855750825f526005602052336001600160a01b0360405f20541614613785565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166137e4565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c161561366b565b506001613665565b359064ffffffffff821682036105bc57565b67ffffffffffffffff8111611b055760051b60200190565b91908260409103126105bc576040516138aa8161354d565b60206138c38183956138bb816135e0565b855201613868565b910152565b91908260409103126105bc576040516138e08161354d565b60208082946138ee81613455565b84520135910152565b908160209103126105bc575180151581036105bc5790565b919081101561391f5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036105bc5790565b604051906139548261354d565b5f6020838281520152565b90815461396b8161387a565b9261397960405194856135a2565b81845260208401905f5260205f205f915b8383106139975750505050565b6001602081926040516139a98161354d565b64ffffffffff86546001600160801b038116835260801c168382015281520192019201919061398a565b906040516139e081613586565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b03811681036105bc5790565b3580151581036105bc5790565b90613a32838284613636565b803b613a3f575b50505050565b602091613a856001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613404565b03815f865af15f9181613af5575b50613ac15750613aa1614644565b80519081613abc5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b911603613ae357505f808080613a39565b633250574960e11b5f5260045260245ffd5b613b0f91925060203d6020116104d1576104c381836135a2565b905f613a93565b908160209103126105bc57516001600160e01b0319811681036105bc5790565b805f5260036020526001600160a01b0360405f20541690811561288c575090565b80511561391f5760200190565b805182101561391f5760209160051b010190565b9064ffffffffff421691805f52600b602052613b9660405f2061395f565b908364ffffffffff6020613ba985613b57565b5101511611613c5857805f52600a6020528364ffffffffff60405f205460c81c161115613c3957506001600160801b03613be282613b57565b515116916001925b8251841015613c32578464ffffffffff6020613c068787613b64565b5101511611613c32576001600160801b0360019181613c258787613b64565b5151160116930192613bea565b9350915050565b919250505f52600a6020526001600160801b03600260405f2001541690565b505f925050565b805f52600a60205260ff600160405f20015460a01c165f14613c815750600490565b805f52600a60205260405f205460f81c613ced57805f52600a60205264ffffffffff60405f205460a01c164210613ce857613cbb81613b78565b905f52600a6020526001600160801b0380600260405f200154169116105f14613ce357600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613e1b575b80613dfe575b6128d5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613dc7575b1680613daf575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613d6b565b613de6835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613d64565b50805f52600a60205260ff600160405f20015460b01c1615613d18565b506001600160a01b0382161515613d12565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e5f57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613ea96001600160801b0360408401511660206101008501510151906146b9565b916001600160a01b03815116906001600160801b0384511660e082015160c083019364ffffffffff85511690156145265782156144fe5780156144d657815180156144ae577f00000000000000000000000000000000000000000000000000000000000000008111614483575064ffffffffff6020613f2784613b57565b5101511681101561443f57505f809180515f915b8183106143bc575050506001600160801b039150169081810361438e57505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140f28751975f19890190613b64565b51015160c81b169360a01b169116171785555f5b8181106142dc575050600187016007556001600160a01b036020830151168015610cf35761413c886001600160a01b0392613cf3565b166142b057868261418a6001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b038551169030903390614796565b6001600160801b0360208401511680614280575b506001600160a01b03815116946142756142576001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996141fc8b61354d565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c08701526101408601906134d4565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b6142aa906001600160a01b036060840151166001600160a01b036101008501515116903390614796565b5f61419e565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f20906142f78160e0870151613b64565b5182549268010000000000000000841015611b05576001840180825584101561391f576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b16911617905501614106565b7fa4cdf853000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9091926143de906001600160801b036143d58685613b64565b51511690614699565b9364ffffffffff8060206143f28786613b64565b5101511691168082111561440d575093926001019190613f3b565b847fbfc5f2fa000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff602061445084613b57565b51015116907fab900963000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f76d9c284000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f814426ed000000000000000000000000000000000000000000000000000000005f5260045ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6d004a9e000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215614594575b50811561457b575090565b90506001600160a01b0361458f33926135f4565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614570565b805f52600a6020526145d7600260405f20016139d3565b90805f52600a60205260ff600160405f20015460a01c165f146146055750602001516001600160801b031690565b90815f52600a60205260405f205460f81c614627575061462490613b78565b90565b61462491506001600160801b036040818351169201511690613616565b3d1561466e573d90614655826135c4565b9161466360405193846135a2565b82523d5f602084013e565b606090565b61462490614680816145c0565b905f52600a602052600260405f20015460801c90613616565b906001600160801b03809116911601906001600160801b03821161213e57565b9190916040516146c88161354d565b5f81525f6020820152926001600160801b0382169081156147795767016345785d8a00008111614742576147046001600160801b0391836148cc565b166020850191818352111561472e576001600160801b03918261472992511690613616565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161478a8161354d565b5f81525f602082015290565b9091926001600160a01b036147f59481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526147f06084836135a2565b614847565b565b6147f5926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526147f06064836135a2565b5f806001600160a01b0361487093169360208151910182865af1614869614644565b908361497a565b80519081151591826148b1575b50506148865750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6148c492506020809183010191016138f7565b155f8061487d565b9091905f198382098382029182808310920391808303921461496957670de0b6b3a7640000821015614939577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906149b7575080511561498f57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806149fd575b6149c8575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156149c056fea164736f6c634300081a000a"; bytes public constant BYTECODE_MERKLE_FACTORY = - hex"60808060405234601557613bb9908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c80631e3238761461044c5780634d7c0f11146103795763769bed201461003a575f80fd5b346103755760c03660031901126103755760043567ffffffffffffffff81116103755761006b9036906004016108c2565b602435906001600160a01b03821691828103610375576040366043190112610375576040519061009a8261080f565b60443564ffffffffff8116810361037557825260643564ffffffffff811681036103755760208301528251906020840151151583604086015192606087015160808801519160405180602081019460208652604082016100f9916109ca565b03601f198101825261010b908261082b565b60a08a01519360c08b0151604051818192519081602084019160200191610131926109a9565b810103808252610144906020018261082b565b61014d906109ef565b9060e08c01511515926040519560208701988961017c9164ffffffffff60208092828151168552015116910152565b6040875261018b60608861082b565b6040519a8b9a60208c019d8e3360601b90526bffffffffffffffffffffffff199060601b1660348d015260f81b60488c015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660498b01526bffffffffffffffffffffffff199060601b16604e8a015251908160628a0161020f926109a9565b8701946062860152608285015260f81b60a28401526bffffffffffffffffffffffff199060601b1660a383015251918260b7830161024c926109a9565b0160620103605501601f1981018252610265908261082b565b51902060405161157280820182811067ffffffffffffffff821117610361578291610ae88339608081526102c260406102a16080840189610a61565b92896020820152018664ffffffffff60208092828151168552015116910152565b03905ff59283156103565761031961033b937f2ba0fe49588281dbb122dd3b7f3e2b3396338f70dbe3c62bf3e3888b4ba7ffb8926001600160a01b036020971695869560405194859460c0865260c0860190610a61565b9289850152604084019064ffffffffff60208092828151168552015116910152565b608435608083015260a43560a08301520390a2604051908152f35b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b346103755760203660031901126103755760043567ffffffffffffffff811161037557366023820112156103755780600401359067ffffffffffffffff8211610375573660248360061b83010111610375575f90815b8383101561042d5760248360061b830101359067ffffffffffffffff82168092036103755767ffffffffffffffff160167ffffffffffffffff8111610419576001909201916103cf565b634e487b7160e01b5f52601160045260245ffd5b602090670de0b6b3a764000067ffffffffffffffff6040519216148152f35b346103755760a03660031901126103755760043567ffffffffffffffff81116103755761047d9036906004016108c2565b6024356001600160a01b03811690818103610375576044359067ffffffffffffffff8211610375573660238301121561037557816004013567ffffffffffffffff811161036157604051926104d860208360051b018561082b565b8184526024602085019260061b8201019036821161037557602401915b8183106107c2575050505f9082515f905b8082106107835750508451906020860151151584604088015192606089015160808a0151916040518060208101946020865260408201610545916109ca565b03601f1981018252610557908261082b565b8b60a08101519460c082015160405181819251908160208401916020019161057e926109a9565b810103808252610591906020018261082b565b61059a906109ef565b9160e001511515926040519586602081019960208b52604082016105bd91610a11565b03601f19810188526105cf908861082b565b6040519a8b9a60208c019d8e3360601b90526bffffffffffffffffffffffff199060601b1660348d015260f81b60488c015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660498b01526bffffffffffffffffffffffff199060601b16604e8a015251908160628a01610653926109a9565b8701946062860152608285015260f81b60a28401526bffffffffffffffffffffffff199060601b1660a383015251918260b78301610690926109a9565b0160620103605501601f19810182526106a9908261082b565b519020604051611b538082019082821067ffffffffffffffff8311176103615782916106fa9161205a8439606081526106e5606082018a610a61565b90886020820152604081830391015286610a11565b03905ff58015610356576020947ffe44018cf74992b2720702385a1728bd329dd136e4f651203176c81c12710a8b926107626001600160a01b03610750941696879660405195869560c0875260c0870190610a61565b918a8601528482036040860152610a11565b906060830152606435608083015260843560a08301520390a2604051908152f35b909284518410156107ae5760019064ffffffffff6020808760051b8901015101511601930190610506565b634e487b7160e01b5f52603260045260245ffd5b60408336031261037557604051906107d98261080f565b83359067ffffffffffffffff8216820361037557826020926040945261080083870161085a565b838201528152019201916104f5565b6040810190811067ffffffffffffffff82111761036157604052565b90601f8019910116810190811067ffffffffffffffff82111761036157604052565b3590811515820361037557565b359064ffffffffff8216820361037557565b81601f820112156103755780359067ffffffffffffffff821161036157604051926108a1601f8401601f19166020018561082b565b8284526020838301011161037557815f926020809301838601378301015290565b919091610100818403126103755760405190610100820182811067ffffffffffffffff82111761036157604052819381356001600160a01b03811681036103755783526109116020830161084d565b60208401526109226040830161085a565b604084015260608201356001600160a01b0381168103610375576060840152608082013567ffffffffffffffff8111610375578161096191840161086c565b608084015260a082013560a084015260c08201359067ffffffffffffffff8211610375578261099960e094926109a49486940161086c565b60c08601520161084d565b910152565b5f5b8381106109ba5750505f910152565b81810151838201526020016109ab565b906020916109e3815180928185528580860191016109a9565b601f01601f1916010190565b602081519101519060208110610a03575090565b5f199060200360031b1b1690565b90602080835192838152019201905f5b818110610a2e5750505090565b8251805167ffffffffffffffff16855260209081015164ffffffffff168186015260409094019390920191600101610a21565b906001600160a01b03825116815260208201511515602082015264ffffffffff60408301511660408201526001600160a01b03606083015116606082015260e080610adc610ac0608086015161010060808701526101008601906109ca565b60a086015160a086015260c086015185820360c08701526109ca565b93015115159101529056fe610160806040523461042857611572803803809161001d8285610560565b833981019080820390608082126104285780516001600160401b03811161042857810190610100828503126104285760405161010081016001600160401b038111828210176105355760405282516001600160a01b038116810361042857815261008960208401610583565b6020820190815261009c60408501610590565b60408301908152606085015194906001600160a01b0386168603610428576060840195865260808201516001600160401b03811161042857886100e09184016105de565b6080850190815260a08381015190860190815260c084015190999192916001600160401b0382116104285761011c60e09161012a9387016105de565b9460c0880195865201610583565b9360e0860194855260208701519560018060a01b038716998a880361042857604090603f1901126104285760408051989089016001600160401b0381118a8210176105355761018d9160609160405261018560408201610590565b8b5201610590565b9860208901998a52855151602081116105495750515f80546001600160a01b0319166001600160a01b0392831617905590511660805251151560a0525164ffffffffff1660c0525180519097906001600160401b03811161053557600154600181811c9116801561052b575b602082101461051757601f81116104b4575b506020601f821160011461044857819064ffffffffff98999a5f9261043d575b50508160011b915f199060031b1c1916176001555b5160e052516040516102736020828161026281830196878151938492016105bd565b81010301601f198101835282610560565b519051906020811061042c575b50610100525115156101205261014052511669ffffffffff0000000000600454925160281b169160018060501b031916171760045560018060a01b0360805116604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526102f0606486610560565b84519082855af16102ff610623565b816103f1575b50806103e7575b156103a2575b604051610e4e90816107248239608051818181610409015281816106440152610ae6015260a05181818161067501526109fe015260c0518181816101520152818161095501528181610c250152610d80015260e05181818161029f015261059d01526101005181610caa01526101205181818161069f01526109c201526101405181818161019501526107b40152f35b6103da6103df936040519063095ea7b360e01b602083015260248201525f6044820152604481526103d4606482610560565b82610652565b610652565b5f8080610312565b50803b151561030c565b8051801592508215610406575b50505f610305565b81925090602091810103126104285760206104219101610583565b5f806103fe565b5f80fd5b5f199060200360031b1b165f610280565b015190505f8061022b565b601f1982169960015f52815f209a5f5b81811061049c57509164ffffffffff999a9b91846001959410610484575b505050811b01600155610240565b01515f1960f88460031b161c191690555f8080610476565b838301518d556001909c019b60209384019301610458565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c8101916020841061050d575b601f0160051c01905b818110610502575061020b565b5f81556001016104f5565b90915081906104ec565b634e487b7160e01b5f52602260045260245ffd5b90607f16906101f9565b634e487b7160e01b5f52604160045260245ffd5b630f39860960e01b5f52600452602060245260445ffd5b601f909101601f19168101906001600160401b0382119082101761053557604052565b5190811515820361042857565b519064ffffffffff8216820361042857565b6001600160401b03811161053557601f01601f191660200190565b5f5b8381106105ce5750505f910152565b81810151838201526020016105bf565b81601f820112156104285780516105f4816105a2565b926106026040519485610560565b818452602082840101116104285761062091602080850191016105bd565b90565b3d1561064d573d90610634826105a2565b916106426040519384610560565b82523d5f602084013e565b606090565b5f8061067a9260018060a01b03169360208151910182865af1610673610623565b90836106c5565b80519081151591826106a2575b50506106905750565b635274afe760e01b5f5260045260245ffd5b81925090602091810103126104285760206106bd9101610583565b155f80610687565b906106e957508051156106da57805190602001fd5b630a12f52160e11b5f5260045ffd5b8151158061071a575b6106fa575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156106f256fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314610c94575080631686c90914610a2357806316c3549d146109e75780631bfd6814146109ab5780633bfe03a81461097d5780633f31ae3f1461042d5780634800d97f146103ea57806349fc73dd146102e65780634e390d3e146102c257806351e75e8b1461028857806375829def146101d357806390e64d13146101b95780639e93e57714610176578063bb4b573414610135578063ce516507146100f55763f851a440146100cc575f80fd5b346100f1575f3660031901126100f15760206001600160a01b035f5416604051908152f35b5f80fd5b346100f15760203660031901126100f157602061012b60043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100f1575f3660031901126100f157602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f1575f3660031901126100f15760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f1575f3660031901126100f157602061012b610d78565b346100f15760203660031901126100f1576101ec610d24565b5f546001600160a01b03811633810361025957506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100f1575f3660031901126100f15760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100f1575f3660031901126100f157602064ffffffffff60035416604051908152f35b346100f1575f3660031901126100f1576040515f6001548060011c906001811680156103e0575b6020831081146103cc578285529081156103a8575060011461034a575b6103468361033a81850382610d56565b60405191829182610cdd565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061038e5750909150810160200161033a61032a565b919260018160209254838588010152019101909291610376565b60ff191660208086019190915291151560051b8401909101915061033a905061032a565b634e487b7160e01b5f52602260045260245ffd5b91607f169161030d565b346100f1575f3660031901126100f15760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f15760803660031901126100f1576004356024356001600160a01b0381168091036100f157604435916fffffffffffffffffffffffffffffffff83168093036100f1576064359067ffffffffffffffff82116100f157366023830112156100f157816004013567ffffffffffffffff81116100f1578060051b92602484820101903682116100f1576040516020810190858252876040820152886060820152606081526104de608082610d56565b51902060405160208101918252602081526104fa604082610d56565b51902092610506610d78565b6109265761052b8560ff6001918060081c5f526002602052161b60405f205416151590565b6108fa5761053f6020604051970187610d56565b8552602401602085015b8282106108ea57505050935f945b83518610156105995760208660051b85010151908181105f14610588575f52602052600160405f205b950194610557565b905f52602052600160405f20610580565b84907f0000000000000000000000000000000000000000000000000000000000000000036108c25760035464ffffffffff8116156108a8575b508260081c5f52600260205260405f20600160ff85161b81541790556001600160a01b035f54169160405161060681610d3a565b5f81525f602082015260405193610100850185811067ffffffffffffffff8211176108945760405284526020840183815260408501838152606086017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815260808701907f00000000000000000000000000000000000000000000000000000000000000001515825260a08801927f000000000000000000000000000000000000000000000000000000000000000015158452604051946106cf86610d3a565b60045464ffffffffff8116875260281c64ffffffffff16602087015260c08a0195865260e08a01968752604051997fab167ccc000000000000000000000000000000000000000000000000000000008b52516001600160a01b031660048b0152516001600160a01b031660248a0152516fffffffffffffffffffffffffffffffff166044890152516001600160a01b03166064880152511515608487015251151560a486015251805164ffffffffff1660c48601526020015164ffffffffff1660e48501525180516001600160a01b03166101048501526020015161012484015282807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165a925f61014492602095f1928315610889575f93610831575b50907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d60406020958594825191825287820152a3604051908152f35b939250906020843d602011610881575b8161084e60209383610d56565b810103126100f15792519192907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d6107f5565b3d9150610841565b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b64ffffffffff19164264ffffffffff1617600355836105d2565b7ffe365d76000000000000000000000000000000000000000000000000000000005f5260045ffd5b8135815260209182019101610549565b847fcd4c86cc000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f99657b41000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b346100f1575f3660031901126100f157604060045464ffffffffff825191818116835260281c166020820152f35b346100f1575f3660031901126100f15760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100f1575f3660031901126100f15760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100f15760403660031901126100f157610a3c610d24565b6024356fffffffffffffffffffffffffffffffff81168091036100f1576001600160a01b035f5416338103610259575064ffffffffff6003541680151580610c5f575b80610c50575b610bf657506040515f806001600160a01b0360208401957fa9059cbb000000000000000000000000000000000000000000000000000000008752169485602485015284604485015260448452610adc606485610d56565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15610bea573d67ffffffffffffffff811161089457610b4f9160405191610b3f6020601f19601f8401160184610d56565b82523d5f602084013e5b83610db5565b8051908115159182610bc6575b5050610b9b57507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100f157602001518015908115036100f1578480610b5c565b610b4f90606090610b49565b7f6df0cfdb000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b50610c59610d78565b15610a85565b5062093a80810164ffffffffff8111610c805764ffffffffff164211610a7f565b634e487b7160e01b5f52601160045260245ffd5b346100f1575f3660031901126100f157610346907f000000000000000000000000000000000000000000000000000000000000000060208201526020815261033a604082610d56565b9190916020815282518060208301525f5b818110610d0e575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201610cee565b600435906001600160a01b03821682036100f157565b6040810190811067ffffffffffffffff82111761089457604052565b90601f8019910116810190811067ffffffffffffffff82111761089457604052565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610dad575090565b905042101590565b90610df25750805115610dca57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580610e38575b610e03575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15610dfb56fea164736f6c634300081a000a610180806040523461044857611b53803803809161001d82856106ab565b83398101906060818303126104485780516001600160401b03811161044857810161010081840312610448576040519061010082016001600160401b038111838210176105025760405280516001600160a01b0381168103610448578252610087602082016106ce565b916020810192835261009b604083016106db565b60408201908152606083015193906001600160a01b0385168503610448576060830194855260808401516001600160401b03811161044857876100df918601610729565b916080840192835260a08501519360a0810194855260c086015160018060401b0381116104485760e06101178b610125938a01610729565b9760c08401988952016106ce565b60e082019081526020890151989097906001600160a01b038a168a03610448576040810151906001600160401b03821161044857018a601f82011215610448578051906001600160401b0382116105025760209b8c6040519d8e61018e828760051b01826106ab565b858152019360061b8301019181831161044857602001925b82841061064f5750505050865151602081116106385750515f80546001600160a01b0319166001600160a01b0392831617905590511660805251151560a0525164ffffffffff1660c052518051906001600160401b0382116105025760015490600182811c9216801561062e575b602083101461061a5781601f8493116105ac575b50602090601f8311600114610546575f9261053b575b50508160011b915f199060031b1c1916176001555b5160e05251604051610286602082816102758183019687815193849201610708565b81010301601f1981018352826106ab565b519051906020811061052a575b506101005251151561012052610140528051905f915f915b81831061044c57836101605260018060a01b036080511660018060a01b03610140511690604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526102ff6064866106ab565b84519082855af161030e610782565b81610411575b5080610407575b156103c2575b6040516112d0908161088382396080518181816105590152818161088e0152610e8e015260a0518181816108b80152610daf015260c0518181816102a101528181610d0901528181610fcd0152611114015260e0518181816103ef01526107260152610100518161103e0152610120518181816108ea0152610d7301526101405181818161011f01526109d00152610160518181816102e5015261060a0152f35b6103fa6103ff936040519063095ea7b360e01b602083015260248201525f6044820152604481526103f46064826106ab565b826107b1565b6107b1565b808080610321565b50803b151561031b565b8051801592508215610426575b505084610314565b819250906020918101031261044857602061044191016106ce565b848061041e565b5f80fd5b91929091906001600160401b03610463858461076e565b5151166001600160401b03918216019081116105165792610484818361076e565b519060045491680100000000000000008310156105025760018301806004558310156104ee5760019260045f5260205f200190838060401b038151166cffffffffff00000000000000006020845493015160401b1691858060681b031916171790550191906102ab565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f199060200360031b1b165f610293565b015190505f8061023e565b60015f9081528281209350601f198516905b818110610594575090846001959493921061057c575b505050811b01600155610253565b01515f1960f88460031b161c191690555f808061056e565b92936020600181928786015181550195019301610558565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c81019160208510610610575b90601f859493920160051c01905b8181106106025750610228565b5f81558493506001016105f5565b90915081906105e7565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610214565b630f39860960e01b5f52600452602060245260445ffd5b6040848303126104485760408051919082016001600160401b03811183821017610502576040528451906001600160401b038216820361044857826020926040945261069c8388016106db565b838201528152019301926101a6565b601f909101601f19168101906001600160401b0382119082101761050257604052565b5190811515820361044857565b519064ffffffffff8216820361044857565b6001600160401b03811161050257601f01601f191660200190565b5f5b8381106107195750505f910152565b818101518382015260200161070a565b81601f8201121561044857805161073f816106ed565b9261074d60405194856106ab565b818452602082840101116104485761076b9160208085019101610708565b90565b80518210156104ee5760209160051b010190565b3d156107ac573d90610793826106ed565b916107a160405193846106ab565b82523d5f602084013e565b606090565b5f806107d99260018060a01b03169360208151910182865af16107d2610782565b9083610824565b8051908115159182610801575b50506107ef5750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261044857602061081c91016106ce565b155f806107e6565b90610848575080511561083957805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580610879575b610859575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561085156fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314611028575080631686c90914610dd457806316c3549d14610d985780631bfd681414610d5c5780633f31ae3f1461057d5780634800d97f1461053a57806349fc73dd146104365780634e390d3e1461041257806351e75e8b146103d857806375829def1461032357806390e64d1314610309578063936c63d9146102c5578063bb4b573414610284578063bf4ed03f14610183578063ce51650714610143578063da792468146101005763f851a440146100d7575f80fd5b346100fc575f3660031901126100fc5760206001600160a01b035f5416604051908152f35b5f80fd5b346100fc575f3660031901126100fc5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fc5760203660031901126100fc57602061017960043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100fc575f3660031901126100fc5760045461019f81611149565b906101ad60405192836110ea565b80825260045f9081526020830191907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b835b838310610247578486604051918291602083019060208452518091526040830191905f5b818110610211575050500390f35b8251805167ffffffffffffffff16855260209081015164ffffffffff168186015286955060409094019390920191600101610203565b600160208192604051610259816110ce565b64ffffffffff865467ffffffffffffffff8116835260401c16838201528152019201920191906101df565b346100fc575f3660031901126100fc57602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fc575f3660031901126100fc57602060405167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fc575f3660031901126100fc57602061017961110c565b346100fc5760203660031901126100fc5761033c6110b8565b5f546001600160a01b0381163381036103a957506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100fc575f3660031901126100fc5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100fc575f3660031901126100fc57602064ffffffffff60035416604051908152f35b346100fc575f3660031901126100fc576040515f6001548060011c90600181168015610530575b60208310811461051c578285529081156104f8575060011461049a575b6104968361048a818503826110ea565b60405191829182611071565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106104de5750909150810160200161048a61047a565b9192600181602092548385880101520191019092916104c6565b60ff191660208086019190915291151560051b8401909101915061048a905061047a565b634e487b7160e01b5f52602260045260245ffd5b91607f169161045d565b346100fc575f3660031901126100fc5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fc5760803660031901126100fc57600435602435906001600160a01b0382168092036100fc57604435916001600160801b038316918284036100fc576064359367ffffffffffffffff85116100fc57366023860112156100fc5784600401359467ffffffffffffffff86116100fc5760248660051b8201013681116100fc5767ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016670de0b6b3a76400008103610d3157506040516020810190858252866040820152876060820152606081526106606080826110ea565b519020604051602081019182526020815261067c6040826110ea565b5190209161068861110c565b610cda576106ad8560ff6001918060081c5f526002602052161b60405f205416151590565b610cae576106ba88611149565b976106c8604051998a6110ea565b8852602401602088015b828210610c9e57505050925f935b8651851015610722576106f38588611161565b519081811015610711575f52602052600160405f205b9401936106e0565b905f52602052600160405f20610709565b85907f000000000000000000000000000000000000000000000000000000000000000003610c765760035464ffffffffff811615610c5c575b506004549261076984611149565b9361077760405195866110ea565b80855260045f9081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b602087015b838310610c1f57505050505f84516107bd81611149565b956107cb60405197886110ea565b818752601f196107da83611149565b015f5b818110610bfc5750505f905b828210610b275750506001600160801b038216848111610b13578411610ae8575b5050508360081c5f52600260205260405f20600160ff86161b81541790556001600160a01b035f541692604051610840816110ce565b5f81525f60208201526040519161010083019583871067ffffffffffffffff881117610ad4576001600160a01b039660409492939452815260208101918583526040820185815260608301887f00000000000000000000000000000000000000000000000000000000000000001681528860808501917f0000000000000000000000000000000000000000000000000000000000000000151583526001600160801b0360a08701947f00000000000000000000000000000000000000000000000000000000000000001515865260c0880196875260e08801998a526040519c8d997f897f362b000000000000000000000000000000000000000000000000000000008b52602060048c0152816101448c019a511660248c0152511660448a0152511660648801525116608486015251151560a485015251151560c4840152519061012060e48401528151809152602061016484019201905f5b818110610a9f57505050819060208094516001600160a01b03815116610104850152015161012483015203815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1928315610a94575f93610a3c575b50907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d60406020958594825191825287820152a3604051908152f35b939250906020843d602011610a8c575b81610a59602093836110ea565b810103126100fc5792519192907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d610a00565b3d9150610a4c565b6040513d5f823e3d90fd5b825180516001600160801b0316855260209081015164ffffffffff168186015289955060409094019390920191600101610999565b634e487b7160e01b5f52604160045260245ffd5b6001600160801b0391610aff83925f190188611161565b51930316818351160116905284808061080a565b634e487b7160e01b5f52600160045260245ffd5b9092610b4867ffffffffffffffff610b3f8685611161565b51511687611189565b6001600160801b038111610bd1576001600160801b038091169164ffffffffff6020610b748887611161565b5101511660405190610b85826110ce565b8482526020820152610b97878c611161565b52610ba2868b611161565b5016016001600160801b038111610bbd5792600101906107e9565b634e487b7160e01b5f52601160045260245ffd5b7f4916adce000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b602090604051610c0b816110ce565b5f81525f8382015282828c010152016107dd565b600160208192604051610c31816110ce565b64ffffffffff865467ffffffffffffffff8116835260401c16838201528152019201920191906107a6565b64ffffffffff19164264ffffffffff16176003558461075b565b7ffe365d76000000000000000000000000000000000000000000000000000000005f5260045ffd5b81358152602091820191016106d2565b847fcd4c86cc000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f99657b41000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b7f36d385ef000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346100fc575f3660031901126100fc5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100fc575f3660031901126100fc5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100fc5760403660031901126100fc57610ded6110b8565b6024356001600160801b0381168091036100fc576001600160a01b035f54163381036103a9575064ffffffffff6003541680151580611007575b80610ff8575b610f9e57506040515f806001600160a01b0360208401957fa9059cbb000000000000000000000000000000000000000000000000000000008752169485602485015284604485015260448452610e846064856110ea565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15610f92573d67ffffffffffffffff8111610ad457610ef79160405191610ee76020601f19601f84011601846110ea565b82523d5f602084013e5b83611237565b8051908115159182610f6e575b5050610f4357507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100fc57602001518015908115036100fc578480610f04565b610ef790606090610ef1565b7f6df0cfdb000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b5061100161110c565b15610e2d565b5062093a80810164ffffffffff8111610bbd5764ffffffffff164211610e27565b346100fc575f3660031901126100fc57610496907f000000000000000000000000000000000000000000000000000000000000000060208201526020815261048a6040826110ea565b9190916020815282518060208301525f5b8181106110a2575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201611082565b600435906001600160a01b03821682036100fc57565b6040810190811067ffffffffffffffff821117610ad457604052565b90601f8019910116810190811067ffffffffffffffff821117610ad457604052565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081611141575090565b905042101590565b67ffffffffffffffff8111610ad45760051b60200190565b80518210156111755760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b9091905f198382098382029182808310920391808303921461122657670de0b6b3a76400008210156111f6577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b90611274575080511561124c57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806112ba575b611285575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561127d56fea164736f6c634300081a000aa164736f6c634300081a000a"; + hex"608034609357601f61577238819003918201601f19168301916001600160401b03831184841017609757808492602094604052833981010312609357516001600160a01b038116908190036093575f80546001600160a01b0319168217815560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36156c690816100ac8239f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c8063070a6b8414610b46578063145e9edb14610b29578063294f73bf14610ad057806345aa93571461075a5780634d7c0f111461068757806375829def14610600578063b3ee17cc146101d2578063f2555278146100a55763f851a4401461007c575f80fd5b346100a1575f3660031901126100a15760206001600160a01b035f5416604051908152f35b5f80fd5b346100a15760403660031901126100a1576004356001600160a01b0381168091036100a1576024356001600160a01b0381168091036100a1576001600160a01b035f54163381036101a3575060205f916024604051809481937f164e68de0000000000000000000000000000000000000000000000000000000083528760048401525af1908115610198575f91610166575b506040519081527f9b5d61c5cfb8ae3875898f5500bd74e04af45a87127b30a4a3d68bf16958047860203392a3005b90506020813d602011610190575b8161018160209383610d24565b810103126100a1575182610137565b3d9150610174565b6040513d5f823e3d90fd5b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100a1576101003660031901126100a15760043567ffffffffffffffff81116100a157610204903690600401610dc2565b6024356001600160a01b038116918282036100a157610221610e83565b610229610e92565b91610232610d46565b9060a4359267ffffffffffffffff84116100a157366023850112156100a157836004013567ffffffffffffffff811161054f576040519461027960208360051b0187610d24565b8186526024602087019260061b820101903682116100a157602401915b8183106105a2575050508351905f915f905b8082106105635750508251906020840151866040860151926060870151906040519b8c80602081019460208652604082016102e291610ec2565b03601f19810182526102f391610d24565b60808901519260a08a015160405181819251908160208401916020019161031992610ea1565b81010380825261032c9060200182610d24565b61033590610ee7565b906040519e8f80602081019860208a526040820161035291610f77565b03601f198101825261036391610d24565b60405198899860208a019b3360601b8d526bffffffffffffffffffffffff199060601b1660348b015260d81b6001600160d81b03191660488a01526bffffffffffffffffffffffff199060601b16604d890152519081606189016103c692610ea1565b860193606185015260818401526bffffffffffffffffffffffff199060601b1660a18301521515998a60f81b60b583015215159a8b60f81b60b683015264ffffffffff89169860d81b6001600160d81b03191660b783015251918260bc830161042e92610ea1565b0160610103605b01601f19810182526104479082610d24565b51902060015460405190611e2e908183019083821067ffffffffffffffff83111761054f57839261388c843960e0825260c06104b08d61048a60e086018b610f09565b9060208601528c60408601528d60608601528a608086015284810360a08601528b610f77565b92015203905ff58015610198576020977f332a019da0fba197fab04e82d49dae180458832766349abd4d0875f255dfedbe9561050c956001600160a01b0361052d9416998a996040519889986101208a526101208a0190610f09565b948d89015260408801526060870152608086015284820360a0860152610f77565b9060c083015260c43560e083015260e4356101008301520390a2604051908152f35b634e487b7160e01b5f52604160045260245ffd5b9092865184101561058e5760019064ffffffffff6020808760051b8b010151015116019301906102a8565b634e487b7160e01b5f52603260045260245ffd5b6040833603126100a157604051906040820182811067ffffffffffffffff82111761054f5760405283359067ffffffffffffffff821682036100a15782602092604094526105f1838701610d5a565b83820152815201920191610296565b346100a15760203660031901126100a1576004356001600160a01b0381168091036100a1575f546001600160a01b0381163381036101a357507fffffffffffffffffffffffff0000000000000000000000000000000000000000829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346100a15760203660031901126100a15760043567ffffffffffffffff81116100a157366023820112156100a15780600401359067ffffffffffffffff82116100a1573660248360061b830101116100a1575f90815b8383101561073b5760248360061b830101359067ffffffffffffffff82168092036100a15767ffffffffffffffff160167ffffffffffffffff8111610727576001909201916106dd565b634e487b7160e01b5f52601160045260245ffd5b602090670de0b6b3a764000067ffffffffffffffff6040519216148152f35b346100a1576101203660031901126100a15760043567ffffffffffffffff81116100a15761078c903690600401610dc2565b6024356001600160a01b038116918282036100a1576107a9610e83565b906107b2610e92565b9160603660831901126100a157604051906060820182811067ffffffffffffffff82111761054f576040526107e5610d46565b825260a43564ffffffffff811681036100a157602083015260c43564ffffffffff811681036100a157604083015282519060208401516040850151916060860151976040519182602081019a60208c526040820161084291610ec2565b03601f19810184526108549084610d24565b60808801519160a089015160405181819251908160208401916020019161087a92610ea1565b81010380825261088d9060200182610d24565b61089690610ee7565b6040519b60208d01956108c8878c64ffffffffff60408092828151168552826020820151166020860152015116910152565b60608e526108d760808f610d24565b60405198899860208a019b3360601b8d526bffffffffffffffffffffffff199060601b1660348b015260d81b6001600160d81b03191660488a01526bffffffffffffffffffffffff199060601b16604d8901525190816061890161093a92610ea1565b860193606185015260818401526bffffffffffffffffffffffff199060601b1660a18301521515978860f81b60b58301521515988960f81b60b683015251918260b7830161098792610ea1565b0160610103605601601f19810182526109a09082610d24565b519020600154604051906117db908183019083821067ffffffffffffffff83111761054f5783926120b18439610100825260e06109e1610100840189610f09565b928b60208201528960408201528a6060820152610a20608082018964ffffffffff60408092828151168552826020820151166020860152015116910152565b015203905ff591821561019857602095610ab3610a7b936001600160a01b037f845a4c1d0848b2ab1afaa55c1dda984f2fecb1007925c78b45b73f557f95325d96169788976040519687966101208852610120880190610f09565b948b87015260408601526060850152608084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b60e43560e0830152610104356101008301520390a2604051908152f35b346100a15760203660031901126100a1576004356001600160a01b035f54163381036101a35750806001556040519081527f7ddad2fcbe59f6ef4aa0bb369d1349aebf41976346ef8dbdc0ff8a92c21bd35860203392a2005b346100a1575f3660031901126100a1576020600154604051908152f35b346100a15760603660031901126100a15760043567ffffffffffffffff81116100a157610b77903690600401610dc2565b80516001600160d81b0319610c7660406061602086015182870151606088015190845191610bc283610bb460208201936020855289830190610ec2565b03601f198101855284610d24565b610c5b60808b015193610c0460a08d0151610bff60208b5183610bee8295518092858086019101610ea1565b81010301601f198101835282610d24565b610ee7565b9388519a8b97602089019d8e3360601b90526bffffffffffffffffffffffff199060601b1660348a015260d81b1660488801526bffffffffffffffffffffffff199060601b16604d87015251809287870190610ea1565b83019184830152608182015203016020810184520182610d24565b519020600154604051906110e9908183019083821067ffffffffffffffff83111761054f578392610fc88439604082526020610cb56040840188610f09565b92015203905ff58015610198576020917f6c8ff1a6e3a223daee8bc86092060b16475c557888c1b051617185a6ebb453256001600160a01b03610d0a9316928392604051918291606083526060830190610f09565b6024358783015260443560408301520390a2604051908152f35b90601f8019910116810190811067ffffffffffffffff82111761054f57604052565b6084359064ffffffffff821682036100a157565b359064ffffffffff821682036100a157565b81601f820112156100a15780359067ffffffffffffffff821161054f5760405192610da1601f8401601f191660200185610d24565b828452602083830101116100a157815f926020809301838601378301015290565b919060c0838203126100a1576040519060c0820182811067ffffffffffffffff82111761054f57604052819380356001600160a01b03811681036100a1578352610e0e60208201610d5a565b602084015260408101356001600160a01b03811681036100a1576040840152606081013567ffffffffffffffff81116100a15782610e4d918301610d6c565b60608401526080810135608084015260a08101359167ffffffffffffffff83116100a15760a092610e7e9201610d6c565b910152565b6044359081151582036100a157565b6064359081151582036100a157565b5f5b838110610eb25750505f910152565b8181015183820152602001610ea3565b90602091610edb81518092818552858086019101610ea1565b601f01601f1916010190565b602081519101519060208110610efb575090565b5f199060200360031b1b1690565b610f74916001600160a01b03825116815264ffffffffff60208301511660208201526001600160a01b03604083015116604082015260a0610f59606084015160c0606085015260c0840190610ec2565b926080810151608084015201519060a0818403910152610ec2565b90565b90602080835192838152019201905f5b818110610f945750505090565b8251805167ffffffffffffffff16855260209081015164ffffffffff168186015260409094019390920191600101610f8756fe61014080604052346103a5576110e9803803809161001d82856103a9565b83398101906040818303126103a55780516001600160401b0381116103a55781019060c0828403126103a5576040519160c083016001600160401b0381118482101761037a5760405280516001600160a01b03811681036103a5578352602081015164ffffffffff811681036103a557602084019081526040820151936001600160a01b03851685036103a5576040810194855260608301516001600160401b0381116103a557866100d09185016103ed565b92606082019384526080810151966080830197885260a082015160018060401b0381116103a55761010192016103ed565b94602060a0830195878752015195516020811161038e5750515f80546001600160a01b0319166001600160a01b039283161790559051166080525164ffffffffff1660a0525180519093906001600160401b03811161037a57600154600181811c91168015610370575b602082101461035c57601f81116102f9575b50602094601f8211600114610296579481929394955f9261028b575b50508160011b915f199060031b1c1916176001555b5160e052516040516101e1602082816101d081830196878151938492016103cc565b81010301601f1981018352826103a9565b519051906020811061027a575b50610100523360c05261012052604051610ca7908161044282396080518181816103f50152818161062a0152610811015260a051818181610181015281816107370152818161089f0152610b07015260c05181818161077e015261093d015260e05181818161028b01526105af015261010051816109fa01526101205181818161014101526104af0152f35b5f199060200360031b1b165f6101ee565b015190505f80610199565b601f1982169560015f52805f20915f5b8881106102e1575083600195969798106102c9575b505050811b016001556101ae565b01515f1960f88460031b161c191690555f80806102bb565b919260206001819286850151815501940192016102a6565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c81019160208410610352575b601f0160051c01905b818110610347575061017d565b5f815560010161033a565b9091508190610331565b634e487b7160e01b5f52602260045260245ffd5b90607f169061016b565b634e487b7160e01b5f52604160045260245ffd5b6371935f2960e11b5f52600452602060245260445ffd5b5f80fd5b601f909101601f19168101906001600160401b0382119082101761037a57604052565b5f5b8381106103dd5750505f910152565b81810151838201526020016103ce565b81601f820112156103a55780516001600160401b03811161037a5760405192610420601f8301601f1916602001856103a9565b818452602082840101116103a55761043e91602080850191016103cc565b9056fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146109e457508063164e68de1461090e5780631686c909146107a25780632dd310001461075f5780633f31ae3f146104195780634800d97f146103d657806349fc73dd146102d25780634e390d3e146102ae57806351e75e8b1461027457806375829def146101bf57806390e64d13146101a5578063bb4b573414610164578063bba72cd31461012a578063ce516507146100ea5763f851a440146100c1575f80fd5b346100e6575f3660031901126100e65760206001600160a01b035f5416604051908152f35b5f80fd5b346100e65760203660031901126100e657602061012060043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100e6575f3660031901126100e65760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100e6575f3660031901126100e657602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100e6575f3660031901126100e6576020610120610aff565b346100e65760203660031901126100e6576101d8610a74565b5f546001600160a01b03811633810361024557506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100e6575f3660031901126100e65760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100e6575f3660031901126100e657602064ffffffffff60035416604051908152f35b346100e6575f3660031901126100e6576040515f6001548060011c906001811680156103cc575b6020831081146103b8578285529081156103945750600114610336575b6103328361032681850382610a8a565b60405191829182610a2d565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061037a57509091508101602001610326610316565b919260018160209254838588010152019101909291610362565b60ff191660208086019190915291151560051b840190910191506103269050610316565b634e487b7160e01b5f52602260045260245ffd5b91607f16916102f9565b346100e6575f3660031901126100e65760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b60803660031901126100e657600435602435906001600160a01b038216918281036100e657604435926fffffffffffffffffffffffffffffffff84168094036100e6576064359367ffffffffffffffff85116100e657366023860112156100e657846004013567ffffffffffffffff81116100e6578060051b95602487820101903682116100e6576104a9610aff565b610708577f00000000000000000000000000000000000000000000000000000000000000008034106106d957506104f78760ff6001918060081c5f526002602052161b60405f205416151590565b6106ad57604051602081019088825286604082015285606082015260608152610521608082610a8a565b519020604051602081019182526020815261053d604082610a8a565b5190209261055160206040519a018a610a8a565b8852602401602088015b82821061069d57505050925f935b86518510156105ab5760208560051b88010151908181105f1461059a575f52602052600160405f205b940193610569565b905f52602052600160405f20610592565b85907f000000000000000000000000000000000000000000000000000000000000000003610675578261064e7f1dcd2362ae467d43bf31cbcac0526c0958b23eb063e011ab49a5179c839ed9a99460409460035464ffffffffff81161561065b575b508460081c5f526002602052855f20600160ff87161b81541790557f0000000000000000000000000000000000000000000000000000000000000000610b3c565b82519182526020820152a2005b64ffffffffff19164264ffffffffff16176003558861060d565b7fb4f06787000000000000000000000000000000000000000000000000000000005f5260045ffd5b813581526020918201910161055b565b867febe6f30d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fa164c6b4000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b7fdf4bae05000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b346100e6575f3660031901126100e65760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100e65760403660031901126100e6576107bb610a74565b602435906fffffffffffffffffffffffffffffffff82168092036100e6576001600160a01b035f5416338103610245575064ffffffffff60035416801515806108d9575b806108ca575b610870575061083582827f0000000000000000000000000000000000000000000000000000000000000000610b3c565b7f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b03805f5416936040519586521693a3005b7fe2e40a0c000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b506108d3610aff565b15610805565b5062093a80810164ffffffffff81116108fa5764ffffffffff1642116107ff565b634e487b7160e01b5f52601160045260245ffd5b346100e65760203660031901126100e6576004356001600160a01b0381168091036100e6576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168033036109b5575047905f80808085855af1610977610ac0565b501561098857602082604051908152f35b7e534073000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e3ddeed000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100e6575f3660031901126100e657610332907f0000000000000000000000000000000000000000000000000000000000000000602082015260208152610326604082610a8a565b9190916020815282518060208301525f5b818110610a5e575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201610a3e565b600435906001600160a01b03821682036100e657565b90601f8019910116810190811067ffffffffffffffff821117610aac57604052565b634e487b7160e01b5f52604160045260245ffd5b3d15610afa573d9067ffffffffffffffff8211610aac5760405191610aef601f8201601f191660200184610a8a565b82523d5f602084013e565b606090565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610b34575090565b905042101590565b5f610ba9926001600160a01b038293604051968260208901947fa9059cbb000000000000000000000000000000000000000000000000000000008652166024890152604488015260448752610b92606488610a8a565b1694519082865af1610ba2610ac0565b9083610c0e565b8051908115159182610bea575b5050610bbf5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100e657602001518015908115036100e6575f80610bb6565b90610c4b5750805115610c2357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580610c91575b610c5c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15610c5456fea164736f6c634300081a000a6101a0806040523461046c576117db803803809161001d82856105aa565b8339810190808203610100811261046c5781516001600160401b03811161046c5782019160c08385031261046c576040519160c083016001600160401b0381118482101761057f5760405283516001600160a01b038116810361046c578352610088602085016105cd565b6020840190815260408501519091906001600160a01b038116810361046c576040850190815260608601516001600160401b03811161046c57876100cd91880161061b565b95606086019687526080810151976080870198895260a082015160018060401b03811161046c576100fe920161061b565b60a0860190815260208501516001600160a01b038116979092909188840361046c5761012c60408801610660565b92606061013a818a01610660565b96607f19011261046c5760405196606088016001600160401b0381118982101761057f5760405261016d60808a016105cd565b885261017b60a08a016105cd565b99602089019a8b5260e061019160c08c016105cd565b9a60408b019b8c52015194845151602081116105935750515f80546001600160a01b0319166001600160a01b039283161790559051166080525164ffffffffff1660a052518051909a906001600160401b03811161057f57600154600181811c91168015610575575b602082101461056157601f81116104fe575b506020601f821160011461048c57819064ffffffffff9a9b9c9d5f92610481575b50508160011b915f199060031b1c1916176001555b5160e052516040516102756020828161026481830196878151938492016105fa565b81010301601f1981018352826105aa565b5190519060208110610470575b50610100523360c0526101205261014052610160526101805251166effffffffff0000000000000000000069ffffffffff0000000000600454945160281b16925160501b169260018060781b03191617171760045560018060a01b0360805116604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526103126064866105aa565b84519082855af161032161066d565b81610435575b508061042b575b156103e6575b60405161106d908161076e823960805181818161049e0152818161076f0152610c4b015260a0518181816101ad01528181610aa201528181610d4b0152610f9f015260c051818181610ae90152610de9015260e051818181610334015261065601526101005181610ea601526101205181818161016d01526105560152610140518181816107a00152610b6001526101605181818161022a01526108c80152610180518181816107ca0152610b240152f35b61041e610423936040519063095ea7b360e01b602083015260248201525f6044820152604481526104186064826105aa565b8261069c565b61069c565b5f8080610334565b50803b151561032e565b805180159250821561044a575b50505f610327565b819250906020918101031261046c5760206104659101610660565b5f80610442565b5f80fd5b5f199060200360031b1b165f610282565b015190505f8061022d565b601f1982169c60015f52815f209d5f5b8181106104e157509164ffffffffff9b9c9d9e918460019594106104c9575b505050811b01600155610242565b01515f1960f88460031b161c191690555f80806104bb565b919e8f60016020928684930151815501940192019e91929e61049c565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c81019160208410610557575b601f0160051c01905b81811061054c575061020c565b5f815560010161053f565b9091508190610536565b634e487b7160e01b5f52602260045260245ffd5b90607f16906101fa565b634e487b7160e01b5f52604160045260245ffd5b6371935f2960e11b5f52600452602060245260445ffd5b601f909101601f19168101906001600160401b0382119082101761057f57604052565b519064ffffffffff8216820361046c57565b6001600160401b03811161057f57601f01601f191660200190565b5f5b83811061060b5750505f910152565b81810151838201526020016105fc565b81601f8201121561046c578051610631816105df565b9261063f60405194856105aa565b8184526020828401011161046c5761065d91602080850191016105fa565b90565b5190811515820361046c57565b3d15610697573d9061067e826105df565b9161068c60405193846105aa565b82523d5f602084013e565b606090565b5f806106c49260018060a01b03169360208151910182865af16106bd61066d565b908361070f565b80519081151591826106ec575b50506106da5750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261046c5760206107079101610660565b155f806106d1565b90610733575080511561072457805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580610764575b610744575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561073c56fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314610e9057508063164e68de14610dba5780631686c90914610b8557806316c3549d14610b495780631bfd681414610b0d5780632dd3100014610aca5780633f31ae3f146104c25780634800d97f1461047f57806349fc73dd1461037b5780634e390d3e1461035757806351e75e8b1461031d57806375829def1461026857806390e64d131461024e5780639e93e5771461020b578063b0604a26146101d1578063bb4b573414610190578063bba72cd314610156578063ce516507146101165763f851a440146100ed575f80fd5b34610112575f3660031901126101125760206001600160a01b035f5416604051908152f35b5f80fd5b3461011257602036600319011261011257602061014c60043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b34610112575f3660031901126101125760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610112575f36600319011261011257602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610112575f36600319011261011257606060045464ffffffffff604051918181168352818160281c16602084015260501c166040820152f35b34610112575f3660031901126101125760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610112575f36600319011261011257602061014c610f97565b3461011257602036600319011261011257610281610f20565b5f546001600160a01b0381163381036102ee57506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610112575f3660031901126101125760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610112575f36600319011261011257602064ffffffffff60035416604051908152f35b34610112575f366003190112610112576040515f6001548060011c90600181168015610475575b6020831081146104615782855290811561043d57506001146103df575b6103db836103cf81850382610f36565b60405191829182610ed9565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b808210610423575090915081016020016103cf6103bf565b91926001816020925483858801015201910190929161040b565b60ff191660208086019190915291151560051b840190910191506103cf90506103bf565b634e487b7160e01b5f52602260045260245ffd5b91607f16916103a2565b34610112575f3660031901126101125760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b608036600319011261011257600435602435906001600160a01b038216809203610112576044356fffffffffffffffffffffffffffffffff8116809103610112576064359067ffffffffffffffff8211610112573660238301121561011257816004013567ffffffffffffffff8111610112578060051b926024848201019036821161011257610550610f97565b610a73577f0000000000000000000000000000000000000000000000000000000000000000803410610a44575061059e8660ff6001918060081c5f526002602052161b60405f205416151590565b610a18576040516020810190878252886040820152856060820152606081526105c8608082610f36565b51902060405160208101918252602081526105e4604082610f36565b519020926105f86020604051970187610f36565b8552602401602085015b828210610a0857505050935f945b83518610156106525760208660051b85010151908181105f14610641575f52602052600160405f205b950194610610565b905f52602052600160405f20610639565b84907f0000000000000000000000000000000000000000000000000000000000000000036109e05760035464ffffffffff8116156109c6575b508060081c5f52600260205260405f20600160ff83161b8154179055604051926060840184811067ffffffffffffffff82111761099b5760405264ffffffffff602085015f81526004549082821680155f146109bf575082421687525b828260281c16806109af575b505081808751169160501c16011660408501526001600160a01b035f541693604051906040820182811067ffffffffffffffff82111761099b576040525f82525f602083015260405195610100870187811067ffffffffffffffff82111761099b5760405286526020860185815260408701848152606088017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815260808901917f00000000000000000000000000000000000000000000000000000000000000001515835260a08a01937f00000000000000000000000000000000000000000000000000000000000000001515855260c08b0195865260e08b019687526040519a7f53b15727000000000000000000000000000000000000000000000000000000008c52516001600160a01b031660048c0152516001600160a01b031660248b0152516fffffffffffffffffffffffffffffffff1660448a0152516001600160a01b03166064890152511515608488015251151560a487015251805164ffffffffff1660c4870152602081015164ffffffffff1660e48701526040015164ffffffffff166101048601525180516001600160a01b03166101248601526020015161014485015283807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165a925f61016492602095f1938415610990575f9461093c575b507f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d9160409182519182526020820152a3005b9093506020813d602011610988575b8161095860209383610f36565b810103126101125751927f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d610909565b3d915061094b565b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b87518416018316905286806106f4565b87526106e8565b64ffffffffff19164264ffffffffff16176003558361068b565b7fb4f06787000000000000000000000000000000000000000000000000000000005f5260045ffd5b8135815260209182019101610602565b857febe6f30d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fa164c6b4000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b7fdf4bae05000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b34610112575f3660031901126101125760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610112575f3660031901126101125760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b34610112575f3660031901126101125760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b3461011257604036600319011261011257610b9e610f20565b6024356fffffffffffffffffffffffffffffffff8116809103610112576001600160a01b035f54163381036102ee575064ffffffffff6003541680151580610d85575b80610d76575b610d1c5750604051610c815f806001600160a01b0360208501967fa9059cbb000000000000000000000000000000000000000000000000000000008852169586602486015285604486015260448552610c41606486610f36565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001694519082865af1610c7a610f58565b9083610fd4565b8051908115159182610cf8575b5050610ccd57507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126101125760200151801590811503610112578480610c8e565b7fe2e40a0c000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b50610d7f610f97565b15610be7565b5062093a80810164ffffffffff8111610da65764ffffffffff164211610be1565b634e487b7160e01b5f52601160045260245ffd5b34610112576020366003190112610112576004356001600160a01b038116809103610112576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803303610e61575047905f80808085855af1610e23610f58565b5015610e3457602082604051908152f35b7e534073000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e3ddeed000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610112575f366003190112610112576103db907f00000000000000000000000000000000000000000000000000000000000000006020820152602081526103cf604082610f36565b9190916020815282518060208301525f5b818110610f0a575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201610eea565b600435906001600160a01b038216820361011257565b90601f8019910116810190811067ffffffffffffffff82111761099b57604052565b3d15610f92573d9067ffffffffffffffff821161099b5760405191610f87601f8201601f191660200184610f36565b82523d5f602084013e565b606090565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610fcc575090565b905042101590565b906110115750805115610fe957805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611057575b611022575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561101a56fea164736f6c634300081a000a6101e0806040523461048c57611e2e803803809161001d82856106ef565b833981019060e08183031261048c5780516001600160401b03811161048c5781019060c08284031261048c576040519160c083016001600160401b038111848210176105465760405280516001600160a01b038116810361048c57835261008660208201610712565b6020840190815260408201516001600160a01b038116810361048c576040850190815260608301516001600160401b03811161048c57866100c8918501610760565b6060860190815260808085015190870190815260a085015191949091906001600160401b03821161048c576100ff91899101610760565b60a087019081526020860151949091906001600160a01b038616860361048c5761012b604088016107a5565b94610138606089016107a5565b9861014560808a01610712565b60a08a01519099906001600160401b03811161048c5781018c601f8201121561048c578051906001600160401b038211610546576040519d8e8360051b60200161018f90826106ef565b8381526020019260061b82016020019181831161048c57602001925b828410610693575050505060c00151958551516020811161067c5750515f80546001600160a01b0319166001600160a01b039283161790559051166080525164ffffffffff1660a052518051906001600160401b0382116105465760015490600182811c92168015610672575b602083101461065e5781601f8493116105f0575b50602090601f831160011461058a575f9261057f575b50508160011b915f199060031b1c1916176001555b5160e0525160405161028a60208281610279818301968781519384920161073f565b81010301601f1981018352826106ef565b519051906020811061056e575b50610100523360c052610120526101405261016052610180526101c0528051905f915f915b81831061049057836101a05260018060a01b036080511660018060a01b03610160511690604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526103106064866106ef565b84519082855af161031f6107c6565b81610455575b508061044b575b15610406575b60405161156790816108c78239608051818181610578015281816109290152610f55015260a0518181816102c001528181610db50152818161105501526112dd015260c051818181610dfc01526110f3015260e05181818161040e015261072e015261010051816111b001526101205181818161028001526106270152610140518181816109590152610e7301526101605181818161014b0152610aa70152610180518181816101cc01526107bc01526101a051818181610304015261078a01526101c0518181816109830152610e370152f35b61043e610443936040519063095ea7b360e01b602083015260248201525f6044820152604481526104386064826106ef565b826107f5565b6107f5565b808080610332565b50803b151561032c565b805180159250821561046a575b505084610325565b819250906020918101031261048c57602061048591016107a5565b8480610462565b5f80fd5b91929091906001600160401b036104a785846107b2565b5151166001600160401b039182160190811161055a57926104c881836107b2565b519060045491680100000000000000008310156105465760018301806004558310156105325760019260045f5260205f200190838060401b038151166cffffffffff00000000000000006020845493015160401b1691858060681b031916171790550191906102bc565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f199060200360031b1b165f610297565b015190505f80610242565b60015f9081528281209350601f198516905b8181106105d857509084600195949392106105c0575b505050811b01600155610257565b01515f1960f88460031b161c191690555f80806105b2565b9293602060018192878601518155019501930161059c565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c81019160208510610654575b90601f859493920160051c01905b818110610646575061022c565b5f8155849350600101610639565b909150819061062b565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610218565b6371935f2960e11b5f52600452602060245260445ffd5b60408483031261048c5760408051919082016001600160401b03811183821017610546576040528451906001600160401b038216820361048c5782602092604094526106e0838801610712565b838201528152019301926101ab565b601f909101601f19168101906001600160401b0382119082101761054657604052565b519064ffffffffff8216820361048c57565b6001600160401b03811161054657601f01601f191660200190565b5f5b8381106107505750505f910152565b8181015183820152602001610741565b81601f8201121561048c57805161077681610724565b9261078460405194856106ef565b8184526020828401011161048c576107a2916020808501910161073f565b90565b5190811515820361048c57565b80518210156105325760209160051b010190565b3d156107f0573d906107d782610724565b916107e560405193846106ef565b82523d5f602084013e565b606090565b5f8061081d9260018060a01b03169360208151910182865af16108166107c6565b9083610868565b8051908115159182610845575b50506108335750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261048c57602061086091016107a5565b155f8061082a565b9061088c575080511561087d57805190602001fd5b630a12f52160e11b5f5260045ffd5b815115806108bd575b61089d575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561089556fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde031461119a57508063164e68de146110c45780631686c90914610e9857806316c3549d14610e5c5780631bfd681414610e205780632dd3100014610ddd5780633f31ae3f1461059c5780634800d97f1461055957806349fc73dd146104555780634e390d3e1461043157806351e75e8b146103f757806375829def1461034257806390e64d1314610328578063936c63d9146102e4578063bb4b5734146102a3578063bba72cd314610269578063bf4ed03f146101f0578063ce36b335146101af578063ce5165071461016f578063da7924681461012c5763f851a44014610103575f80fd5b34610128575f3660031901126101285760206001600160a01b035f5416604051908152f35b5f80fd5b34610128575f3660031901126101285760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346101285760203660031901126101285760206101a560043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b34610128575f36600319011261012857602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f36600319011261012857610208611312565b6040518091602082016020835281518091526020604084019201905f5b818110610233575050500390f35b8251805167ffffffffffffffff16855260209081015164ffffffffff168186015286955060409094019390920191600101610225565b34610128575f3660031901126101285760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610128575f36600319011261012857602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f36600319011261012857602060405167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f3660031901126101285760206101a56112d5565b346101285760203660031901126101285761035b61122a565b5f546001600160a01b0381163381036103c857506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610128575f3660031901126101285760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610128575f36600319011261012857602064ffffffffff60035416604051908152f35b34610128575f366003190112610128576040515f6001548060011c9060018116801561054f575b60208310811461053b5782855290811561051757506001146104b9575b6104b5836104a98185038261125c565b604051918291826111e3565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106104fd575090915081016020016104a9610499565b9192600181602092548385880101520191019092916104e5565b60ff191660208086019190915291151560051b840190910191506104a99050610499565b634e487b7160e01b5f52602260045260245ffd5b91607f169161047c565b34610128575f3660031901126101285760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b608036600319011261012857600435602435906001600160a01b03821680920361012857604435906001600160801b03821691828103610128576064359367ffffffffffffffff851161012857366023860112156101285784600401359467ffffffffffffffff86116101285760248660051b820101368111610128576106216112d5565b610d86577f0000000000000000000000000000000000000000000000000000000000000000803410610d57575061066f8560ff6001918060081c5f526002602052161b60405f205416151590565b610d2b5760405160208101908682528460408201528760608201526060815261069960808261125c565b51902060405160208101918252602081526106b560408261125c565b519020916106c2886112bd565b976106d0604051998a61125c565b8852602401602088015b828210610d1b57505050925f935b865185101561072a576106fb85886113c7565b519081811015610719575f52602052600160405f205b9401936106e8565b905f52602052600160405f20610711565b85907f000000000000000000000000000000000000000000000000000000000000000003610cf35760035464ffffffffff811615610cd9575b508160081c5f52600260205260405f20600160ff84161b815417905567ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016670de0b6b3a76400008103610cae57507f000000000000000000000000000000000000000000000000000000000000000064ffffffffff8116610ca8575064ffffffffff4216935b6107fa611312565b90815191610807836112bd565b92610815604051948561125c565b808452601f19610824826112bd565b015f5b818110610c8557505061085661085167ffffffffffffffff610848856113a6565b51511687611420565b6113db565b64ffffffffff806020610868866113a6565b510151168a0116906001600160801b036040519161088583611240565b16918282526020820152610898866113a6565b526108a2856113a6565b50916001905b828210610bf15750506001600160801b038216858111610bdd578511610bb2575b5050506001600160a01b035f541690604051906108e582611240565b5f82525f602083015260405192610120840184811067ffffffffffffffff821117610b9e5760409492939452815260208101918683526040820197858952606083017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152608084017f00000000000000000000000000000000000000000000000000000000000000001515815260a08501917f00000000000000000000000000000000000000000000000000000000000000001515835260c086019364ffffffffff16845260e0860194855261010086019788526040519b8c977f32fbe22b0000000000000000000000000000000000000000000000000000000089526004890160209052610164890197516001600160a01b031660248a0152516001600160a01b03166044890152516001600160801b03166064880152516001600160a01b0316608487015251151560a486015251151560c48501525164ffffffffff1660e48401525190610104830161014090528151809152610184830191602001905f5b818110610b6957505050819060208094516001600160a01b03815116610124850152015161014483015203815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1938415610b5e575f94610b0a575b507f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d9160409182519182526020820152a3005b9093506020813d602011610b56575b81610b266020938361125c565b810103126101285751927f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d610ad7565b3d9150610b19565b6040513d5f823e3d90fd5b825180516001600160801b0316855260209081015164ffffffffff16818601528a955060409094019390920191600101610a70565b634e487b7160e01b5f52604160045260245ffd5b6001600160801b0391610bc983925f1901866113c7565b5193031681835116011690528580806108c9565b634e487b7160e01b5f52600160045260245ffd5b90926001600160801b03600191610c2061085167ffffffffffffffff610c1789886113c7565b5151168b611420565b9064ffffffffff806020610c375f198b018d6113c7565b51015116816020610c488b8a6113c7565b51015116011660405190610c5b82611240565b84841682526020820152610c6f888b6113c7565b52610c7a878a6113c7565b5001169301906108a8565b602090604051610c9481611240565b5f81525f8382015282828901015201610827565b936107f2565b7f36d385ef000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b64ffffffffff19164264ffffffffff161760035584610763565b7fb4f06787000000000000000000000000000000000000000000000000000000005f5260045ffd5b81358152602091820191016106da565b847febe6f30d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fa164c6b4000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b7fdf4bae05000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b34610128575f3660031901126101285760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f3660031901126101285760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b34610128575f3660031901126101285760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b3461012857604036600319011261012857610eb161122a565b6024356001600160801b038116809103610128576001600160a01b035f54163381036103c8575064ffffffffff600354168015158061108f575b80611080575b6110265750604051610f8b5f806001600160a01b0360208501967fa9059cbb000000000000000000000000000000000000000000000000000000008852169586602486015285604486015260448552610f4b60648661125c565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001694519082865af1610f8461127e565b90836114ce565b8051908115159182611002575b5050610fd757507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126101285760200151801590811503610128578480610f98565b7fe2e40a0c000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b506110896112d5565b15610ef1565b5062093a80810164ffffffffff81116110b05764ffffffffff164211610eeb565b634e487b7160e01b5f52601160045260245ffd5b34610128576020366003190112610128576004356001600160a01b038116809103610128576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001680330361116b575047905f80808085855af161112d61127e565b501561113e57602082604051908152f35b7e534073000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e3ddeed000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610128575f366003190112610128576104b5907f00000000000000000000000000000000000000000000000000000000000000006020820152602081526104a960408261125c565b9190916020815282518060208301525f5b818110611214575060409293505f838284010152601f8019910116010190565b80602080928701015160408286010152016111f4565b600435906001600160a01b038216820361012857565b6040810190811067ffffffffffffffff821117610b9e57604052565b90601f8019910116810190811067ffffffffffffffff821117610b9e57604052565b3d156112b8573d9067ffffffffffffffff8211610b9e57604051916112ad601f8201601f19166020018461125c565b82523d5f602084013e565b606090565b67ffffffffffffffff8111610b9e5760051b60200190565b64ffffffffff7f000000000000000000000000000000000000000000000000000000000000000016801515908161130a575090565b905042101590565b6004549061131f826112bd565b9161132d604051938461125c565b80835260045f9081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b602085015b8383106113695750505050565b60016020819260405161137b81611240565b64ffffffffff865467ffffffffffffffff8116835260401c168382015281520192019201919061135c565b8051156113b35760200190565b634e487b7160e01b5f52603260045260245ffd5b80518210156113b35760209160051b010190565b6001600160801b0381116113f5576001600160801b031690565b7f4916adce000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f19838209838202918280831092039180830392146114bd57670de0b6b3a764000082101561148d577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b9061150b57508051156114e357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611551575b61151c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561151456fea164736f6c634300081a000aa164736f6c634300081a000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = - hex"60808060405234601557615f8d908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bc5760403660031901126141bc576001600160a01b036004351680600435036141bc576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614824565b61032052614b1e565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f91614681575b506001600160a01b0361012791168061024052614c1a565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8576fffffffffffffffffffffffffffffffff915f91614662575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8575f90614625575b6101f59150614dbc565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f916145f6575b50610280516fffffffffffffffffffffffffffffffff1680156145e2576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614710565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d166154e9565b9701166154e9565b9801166154e9565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146ca565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146ca565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146ca565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ebc565b1690615022565b9061045a6001600160a01b036102405116614b1e565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b8576024915f916145c3575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b85764ffffffffff8091610521945f91614589575b50169116615318565b610340516103a05190939091906105ac600161054a6064610543818806615994565b96046154e9565b6020604051968261056489945180928580880191016146ca565b8301610578825180938580850191016146ca565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614710565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614575576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457557604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c0610160510151610160515190615a95565b60b76106ed5f615d85565b985f6102205260206102205261071560405161070c6102205182614710565b5f8152846157b3565b1561456b57601b60909a5b6107298c6154e9565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146ca565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146ca565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146ca565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146ca565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146ca565b0101631e17b39f60e11b838201520301601b19810184520182614710565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614710565b5f815260b7610a0c6001615d85565b98601b6028610a1a8c615e90565b610a2384615f08565b8082111561456457505b019a6107298c6154e9565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614710565b5f815260b7610a0c6002615d85565b8252602082015260286080610160510151604051610a9a6102205182614710565b5f81526108eb610ae46004600760276058610ab56003615d85565b9660b7610ac189615e90565b610aca8b615f08565b8082111561455c5750995b601b8c8c019a6107298c6154e9565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614fb5565b60608201526101006101208190526040516101a0819052610b949190614710565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614710565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614710565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614710565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614710565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c60146022611409615a5a565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146ca565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146ca565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614710565b61165585602361154c615a5a565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614710565b6117df60726023611664615a5a565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146ca565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146ca565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614710565b6117e7615a5a565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614710565b614fb5565b60e05261195561194f614d46565b856157b3565b938415614541575b5060c061010081905260405191906119759083614710565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614710565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432c57604051611dcd6102205182614710565b5f8152955b156141d957604051611de66101e082614710565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614710565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146ca565b840160c051519060328101826102205160c0510191612a0c926146ca565b016032018082518093610220510191612a24926146ca565b018082518093610220510191612a39926146ca565b018082518093610220510191612a4e926146ca565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614710565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146ca565b60805101815191826026830191610220510191612ada926146ca565b016026018082518093610220510191612af2926146ca565b0160a051519080826102205160a0510191612b0c926146ca565b0160e051519080826102205160e0510191612b26926146ca565b018082518093610220510191612b3b926146ca565b01610140515190808261022051610140510191612b57926146ca565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614710565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615cd9565b916040958651612bd78882614710565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614710565b612dc891615cd9565b928551612dd58782614710565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614710565b612fc08282615d40565b918651612fcd8882614710565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614710565b6131b791615d40565b9085516131c48782614710565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614710565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146ca565b840181519182604583019161022051019161342b926146ca565b016045018082518093610220510191613443926146ca565b018082518093610220510191613458926146ca565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614710565b610140820151916101a08101519060408101519060e001519361349d906154e9565b916134a7906154e9565b906134b1906154e9565b936134bb906154e9565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146ca565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146ca565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146ca565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146ca565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614710565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146ca565b84016080515190607b810182610220516080510191613855926146ca565b01607b01808251809361022051019161386d926146ca565b0191829151809361387d926146ca565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614710565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614710565b515a925f93928493fa61391c614793565b6102e0819052901580156103c0526141d15761022051818051810103126141bc5761022051015180151581036141bc575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141c7575f9161417b575b50600360236139be613ad693614b1e565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146ca565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146ca565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146ca565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614710565b6103205161026051610340516102405191939291613afc906001600160a01b0316614b1e565b613b076024356154e9565b6102a051909190156140ef5761010051875190613b249082614710565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c696572204c6f636b757020000000000000009052805190610220518101918060598a0190613c5c91856146ca565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546059918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460798201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609982015284516102205186019691613cea8260b583018a6146ca565b01605901605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146ca565b01605c0190601282016302e3716960e51b905251918260168301613d50926146ca565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146ca565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146ca565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146ca565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146ca565b01600a0103600401601f1981018452613e2f9084614710565b61032051613e3e6024356154e9565b855180916102205182019367029b0b13634b2b9160c51b8552805190816028850191610220510191613e6f926146ca565b8201602881017f2023000000000000000000000000000000000000000000000000000000000000905281519182602a830191610220510191613eb0926146ca565b0160280103600201601f1981018252613ec99082614710565b61038051613ed690615648565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f1d926146ca565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f57926146ca565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fba926146ca565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614024926146ca565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d19810182526002016140679082614710565b6102c081905261407690615648565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bc926146ca565b810103603d01601f19810183526140d39083614710565b5180916102205182526102205182016140eb916146eb565b0390f35b86516140fc608082614710565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c0575b6141968183614710565b816102205191810103126141bc57516001600160a01b03811681036141bc5760036139ad565b5f80fd5b503d61418c565b83513d5f823e3d90fd5b50600161394d565b6040516141e861012082614710565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433b6101c082614710565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b61455591945061454f614d81565b906157b3565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ab915060203d6020116145b1575b6145a38183614710565b81019061475a565b5f610518565b503d614599565b6040513d5f823e3d90fd5b6145dc915060203d6020116145b1576145a38183614710565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b614618915060203d60201161461e575b6146108183614710565b810190614732565b5f61024e565b503d614606565b506020813d60201161465a575b8161463f60209383614710565b810103126141bc575160058110156141bc576101f5906101eb565b3d9150614632565b61467b915060203d60201161461e576146108183614710565b5f610191565b90506020813d6020116146c2575b8161469c60209383614710565b810103126141bc57516001600160a01b03811681036141bc576001600160a01b0361010f565b3d915061468f565b5f5b8381106146db5750505f910152565b81810151838201526020016146cc565b90602091614704815180928185528580860191016146ca565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457557604052565b908160209103126141bc57516fffffffffffffffffffffffffffffffff811681036141bc5790565b908160209103126141bc575164ffffffffff811681036141bc5790565b67ffffffffffffffff811161457557601f01601f191660200190565b3d156147bd573d906147a482614777565b916147b26040519384614710565b82523d5f602084013e565b606090565b6020818303126141bc5780519067ffffffffffffffff82116141bc570181601f820112156141bc5780516147f581614777565b926148036040519485614710565b818452602082840101116141bc5761482191602080850191016146ca565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145b8575f92614afa575b5060409161489483516148648582614710565b600e81527f5341422d4c4f434b55502d4c494e0000000000000000000000000000000000006020820152826157b3565b8015614ab5575b156148db5750506148ae81519182614710565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491a83516148ea8582614710565b600e81527f5341422d4c4f434b55502d44594e0000000000000000000000000000000000006020820152826157b3565b8015614a70575b1561496157505061493481519182614710565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b6149a083516149708582614710565b600e81527f5341422d4c4f434b55502d5452410000000000000000000000000000000000006020820152826157b3565b8015614a2b575b156149e75750506149ba81519182614710565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a279083519384937f7498e3a50000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146eb565b0390fd5b50614a6b8351614a3b8582614710565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826157b3565b6149a7565b50614ab08351614a808582614710565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826157b3565b614921565b50614af58351614ac58582614710565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826157b3565b61489b565b614b179192503d805f833e614b0f8183614710565b8101906147c2565b905f614851565b6001600160a01b03168060405191614b37606084614710565b602a8352602083016040368237835115614c065760309053825160011015614c06576078602184015360295b60018111614ba45750614b74575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614c06577f3031323334353637383961626364656600000000000000000000000000000000901a614bdf83866157e0565b5360041c908015614bf2575f1901614b63565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614c3e602482614710565b51915afa614c4a614793565b90158015614d3a575b614cfe5780602080614c6a935183010191016147c2565b601e8151115f14614cb15750604051614c84604082614710565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614cba816157f1565b15614cc25790565b50604051614cd1604082614710565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614d0d604082614710565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614c53565b60405190614d55604083614710565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614d90604083614710565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614ea85760048103614dd65750614821614d81565b60038103614e1a5750604051614ded604082614710565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614e5e5750604051614e31604082614710565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614e6d57614821614d46565b604051614e7b604082614710565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614ef9602482614710565b51915afa614f05614793565b9080614f34575b15614f2f576020818051810103126141bc576020015160ff811681036141bc5790565b505f90565b506020815114614f0c565b60405190614f4e604083614710565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614f89604083614710565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614fe09493615011602061502095615003828096816040519c8d8b83829d519485930191016146ca565b8901614ff4825180938580850191016146ca565b010191828151948592016146ca565b0191828151948592016146ca565b0103601f198101845283614710565b565b9081156152f757806152e757505b806001811015615099575050615044614f7a565b614821600260206040518461506282965180928580860191016146ca565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b66038d7ea4c680001115615289576040519060a0820182811067ffffffffffffffff821117614575576040526020916040516150d58482614710565b5f8152815260409182516150e98482614710565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516151228482614710565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161515b8482614710565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516151958482614710565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561526f578451946151df8187614710565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061525c575050600160fd1b602786015250600884526152439061523d90615238602887614710565b6154e9565b91615994565b916005851015614c06576148219460051b015192614fb5565b818101830151878201840152820161520c565b9490915060016103e86064600a85040693049101946151c8565b50615292614f3f565b61482160086020604051846152b082965180928580860191016146ca565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614710565b600a0a9081156145e25704615030565b5050604051615307604082614710565b60018152600360fc1b602082015290565b6201518091030480615382575061532d614f7a565b614821600660206040518461534b82965180928580860191016146ca565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614710565b61270f81116154595760018103615415576148216153d76040516153a7604082614710565b600481527f20446179000000000000000000000000000000000000000000000000000000006020820152926154e9565b602060405193826153f186945180928580880191016146ca565b8301615405825180938580850191016146ca565b010103601f198101835282614710565b6148216153d7604051615429604082614710565b600581527f20446179730000000000000000000000000000000000000000000000000000006020820152926154e9565b50615462614f3f565b614821600a60206040518461548082965180928580860191016146ca565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614710565b906154c182614777565b6154ce6040519182614710565b82815280926154df601f1991614777565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000821015615620575b806d04ee2d6d415b85acef8100000000600a921015615605575b662386f26fc100008110156155f1575b6305f5e1008110156155e0575b6127108110156155d1575b60648110156155c3575b10156155b8575b600a6021615573600185016154b7565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156155b357600a9091615578565b505090565b600190910190615563565b60646002910493019261555c565b61271060049104930192615552565b6305f5e10060089104930192615547565b662386f26fc100006010910493019261553a565b6d04ee2d6d415b85acef81000000006020910493019261552a565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008104615510565b9081511561579d576040519161565f606084614710565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614bf257600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614bf2576156f59060021b6154b7565b90602082019080815182019560208701908151925f83525b88811061574f575050600393949596505251068060011461573d57600214615733575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761570d565b90506040516157ad602082614710565b5f815290565b90815181519081811493846157ca575b5050505090565b602092939450820120920120145f8080806157c3565b908151811015614c06570160200190565b8051905f5b82811061580557505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061583082846157e0565b5116600160fd1b811490600360fc1b8110158061596a575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161593f575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615914575b84156158ea575b5083156158e2575b5082156158da575b5081156158d2575b50156158cb576001016157f6565b5050505f90565b90505f6158bd565b91505f6158b5565b92505f6158ad565b7f2d000000000000000000000000000000000000000000000000000000000000001493505f6158a5565b7f7a00000000000000000000000000000000000000000000000000000000000000811115935061589e565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615873565b507f3900000000000000000000000000000000000000000000000000000000000000811115615848565b806159a857506040516157ad602082614710565b600a811015615a0e576159ba906154e9565b614821602260405180937f2e3000000000000000000000000000000000000000000000000000000000000060208301526159fd81518092602086860191016146ca565b81010301601f198101835282614710565b615a17906154e9565b614821602160405180937f2e0000000000000000000000000000000000000000000000000000000000000060208301526159fd81518092602086860191016146ca565b60405190615a69604083614710565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615cc957615aa3615a5a565b9061271003906127108211614bf257602e6061916050615ac5614821956154e9565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615b52815180926020868a0191016146ca565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615bd982518093602060a7850191016146ca565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615c3a825180936020607e850191016146ca565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614710565b50506040516157ad602082614710565b600d6150209193929360206040519582615cfc88945180928580880191016146ca565b830164010714051160dd1b8382015267029b0b13634b2b9160c51b6025820152615d2f8251809385602d850191016146ca565b01010301601f198101845283614710565b60056150209193929360206040519582615d6388945180928580880191016146ca565b830164010714051160dd1b83820152615d2f82518093856025850191016146ca565b6004811015614ea85780615dcf5750604051615da2604082614710565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615e135750604051615de6604082614710565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615e5557604051615e28604082614710565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615e63604082614710565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156158cb5790600d915f925f925b828410615eb65750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615eea88856157e0565b511614615f00575b820194600101929190615ea3565b859450615ef2565b5f90805180156158cb57906010915f925f925b828410615f2e575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615f6288856157e0565b511614615f78575b820194600101929190615f1b565b859450615f6a56fea164736f6c634300081a000a"; + hex"60808060405234601557615f8d908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bc5760403660031901126141bc576001600160a01b036004351680600435036141bc576103e06040525f61024081905260606102608190526102808290526102a08290526102c0819052610300819052610320819052610340819052610360819052610380526103a08190526103c0526102e08190526100b6906100ad600435614824565b61030052614b1e565b610320526102e0516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f91614681575b506001600160a01b0361012791168061024052614c1a565b610260526102e0516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8576fffffffffffffffffffffffffffffffff915f91614662575b5016610280526102e0516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8575f90614625575b6101f59150614dbc565b610360526102e0516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f916145f6575b50610280516fffffffffffffffffffffffffffffffff1680156145e2576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614710565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d166154e9565b9701166154e9565b9801166154e9565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146ca565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146ca565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146ca565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ebc565b1690615022565b9061045a6001600160a01b036102405116614b1e565b906020610240015190602460206001600160a01b0360a0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b8576024915f916145c3575b5060206001600160a01b0360a0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b85764ffffffffff8091610522945f91614589575b50169116615318565b610320516103a051939091906105ac600161054a6064610543818a06615994565b98046154e9565b602060405198826105648b945180928580880191016146ca565b8301610578825180938580850191016146ca565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810188520186614710565b61016061024001519561012061024001519760c061024001519560405161016052610140610160510161016051811067ffffffffffffffff821117614575576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457557604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260e06101605101516108ec6109cb60046007602760586106e3610100610160510151610160515190615a95565b60b76106ee5f615d85565b985f6102205260206102205261071660405161070d6102205182614710565b5f8152846157b3565b1561456b57601b60909a5b61072a8c6154e9565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161077081846102205188019801886146ca565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d382518093604284019061022051016146ca565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146ca565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109868251809361010f84019061022051016146ca565b0101661e17ba32bc3a1f60c91b838201526109ad82518093605f84019061022051016146ca565b0101631e17b39f60e11b838201520301601b19810184520182614710565b6101008301526101208201526101206101605101516108ec610a3960046007602760586040516109fe6102205182614710565b5f815260b7610a0d6001615d85565b98601b6028610a1b8c615e90565b610a2484615f08565b8082111561456457505b019a61072a8c6154e9565b61016083015261018082015260206101605101516108ec610a7a6004600760276058604051610a6b6102205182614710565b5f815260b7610a0d6002615d85565b8252602082015260286080610160510151604051610a9b6102205182614710565b5f81526108ec610ae56004600760276058610ab66003615d85565b9660b7610ac289615e90565b610acb8b615f08565b8082111561455c5750995b601b8c8c019a61072a8c6154e9565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7461010082015161016083015183519060a085015192614fb5565b60608201526101006101208190526040516101a0819052610b959190614710565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf7610200516101e051614710565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d638183614710565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119426118bd6073606b60405196610eec6101c05189614710565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113516101805160a051614710565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193d6014602261140a615a5a565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153f6025603589605e87519561022051890196611480818486018a6146ca565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e382518093609384019061022051016146ca565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614710565b61165685602361154d615a5a565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d6818486018a6146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161f82518093608e84019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614710565b6117e060726023611665615a5a565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f4815180928486019061022051016146ca565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173882609683018a6146ca565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614710565b6117e8615a5a565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119068251809360c484019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614710565b614fb5565b60e052611956611950614d46565b856157b3565b938415614541575b5060c061010081905260405191906119769083614710565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a538160c051614710565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432c57604051611dce6102205182614710565b5f8152955b156141d957604051611de76101e082614710565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b604051926120206107e085614710565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ef9183916032890191016146ca565b840160c051519060328101826102205160c0510191612a0d926146ca565b016032018082518093610220510191612a25926146ca565b018082518093610220510191612a3a926146ca565b018082518093610220510191612a4f926146ca565b01631e17b39f60e11b815203601b1981018452600401612a6f9084614710565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abf926146ca565b60805101815191826026830191610220510191612adb926146ca565b016026018082518093610220510191612af3926146ca565b0160a051519080826102205160a0510191612b0d926146ca565b0160e051519080826102205160e0510191612b27926146ca565b018082518093610220510191612b3c926146ca565b01610140515190808261022051610140510191612b58926146ca565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9a91614710565b6101605160a00151906101605160c00151916101605160400151906101605160600151612bc78583615cd9565b916040958651612bd78882614710565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614710565b612dc891615cd9565b928551612dd58782614710565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614710565b612fc08282615d40565b918651612fcd8882614710565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614710565b6131b791615d40565b9085516131c48782614710565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614710565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146ca565b840181519182604583019161022051019161342b926146ca565b016045018082518093610220510191613443926146ca565b018082518093610220510191613458926146ca565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614710565b610140820151916101a08101519060408101519060e001519361349d906154e9565b916134a7906154e9565b906134b1906154e9565b936134bb906154e9565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146ca565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146ca565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146ca565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146ca565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614710565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146ca565b84016080515190607b810182610220516080510191613855926146ca565b01607b01808251809361022051019161386d926146ca565b0191829151809361387d926146ca565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614710565b610380526102e0518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614710565b515a925f93928493fa61391c614793565b610340819052901580156103c0526141d15761022051818051810103126141bc5761022051015180151581036141bc575b15156102a052610260516102e05182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141c7575f9161417b575b50600360236139be613ad693614b1e565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146ca565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146ca565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146ca565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614710565b6103005161026051610320516102405191939291613afc906001600160a01b0316614b1e565b613b076024356154e9565b6102a051909190156140ef5761010051875190613b249082614710565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c696572204c6f636b757020000000000000009052805190610220518101918060598a0190613c5c91856146ca565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546059918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460798201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609982015284516102205186019691613cea8260b583018a6146ca565b01605901605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146ca565b01605c0190601282016302e3716960e51b905251918260168301613d50926146ca565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146ca565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146ca565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146ca565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146ca565b01600a0103600401601f1981018452613e2f9084614710565b61030051613e3e6024356154e9565b855180916102205182019367029b0b13634b2b9160c51b8552805190816028850191610220510191613e6f926146ca565b8201602881017f2023000000000000000000000000000000000000000000000000000000000000905281519182602a830191610220510191613eb0926146ca565b0160280103600201601f1981018252613ec99082614710565b61038051613ed690615648565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f1d926146ca565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f57926146ca565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fba926146ca565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614024926146ca565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d19810182526002016140679082614710565b6102c081905261407690615648565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bc926146ca565b810103603d01601f19810183526140d39083614710565b5180916102205182526102205182016140eb916146eb565b0390f35b86516140fc608082614710565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c0575b6141968183614710565b816102205191810103126141bc57516001600160a01b03811681036141bc5760036139ad565b5f80fd5b503d61418c565b83513d5f823e3d90fd5b50600161394d565b6040516141e861012082614710565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e00000000000000006101205182015290612010565b60405161433b6101c082614710565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd3565b61455591945061454f614d81565b906157b3565b925f61195e565b905099610ad6565b9050610a2e565b601b60d09a610721565b634e487b7160e01b5f52604160045260245ffd5b6145ab915060203d6020116145b1575b6145a38183614710565b81019061475a565b5f610519565b503d614599565b6040513d5f823e3d90fd5b6145dc915060203d6020116145b1576145a38183614710565b5f6104ba565b634e487b7160e01b5f52601260045260245ffd5b614618915060203d60201161461e575b6146108183614710565b810190614732565b5f61024e565b503d614606565b506020813d60201161465a575b8161463f60209383614710565b810103126141bc575160058110156141bc576101f5906101eb565b3d9150614632565b61467b915060203d60201161461e576146108183614710565b5f610191565b90506020813d6020116146c2575b8161469c60209383614710565b810103126141bc57516001600160a01b03811681036141bc576001600160a01b0361010f565b3d915061468f565b5f5b8381106146db5750505f910152565b81810151838201526020016146cc565b90602091614704815180928185528580860191016146ca565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457557604052565b908160209103126141bc57516fffffffffffffffffffffffffffffffff811681036141bc5790565b908160209103126141bc575164ffffffffff811681036141bc5790565b67ffffffffffffffff811161457557601f01601f191660200190565b3d156147bd573d906147a482614777565b916147b26040519384614710565b82523d5f602084013e565b606090565b6020818303126141bc5780519067ffffffffffffffff82116141bc570181601f820112156141bc5780516147f581614777565b926148036040519485614710565b818452602082840101116141bc5761482191602080850191016146ca565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145b8575f92614afa575b5060409161489483516148648582614710565b600e81527f5341422d4c4f434b55502d4c494e0000000000000000000000000000000000006020820152826157b3565b8015614ab5575b156148db5750506148ae81519182614710565b601581527f5361626c696572204c6f636b7570204c696e6561720000000000000000000000602082015290565b61491a83516148ea8582614710565b600e81527f5341422d4c4f434b55502d44594e0000000000000000000000000000000000006020820152826157b3565b8015614a70575b1561496157505061493481519182614710565b601681527f5361626c696572204c6f636b75702044796e616d696300000000000000000000602082015290565b6149a083516149708582614710565b600e81527f5341422d4c4f434b55502d5452410000000000000000000000000000000000006020820152826157b3565b8015614a2b575b156149e75750506149ba81519182614710565b601781527f5361626c696572204c6f636b7570205472616e63686564000000000000000000602082015290565b614a279083519384937f16ee429d0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146eb565b0390fd5b50614a6b8351614a3b8582614710565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826157b3565b6149a7565b50614ab08351614a808582614710565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826157b3565b614921565b50614af58351614ac58582614710565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826157b3565b61489b565b614b179192503d805f833e614b0f8183614710565b8101906147c2565b905f614851565b6001600160a01b03168060405191614b37606084614710565b602a8352602083016040368237835115614c065760309053825160011015614c06576078602184015360295b60018111614ba45750614b74575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614c06577f3031323334353637383961626364656600000000000000000000000000000000901a614bdf83866157e0565b5360041c908015614bf2575f1901614b63565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614c3e602482614710565b51915afa614c4a614793565b90158015614d3a575b614cfe5780602080614c6a935183010191016147c2565b601e8151115f14614cb15750604051614c84604082614710565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614cba816157f1565b15614cc25790565b50604051614cd1604082614710565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614d0d604082614710565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614c53565b60405190614d55604083614710565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614d90604083614710565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614ea85760048103614dd65750614821614d81565b60038103614e1a5750604051614ded604082614710565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614e5e5750604051614e31604082614710565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614e6d57614821614d46565b604051614e7b604082614710565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614ef9602482614710565b51915afa614f05614793565b9080614f34575b15614f2f576020818051810103126141bc576020015160ff811681036141bc5790565b505f90565b506020815114614f0c565b60405190614f4e604083614710565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614f89604083614710565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614fe09493615011602061502095615003828096816040519c8d8b83829d519485930191016146ca565b8901614ff4825180938580850191016146ca565b010191828151948592016146ca565b0191828151948592016146ca565b0103601f198101845283614710565b565b9081156152f757806152e757505b806001811015615099575050615044614f7a565b614821600260206040518461506282965180928580860191016146ca565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b66038d7ea4c680001115615289576040519060a0820182811067ffffffffffffffff821117614575576040526020916040516150d58482614710565b5f8152815260409182516150e98482614710565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516151228482614710565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161515b8482614710565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516151958482614710565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561526f578451946151df8187614710565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061525c575050600160fd1b602786015250600884526152439061523d90615238602887614710565b6154e9565b91615994565b916005851015614c06576148219460051b015192614fb5565b818101830151878201840152820161520c565b9490915060016103e86064600a85040693049101946151c8565b50615292614f3f565b61482160086020604051846152b082965180928580860191016146ca565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614710565b600a0a9081156145e25704615030565b5050604051615307604082614710565b60018152600360fc1b602082015290565b6201518091030480615382575061532d614f7a565b614821600660206040518461534b82965180928580860191016146ca565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614710565b61270f81116154595760018103615415576148216153d76040516153a7604082614710565b600481527f20446179000000000000000000000000000000000000000000000000000000006020820152926154e9565b602060405193826153f186945180928580880191016146ca565b8301615405825180938580850191016146ca565b010103601f198101835282614710565b6148216153d7604051615429604082614710565b600581527f20446179730000000000000000000000000000000000000000000000000000006020820152926154e9565b50615462614f3f565b614821600a60206040518461548082965180928580860191016146ca565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614710565b906154c182614777565b6154ce6040519182614710565b82815280926154df601f1991614777565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000821015615620575b806d04ee2d6d415b85acef8100000000600a921015615605575b662386f26fc100008110156155f1575b6305f5e1008110156155e0575b6127108110156155d1575b60648110156155c3575b10156155b8575b600a6021615573600185016154b7565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156155b357600a9091615578565b505090565b600190910190615563565b60646002910493019261555c565b61271060049104930192615552565b6305f5e10060089104930192615547565b662386f26fc100006010910493019261553a565b6d04ee2d6d415b85acef81000000006020910493019261552a565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008104615510565b9081511561579d576040519161565f606084614710565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614bf257600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614bf2576156f59060021b6154b7565b90602082019080815182019560208701908151925f83525b88811061574f575050600393949596505251068060011461573d57600214615733575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761570d565b90506040516157ad602082614710565b5f815290565b90815181519081811493846157ca575b5050505090565b602092939450820120920120145f8080806157c3565b908151811015614c06570160200190565b8051905f5b82811061580557505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061583082846157e0565b5116600160fd1b811490600360fc1b8110158061596a575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161593f575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615914575b84156158ea575b5083156158e2575b5082156158da575b5081156158d2575b50156158cb576001016157f6565b5050505f90565b90505f6158bd565b91505f6158b5565b92505f6158ad565b7f2d000000000000000000000000000000000000000000000000000000000000001493505f6158a5565b7f7a00000000000000000000000000000000000000000000000000000000000000811115935061589e565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615873565b507f3900000000000000000000000000000000000000000000000000000000000000811115615848565b806159a857506040516157ad602082614710565b600a811015615a0e576159ba906154e9565b614821602260405180937f2e3000000000000000000000000000000000000000000000000000000000000060208301526159fd81518092602086860191016146ca565b81010301601f198101835282614710565b615a17906154e9565b614821602160405180937f2e0000000000000000000000000000000000000000000000000000000000000060208301526159fd81518092602086860191016146ca565b60405190615a69604083614710565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615cc957615aa3615a5a565b9061271003906127108211614bf257602e6061916050615ac5614821956154e9565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615b52815180926020868a0191016146ca565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615bd982518093602060a7850191016146ca565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615c3a825180936020607e850191016146ca565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614710565b50506040516157ad602082614710565b600d6150209193929360206040519582615cfc88945180928580880191016146ca565b830164010714051160dd1b8382015267029b0b13634b2b9160c51b6025820152615d2f8251809385602d850191016146ca565b01010301601f198101845283614710565b60056150209193929360206040519582615d6388945180928580880191016146ca565b830164010714051160dd1b83820152615d2f82518093856025850191016146ca565b6004811015614ea85780615dcf5750604051615da2604082614710565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615e135750604051615de6604082614710565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615e5557604051615e28604082614710565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615e63604082614710565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156158cb5790600d915f925f925b828410615eb65750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615eea88856157e0565b511614615f00575b820194600101929190615ea3565b859450615ef2565b5f90805180156158cb57906010915f925f925b828410615f2e575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615f6288856157e0565b511614615f78575b820194600101929190615f1b565b859450615f6a56fea164736f6c634300081a000a"; uint256 public constant MAX_SEGMENT_COUNT = 500; uint256 public constant MAX_TRANCHE_COUNT = 500; diff --git a/src/periphery/SablierMerkleFactory.sol b/src/periphery/SablierMerkleFactory.sol index d37900bf3..7221a8955 100644 --- a/src/periphery/SablierMerkleFactory.sol +++ b/src/periphery/SablierMerkleFactory.sol @@ -64,7 +64,7 @@ contract SablierMerkleFactory is //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc ISablierMerkleFactory - function setSablierFee(uint256 fee) external onlyAdmin { + function setSablierFee(uint256 fee) external override onlyAdmin { // Effect: update the Sablier fee. sablierFee = fee; @@ -72,14 +72,12 @@ contract SablierMerkleFactory is } /// @inheritdoc ISablierMerkleFactory - function withdrawFees(address payable to, ISablierMerkleBase merkleLockup) external onlyAdmin { - uint256 feesAccrued = address(merkleLockup).balance; - + function withdrawFees(address payable to, ISablierMerkleBase merkleLockup) external override onlyAdmin { // Effect: call `withdrawFees` on the MerkleLockup contract. - merkleLockup.withdrawFees(to, feesAccrued); + uint256 fees = merkleLockup.withdrawFees(to); // Log the withdrawal. - emit WithdrawSablierFees(msg.sender, to, feesAccrued); + emit WithdrawSablierFees(msg.sender, to, fees); } /*////////////////////////////////////////////////////////////////////////// @@ -93,6 +91,7 @@ contract SablierMerkleFactory is uint256 recipientCount ) external + override returns (ISablierMerkleInstant merkleInstant) { // Hash the parameters to generate a salt. @@ -126,6 +125,7 @@ contract SablierMerkleFactory is uint256 recipientCount ) external + override returns (ISablierMerkleLL merkleLL) { // Hash the parameters to generate a salt. @@ -167,6 +167,7 @@ contract SablierMerkleFactory is uint256 recipientCount ) external + override returns (ISablierMerkleLT merkleLT) { // Calculate the sum of percentages and durations across all tranches. diff --git a/src/periphery/abstracts/SablierMerkleBase.sol b/src/periphery/abstracts/SablierMerkleBase.sol index c2dc9d82d..84f6a06f1 100644 --- a/src/periphery/abstracts/SablierMerkleBase.sol +++ b/src/periphery/abstracts/SablierMerkleBase.sol @@ -165,12 +165,14 @@ abstract contract SablierMerkleBase is } /// @inheritdoc ISablierMerkleBase - function withdrawFees(address payable to, uint256 feeAmount) external { + function withdrawFees(address payable to) external override returns (uint256 feeAmount) { // Check: the caller is the factory. if (msg.sender != FACTORY) { revert Errors.SablierMerkleBase_CallerNotFactory(FACTORY, msg.sender); } + feeAmount = address(this).balance; + // Effect: transfer the fees to the provided address. (bool success,) = to.call{ value: feeAmount }(""); diff --git a/src/periphery/interfaces/ISablierMerkleBase.sol b/src/periphery/interfaces/ISablierMerkleBase.sol index 96062f7a5..d433f4123 100644 --- a/src/periphery/interfaces/ISablierMerkleBase.sol +++ b/src/periphery/interfaces/ISablierMerkleBase.sol @@ -98,6 +98,6 @@ interface ISablierMerkleBase is IAdminable { /// - The caller must be the Factory contract. /// /// @param to The address to receive the Sablier fees. - /// @param feeAmount The fee amount to withdraw from the contract. - function withdrawFees(address payable to, uint256 feeAmount) external; + /// @return feeAmount The amount of ETH transferred to the provided address. + function withdrawFees(address payable to) external returns (uint256 feeAmount); } diff --git a/test/mocks/ReceiveEth.sol b/test/mocks/ReceiveEth.sol new file mode 100644 index 000000000..476416a20 --- /dev/null +++ b/test/mocks/ReceiveEth.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22; + +/// @dev This contract does not implement receive ether or fallback function. +contract ContractWithoutReceiveEth { } + +/// @dev This contract implements receive ether function. +contract ContractWithReceiveEth { + receive() external payable { } +} diff --git a/test/periphery/Periphery.t.sol b/test/periphery/Periphery.t.sol index 05281a3b2..461123f66 100644 --- a/test/periphery/Periphery.t.sol +++ b/test/periphery/Periphery.t.sol @@ -8,10 +8,27 @@ import { SablierMerkleLL } from "src/periphery/SablierMerkleLL.sol"; import { SablierMerkleLT } from "src/periphery/SablierMerkleLT.sol"; import { Base_Test } from "../Base.t.sol"; +import { ContractWithoutReceiveEth, ContractWithReceiveEth } from "../mocks/ReceiveEth.sol"; contract Periphery_Test is Base_Test { + /*////////////////////////////////////////////////////////////////////////// + TEST CONTRACTS + //////////////////////////////////////////////////////////////////////////*/ + + ContractWithoutReceiveEth internal contractWithoutReceiveEth; + ContractWithReceiveEth internal contractWithReceiveEth; + + /*////////////////////////////////////////////////////////////////////////// + SET-UP FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + function setUp() public virtual override { Base_Test.setUp(); + + contractWithoutReceiveEth = new ContractWithoutReceiveEth(); + contractWithReceiveEth = new ContractWithReceiveEth(); + vm.label({ account: address(contractWithoutReceiveEth), newLabel: "Contract Without Receive Eth" }); + vm.label({ account: address(contractWithReceiveEth), newLabel: "Contract With Receive Eth" }); } /*////////////////////////////////////////////////////////////////////////// diff --git a/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.t.sol b/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.t.sol new file mode 100644 index 000000000..18d547892 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.t.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; +import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; + +import { MerkleCampaign_Integration_Shared_Test } from "../../shared/MerkleCampaign.t.sol"; + +contract WithdrawFees_Integration_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + + // Set the `merkleBase` to the merkleLL contract to use it in the tests. + merkleBase = ISablierMerkleBase(merkleLL); + + // Claim to collect some fees. + resetPrank(users.recipient); + claim(); + } + + function test_RevertWhen_CallerNotAdmin() external { + resetPrank(users.eve); + + vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); + merkleFactory.withdrawFees(users.eve, merkleBase); + } + + function test_RevertWhen_ProvidedMerkleLockupNotValid() external whenCallerAdmin { + vm.expectRevert(); + merkleFactory.withdrawFees(users.eve, ISablierMerkleBase(users.eve)); + } + + modifier whenProvidedMerkleLockupValid() { + _; + } + + function test_WhenProvidedAddressNotContract() external whenCallerAdmin whenProvidedMerkleLockupValid { + uint256 previousToBalance = users.eve.balance; + + merkleFactory.withdrawFees(users.eve, merkleBase); + + // It should set the ETH balance to 0. + assertEq(address(merkleBase).balance, 0, "merkle lockup eth balance"); + // It should transfer fee collected in ETH to the provided address. + assertEq(users.eve.balance, previousToBalance + defaults.SABLIER_FEE(), "eth balance"); + } + + modifier whenProvidedAddressContract() { + _; + } + + function test_RevertWhen_ProvidedAddressNotImplementReceiveEth() + external + whenCallerAdmin + whenProvidedMerkleLockupValid + whenProvidedAddressContract + { + address payable noReceiveEth = payable(address(contractWithoutReceiveEth)); + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierMerkleBase_FeeWithdrawFailed.selector, noReceiveEth, address(merkleBase).balance + ) + ); + merkleFactory.withdrawFees(noReceiveEth, merkleBase); + } + + function test_WhenProvidedAddressImplementReceiveEth() + external + whenCallerAdmin + whenProvidedMerkleLockupValid + whenProvidedAddressContract + { + address payable receiveEth = payable(address(contractWithReceiveEth)); + + merkleFactory.withdrawFees(receiveEth, merkleBase); + + // It should set the ETH balance to 0. + assertEq(address(merkleBase).balance, 0, "merkle lockup eth balance"); + // It should transfer fee collected in ETH to the provided address. + assertEq(receiveEth.balance, defaults.SABLIER_FEE(), "eth balance"); + } +} diff --git a/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.tree b/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.tree new file mode 100644 index 000000000..58b83e6a7 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.tree @@ -0,0 +1,16 @@ +WithdrawFees_Integration_Test +├── when caller not admin +│ └── it should revert +└── when caller admin + ├── when provided merkle lockup not valid + │ └── it should revert + └── when provided merkle lockup valid + ├── when provided address not contract + │ ├── it should transfer fee collected in ETH to the provided address + │ └── it should set the ETH balance to 0 + └── when provided address contract + ├── when provided address not implement receive eth + │ └── it should revert + └── when provided address implement receive eth + ├── it should transfer fee collected in ETH to the provided address + └── it should set the ETH balance to 0 diff --git a/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol b/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol index 617617aff..1d9ea9749 100644 --- a/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol +++ b/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol @@ -7,6 +7,7 @@ import { Clawback_Integration_Test } from "../shared/clawback/clawback.t.sol"; import { GetFirstClaimTime_Integration_Test } from "../shared/get-first-claim-time/getFirstClaimTime.t.sol"; import { HasClaimed_Integration_Test } from "../shared/has-claimed/hasClaimed.t.sol"; import { HasExpired_Integration_Test } from "../shared/has-expired/hasExpired.t.sol"; +import { WithdrawFees_Integration_Test } from "../shared/withdraw-fees/withdrawFees.t.sol"; import { MerkleCampaign_Integration_Shared_Test } from "../shared/MerkleCampaign.t.sol"; /*////////////////////////////////////////////////////////////////////////// @@ -26,17 +27,14 @@ abstract contract MerkleInstant_Integration_Shared_Test is MerkleCampaign_Integr SHARED TESTS //////////////////////////////////////////////////////////////////////////*/ -contract Clawback_MerkleLInstant_Integration_Test is - Clawback_Integration_Test, - MerkleInstant_Integration_Shared_Test -{ +contract Clawback_MerkleInstant_Integration_Test is Clawback_Integration_Test, MerkleInstant_Integration_Shared_Test { function setUp() public override(Clawback_Integration_Test, MerkleInstant_Integration_Shared_Test) { Clawback_Integration_Test.setUp(); MerkleInstant_Integration_Shared_Test.setUp(); } } -contract GetFirstClaimTime_MerkleLInstant_Integration_Test is +contract GetFirstClaimTime_MerkleInstant_Integration_Test is GetFirstClaimTime_Integration_Test, MerkleInstant_Integration_Shared_Test { @@ -46,7 +44,7 @@ contract GetFirstClaimTime_MerkleLInstant_Integration_Test is } } -contract HasClaimed_MerkleLInstant_Integration_Test is +contract HasClaimed_MerkleInstant_Integration_Test is HasClaimed_Integration_Test, MerkleInstant_Integration_Shared_Test { @@ -56,7 +54,7 @@ contract HasClaimed_MerkleLInstant_Integration_Test is } } -contract HasExpired_MerkleLInstant_Integration_Test is +contract HasExpired_MerkleInstant_Integration_Test is HasExpired_Integration_Test, MerkleInstant_Integration_Shared_Test { @@ -65,3 +63,13 @@ contract HasExpired_MerkleLInstant_Integration_Test is MerkleInstant_Integration_Shared_Test.setUp(); } } + +contract WithdrawFees_MerkleInstant_Integration_Test is + WithdrawFees_Integration_Test, + MerkleInstant_Integration_Shared_Test +{ + function setUp() public override(WithdrawFees_Integration_Test, MerkleInstant_Integration_Shared_Test) { + WithdrawFees_Integration_Test.setUp(); + MerkleInstant_Integration_Shared_Test.setUp(); + } +} diff --git a/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol b/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol index 24b5fac7a..69774c03b 100644 --- a/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol @@ -7,6 +7,7 @@ import { Clawback_Integration_Test } from "../shared/clawback/clawback.t.sol"; import { GetFirstClaimTime_Integration_Test } from "../shared/get-first-claim-time/getFirstClaimTime.t.sol"; import { HasClaimed_Integration_Test } from "../shared/has-claimed/hasClaimed.t.sol"; import { HasExpired_Integration_Test } from "../shared/has-expired/hasExpired.t.sol"; +import { WithdrawFees_Integration_Test } from "../shared/withdraw-fees/withdrawFees.t.sol"; import { MerkleCampaign_Integration_Shared_Test } from "../shared/MerkleCampaign.t.sol"; /*////////////////////////////////////////////////////////////////////////// @@ -56,3 +57,10 @@ contract HasExpired_MerkleLL_Integration_Test is HasExpired_Integration_Test, Me MerkleLL_Integration_Shared_Test.setUp(); } } + +contract WithdrawFees_MerkleLL_Integration_Test is WithdrawFees_Integration_Test, MerkleLL_Integration_Shared_Test { + function setUp() public override(WithdrawFees_Integration_Test, MerkleLL_Integration_Shared_Test) { + WithdrawFees_Integration_Test.setUp(); + MerkleLL_Integration_Shared_Test.setUp(); + } +} diff --git a/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol b/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol index b9e042f8a..d53c6f740 100644 --- a/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol @@ -7,6 +7,7 @@ import { Clawback_Integration_Test } from "../shared/clawback/clawback.t.sol"; import { GetFirstClaimTime_Integration_Test } from "../shared/get-first-claim-time/getFirstClaimTime.t.sol"; import { HasClaimed_Integration_Test } from "../shared/has-claimed/hasClaimed.t.sol"; import { HasExpired_Integration_Test } from "../shared/has-expired/hasExpired.t.sol"; +import { WithdrawFees_Integration_Test } from "../shared/withdraw-fees/withdrawFees.t.sol"; import { MerkleCampaign_Integration_Shared_Test } from "../shared/MerkleCampaign.t.sol"; /*////////////////////////////////////////////////////////////////////////// @@ -56,3 +57,10 @@ contract HasExpired_MerkleLT_Integration_Test is HasExpired_Integration_Test, Me MerkleLT_Integration_Shared_Test.setUp(); } } + +contract WithdrawFees_MerkleLT_Integration_Test is WithdrawFees_Integration_Test, MerkleLT_Integration_Shared_Test { + function setUp() public override(WithdrawFees_Integration_Test, MerkleLT_Integration_Shared_Test) { + WithdrawFees_Integration_Test.setUp(); + MerkleLT_Integration_Shared_Test.setUp(); + } +} diff --git a/test/periphery/integration/merkle-campaign/shared/withdraw-fees/withdrawFees.t.sol b/test/periphery/integration/merkle-campaign/shared/withdraw-fees/withdrawFees.t.sol new file mode 100644 index 000000000..8456a8fb1 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/shared/withdraw-fees/withdrawFees.t.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors } from "src/periphery/libraries/Errors.sol"; + +import { MerkleCampaign_Integration_Shared_Test } from "../../shared/MerkleCampaign.t.sol"; + +abstract contract WithdrawFees_Integration_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + } + + function test_RevertWhen_CallerNotFactory() external { + // Set the caller to anything other than the factory. + resetPrank(users.admin); + + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierMerkleBase_CallerNotFactory.selector, address(merkleFactory), users.admin + ) + ); + merkleBase.withdrawFees(users.admin); + } + + modifier whenCallerFactory() { + // Claim to collect some fees. + claim(); + resetPrank(address(merkleFactory)); + _; + } + + function test_WhenProvidedAddressNotContract() external whenCallerFactory { + uint256 previousToBalance = users.admin.balance; + + merkleBase.withdrawFees(users.admin); + + // It should set the ETH balance to 0. + assertEq(address(merkleBase).balance, 0, "merkle lockup eth balance"); + // It should transfer fee collected in ETH to the provided address. + assertEq(users.admin.balance, previousToBalance + defaults.SABLIER_FEE(), "eth balance"); + } + + modifier whenProvidedAddressContract() { + _; + } + + function test_RevertWhen_ProvidedAddressNotImplementReceiveEth() + external + whenCallerFactory + whenProvidedAddressContract + { + address payable noReceiveEth = payable(address(contractWithoutReceiveEth)); + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierMerkleBase_FeeWithdrawFailed.selector, noReceiveEth, address(merkleBase).balance + ) + ); + merkleBase.withdrawFees(noReceiveEth); + } + + function test_WhenProvidedAddressImplementReceiveEth() external whenCallerFactory whenProvidedAddressContract { + address payable receiveEth = payable(address(contractWithReceiveEth)); + + merkleBase.withdrawFees(receiveEth); + + // It should set the ETH balance to 0. + assertEq(address(merkleBase).balance, 0, "merkle lockup eth balance"); + // It should transfer fee collected in ETH to the provided address. + assertEq(receiveEth.balance, defaults.SABLIER_FEE(), "eth balance"); + } +} diff --git a/test/periphery/integration/merkle-campaign/shared/withdraw-fees/withdrawFees.tree b/test/periphery/integration/merkle-campaign/shared/withdraw-fees/withdrawFees.tree new file mode 100644 index 000000000..b5839e6ac --- /dev/null +++ b/test/periphery/integration/merkle-campaign/shared/withdraw-fees/withdrawFees.tree @@ -0,0 +1,13 @@ +WithdrawFees_Integration_Test +├── when caller not factory +│ └── it should revert +└── when caller factory + ├── when provided address not contract + │ ├── it should transfer fee collected in ETH to the provided address + │ └── it should set the ETH balance to 0 + └── when provided address contract + ├── when provided address not implement receive eth + │ └── it should revert + └── when provided address implement receive eth + ├── it should transfer fee collected in ETH to the provided address + └── it should set the ETH balance to 0 diff --git a/test/utils/DeployOptimized.sol b/test/utils/DeployOptimized.sol index 5d50392ec..a39ed11e6 100644 --- a/test/utils/DeployOptimized.sol +++ b/test/utils/DeployOptimized.sol @@ -105,16 +105,21 @@ abstract contract DeployOptimized is StdCheats { } /// @dev Deploys {SablierMerkleFactory} from an optimized source compiled with `--via-ir`. - function deployOptimizedMerkleFactory() internal returns (ISablierMerkleFactory) { - return ISablierMerkleFactory(deployCode("out-optimized/SablierMerkleFactory.sol/SablierMerkleFactory.json")); + function deployOptimizedMerkleFactory(address initialAdmin) internal returns (ISablierMerkleFactory) { + return ISablierMerkleFactory( + deployCode("out-optimized/SablierMerkleFactory.sol/SablierMerkleFactory.json", abi.encode(initialAdmin)) + ); } /// @notice Deploys all Periphery contracts from an optimized source in the following order: /// /// 1. {SablierBatchLockup} /// 2. {SablierMerkleFactory} - function deployOptimizedPeriphery() internal returns (ISablierBatchLockup, ISablierMerkleFactory) { - return (deployOptimizedBatchLockup(), deployOptimizedMerkleFactory()); + function deployOptimizedPeriphery(address initialAdmin) + internal + returns (ISablierBatchLockup, ISablierMerkleFactory) + { + return (deployOptimizedBatchLockup(), deployOptimizedMerkleFactory(initialAdmin)); } /*////////////////////////////////////////////////////////////////////////// @@ -146,6 +151,6 @@ abstract contract DeployOptimized is StdCheats { { (nftDescriptor_, lockupDynamic_, lockupLinear_, lockupTranched_) = deployOptimizedCore(initialAdmin, maxSegmentCount, maxTrancheCount); - (batchLockup_, merkleFactory_) = deployOptimizedPeriphery(); + (batchLockup_, merkleFactory_) = deployOptimizedPeriphery(initialAdmin); } } diff --git a/test/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol index 31b9fa6ee..40355414c 100644 --- a/test/utils/Precompiles.t.sol +++ b/test/utils/Precompiles.t.sol @@ -103,7 +103,7 @@ contract Precompiles_Test is Base_Test { function test_DeployMerkleFactory() external onlyTestOptimizedProfile { address actualFactory = address(precompiles.deployMerkleFactory(users.admin)); - address expectedFactory = address(deployOptimizedMerkleFactory()); + address expectedFactory = address(deployOptimizedMerkleFactory(users.admin)); assertEq(actualFactory.code, expectedFactory.code, "bytecodes mismatch"); } @@ -112,7 +112,7 @@ contract Precompiles_Test is Base_Test { precompiles.deployPeriphery(users.admin); (ISablierBatchLockup expectedBatchLockup, ISablierMerkleFactory expectedMerkleFactory) = - deployOptimizedPeriphery(); + deployOptimizedPeriphery(users.admin); assertEq(address(actualBatchLockup).code, address(expectedBatchLockup).code, "bytecodes mismatch"); assertEq(address(actualMerkleFactory).code, address(expectedMerkleFactory).code, "bytecodes mismatch"); From 6eefaf9d387ad0ba8ca87ea36e2d3c6fba424984 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 10 Sep 2024 13:07:53 +0100 Subject: [PATCH 06/21] refactor: include merkleLockup address in WithdrawSablierFees event --- src/periphery/SablierMerkleFactory.sol | 2 +- src/periphery/abstracts/SablierMerkleBase.sol | 2 +- .../interfaces/ISablierMerkleFactory.sol | 4 +++- .../factory/withdraw-fees/withdrawFees.t.sol | 18 ++++++++++++++++++ .../factory/withdraw-fees/withdrawFees.tree | 6 ++++-- test/utils/Events.sol | 5 ++++- 6 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/periphery/SablierMerkleFactory.sol b/src/periphery/SablierMerkleFactory.sol index 7221a8955..c027a05df 100644 --- a/src/periphery/SablierMerkleFactory.sol +++ b/src/periphery/SablierMerkleFactory.sol @@ -77,7 +77,7 @@ contract SablierMerkleFactory is uint256 fees = merkleLockup.withdrawFees(to); // Log the withdrawal. - emit WithdrawSablierFees(msg.sender, to, fees); + emit WithdrawSablierFees({ admin: msg.sender, merkleLockup: merkleLockup, to: to, sablierFees: fees }); } /*////////////////////////////////////////////////////////////////////////// diff --git a/src/periphery/abstracts/SablierMerkleBase.sol b/src/periphery/abstracts/SablierMerkleBase.sol index 84f6a06f1..10cac68e9 100644 --- a/src/periphery/abstracts/SablierMerkleBase.sol +++ b/src/periphery/abstracts/SablierMerkleBase.sol @@ -64,10 +64,10 @@ abstract contract SablierMerkleBase is admin = params.initialAdmin; ASSET = params.asset; EXPIRATION = params.expiration; + FACTORY = msg.sender; ipfsCID = params.ipfsCID; MERKLE_ROOT = params.merkleRoot; NAME = bytes32(abi.encodePacked(params.name)); - FACTORY = msg.sender; SABLIER_FEE = sablierFee; } diff --git a/src/periphery/interfaces/ISablierMerkleFactory.sol b/src/periphery/interfaces/ISablierMerkleFactory.sol index f6179c245..54a925de3 100644 --- a/src/periphery/interfaces/ISablierMerkleFactory.sol +++ b/src/periphery/interfaces/ISablierMerkleFactory.sol @@ -61,7 +61,9 @@ interface ISablierMerkleFactory is IAdminable { event SetSablierFee(address indexed admin, uint256 sablierFee); /// @notice Emitted when the sablier fees are claimed by the sablier admin. - event WithdrawSablierFees(address indexed admin, address indexed to, uint256 sablierFees); + event WithdrawSablierFees( + address indexed admin, ISablierMerkleBase indexed merkleLockup, address to, uint256 sablierFees + ); /*////////////////////////////////////////////////////////////////////////// CONSTANT FUNCTIONS diff --git a/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.t.sol b/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.t.sol index 18d547892..b9b449bd5 100644 --- a/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.t.sol @@ -38,6 +38,15 @@ contract WithdrawFees_Integration_Test is MerkleCampaign_Integration_Shared_Test function test_WhenProvidedAddressNotContract() external whenCallerAdmin whenProvidedMerkleLockupValid { uint256 previousToBalance = users.eve.balance; + // It should emit {WithdrawSablierFees} event. + vm.expectEmit({ emitter: address(merkleFactory) }); + emit WithdrawSablierFees({ + admin: users.admin, + merkleLockup: merkleBase, + to: users.eve, + sablierFees: defaults.SABLIER_FEE() + }); + merkleFactory.withdrawFees(users.eve, merkleBase); // It should set the ETH balance to 0. @@ -73,6 +82,15 @@ contract WithdrawFees_Integration_Test is MerkleCampaign_Integration_Shared_Test { address payable receiveEth = payable(address(contractWithReceiveEth)); + // It should emit {WithdrawSablierFees} event. + vm.expectEmit({ emitter: address(merkleFactory) }); + emit WithdrawSablierFees({ + admin: users.admin, + merkleLockup: merkleBase, + to: receiveEth, + sablierFees: defaults.SABLIER_FEE() + }); + merkleFactory.withdrawFees(receiveEth, merkleBase); // It should set the ETH balance to 0. diff --git a/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.tree b/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.tree index 58b83e6a7..4f871faaf 100644 --- a/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.tree +++ b/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.tree @@ -7,10 +7,12 @@ WithdrawFees_Integration_Test └── when provided merkle lockup valid ├── when provided address not contract │ ├── it should transfer fee collected in ETH to the provided address - │ └── it should set the ETH balance to 0 + │ ├── it should set the ETH balance to 0 + │ └── it should emit {WithdrawSablierFees} event └── when provided address contract ├── when provided address not implement receive eth │ └── it should revert └── when provided address implement receive eth ├── it should transfer fee collected in ETH to the provided address - └── it should set the ETH balance to 0 + ├── it should set the ETH balance to 0 + └── it should emit {WithdrawSablierFees} event diff --git a/test/utils/Events.sol b/test/utils/Events.sol index c5b18c686..912447a62 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -7,6 +7,7 @@ import { ILockupNFTDescriptor } from "../../src/core/interfaces/ILockupNFTDescri import { ISablierLockupLinear } from "../../src/core/interfaces/ISablierLockupLinear.sol"; import { ISablierLockupTranched } from "../../src/core/interfaces/ISablierLockupTranched.sol"; import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../src/core/types/DataTypes.sol"; +import { ISablierMerkleBase } from "../../src/periphery/interfaces/ISablierMerkleBase.sol"; import { ISablierMerkleInstant } from "../../src/periphery/interfaces/ISablierMerkleInstant.sol"; import { ISablierMerkleLL } from "../../src/periphery/interfaces/ISablierMerkleLL.sol"; import { ISablierMerkleLT } from "../../src/periphery/interfaces/ISablierMerkleLT.sol"; @@ -140,5 +141,7 @@ abstract contract Events { event SetSablierFee(address indexed admin, uint256 sablierFee); - event WithdrawSablierFees(address indexed admin, address indexed to, uint256 sablierFees); + event WithdrawSablierFees( + address indexed admin, ISablierMerkleBase indexed merkleLockup, address to, uint256 sablierFees + ); } From 3135886820c5fb6f163091f21d0ba938eff9e6b1 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 10 Sep 2024 13:25:02 +0100 Subject: [PATCH 07/21] test: withdraw-fees in fork tests --- .../fork/merkle-campaign/MerkleInstant.t.sol | 35 +++++++++++++++++++ .../fork/merkle-campaign/MerkleLL.t.sol | 35 +++++++++++++++++++ .../fork/merkle-campaign/MerkleLT.t.sol | 35 +++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol index 5693a49d6..2f70864bf 100644 --- a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol @@ -3,6 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; +import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; import { ISablierMerkleInstant } from "src/periphery/interfaces/ISablierMerkleInstant.sol"; import { MerkleBase } from "src/periphery/types/DataTypes.sol"; import { MerkleBuilder } from "./../../../utils/MerkleBuilder.sol"; @@ -164,6 +165,21 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test { vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); } + // Expect call to `claim` with `sablierFee` as msg.value on the merkleInstant contract. + vm.expectCall( + address(vars.merkleInstant), + sablierFee, + abi.encodeCall( + ISablierMerkleBase.claim, + ( + vars.indexes[params.posBeforeSort], + vars.recipients[params.posBeforeSort], + vars.amounts[params.posBeforeSort], + vars.merkleProof + ) + ) + ); + expectCallToTransfer({ asset: FORK_ASSET, to: vars.recipients[params.posBeforeSort], @@ -195,5 +211,24 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test { emit Clawback({ to: params.admin, admin: params.admin, amount: vars.clawbackAmount }); vars.merkleInstant.clawback({ to: params.admin, amount: vars.clawbackAmount }); } + + /*////////////////////////////////////////////////////////////////////////// + WITHDRAW-FEE + //////////////////////////////////////////////////////////////////////////*/ + + // Make the factory admin as the caller. + resetPrank({ msgSender: users.admin }); + + vm.expectEmit({ emitter: address(merkleFactory) }); + emit WithdrawSablierFees({ + admin: users.admin, + merkleLockup: vars.merkleInstant, + to: users.admin, + sablierFees: sablierFee + }); + merkleFactory.withdrawFees({ to: payable(users.admin), merkleLockup: vars.merkleInstant }); + + assertEq(address(vars.merkleInstant).balance, 0, "merkle lockup ether balance"); + assertEq(users.admin.balance, sablierFee, "admin ether balance"); } } diff --git a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol index cb11afdc0..81d4e35a4 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol @@ -4,6 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; import { Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; +import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; import { MerkleBase } from "src/periphery/types/DataTypes.sol"; import { MerkleBuilder } from "./../../../utils/MerkleBuilder.sol"; @@ -175,6 +176,21 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); } + // Expect call to `claim` with `sablierFee` as msg.value on the merkleLL contract. + vm.expectCall( + address(vars.merkleLL), + sablierFee, + abi.encodeCall( + ISablierMerkleBase.claim, + ( + vars.indexes[params.posBeforeSort], + vars.recipients[params.posBeforeSort], + vars.amounts[params.posBeforeSort], + vars.merkleProof + ) + ) + ); + vars.merkleLL.claim{ value: sablierFee }({ index: vars.indexes[params.posBeforeSort], recipient: vars.recipients[params.posBeforeSort], @@ -217,5 +233,24 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { emit Clawback({ to: params.admin, admin: params.admin, amount: vars.clawbackAmount }); vars.merkleLL.clawback({ to: params.admin, amount: vars.clawbackAmount }); } + + /*////////////////////////////////////////////////////////////////////////// + WITHDRAW-FEE + //////////////////////////////////////////////////////////////////////////*/ + + // Make the factory admin as the caller. + resetPrank({ msgSender: users.admin }); + + vm.expectEmit({ emitter: address(merkleFactory) }); + emit WithdrawSablierFees({ + admin: users.admin, + merkleLockup: vars.merkleLL, + to: users.admin, + sablierFees: sablierFee + }); + merkleFactory.withdrawFees({ to: payable(users.admin), merkleLockup: vars.merkleLL }); + + assertEq(address(vars.merkleLL).balance, 0, "merkle lockup ether balance"); + assertEq(users.admin.balance, sablierFee, "admin ether balance"); } } diff --git a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol index b1bc5dc7d..d54b31d3a 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol @@ -4,6 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; +import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; import { MerkleBase } from "src/periphery/types/DataTypes.sol"; import { MerkleBuilder } from "./../../../utils/MerkleBuilder.sol"; @@ -178,6 +179,21 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); } + // Expect call to `claim` with `sablierFee` as msg.value on the merkleLL contract. + vm.expectCall( + address(vars.merkleLT), + sablierFee, + abi.encodeCall( + ISablierMerkleBase.claim, + ( + vars.indexes[params.posBeforeSort], + vars.recipients[params.posBeforeSort], + vars.amounts[params.posBeforeSort], + vars.merkleProof + ) + ) + ); + vars.merkleLT.claim{ value: sablierFee }({ index: vars.indexes[params.posBeforeSort], recipient: vars.recipients[params.posBeforeSort], @@ -224,5 +240,24 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { emit Clawback({ to: params.admin, admin: params.admin, amount: vars.clawbackAmount }); vars.merkleLT.clawback({ to: params.admin, amount: vars.clawbackAmount }); } + + /*////////////////////////////////////////////////////////////////////////// + WITHDRAW-FEE + //////////////////////////////////////////////////////////////////////////*/ + + // Make the factory admin as the caller. + resetPrank({ msgSender: users.admin }); + + vm.expectEmit({ emitter: address(merkleFactory) }); + emit WithdrawSablierFees({ + admin: users.admin, + merkleLockup: vars.merkleLT, + to: users.admin, + sablierFees: sablierFee + }); + merkleFactory.withdrawFees({ to: payable(users.admin), merkleLockup: vars.merkleLT }); + + assertEq(address(vars.merkleLT).balance, 0, "merkle lockup ether balance"); + assertEq(users.admin.balance, sablierFee, "admin ether balance"); } } From 90ca9d01eb697a283435a72844239d1863ad2ea7 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 10 Sep 2024 13:26:37 +0100 Subject: [PATCH 08/21] chore: add BUSL license to factory contract --- src/periphery/SablierMerkleFactory.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/periphery/SablierMerkleFactory.sol b/src/periphery/SablierMerkleFactory.sol index c027a05df..012136472 100644 --- a/src/periphery/SablierMerkleFactory.sol +++ b/src/periphery/SablierMerkleFactory.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.22; import { uUNIT } from "@prb/math/src/UD2x18.sol"; From 394cf2732f84a59deaa74a41a251a15e60df3533 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 11 Sep 2024 12:22:29 +0100 Subject: [PATCH 09/21] refactor: rename sablierFee to defaultSablierFee in factory --- src/periphery/SablierMerkleFactory.sol | 25 +++++++++----- .../interfaces/ISablierMerkleFactory.sol | 18 +++++----- test/Base.t.sol | 2 +- .../fork/merkle-campaign/MerkleInstant.t.sol | 2 +- .../fork/merkle-campaign/MerkleLL.t.sol | 2 +- .../fork/merkle-campaign/MerkleLT.t.sol | 2 +- .../merkle-campaign/MerkleCampaign.t.sol | 34 +++++++++++-------- .../merkle-campaign/factory/constructor.t.sol | 4 +-- .../setDefaultSablierFee.t.sol | 28 +++++++++++++++ .../setDefaultSablierFee.tree | 6 ++++ .../set-sablier-fee/setSablierFee.t.sol | 28 --------------- .../set-sablier-fee/setSablierFee.tree | 6 ---- .../factory/withdraw-fees/withdrawFees.t.sol | 8 ++--- .../merkle-campaign/instant/claim/claim.t.sol | 4 +-- .../merkle-campaign/instant/constructor.t.sol | 4 +-- .../merkle-campaign/ll/claim/claim.t.sol | 4 +-- .../merkle-campaign/ll/constructor.t.sol | 4 +-- .../merkle-campaign/lt/claim/claim.t.sol | 8 ++--- .../merkle-campaign/lt/constructor.t.sol | 4 +-- .../shared/MerkleCampaign.t.sol | 2 +- .../merkle-campaign/shared/claim/claim.t.sol | 14 ++++---- .../shared/withdraw-fees/withdrawFees.t.sol | 4 +-- test/utils/Defaults.sol | 2 +- test/utils/Events.sol | 2 +- 24 files changed, 115 insertions(+), 102 deletions(-) create mode 100644 test/periphery/integration/merkle-campaign/factory/set-default-sablier-fee/setDefaultSablierFee.t.sol create mode 100644 test/periphery/integration/merkle-campaign/factory/set-default-sablier-fee/setDefaultSablierFee.tree delete mode 100644 test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.tree diff --git a/src/periphery/SablierMerkleFactory.sol b/src/periphery/SablierMerkleFactory.sol index 012136472..8f688d51c 100644 --- a/src/periphery/SablierMerkleFactory.sol +++ b/src/periphery/SablierMerkleFactory.sol @@ -28,7 +28,7 @@ contract SablierMerkleFactory is //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc ISablierMerkleFactory - uint256 public sablierFee; + uint256 public defaultSablierFee; /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR @@ -64,11 +64,11 @@ contract SablierMerkleFactory is //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc ISablierMerkleFactory - function setSablierFee(uint256 fee) external override onlyAdmin { - // Effect: update the Sablier fee. - sablierFee = fee; + function setDefaultSablierFee(uint256 defaultFee) external override onlyAdmin { + // Effect: update the default Sablier fee. + defaultSablierFee = defaultFee; - emit SetSablierFee(msg.sender, fee); + emit SetDefaultSablierFee(msg.sender, defaultFee); } /// @inheritdoc ISablierMerkleFactory @@ -108,7 +108,7 @@ contract SablierMerkleFactory is ); // Deploy the MerkleInstant contract with CREATE2. - merkleInstant = new SablierMerkleInstant{ salt: salt }(baseParams, sablierFee); + merkleInstant = new SablierMerkleInstant{ salt: salt }(baseParams, defaultSablierFee); // Log the creation of the MerkleInstant contract, including some metadata that is not stored on-chain. emit CreateMerkleInstant(merkleInstant, baseParams, aggregateAmount, recipientCount); @@ -146,8 +146,9 @@ contract SablierMerkleFactory is ); // Deploy the MerkleLL contract with CREATE2. - merkleLL = - new SablierMerkleLL{ salt: salt }(baseParams, lockupLinear, cancelable, transferable, schedule, sablierFee); + merkleLL = new SablierMerkleLL{ salt: salt }( + baseParams, lockupLinear, cancelable, transferable, schedule, defaultSablierFee + ); // Log the creation of the MerkleLL contract, including some metadata that is not stored on-chain. emit CreateMerkleLL( @@ -237,7 +238,13 @@ contract SablierMerkleFactory is // Deploy the MerkleLT contract with CREATE2. merkleLT = new SablierMerkleLT{ salt: salt }( - baseParams, lockupTranched, cancelable, transferable, streamStartTime, tranchesWithPercentages, sablierFee + baseParams, + lockupTranched, + cancelable, + transferable, + streamStartTime, + tranchesWithPercentages, + defaultSablierFee ); } } diff --git a/src/periphery/interfaces/ISablierMerkleFactory.sol b/src/periphery/interfaces/ISablierMerkleFactory.sol index 54a925de3..0ee3bd6b0 100644 --- a/src/periphery/interfaces/ISablierMerkleFactory.sol +++ b/src/periphery/interfaces/ISablierMerkleFactory.sol @@ -57,8 +57,8 @@ interface ISablierMerkleFactory is IAdminable { uint256 recipientCount ); - /// @notice Emitted when the Sablier fee is set by the admin. - event SetSablierFee(address indexed admin, uint256 sablierFee); + /// @notice Emitted when the default Sablier fee is set by the admin. + event SetDefaultSablierFee(address indexed admin, uint256 defaultSablierFee); /// @notice Emitted when the sablier fees are claimed by the sablier admin. event WithdrawSablierFees( @@ -78,9 +78,9 @@ interface ISablierMerkleFactory is IAdminable { pure returns (bool result); - /// @notice Retrieves the sablier fee required to claim an airstream. + /// @notice Retrieves the default sablier fee required to claim an airstream. /// @dev A minimum of this fee must be paid in ETH during `claim`. - function sablierFee() external view returns (uint256); + function defaultSablierFee() external view returns (uint256); /*////////////////////////////////////////////////////////////////////////// NON-CONSTANT FUNCTIONS @@ -150,17 +150,17 @@ interface ISablierMerkleFactory is IAdminable { external returns (ISablierMerkleLT merkleLT); - /// @notice Sets the Sablier fee for claiming an airstream. - /// @dev Emits a {SetSablierFee} event. + /// @notice Sets the default Sablier fee for claiming an airstream. + /// @dev Emits a {SetDefaultSablierFee} event. /// /// Notes: - /// - The new fee will only be applied to the future campaigns. + /// - The new default fee will only be applied to the future campaigns. /// /// Requiurements: /// - The caller must be the admin. /// - /// @param fee The new fee to be set. - function setSablierFee(uint256 fee) external; + /// @param defaultFee The new detault fee to be set. + function setDefaultSablierFee(uint256 defaultFee) external; /// @notice Withdraws the Sablier fees accrued on `merkleLockup` to the provided address. /// @dev Emits a {WithdrawSablierFees} event. diff --git a/test/Base.t.sol b/test/Base.t.sol index ed86bc682..cfc418a1a 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -88,7 +88,7 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi deployProtocolConditionally(); // Set the Sablier fee on the Merkle factory. - merkleFactory.setSablierFee(defaults.SABLIER_FEE()); + merkleFactory.setDefaultSablierFee(defaults.DEFAULT_SABLIER_FEE()); // Create users for testing. users.alice = createUser("Alice"); diff --git a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol index 2f70864bf..01adac114 100644 --- a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol @@ -96,7 +96,7 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test { // Make the admin as the caller. resetPrank({ msgSender: params.admin }); - uint256 sablierFee = defaults.SABLIER_FEE(); + uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); vars.expectedMerkleInstant = computeMerkleInstantAddress( params.admin, params.admin, FORK_ASSET, vars.merkleRoot, params.expiration, sablierFee diff --git a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol index 81d4e35a4..678650cdd 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol @@ -100,7 +100,7 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { // Make the admin as the caller. resetPrank({ msgSender: params.admin }); - uint256 sablierFee = defaults.SABLIER_FEE(); + uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); vars.expectedLL = computeMerkleLLAddress( params.admin, params.admin, FORK_ASSET, vars.merkleRoot, params.expiration, sablierFee diff --git a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol index d54b31d3a..c1e5b4cbd 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol @@ -101,7 +101,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { // Make the admin as the caller. resetPrank({ msgSender: params.admin }); - uint256 sablierFee = defaults.SABLIER_FEE(); + uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); vars.expectedLT = computeMerkleLTAddress( params.admin, params.admin, FORK_ASSET, vars.merkleRoot, params.expiration, sablierFee diff --git a/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol index 5156ef65c..4851443a2 100644 --- a/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol +++ b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol @@ -35,20 +35,22 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { function computeMerkleInstantAddress() internal view returns (address) { return computeMerkleInstantAddress( - users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.SABLIER_FEE() + users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE() ); } function computeMerkleInstantAddress(address admin) internal view returns (address) { - return computeMerkleInstantAddress(admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.SABLIER_FEE()); + return computeMerkleInstantAddress( + admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE() + ); } function computeMerkleInstantAddress(address admin, uint40 expiration) internal view returns (address) { - return computeMerkleInstantAddress(admin, defaults.MERKLE_ROOT(), expiration, defaults.SABLIER_FEE()); + return computeMerkleInstantAddress(admin, defaults.MERKLE_ROOT(), expiration, defaults.DEFAULT_SABLIER_FEE()); } function computeMerkleInstantAddress(address admin, bytes32 merkleRoot) internal view returns (address) { - return computeMerkleInstantAddress(admin, merkleRoot, defaults.EXPIRATION(), defaults.SABLIER_FEE()); + return computeMerkleInstantAddress(admin, merkleRoot, defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE()); } function computeMerkleInstantAddress( @@ -89,20 +91,22 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { //////////////////////////////////////////////////////////////////////////*/ function computeMerkleLLAddress() internal view returns (address) { - return - computeMerkleLLAddress(users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.SABLIER_FEE()); + return computeMerkleLLAddress( + users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE() + ); } function computeMerkleLLAddress(address admin) internal view returns (address) { - return computeMerkleLLAddress(admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.SABLIER_FEE()); + return + computeMerkleLLAddress(admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE()); } function computeMerkleLLAddress(address admin, uint40 expiration) internal view returns (address) { - return computeMerkleLLAddress(admin, defaults.MERKLE_ROOT(), expiration, defaults.SABLIER_FEE()); + return computeMerkleLLAddress(admin, defaults.MERKLE_ROOT(), expiration, defaults.DEFAULT_SABLIER_FEE()); } function computeMerkleLLAddress(address admin, bytes32 merkleRoot) internal view returns (address) { - return computeMerkleLLAddress(admin, merkleRoot, defaults.EXPIRATION(), defaults.SABLIER_FEE()); + return computeMerkleLLAddress(admin, merkleRoot, defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE()); } function computeMerkleLLAddress( @@ -147,20 +151,22 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { //////////////////////////////////////////////////////////////////////////*/ function computeMerkleLTAddress() internal view returns (address) { - return - computeMerkleLTAddress(users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.SABLIER_FEE()); + return computeMerkleLTAddress( + users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE() + ); } function computeMerkleLTAddress(address admin) internal view returns (address) { - return computeMerkleLTAddress(admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.SABLIER_FEE()); + return + computeMerkleLTAddress(admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE()); } function computeMerkleLTAddress(address admin, uint40 expiration) internal view returns (address) { - return computeMerkleLTAddress(admin, defaults.MERKLE_ROOT(), expiration, defaults.SABLIER_FEE()); + return computeMerkleLTAddress(admin, defaults.MERKLE_ROOT(), expiration, defaults.DEFAULT_SABLIER_FEE()); } function computeMerkleLTAddress(address admin, bytes32 merkleRoot) internal view returns (address) { - return computeMerkleLTAddress(admin, merkleRoot, defaults.EXPIRATION(), defaults.SABLIER_FEE()); + return computeMerkleLTAddress(admin, merkleRoot, defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE()); } function computeMerkleLTAddress( diff --git a/test/periphery/integration/merkle-campaign/factory/constructor.t.sol b/test/periphery/integration/merkle-campaign/factory/constructor.t.sol index c09c9f0ab..3d9a58029 100644 --- a/test/periphery/integration/merkle-campaign/factory/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/constructor.t.sol @@ -12,7 +12,7 @@ contract Constructor_MerkleFactory_Integration_Test is MerkleCampaign_Integratio address actualAdmin = constructedFactory.admin(); assertEq(actualAdmin, users.admin, "factory admin"); - uint256 actualSablierFee = constructedFactory.sablierFee(); - assertEq(actualSablierFee, 0, "sablier fee"); + uint256 actualDefaultSablierFee = constructedFactory.defaultSablierFee(); + assertEq(actualDefaultSablierFee, 0, "default sablier fee"); } } diff --git a/test/periphery/integration/merkle-campaign/factory/set-default-sablier-fee/setDefaultSablierFee.t.sol b/test/periphery/integration/merkle-campaign/factory/set-default-sablier-fee/setDefaultSablierFee.t.sol new file mode 100644 index 000000000..67114556d --- /dev/null +++ b/test/periphery/integration/merkle-campaign/factory/set-default-sablier-fee/setDefaultSablierFee.t.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; + +import { MerkleCampaign_Integration_Shared_Test } from "../../shared/MerkleCampaign.t.sol"; + +contract SetDefaultSablierFee_Integration_Test is MerkleCampaign_Integration_Shared_Test { + function test_RevertWhen_CallerNotAdmin() external { + uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); + resetPrank({ msgSender: users.eve }); + vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); + merkleFactory.setDefaultSablierFee({ defaultFee: sablierFee }); + } + + function test_WhenCallerAdmin() external { + resetPrank({ msgSender: users.admin }); + + // It should emit a {SetDefaultSablierFee} event. + vm.expectEmit({ emitter: address(merkleFactory) }); + emit SetDefaultSablierFee({ admin: users.admin, sablierFee: defaults.DEFAULT_SABLIER_FEE() }); + + merkleFactory.setDefaultSablierFee({ defaultFee: defaults.DEFAULT_SABLIER_FEE() }); + + // It should set the default Sablier fee. + assertEq(merkleFactory.defaultSablierFee(), defaults.DEFAULT_SABLIER_FEE(), "sablier fee"); + } +} diff --git a/test/periphery/integration/merkle-campaign/factory/set-default-sablier-fee/setDefaultSablierFee.tree b/test/periphery/integration/merkle-campaign/factory/set-default-sablier-fee/setDefaultSablierFee.tree new file mode 100644 index 000000000..5c7a8d5f8 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/factory/set-default-sablier-fee/setDefaultSablierFee.tree @@ -0,0 +1,6 @@ +SetDefaultSablierFee_Integration_Test +├── when caller not admin +│ └── it should revert +└── when caller admin + ├── it should set the default Sablier fee + └── it should emit a {SetDefaultSablierFee} event diff --git a/test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.t.sol b/test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.t.sol deleted file mode 100644 index c988778dd..000000000 --- a/test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.t.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; - -import { MerkleCampaign_Integration_Shared_Test } from "../../shared/MerkleCampaign.t.sol"; - -contract SetSablierFee_Integration_Test is MerkleCampaign_Integration_Shared_Test { - function test_RevertWhen_CallerNotAdmin() external { - uint256 sablierFee = defaults.SABLIER_FEE(); - resetPrank({ msgSender: users.eve }); - vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); - merkleFactory.setSablierFee({ fee: sablierFee }); - } - - function test_WhenCallerAdmin() external { - resetPrank({ msgSender: users.admin }); - - // It should emit a {SetSablierFee} event. - vm.expectEmit({ emitter: address(merkleFactory) }); - emit SetSablierFee({ admin: users.admin, sablierFee: defaults.SABLIER_FEE() }); - - merkleFactory.setSablierFee({ fee: defaults.SABLIER_FEE() }); - - // It should set the Sablier fee. - assertEq(merkleFactory.sablierFee(), defaults.SABLIER_FEE(), "sablier fee"); - } -} diff --git a/test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.tree b/test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.tree deleted file mode 100644 index 71420c45b..000000000 --- a/test/periphery/integration/merkle-campaign/factory/set-sablier-fee/setSablierFee.tree +++ /dev/null @@ -1,6 +0,0 @@ -SetSablierFee_Integration_Test -├── when caller not admin -│ └── it should revert -└── when caller admin - ├── it should set the Sablier fee - └── it should emit a {SetSablierFee} event diff --git a/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.t.sol b/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.t.sol index b9b449bd5..94649fb45 100644 --- a/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.t.sol @@ -44,7 +44,7 @@ contract WithdrawFees_Integration_Test is MerkleCampaign_Integration_Shared_Test admin: users.admin, merkleLockup: merkleBase, to: users.eve, - sablierFees: defaults.SABLIER_FEE() + sablierFees: defaults.DEFAULT_SABLIER_FEE() }); merkleFactory.withdrawFees(users.eve, merkleBase); @@ -52,7 +52,7 @@ contract WithdrawFees_Integration_Test is MerkleCampaign_Integration_Shared_Test // It should set the ETH balance to 0. assertEq(address(merkleBase).balance, 0, "merkle lockup eth balance"); // It should transfer fee collected in ETH to the provided address. - assertEq(users.eve.balance, previousToBalance + defaults.SABLIER_FEE(), "eth balance"); + assertEq(users.eve.balance, previousToBalance + defaults.DEFAULT_SABLIER_FEE(), "eth balance"); } modifier whenProvidedAddressContract() { @@ -88,7 +88,7 @@ contract WithdrawFees_Integration_Test is MerkleCampaign_Integration_Shared_Test admin: users.admin, merkleLockup: merkleBase, to: receiveEth, - sablierFees: defaults.SABLIER_FEE() + sablierFees: defaults.DEFAULT_SABLIER_FEE() }); merkleFactory.withdrawFees(receiveEth, merkleBase); @@ -96,6 +96,6 @@ contract WithdrawFees_Integration_Test is MerkleCampaign_Integration_Shared_Test // It should set the ETH balance to 0. assertEq(address(merkleBase).balance, 0, "merkle lockup eth balance"); // It should transfer fee collected in ETH to the provided address. - assertEq(receiveEth.balance, defaults.SABLIER_FEE(), "eth balance"); + assertEq(receiveEth.balance, defaults.DEFAULT_SABLIER_FEE(), "eth balance"); } } diff --git a/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol index bdfebd3c6..b88e503e1 100644 --- a/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol @@ -25,11 +25,11 @@ contract Claim_MerkleInstant_Integration_Test is Claim_Integration_Test, MerkleI emit Claim(defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT()); expectCallToTransfer({ to: users.recipient1, value: defaults.CLAIM_AMOUNT() }); - expectCallToClaimWithMsgValue(address(merkleInstant), defaults.SABLIER_FEE()); + expectCallToClaimWithMsgValue(address(merkleInstant), defaults.DEFAULT_SABLIER_FEE()); claim(); assertTrue(merkleInstant.hasClaimed(defaults.INDEX1()), "not claimed"); - assertEq(address(merkleInstant).balance, previousFeeAccrued + defaults.SABLIER_FEE(), "fee collected"); + assertEq(address(merkleInstant).balance, previousFeeAccrued + defaults.DEFAULT_SABLIER_FEE(), "fee collected"); } } diff --git a/test/periphery/integration/merkle-campaign/instant/constructor.t.sol b/test/periphery/integration/merkle-campaign/instant/constructor.t.sol index e53c974df..a0092ae0f 100644 --- a/test/periphery/integration/merkle-campaign/instant/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/instant/constructor.t.sol @@ -31,7 +31,7 @@ contract Constructor_MerkleInstant_Integration_Test is MerkleCampaign_Integratio resetPrank(address(merkleFactory)); SablierMerkleInstant constructedInstant = - new SablierMerkleInstant(defaults.baseParams(), defaults.SABLIER_FEE()); + new SablierMerkleInstant(defaults.baseParams(), defaults.DEFAULT_SABLIER_FEE()); Vars memory vars; @@ -64,7 +64,7 @@ contract Constructor_MerkleInstant_Integration_Test is MerkleCampaign_Integratio assertEq(bytes32(abi.encodePacked(vars.actualName)), vars.expectedName, "name"); vars.actualSablierFee = constructedInstant.SABLIER_FEE(); - vars.expectedSablierFee = defaults.SABLIER_FEE(); + vars.expectedSablierFee = defaults.DEFAULT_SABLIER_FEE(); assertEq(vars.actualSablierFee, vars.expectedSablierFee, "sablierFee"); } } diff --git a/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol index 4fd751ed0..fc272e207 100644 --- a/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol @@ -65,7 +65,7 @@ contract Claim_MerkleLL_Integration_Test is Claim_Integration_Test, MerkleLL_Int /// @dev Helper function to test claim. function _test_Claim(uint40 startTime, uint40 cliffTime) private { - uint256 sablierFee = defaults.SABLIER_FEE(); + uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); deal({ token: address(dai), to: address(merkleLL), give: defaults.AGGREGATE_AMOUNT() }); uint256 expectedStreamId = lockupLinear.nextStreamId(); @@ -102,6 +102,6 @@ contract Claim_MerkleLL_Integration_Test is Claim_Integration_Test, MerkleLL_Int assertEq(actualStream, expectedStream); assertTrue(merkleLL.hasClaimed(defaults.INDEX1()), "not claimed"); - assertEq(address(merkleLL).balance, previousFeeAccrued + defaults.SABLIER_FEE(), "fee collected"); + assertEq(address(merkleLL).balance, previousFeeAccrued + defaults.DEFAULT_SABLIER_FEE(), "fee collected"); } } diff --git a/test/periphery/integration/merkle-campaign/ll/constructor.t.sol b/test/periphery/integration/merkle-campaign/ll/constructor.t.sol index 9f3187da4..dda08b6bb 100644 --- a/test/periphery/integration/merkle-campaign/ll/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/constructor.t.sol @@ -47,7 +47,7 @@ contract Constructor_MerkleLL_Integration_Test is MerkleCampaign_Integration_Tes defaults.CANCELABLE(), defaults.TRANSFERABLE(), defaults.schedule(), - defaults.SABLIER_FEE() + defaults.DEFAULT_SABLIER_FEE() ); Vars memory vars; @@ -104,7 +104,7 @@ contract Constructor_MerkleLL_Integration_Test is MerkleCampaign_Integration_Tes assertEq(vars.actualTransferable, vars.expectedTransferable, "transferable"); vars.actualSablierFee = constructedLL.SABLIER_FEE(); - vars.expectedSablierFee = defaults.SABLIER_FEE(); + vars.expectedSablierFee = defaults.DEFAULT_SABLIER_FEE(); assertEq(vars.actualSablierFee, vars.expectedSablierFee, "sablierFee"); } } diff --git a/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol index c4e0d3623..13f1bf7b0 100644 --- a/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol @@ -20,7 +20,7 @@ contract Claim_MerkleLT_Integration_Test is Claim_Integration_Test, MerkleLT_Int } function test_RevertWhen_TotalPercentageLessThan100() external whenMerkleProofValid whenTotalPercentageNot100 { - uint256 sablierFee = defaults.SABLIER_FEE(); + uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); // Create a MerkleLT campaign with a total percentage less than 100. MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = defaults.tranchesWithPercentages(); @@ -57,7 +57,7 @@ contract Claim_MerkleLT_Integration_Test is Claim_Integration_Test, MerkleLT_Int } function test_RevertWhen_TotalPercentageGreaterThan100() external whenMerkleProofValid whenTotalPercentageNot100 { - uint256 sablierFee = defaults.SABLIER_FEE(); + uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); // Create a MerkleLT campaign with a total percentage less than 100. MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = defaults.tranchesWithPercentages(); tranchesWithPercentages[0].unlockPercentage = ud2x18(0.75e18); @@ -122,7 +122,7 @@ contract Claim_MerkleLT_Integration_Test is Claim_Integration_Test, MerkleLT_Int /// @dev Helper function to test claim. function _test_Claim(uint40 streamStartTime, uint40 startTime) private { - uint256 sablierFee = defaults.SABLIER_FEE(); + uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); deal({ token: address(dai), to: address(merkleLT), give: defaults.AGGREGATE_AMOUNT() }); @@ -161,6 +161,6 @@ contract Claim_MerkleLT_Integration_Test is Claim_Integration_Test, MerkleLT_Int assertEq(actualStream, expectedStream); assertTrue(merkleLT.hasClaimed(defaults.INDEX1()), "not claimed"); - assertEq(address(merkleLT).balance, previousFeeAccrued + defaults.SABLIER_FEE(), "fee collected"); + assertEq(address(merkleLT).balance, previousFeeAccrued + defaults.DEFAULT_SABLIER_FEE(), "fee collected"); } } diff --git a/test/periphery/integration/merkle-campaign/lt/constructor.t.sol b/test/periphery/integration/merkle-campaign/lt/constructor.t.sol index e712a603b..3fdb4c4c0 100644 --- a/test/periphery/integration/merkle-campaign/lt/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/constructor.t.sol @@ -52,7 +52,7 @@ contract Constructor_MerkleLT_Integration_Test is MerkleCampaign_Integration_Tes defaults.TRANSFERABLE(), defaults.STREAM_START_TIME_ZERO(), defaults.tranchesWithPercentages(), - defaults.SABLIER_FEE() + defaults.DEFAULT_SABLIER_FEE() ); Vars memory vars; @@ -98,7 +98,7 @@ contract Constructor_MerkleLT_Integration_Test is MerkleCampaign_Integration_Tes assertEq(bytes32(abi.encodePacked(vars.actualName)), vars.expectedName, "name"); vars.actualSablierFee = constructedLT.SABLIER_FEE(); - vars.expectedSablierFee = defaults.SABLIER_FEE(); + vars.expectedSablierFee = defaults.DEFAULT_SABLIER_FEE(); assertEq(vars.actualSablierFee, vars.expectedSablierFee, "sablierFee"); vars.actualStreamStartTime = constructedLT.STREAM_START_TIME(); diff --git a/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol b/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol index c3ba552c2..df62950c9 100644 --- a/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol +++ b/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol @@ -19,7 +19,7 @@ abstract contract MerkleCampaign_Integration_Shared_Test is MerkleCampaign_Integ //////////////////////////////////////////////////////////////////////////*/ function claim() internal { - merkleBase.claim{ value: defaults.SABLIER_FEE() }({ + merkleBase.claim{ value: defaults.DEFAULT_SABLIER_FEE() }({ index: defaults.INDEX1(), recipient: users.recipient1, amount: defaults.CLAIM_AMOUNT(), diff --git a/test/periphery/integration/merkle-campaign/shared/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/shared/claim/claim.t.sol index 80f4e4b75..484e2272d 100644 --- a/test/periphery/integration/merkle-campaign/shared/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/shared/claim/claim.t.sol @@ -12,7 +12,7 @@ abstract contract Claim_Integration_Test is MerkleCampaign_Integration_Shared_Te function test_RevertGiven_CampaignExpired() external { uint40 expiration = defaults.EXPIRATION(); - uint256 sablierFee = defaults.SABLIER_FEE(); + uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); uint256 warpTime = expiration + 1 seconds; bytes32[] memory merkleProof; vm.warp({ newTimestamp: warpTime }); @@ -29,7 +29,7 @@ abstract contract Claim_Integration_Test is MerkleCampaign_Integration_Shared_Te uint256 index1 = defaults.INDEX1(); uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory merkleProof = defaults.index1Proof(); - uint256 sablierFee = defaults.SABLIER_FEE(); + uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InsufficientFeePayment.selector, 0, sablierFee)); merkleBase.claim{ value: 0 }(index1, users.recipient1, amount, merkleProof); @@ -43,7 +43,7 @@ abstract contract Claim_Integration_Test is MerkleCampaign_Integration_Shared_Te claim(); uint256 index1 = defaults.INDEX1(); uint128 amount = defaults.CLAIM_AMOUNT(); - uint256 sablierFee = defaults.SABLIER_FEE(); + uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); bytes32[] memory merkleProof = defaults.index1Proof(); vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_StreamClaimed.selector, index1)); merkleBase.claim{ value: sablierFee }(index1, users.recipient1, amount, merkleProof); @@ -61,7 +61,7 @@ abstract contract Claim_Integration_Test is MerkleCampaign_Integration_Shared_Te { uint256 invalidIndex = 1337; uint128 amount = defaults.CLAIM_AMOUNT(); - uint256 sablierFee = defaults.SABLIER_FEE(); + uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); bytes32[] memory merkleProof = defaults.index1Proof(); vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); merkleBase.claim{ value: sablierFee }(invalidIndex, users.recipient1, amount, merkleProof); @@ -81,7 +81,7 @@ abstract contract Claim_Integration_Test is MerkleCampaign_Integration_Shared_Te uint256 index1 = defaults.INDEX1(); address invalidRecipient = address(1337); uint128 amount = defaults.CLAIM_AMOUNT(); - uint256 sablierFee = defaults.SABLIER_FEE(); + uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); bytes32[] memory merkleProof = defaults.index1Proof(); vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); merkleBase.claim{ value: sablierFee }(index1, invalidRecipient, amount, merkleProof); @@ -101,7 +101,7 @@ abstract contract Claim_Integration_Test is MerkleCampaign_Integration_Shared_Te { uint256 index1 = defaults.INDEX1(); uint128 invalidAmount = 1337; - uint256 sablierFee = defaults.SABLIER_FEE(); + uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); bytes32[] memory merkleProof = defaults.index1Proof(); vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); merkleBase.claim{ value: sablierFee }(index1, users.recipient1, invalidAmount, merkleProof); @@ -122,7 +122,7 @@ abstract contract Claim_Integration_Test is MerkleCampaign_Integration_Shared_Te { uint256 index1 = defaults.INDEX1(); uint128 amount = defaults.CLAIM_AMOUNT(); - uint256 sablierFee = defaults.SABLIER_FEE(); + uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); bytes32[] memory invalidMerkleProof = defaults.index2Proof(); vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); merkleBase.claim{ value: sablierFee }(index1, users.recipient1, amount, invalidMerkleProof); diff --git a/test/periphery/integration/merkle-campaign/shared/withdraw-fees/withdrawFees.t.sol b/test/periphery/integration/merkle-campaign/shared/withdraw-fees/withdrawFees.t.sol index 8456a8fb1..ca5b12752 100644 --- a/test/periphery/integration/merkle-campaign/shared/withdraw-fees/withdrawFees.t.sol +++ b/test/periphery/integration/merkle-campaign/shared/withdraw-fees/withdrawFees.t.sol @@ -37,7 +37,7 @@ abstract contract WithdrawFees_Integration_Test is MerkleCampaign_Integration_Sh // It should set the ETH balance to 0. assertEq(address(merkleBase).balance, 0, "merkle lockup eth balance"); // It should transfer fee collected in ETH to the provided address. - assertEq(users.admin.balance, previousToBalance + defaults.SABLIER_FEE(), "eth balance"); + assertEq(users.admin.balance, previousToBalance + defaults.DEFAULT_SABLIER_FEE(), "eth balance"); } modifier whenProvidedAddressContract() { @@ -66,6 +66,6 @@ abstract contract WithdrawFees_Integration_Test is MerkleCampaign_Integration_Sh // It should set the ETH balance to 0. assertEq(address(merkleBase).balance, 0, "merkle lockup eth balance"); // It should transfer fee collected in ETH to the provided address. - assertEq(receiveEth.balance, defaults.SABLIER_FEE(), "eth balance"); + assertEq(receiveEth.balance, defaults.DEFAULT_SABLIER_FEE(), "eth balance"); } } diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 095b09b62..9e391a94f 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -52,6 +52,7 @@ contract Defaults is Constants, Merkle { uint256 public constant AGGREGATE_AMOUNT = CLAIM_AMOUNT * RECIPIENT_COUNT; bool public constant CANCELABLE = false; uint128 public constant CLAIM_AMOUNT = 10_000e18; + uint256 public constant DEFAULT_SABLIER_FEE = 0.005e18; uint40 public immutable EXPIRATION; uint40 public constant FIRST_CLAIM_TIME = JULY_1_2024; uint256 public constant INDEX1 = 1; @@ -64,7 +65,6 @@ contract Defaults is Constants, Merkle { bytes32 public MERKLE_ROOT; string public constant NAME = "Airdrop Campaign"; bytes32 public constant NAME_BYTES32 = bytes32(abi.encodePacked("Airdrop Campaign")); - uint256 public constant SABLIER_FEE = 0.005e18; uint40 public immutable STREAM_START_TIME_NON_ZERO = JULY_1_2024 - 2 days; uint40 public immutable STREAM_START_TIME_ZERO = 0; uint64 public constant TOTAL_PERCENTAGE = uUNIT; diff --git a/test/utils/Events.sol b/test/utils/Events.sol index 912447a62..7bcf22616 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -139,7 +139,7 @@ abstract contract Events { uint256 recipientCount ); - event SetSablierFee(address indexed admin, uint256 sablierFee); + event SetDefaultSablierFee(address indexed admin, uint256 sablierFee); event WithdrawSablierFees( address indexed admin, ISablierMerkleBase indexed merkleLockup, address to, uint256 sablierFees From a582341c3e2adc0e19f7c4a3df114f913fa3f29e Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 11 Sep 2024 15:12:41 +0100 Subject: [PATCH 10/21] feat: custom sablier fee --- src/periphery/SablierMerkleFactory.sol | 64 +++++++++++++++---- .../interfaces/ISablierMerkleFactory.sol | 58 ++++++++++++++++- src/periphery/types/DataTypes.sol | 11 ++++ 3 files changed, 120 insertions(+), 13 deletions(-) diff --git a/src/periphery/SablierMerkleFactory.sol b/src/periphery/SablierMerkleFactory.sol index 8f688d51c..ed0c35d92 100644 --- a/src/periphery/SablierMerkleFactory.sol +++ b/src/periphery/SablierMerkleFactory.sol @@ -15,7 +15,7 @@ import { ISablierMerkleLT } from "./interfaces/ISablierMerkleLT.sol"; import { SablierMerkleInstant } from "./SablierMerkleInstant.sol"; import { SablierMerkleLL } from "./SablierMerkleLL.sol"; import { SablierMerkleLT } from "./SablierMerkleLT.sol"; -import { MerkleBase, MerkleLL, MerkleLT } from "./types/DataTypes.sol"; +import { MerkleBase, MerkleFactory, MerkleLL, MerkleLT } from "./types/DataTypes.sol"; /// @title SablierMerkleFactory /// @notice See the documentation in {ISablierMerkleFactory}. @@ -30,6 +30,9 @@ contract SablierMerkleFactory is /// @inheritdoc ISablierMerkleFactory uint256 public defaultSablierFee; + /// @dev A mapping of custom Sablier fees by user. + mapping(address campaignCreator => MerkleFactory.SablierFee) private _sablierFeeByUser; + /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ @@ -59,10 +62,28 @@ contract SablierMerkleFactory is return totalPercentage == uUNIT; } + /// @inheritdoc ISablierMerkleFactory + function sablierFeeByUser(address campaignCreator) + external + view + override + returns (MerkleFactory.SablierFee memory) + { + return _sablierFeeByUser[campaignCreator]; + } + /*////////////////////////////////////////////////////////////////////////// ADMIN-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ + /// @inheritdoc ISablierMerkleFactory + function resetSablierFeeByUser(address campaignCreator) external override onlyAdmin { + delete _sablierFeeByUser[campaignCreator]; + + // Log the reset. + emit ResetSablierFeeFor({ admin: msg.sender, user: campaignCreator }); + } + /// @inheritdoc ISablierMerkleFactory function setDefaultSablierFee(uint256 defaultFee) external override onlyAdmin { // Effect: update the default Sablier fee. @@ -71,6 +92,20 @@ contract SablierMerkleFactory is emit SetDefaultSablierFee(msg.sender, defaultFee); } + /// @inheritdoc ISablierMerkleFactory + function setSablierFeeByUser(address campaignCreator, uint256 fee) external override onlyAdmin { + MerkleFactory.SablierFee storage feeByUser = _sablierFeeByUser[campaignCreator]; + + // If user does not belong to the custom fee list. + if (!feeByUser.enabled) feeByUser.enabled = true; + + // Effect: update the Sablier fee for the given campaign creator. + feeByUser.fee = fee; + + // Log the update. + emit UpdateSablierFeeFor({ admin: msg.sender, user: campaignCreator, sablierFee: fee }); + } + /// @inheritdoc ISablierMerkleFactory function withdrawFees(address payable to, ISablierMerkleBase merkleLockup) external override onlyAdmin { // Effect: call `withdrawFees` on the MerkleLockup contract. @@ -107,8 +142,12 @@ contract SablierMerkleFactory is ) ); + // Fetch the Sablier fee for the user, or use the default fee. + uint256 sablierFee = + _sablierFeeByUser[msg.sender].enabled ? _sablierFeeByUser[msg.sender].fee : defaultSablierFee; + // Deploy the MerkleInstant contract with CREATE2. - merkleInstant = new SablierMerkleInstant{ salt: salt }(baseParams, defaultSablierFee); + merkleInstant = new SablierMerkleInstant{ salt: salt }(baseParams, sablierFee); // Log the creation of the MerkleInstant contract, including some metadata that is not stored on-chain. emit CreateMerkleInstant(merkleInstant, baseParams, aggregateAmount, recipientCount); @@ -145,10 +184,13 @@ contract SablierMerkleFactory is ) ); + // Fetch the Sablier fee for the user, or use the default fee. + uint256 sablierFee = + _sablierFeeByUser[msg.sender].enabled ? _sablierFeeByUser[msg.sender].fee : defaultSablierFee; + // Deploy the MerkleLL contract with CREATE2. - merkleLL = new SablierMerkleLL{ salt: salt }( - baseParams, lockupLinear, cancelable, transferable, schedule, defaultSablierFee - ); + merkleLL = + new SablierMerkleLL{ salt: salt }(baseParams, lockupLinear, cancelable, transferable, schedule, sablierFee); // Log the creation of the MerkleLL contract, including some metadata that is not stored on-chain. emit CreateMerkleLL( @@ -236,15 +278,13 @@ contract SablierMerkleFactory is ) ); + // Fetch the Sablier fee for the user, or use the default fee. + uint256 sablierFee = + _sablierFeeByUser[msg.sender].enabled ? _sablierFeeByUser[msg.sender].fee : defaultSablierFee; + // Deploy the MerkleLT contract with CREATE2. merkleLT = new SablierMerkleLT{ salt: salt }( - baseParams, - lockupTranched, - cancelable, - transferable, - streamStartTime, - tranchesWithPercentages, - defaultSablierFee + baseParams, lockupTranched, cancelable, transferable, streamStartTime, tranchesWithPercentages, sablierFee ); } } diff --git a/src/periphery/interfaces/ISablierMerkleFactory.sol b/src/periphery/interfaces/ISablierMerkleFactory.sol index 0ee3bd6b0..7633a517b 100644 --- a/src/periphery/interfaces/ISablierMerkleFactory.sol +++ b/src/periphery/interfaces/ISablierMerkleFactory.sol @@ -6,7 +6,7 @@ import { ISablierLockupLinear } from "../../core/interfaces/ISablierLockupLinear import { ISablierLockupTranched } from "../../core/interfaces/ISablierLockupTranched.sol"; import { ISablierMerkleBase } from "../interfaces/ISablierMerkleBase.sol"; -import { MerkleBase, MerkleLL, MerkleLT } from "../types/DataTypes.sol"; +import { MerkleBase, MerkleFactory, MerkleLL, MerkleLT } from "../types/DataTypes.sol"; import { ISablierMerkleInstant } from "./ISablierMerkleInstant.sol"; import { ISablierMerkleLL } from "./ISablierMerkleLL.sol"; import { ISablierMerkleLT } from "./ISablierMerkleLT.sol"; @@ -57,9 +57,15 @@ interface ISablierMerkleFactory is IAdminable { uint256 recipientCount ); + /// @notice Emitted when the admin resets Sablier fee to default for a specific user. + event ResetSablierFeeFor(address indexed admin, address indexed user); + /// @notice Emitted when the default Sablier fee is set by the admin. event SetDefaultSablierFee(address indexed admin, uint256 defaultSablierFee); + /// @notice Emitted when the admin sets Sablier fee for a specific user. + event UpdateSablierFeeFor(address indexed admin, address indexed user, uint256 sablierFee); + /// @notice Emitted when the sablier fees are claimed by the sablier admin. event WithdrawSablierFees( address indexed admin, ISablierMerkleBase indexed merkleLockup, address to, uint256 sablierFees @@ -82,12 +88,26 @@ interface ISablierMerkleFactory is IAdminable { /// @dev A minimum of this fee must be paid in ETH during `claim`. function defaultSablierFee() external view returns (uint256); + /// @notice Retrieves the custom sablier fee struct for a specified campaign creator. + /// @dev It return two fields: + /// - `enabled` indicates if the custom fee is enabled. If it is not enabled, the default fee will be used for + /// campaigns. + /// - `fee` is the custom fee set by the admin. + /// @param campaignCreator The user for whom the details are being queried. + function sablierFeeByUser(address campaignCreator) external view returns (MerkleFactory.SablierFee memory); + /*////////////////////////////////////////////////////////////////////////// NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /// @notice Creates a new MerkleInstant campaign for instant distribution of assets. + /// /// @dev Emits a {CreateMerkleInstant} event. + /// + /// Notes: + /// - The MerkleInstant contract is created with CREATE2. + /// - The immutable sablier fee will be set to the default value unless a custom fee is set. + /// /// @param baseParams Struct encapsulating the {SablierMerkleBase} parameters, which are documented in /// {DataTypes}. /// @param aggregateAmount The total amount of ERC-20 assets to be distributed to all recipients. @@ -102,7 +122,13 @@ interface ISablierMerkleFactory is IAdminable { returns (ISablierMerkleInstant merkleInstant); /// @notice Creates a new Merkle Lockup campaign with a LockupLinear distribution. + /// /// @dev Emits a {CreateMerkleLL} event. + /// + /// Notes: + /// - The MerkleLL contract is created with CREATE2. + /// - The immutable sablier fee will be set to the default value unless a custom fee is set. + /// /// @param baseParams Struct encapsulating the {SablierMerkleBase} parameters, which are documented in /// {DataTypes}. /// @param lockupLinear The address of the {SablierLockupLinear} contract. @@ -125,8 +151,13 @@ interface ISablierMerkleFactory is IAdminable { returns (ISablierMerkleLL merkleLL); /// @notice Creates a new Merkle Lockup campaign with a LockupTranched distribution. + /// /// @dev Emits a {CreateMerkleLT} event. /// + /// Notes: + /// - The MerkleLT contract is created with CREATE2. + /// - The immutable sablier fee will be set to the default value unless a custom fee is set. + /// /// @param baseParams Struct encapsulating the {SablierMerkleBase} parameters, which are documented in /// {DataTypes}. /// @param lockupTranched The address of the {SablierLockupTranched} contract. @@ -150,6 +181,31 @@ interface ISablierMerkleFactory is IAdminable { external returns (ISablierMerkleLT merkleLT); + /// @notice Resets the Sablier fee to default. + /// @dev Emits a {ResetSablierFeeFor} event. + /// + /// Notes: + /// - The default fee will only be applied to the future campaigns. + /// + /// Requiurements: + /// - The caller must be the admin. + /// + /// @param campaignCreator The user for whom the fee is being reset for. + function resetSablierFeeByUser(address campaignCreator) external; + + /// @notice Sets the custom Sablier fee for a campaign creator. + /// @dev Emits a {UpdateSablierFeeFor} event. + /// + /// Notes: + /// - The new fee will only be applied to the future campaigns. + /// + /// Requiurements: + /// - The caller must be the admin. + /// + /// @param campaignCreator The user for whom the fee is being set. + /// @param fee The new fee to be set. + function setSablierFeeByUser(address campaignCreator, uint256 fee) external; + /// @notice Sets the default Sablier fee for claiming an airstream. /// @dev Emits a {SetDefaultSablierFee} event. /// diff --git a/src/periphery/types/DataTypes.sol b/src/periphery/types/DataTypes.sol index 333aaa6a8..016e5822b 100644 --- a/src/periphery/types/DataTypes.sol +++ b/src/periphery/types/DataTypes.sol @@ -100,6 +100,17 @@ library MerkleBase { } } +library MerkleFactory { + /// @notice Struct encapsulating the custom fee details for a given campaign creator. + /// @param enabled Whether the fee is enabled. If false, the default fee will be applied for campaigns created by + /// the given creator. + /// @param fee The fee amount. + struct SablierFee { + bool enabled; + uint256 fee; + } +} + library MerkleLL { /// @notice Struct encapsulating the start time, cliff duration and the end duration used to construct the time /// variables in `LockupLinear.CreateWithTimestamps`. From d019b8d88c2222e4f274f69d59d0a1a69dcafa31 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 11 Sep 2024 15:35:54 +0100 Subject: [PATCH 11/21] test(refactor): add a new user: campaignOwner in User struct --- test/Base.t.sol | 1 + test/periphery/Periphery.t.sol | 32 +++--- .../fork/merkle-campaign/MerkleInstant.t.sol | 24 ++--- .../fork/merkle-campaign/MerkleLL.t.sol | 26 ++--- .../fork/merkle-campaign/MerkleLT.t.sol | 28 ++--- .../merkle-campaign/MerkleCampaign.t.sol | 100 ++++++++++-------- .../createMerkleInstant.t.sol | 10 +- .../create-merkle-ll/createMerkleLL.t.sol | 10 +- .../create-merkle-lt/createMerkleLT.t.sol | 10 +- .../merkle-campaign/instant/constructor.t.sol | 2 +- .../merkle-campaign/ll/claim/claim.t.sol | 2 +- .../merkle-campaign/ll/constructor.t.sol | 2 +- .../merkle-campaign/lt/claim/claim.t.sol | 2 +- .../merkle-campaign/lt/constructor.t.sol | 2 +- .../shared/MerkleCampaign.t.sol | 9 +- .../shared/clawback/clawback.t.sol | 30 ++++-- .../shared/clawback/clawback.tree | 4 +- test/utils/Defaults.sol | 6 +- test/utils/Types.sol | 2 + 19 files changed, 164 insertions(+), 138 deletions(-) diff --git a/test/Base.t.sol b/test/Base.t.sol index cfc418a1a..a2835f07d 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -93,6 +93,7 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi // Create users for testing. users.alice = createUser("Alice"); users.broker = createUser("Broker"); + users.campaignOwner = createUser("CampaignOwner"); users.eve = createUser("Eve"); users.operator = createUser("Operator"); users.recipient = createUser("Recipient"); diff --git a/test/periphery/Periphery.t.sol b/test/periphery/Periphery.t.sol index 461123f66..9cc4127be 100644 --- a/test/periphery/Periphery.t.sol +++ b/test/periphery/Periphery.t.sol @@ -37,7 +37,7 @@ contract Periphery_Test is Base_Test { function computeMerkleInstantAddress( address caller, - address admin, + address campaignOwner, IERC20 asset_, bytes32 merkleRoot, uint40 expiration, @@ -52,14 +52,14 @@ contract Periphery_Test is Base_Test { caller, address(asset_), expiration, - admin, + campaignOwner, abi.encode(defaults.IPFS_CID()), merkleRoot, defaults.NAME_BYTES32() ) ); bytes32 creationBytecodeHash = - keccak256(getMerkleInstantBytecode(admin, asset_, merkleRoot, expiration, sablierFee)); + keccak256(getMerkleInstantBytecode(campaignOwner, asset_, merkleRoot, expiration, sablierFee)); return vm.computeCreate2Address({ salt: salt, initCodeHash: creationBytecodeHash, @@ -69,7 +69,7 @@ contract Periphery_Test is Base_Test { function computeMerkleLLAddress( address caller, - address admin, + address campaignOwner, IERC20 asset_, bytes32 merkleRoot, uint40 expiration, @@ -84,7 +84,7 @@ contract Periphery_Test is Base_Test { caller, address(asset_), expiration, - admin, + campaignOwner, abi.encode(defaults.IPFS_CID()), merkleRoot, defaults.NAME_BYTES32(), @@ -94,7 +94,8 @@ contract Periphery_Test is Base_Test { abi.encode(defaults.schedule()) ) ); - bytes32 creationBytecodeHash = keccak256(getMerkleLLBytecode(admin, asset_, merkleRoot, expiration, sablierFee)); + bytes32 creationBytecodeHash = + keccak256(getMerkleLLBytecode(campaignOwner, asset_, merkleRoot, expiration, sablierFee)); return vm.computeCreate2Address({ salt: salt, initCodeHash: creationBytecodeHash, @@ -104,7 +105,7 @@ contract Periphery_Test is Base_Test { function computeMerkleLTAddress( address caller, - address admin, + address campaignOwner, IERC20 asset_, bytes32 merkleRoot, uint40 expiration, @@ -119,7 +120,7 @@ contract Periphery_Test is Base_Test { caller, address(asset_), expiration, - admin, + campaignOwner, abi.encode(defaults.IPFS_CID()), merkleRoot, defaults.NAME_BYTES32(), @@ -130,7 +131,8 @@ contract Periphery_Test is Base_Test { abi.encode(defaults.tranchesWithPercentages()) ) ); - bytes32 creationBytecodeHash = keccak256(getMerkleLTBytecode(admin, asset_, merkleRoot, expiration, sablierFee)); + bytes32 creationBytecodeHash = + keccak256(getMerkleLTBytecode(campaignOwner, asset_, merkleRoot, expiration, sablierFee)); return vm.computeCreate2Address({ salt: salt, initCodeHash: creationBytecodeHash, @@ -139,7 +141,7 @@ contract Periphery_Test is Base_Test { } function getMerkleInstantBytecode( - address admin, + address campaignOwner, IERC20 asset_, bytes32 merkleRoot, uint40 expiration, @@ -150,7 +152,7 @@ contract Periphery_Test is Base_Test { returns (bytes memory) { bytes memory constructorArgs = - abi.encode(defaults.baseParams(admin, asset_, expiration, merkleRoot), sablierFee); + abi.encode(defaults.baseParams(campaignOwner, asset_, expiration, merkleRoot), sablierFee); if (!isTestOptimizedProfile()) { return bytes.concat(type(SablierMerkleInstant).creationCode, constructorArgs); } else { @@ -161,7 +163,7 @@ contract Periphery_Test is Base_Test { } function getMerkleLLBytecode( - address admin, + address campaignOwner, IERC20 asset_, bytes32 merkleRoot, uint40 expiration, @@ -172,7 +174,7 @@ contract Periphery_Test is Base_Test { returns (bytes memory) { bytes memory constructorArgs = abi.encode( - defaults.baseParams(admin, asset_, expiration, merkleRoot), + defaults.baseParams(campaignOwner, asset_, expiration, merkleRoot), lockupLinear, defaults.CANCELABLE(), defaults.TRANSFERABLE(), @@ -187,7 +189,7 @@ contract Periphery_Test is Base_Test { } function getMerkleLTBytecode( - address admin, + address campaignOwner, IERC20 asset_, bytes32 merkleRoot, uint40 expiration, @@ -198,7 +200,7 @@ contract Periphery_Test is Base_Test { returns (bytes memory) { bytes memory constructorArgs = abi.encode( - defaults.baseParams(admin, asset_, expiration, merkleRoot), + defaults.baseParams(campaignOwner, asset_, expiration, merkleRoot), lockupTranched, defaults.CANCELABLE(), defaults.TRANSFERABLE(), diff --git a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol index 01adac114..cbca6f208 100644 --- a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol @@ -22,7 +22,7 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test { } struct Params { - address admin; + address campaignOwner; uint40 expiration; LeafData[] leafData; uint256 posBeforeSort; @@ -48,9 +48,9 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test { uint256[] public leaves; function testForkFuzz_MerkleInstant(Params memory params) external { - vm.assume(params.admin != address(0) && params.admin != users.admin); + vm.assume(params.campaignOwner != address(0) && params.campaignOwner != users.campaignOwner); vm.assume(params.leafData.length > 0); - assumeNoBlacklisted({ token: address(FORK_ASSET), addr: params.admin }); + assumeNoBlacklisted({ token: address(FORK_ASSET), addr: params.campaignOwner }); params.posBeforeSort = _bound(params.posBeforeSort, 0, params.leafData.length - 1); // The expiration must be either zero or greater than the block timestamp. @@ -93,17 +93,17 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test { vars.merkleRoot = getRoot(leaves.toBytes32()); } - // Make the admin as the caller. - resetPrank({ msgSender: params.admin }); + // Make the campaign owner as the caller. + resetPrank({ msgSender: params.campaignOwner }); uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); vars.expectedMerkleInstant = computeMerkleInstantAddress( - params.admin, params.admin, FORK_ASSET, vars.merkleRoot, params.expiration, sablierFee + params.campaignOwner, params.campaignOwner, FORK_ASSET, vars.merkleRoot, params.expiration, sablierFee ); vars.baseParams = defaults.baseParams({ - admin: params.admin, + campaignOwner: params.campaignOwner, asset_: FORK_ASSET, merkleRoot: vars.merkleRoot, expiration: params.expiration @@ -199,17 +199,17 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test { CLAWBACK //////////////////////////////////////////////////////////////////////////*/ - // Make the admin as the caller. - resetPrank({ msgSender: params.admin }); + // Make the campaign owner as the caller. + resetPrank({ msgSender: params.campaignOwner }); if (params.expiration > 0) { vars.clawbackAmount = uint128(FORK_ASSET.balanceOf(address(vars.merkleInstant))); vm.warp({ newTimestamp: uint256(params.expiration) + 1 seconds }); - expectCallToTransfer({ asset: FORK_ASSET, to: params.admin, value: vars.clawbackAmount }); + expectCallToTransfer({ asset: FORK_ASSET, to: params.campaignOwner, value: vars.clawbackAmount }); vm.expectEmit({ emitter: address(vars.merkleInstant) }); - emit Clawback({ to: params.admin, admin: params.admin, amount: vars.clawbackAmount }); - vars.merkleInstant.clawback({ to: params.admin, amount: vars.clawbackAmount }); + emit Clawback({ to: params.campaignOwner, admin: params.campaignOwner, amount: vars.clawbackAmount }); + vars.merkleInstant.clawback({ to: params.campaignOwner, amount: vars.clawbackAmount }); } /*////////////////////////////////////////////////////////////////////////// diff --git a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol index 678650cdd..82ebf6fd1 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol @@ -23,7 +23,7 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { } struct Params { - address admin; + address campaignOwner; uint40 expiration; LeafData[] leafData; uint256 posBeforeSort; @@ -52,9 +52,9 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { uint256[] public leaves; function testForkFuzz_MerkleLL(Params memory params) external { - vm.assume(params.admin != address(0) && params.admin != users.admin); + vm.assume(params.campaignOwner != address(0) && params.campaignOwner != users.campaignOwner); vm.assume(params.leafData.length > 0); - assumeNoBlacklisted({ token: address(FORK_ASSET), addr: params.admin }); + assumeNoBlacklisted({ token: address(FORK_ASSET), addr: params.campaignOwner }); params.posBeforeSort = _bound(params.posBeforeSort, 0, params.leafData.length - 1); // The expiration must be either zero or greater than the block timestamp. @@ -97,17 +97,17 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { vars.merkleRoot = getRoot(leaves.toBytes32()); } - // Make the admin as the caller. - resetPrank({ msgSender: params.admin }); + // Make the campaign owner as the caller. + resetPrank({ msgSender: params.campaignOwner }); uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); vars.expectedLL = computeMerkleLLAddress( - params.admin, params.admin, FORK_ASSET, vars.merkleRoot, params.expiration, sablierFee + params.campaignOwner, params.campaignOwner, FORK_ASSET, vars.merkleRoot, params.expiration, sablierFee ); vars.baseParams = defaults.baseParams({ - admin: params.admin, + campaignOwner: params.campaignOwner, asset_: FORK_ASSET, merkleRoot: vars.merkleRoot, expiration: params.expiration @@ -209,7 +209,7 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { isStream: true, isTransferable: defaults.TRANSFERABLE(), recipient: vars.recipients[params.posBeforeSort], - sender: params.admin, + sender: params.campaignOwner, startTime: getBlockTimestamp(), wasCanceled: false }); @@ -221,17 +221,17 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { CLAWBACK //////////////////////////////////////////////////////////////////////////*/ - // Make the admin as the caller. - resetPrank({ msgSender: params.admin }); + // Make the campaign owner as the caller. + resetPrank({ msgSender: params.campaignOwner }); if (params.expiration > 0) { vars.clawbackAmount = uint128(FORK_ASSET.balanceOf(address(vars.merkleLL))); vm.warp({ newTimestamp: uint256(params.expiration) + 1 seconds }); - expectCallToTransfer({ asset: FORK_ASSET, to: params.admin, value: vars.clawbackAmount }); + expectCallToTransfer({ asset: FORK_ASSET, to: params.campaignOwner, value: vars.clawbackAmount }); vm.expectEmit({ emitter: address(vars.merkleLL) }); - emit Clawback({ to: params.admin, admin: params.admin, amount: vars.clawbackAmount }); - vars.merkleLL.clawback({ to: params.admin, amount: vars.clawbackAmount }); + emit Clawback({ to: params.campaignOwner, admin: params.campaignOwner, amount: vars.clawbackAmount }); + vars.merkleLL.clawback({ to: params.campaignOwner, amount: vars.clawbackAmount }); } /*////////////////////////////////////////////////////////////////////////// diff --git a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol index c1e5b4cbd..099bd5d4c 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol @@ -23,7 +23,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { } struct Params { - address admin; + address campaignOwner; uint40 expiration; LeafData[] leafData; uint256 posBeforeSort; @@ -53,9 +53,9 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { uint256[] public leaves; function testForkFuzz_MerkleLT(Params memory params) external { - vm.assume(params.admin != address(0) && params.admin != users.admin); + vm.assume(params.campaignOwner != address(0) && params.campaignOwner != users.campaignOwner); vm.assume(params.leafData.length > 0); - assumeNoBlacklisted({ token: address(FORK_ASSET), addr: params.admin }); + assumeNoBlacklisted({ token: address(FORK_ASSET), addr: params.campaignOwner }); params.posBeforeSort = _bound(params.posBeforeSort, 0, params.leafData.length - 1); // The expiration must be either zero or greater than the block timestamp. @@ -98,17 +98,17 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { vars.merkleRoot = getRoot(leaves.toBytes32()); } - // Make the admin as the caller. - resetPrank({ msgSender: params.admin }); + // Make the campaign owner as the caller. + resetPrank({ msgSender: params.campaignOwner }); uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); vars.expectedLT = computeMerkleLTAddress( - params.admin, params.admin, FORK_ASSET, vars.merkleRoot, params.expiration, sablierFee + params.campaignOwner, params.campaignOwner, FORK_ASSET, vars.merkleRoot, params.expiration, sablierFee ); vars.baseParams = defaults.baseParams({ - admin: params.admin, + campaignOwner: params.campaignOwner, asset_: FORK_ASSET, merkleRoot: vars.merkleRoot, expiration: params.expiration @@ -211,7 +211,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { isStream: true, isTransferable: defaults.TRANSFERABLE(), recipient: vars.recipients[params.posBeforeSort], - sender: params.admin, + sender: params.campaignOwner, startTime: getBlockTimestamp(), tranches: defaults.tranchesMerkleLT({ streamStartTime: defaults.STREAM_START_TIME_ZERO(), @@ -227,18 +227,18 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { CLAWBACK //////////////////////////////////////////////////////////////////////////*/ - // Make the admin as the caller. - resetPrank({ msgSender: params.admin }); + // Make the campaign owner as the caller. + resetPrank({ msgSender: params.campaignOwner }); if (params.expiration > 0) { vars.clawbackAmount = uint128(FORK_ASSET.balanceOf(address(vars.merkleLT))); vm.warp({ newTimestamp: uint256(params.expiration) + 1 seconds }); - resetPrank({ msgSender: params.admin }); - expectCallToTransfer({ asset: FORK_ASSET, to: params.admin, value: vars.clawbackAmount }); + resetPrank({ msgSender: params.campaignOwner }); + expectCallToTransfer({ asset: FORK_ASSET, to: params.campaignOwner, value: vars.clawbackAmount }); vm.expectEmit({ emitter: address(vars.merkleLT) }); - emit Clawback({ to: params.admin, admin: params.admin, amount: vars.clawbackAmount }); - vars.merkleLT.clawback({ to: params.admin, amount: vars.clawbackAmount }); + emit Clawback({ to: params.campaignOwner, admin: params.campaignOwner, amount: vars.clawbackAmount }); + vars.merkleLT.clawback({ to: params.campaignOwner, amount: vars.clawbackAmount }); } /*////////////////////////////////////////////////////////////////////////// diff --git a/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol index 4851443a2..fd4f8d9f9 100644 --- a/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol +++ b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol @@ -35,26 +35,30 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { function computeMerkleInstantAddress() internal view returns (address) { return computeMerkleInstantAddress( - users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE() + users.campaignOwner, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE() ); } - function computeMerkleInstantAddress(address admin) internal view returns (address) { + function computeMerkleInstantAddress(address campaignOwner) internal view returns (address) { return computeMerkleInstantAddress( - admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE() + campaignOwner, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE() ); } - function computeMerkleInstantAddress(address admin, uint40 expiration) internal view returns (address) { - return computeMerkleInstantAddress(admin, defaults.MERKLE_ROOT(), expiration, defaults.DEFAULT_SABLIER_FEE()); + function computeMerkleInstantAddress(address campaignOwner, uint40 expiration) internal view returns (address) { + return computeMerkleInstantAddress( + campaignOwner, defaults.MERKLE_ROOT(), expiration, defaults.DEFAULT_SABLIER_FEE() + ); } - function computeMerkleInstantAddress(address admin, bytes32 merkleRoot) internal view returns (address) { - return computeMerkleInstantAddress(admin, merkleRoot, defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE()); + function computeMerkleInstantAddress(address campaignOwner, bytes32 merkleRoot) internal view returns (address) { + return computeMerkleInstantAddress( + campaignOwner, merkleRoot, defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE() + ); } function computeMerkleInstantAddress( - address admin, + address campaignOwner, bytes32 merkleRoot, uint40 expiration, uint256 sablierFee @@ -63,24 +67,24 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { view returns (address) { - return computeMerkleInstantAddress(users.alice, admin, dai, merkleRoot, expiration, sablierFee); + return computeMerkleInstantAddress(users.alice, campaignOwner, dai, merkleRoot, expiration, sablierFee); } function createMerkleInstant() internal returns (ISablierMerkleInstant) { - return createMerkleInstant(users.admin, defaults.EXPIRATION()); + return createMerkleInstant(users.campaignOwner, defaults.EXPIRATION()); } - function createMerkleInstant(address admin) internal returns (ISablierMerkleInstant) { - return createMerkleInstant(admin, defaults.EXPIRATION()); + function createMerkleInstant(address campaignOwner) internal returns (ISablierMerkleInstant) { + return createMerkleInstant(campaignOwner, defaults.EXPIRATION()); } function createMerkleInstant(uint40 expiration) internal returns (ISablierMerkleInstant) { - return createMerkleInstant(users.admin, expiration); + return createMerkleInstant(users.campaignOwner, expiration); } - function createMerkleInstant(address admin, uint40 expiration) internal returns (ISablierMerkleInstant) { + function createMerkleInstant(address campaignOwner, uint40 expiration) internal returns (ISablierMerkleInstant) { return merkleFactory.createMerkleInstant({ - baseParams: defaults.baseParams(admin, dai, expiration, defaults.MERKLE_ROOT()), + baseParams: defaults.baseParams(campaignOwner, dai, expiration, defaults.MERKLE_ROOT()), aggregateAmount: defaults.AGGREGATE_AMOUNT(), recipientCount: defaults.RECIPIENT_COUNT() }); @@ -92,25 +96,26 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { function computeMerkleLLAddress() internal view returns (address) { return computeMerkleLLAddress( - users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE() + users.campaignOwner, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE() ); } - function computeMerkleLLAddress(address admin) internal view returns (address) { - return - computeMerkleLLAddress(admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE()); + function computeMerkleLLAddress(address campaignOwner) internal view returns (address) { + return computeMerkleLLAddress( + campaignOwner, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE() + ); } - function computeMerkleLLAddress(address admin, uint40 expiration) internal view returns (address) { - return computeMerkleLLAddress(admin, defaults.MERKLE_ROOT(), expiration, defaults.DEFAULT_SABLIER_FEE()); + function computeMerkleLLAddress(address campaignOwner, uint40 expiration) internal view returns (address) { + return computeMerkleLLAddress(campaignOwner, defaults.MERKLE_ROOT(), expiration, defaults.DEFAULT_SABLIER_FEE()); } - function computeMerkleLLAddress(address admin, bytes32 merkleRoot) internal view returns (address) { - return computeMerkleLLAddress(admin, merkleRoot, defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE()); + function computeMerkleLLAddress(address campaignOwner, bytes32 merkleRoot) internal view returns (address) { + return computeMerkleLLAddress(campaignOwner, merkleRoot, defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE()); } function computeMerkleLLAddress( - address admin, + address campaignOwner, bytes32 merkleRoot, uint40 expiration, uint256 sablierFee @@ -119,24 +124,24 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { view returns (address) { - return computeMerkleLLAddress(users.alice, admin, dai, merkleRoot, expiration, sablierFee); + return computeMerkleLLAddress(users.alice, campaignOwner, dai, merkleRoot, expiration, sablierFee); } function createMerkleLL() internal returns (ISablierMerkleLL) { - return createMerkleLL(users.admin, defaults.EXPIRATION()); + return createMerkleLL(users.campaignOwner, defaults.EXPIRATION()); } - function createMerkleLL(address admin) internal returns (ISablierMerkleLL) { - return createMerkleLL(admin, defaults.EXPIRATION()); + function createMerkleLL(address campaignOwner) internal returns (ISablierMerkleLL) { + return createMerkleLL(campaignOwner, defaults.EXPIRATION()); } function createMerkleLL(uint40 expiration) internal returns (ISablierMerkleLL) { - return createMerkleLL(users.admin, expiration); + return createMerkleLL(users.campaignOwner, expiration); } - function createMerkleLL(address admin, uint40 expiration) internal returns (ISablierMerkleLL) { + function createMerkleLL(address campaignOwner, uint40 expiration) internal returns (ISablierMerkleLL) { return merkleFactory.createMerkleLL({ - baseParams: defaults.baseParams(admin, dai, expiration, defaults.MERKLE_ROOT()), + baseParams: defaults.baseParams(campaignOwner, dai, expiration, defaults.MERKLE_ROOT()), lockupLinear: lockupLinear, cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), @@ -152,25 +157,26 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { function computeMerkleLTAddress() internal view returns (address) { return computeMerkleLTAddress( - users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE() + users.campaignOwner, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE() ); } - function computeMerkleLTAddress(address admin) internal view returns (address) { - return - computeMerkleLTAddress(admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE()); + function computeMerkleLTAddress(address campaignOwner) internal view returns (address) { + return computeMerkleLTAddress( + campaignOwner, defaults.MERKLE_ROOT(), defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE() + ); } - function computeMerkleLTAddress(address admin, uint40 expiration) internal view returns (address) { - return computeMerkleLTAddress(admin, defaults.MERKLE_ROOT(), expiration, defaults.DEFAULT_SABLIER_FEE()); + function computeMerkleLTAddress(address campaignOwner, uint40 expiration) internal view returns (address) { + return computeMerkleLTAddress(campaignOwner, defaults.MERKLE_ROOT(), expiration, defaults.DEFAULT_SABLIER_FEE()); } - function computeMerkleLTAddress(address admin, bytes32 merkleRoot) internal view returns (address) { - return computeMerkleLTAddress(admin, merkleRoot, defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE()); + function computeMerkleLTAddress(address campaignOwner, bytes32 merkleRoot) internal view returns (address) { + return computeMerkleLTAddress(campaignOwner, merkleRoot, defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE()); } function computeMerkleLTAddress( - address admin, + address campaignOwner, bytes32 merkleRoot, uint40 expiration, uint256 sablierFee @@ -179,24 +185,24 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { view returns (address) { - return computeMerkleLTAddress(users.alice, admin, dai, merkleRoot, expiration, sablierFee); + return computeMerkleLTAddress(users.alice, campaignOwner, dai, merkleRoot, expiration, sablierFee); } function createMerkleLT() internal returns (ISablierMerkleLT) { - return createMerkleLT(users.admin, defaults.EXPIRATION()); + return createMerkleLT(users.campaignOwner, defaults.EXPIRATION()); } - function createMerkleLT(address admin) internal returns (ISablierMerkleLT) { - return createMerkleLT(admin, defaults.EXPIRATION()); + function createMerkleLT(address campaignOwner) internal returns (ISablierMerkleLT) { + return createMerkleLT(campaignOwner, defaults.EXPIRATION()); } function createMerkleLT(uint40 expiration) internal returns (ISablierMerkleLT) { - return createMerkleLT(users.admin, expiration); + return createMerkleLT(users.campaignOwner, expiration); } - function createMerkleLT(address admin, uint40 expiration) internal returns (ISablierMerkleLT) { + function createMerkleLT(address campaignOwner, uint40 expiration) internal returns (ISablierMerkleLT) { return merkleFactory.createMerkleLT({ - baseParams: defaults.baseParams(admin, dai, expiration, defaults.MERKLE_ROOT()), + baseParams: defaults.baseParams(campaignOwner, dai, expiration, defaults.MERKLE_ROOT()), lockupTranched: lockupTranched, cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol b/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol index 503ae077b..8fa1df962 100644 --- a/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol @@ -47,12 +47,12 @@ contract CreateMerkleInstant_Integration_Test is MerkleCampaign_Integration_Test }); } - function test_GivenCampaignNotExists(address admin, uint40 expiration) external whenNameNotTooLong { - vm.assume(admin != users.admin); - address expectedMerkleInstant = computeMerkleInstantAddress(admin, expiration); + function test_GivenCampaignNotExists(address campaignOwner, uint40 expiration) external whenNameNotTooLong { + vm.assume(campaignOwner != users.campaignOwner); + address expectedMerkleInstant = computeMerkleInstantAddress(campaignOwner, expiration); MerkleBase.ConstructorParams memory baseParams = defaults.baseParams({ - admin: admin, + campaignOwner: campaignOwner, asset_: dai, merkleRoot: defaults.MERKLE_ROOT(), expiration: expiration @@ -66,7 +66,7 @@ contract CreateMerkleInstant_Integration_Test is MerkleCampaign_Integration_Test recipientCount: defaults.RECIPIENT_COUNT() }); - address actualInstant = address(createMerkleInstant(admin, expiration)); + address actualInstant = address(createMerkleInstant(campaignOwner, expiration)); assertGt(actualInstant.code.length, 0, "MerkleInstant contract not created"); assertEq(actualInstant, expectedMerkleInstant, "MerkleInstant contract does not match computed address"); } diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol b/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol index 8b092dfe6..64a213c5d 100644 --- a/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol @@ -61,12 +61,12 @@ contract CreateMerkleLL_Integration_Test is MerkleCampaign_Integration_Test { }); } - function test_GivenCampaignNotExists(address admin, uint40 expiration) external whenNameNotTooLong { - vm.assume(admin != users.admin); - address expectedLL = computeMerkleLLAddress(admin, expiration); + function test_GivenCampaignNotExists(address campaignOwner, uint40 expiration) external whenNameNotTooLong { + vm.assume(campaignOwner != users.campaignOwner); + address expectedLL = computeMerkleLLAddress(campaignOwner, expiration); MerkleBase.ConstructorParams memory baseParams = defaults.baseParams({ - admin: admin, + campaignOwner: campaignOwner, asset_: dai, merkleRoot: defaults.MERKLE_ROOT(), expiration: expiration @@ -84,7 +84,7 @@ contract CreateMerkleLL_Integration_Test is MerkleCampaign_Integration_Test { recipientCount: defaults.RECIPIENT_COUNT() }); - address actualLL = address(createMerkleLL(admin, expiration)); + address actualLL = address(createMerkleLL(campaignOwner, expiration)); assertGt(actualLL.code.length, 0, "MerkleLL contract not created"); assertEq(actualLL, expectedLL, "MerkleLL contract does not match computed address"); } diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol b/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol index db09f2312..fe5dc19da 100644 --- a/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol @@ -65,12 +65,12 @@ contract CreateMerkleLT_Integration_Test is MerkleCampaign_Integration_Test { ); } - function test_GivenCampaignNotExists(address admin, uint40 expiration) external whenNameNotTooLong { - vm.assume(admin != users.admin); - address expectedLT = computeMerkleLTAddress(admin, expiration); + function test_GivenCampaignNotExists(address campaignOwner, uint40 expiration) external whenNameNotTooLong { + vm.assume(campaignOwner != users.campaignOwner); + address expectedLT = computeMerkleLTAddress(campaignOwner, expiration); MerkleBase.ConstructorParams memory baseParams = defaults.baseParams({ - admin: admin, + campaignOwner: campaignOwner, asset_: dai, merkleRoot: defaults.MERKLE_ROOT(), expiration: expiration @@ -90,7 +90,7 @@ contract CreateMerkleLT_Integration_Test is MerkleCampaign_Integration_Test { recipientCount: defaults.RECIPIENT_COUNT() }); - address actualLT = address(createMerkleLT(admin, expiration)); + address actualLT = address(createMerkleLT(campaignOwner, expiration)); assertGt(actualLT.code.length, 0, "MerkleLT contract not created"); assertEq(actualLT, expectedLT, "MerkleLT contract does not match computed address"); } diff --git a/test/periphery/integration/merkle-campaign/instant/constructor.t.sol b/test/periphery/integration/merkle-campaign/instant/constructor.t.sol index a0092ae0f..c4917d854 100644 --- a/test/periphery/integration/merkle-campaign/instant/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/instant/constructor.t.sol @@ -36,7 +36,7 @@ contract Constructor_MerkleInstant_Integration_Test is MerkleCampaign_Integratio Vars memory vars; vars.actualAdmin = constructedInstant.admin(); - vars.expectedAdmin = users.admin; + vars.expectedAdmin = users.campaignOwner; assertEq(vars.actualAdmin, vars.expectedAdmin, "admin"); vars.actualAsset = address(constructedInstant.ASSET()); diff --git a/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol index fc272e207..0f57f592f 100644 --- a/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol @@ -94,7 +94,7 @@ contract Claim_MerkleLL_Integration_Test is Claim_Integration_Test, MerkleLL_Int isStream: true, isTransferable: defaults.TRANSFERABLE(), recipient: users.recipient1, - sender: users.admin, + sender: users.campaignOwner, startTime: startTime, wasCanceled: false }); diff --git a/test/periphery/integration/merkle-campaign/ll/constructor.t.sol b/test/periphery/integration/merkle-campaign/ll/constructor.t.sol index dda08b6bb..ad3440655 100644 --- a/test/periphery/integration/merkle-campaign/ll/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/constructor.t.sol @@ -53,7 +53,7 @@ contract Constructor_MerkleLL_Integration_Test is MerkleCampaign_Integration_Tes Vars memory vars; vars.actualAdmin = constructedLL.admin(); - vars.expectedAdmin = users.admin; + vars.expectedAdmin = users.campaignOwner; assertEq(vars.actualAdmin, vars.expectedAdmin, "admin"); vars.actualAllowance = dai.allowance(address(constructedLL), address(lockupLinear)); diff --git a/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol index 13f1bf7b0..bfd9f1e4f 100644 --- a/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol @@ -152,7 +152,7 @@ contract Claim_MerkleLT_Integration_Test is Claim_Integration_Test, MerkleLT_Int isStream: true, isTransferable: defaults.TRANSFERABLE(), recipient: users.recipient1, - sender: users.admin, + sender: users.campaignOwner, startTime: startTime, tranches: defaults.tranchesMerkleLT({ streamStartTime: streamStartTime, totalAmount: defaults.CLAIM_AMOUNT() }), wasCanceled: false diff --git a/test/periphery/integration/merkle-campaign/lt/constructor.t.sol b/test/periphery/integration/merkle-campaign/lt/constructor.t.sol index 3fdb4c4c0..772eb86fd 100644 --- a/test/periphery/integration/merkle-campaign/lt/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/constructor.t.sol @@ -58,7 +58,7 @@ contract Constructor_MerkleLT_Integration_Test is MerkleCampaign_Integration_Tes Vars memory vars; vars.actualAdmin = constructedLT.admin(); - vars.expectedAdmin = users.admin; + vars.expectedAdmin = users.campaignOwner; assertEq(vars.actualAdmin, vars.expectedAdmin, "admin"); vars.actualAllowance = dai.allowance(address(constructedLT), address(lockupTranched)); diff --git a/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol b/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol index df62950c9..0a7f1e865 100644 --- a/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol +++ b/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol @@ -45,6 +45,11 @@ abstract contract MerkleCampaign_Integration_Shared_Test is MerkleCampaign_Integ _; } + modifier whenCallerCampaignOwner() { + resetPrank({ msgSender: users.campaignOwner }); + _; + } + modifier whenExpirationNotZero() { _; } @@ -55,8 +60,8 @@ abstract contract MerkleCampaign_Integration_Shared_Test is MerkleCampaign_Integ // Make the first claim to set `_firstClaimTime`. claim(); - // Reset the prank back to the users.admin. - resetPrank(users.admin); + // Reset the prank back to the campaign owner. + resetPrank(users.campaignOwner); _; } diff --git a/test/periphery/integration/merkle-campaign/shared/clawback/clawback.t.sol b/test/periphery/integration/merkle-campaign/shared/clawback/clawback.t.sol index d8756407f..3318ed198 100644 --- a/test/periphery/integration/merkle-campaign/shared/clawback/clawback.t.sol +++ b/test/periphery/integration/merkle-campaign/shared/clawback/clawback.t.sol @@ -11,22 +11,27 @@ abstract contract Clawback_Integration_Test is MerkleCampaign_Integration_Shared MerkleCampaign_Integration_Shared_Test.setUp(); } - function test_RevertWhen_CallerNotAdmin() external { + function test_RevertWhen_CallerNotCampaignOwner() external { resetPrank({ msgSender: users.eve }); - vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); + vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.campaignOwner, users.eve)); merkleBase.clawback({ to: users.eve, amount: 1 }); } - function test_WhenFirstClaimNotMade() external whenCallerAdmin { - test_Clawback(users.admin); + function test_WhenFirstClaimNotMade() external whenCallerCampaignOwner { + test_Clawback(users.campaignOwner); } - function test_GivenSevenDaysNotPassed() external whenCallerAdmin whenFirstClaimMade { + function test_GivenSevenDaysNotPassed() external whenCallerCampaignOwner whenFirstClaimMade { vm.warp({ newTimestamp: getBlockTimestamp() + 6 days }); - test_Clawback(users.admin); + test_Clawback(users.campaignOwner); } - function test_RevertGiven_CampaignNotExpired() external whenCallerAdmin whenFirstClaimMade givenSevenDaysPassed { + function test_RevertGiven_CampaignNotExpired() + external + whenCallerCampaignOwner + whenFirstClaimMade + givenSevenDaysPassed + { vm.expectRevert( abi.encodeWithSelector( Errors.SablierMerkleBase_ClawbackNotAllowed.selector, @@ -35,10 +40,15 @@ abstract contract Clawback_Integration_Test is MerkleCampaign_Integration_Shared defaults.FIRST_CLAIM_TIME() ) ); - merkleBase.clawback({ to: users.admin, amount: 1 }); + merkleBase.clawback({ to: users.campaignOwner, amount: 1 }); } - function test_GivenCampaignExpired(address to) external whenCallerAdmin whenFirstClaimMade givenSevenDaysPassed { + function test_GivenCampaignExpired(address to) + external + whenCallerCampaignOwner + whenFirstClaimMade + givenSevenDaysPassed + { vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); vm.assume(to != address(0)); test_Clawback(to); @@ -50,7 +60,7 @@ abstract contract Clawback_Integration_Test is MerkleCampaign_Integration_Shared expectCallToTransfer({ to: to, value: clawbackAmount }); // It should emit a {Clawback} event. vm.expectEmit({ emitter: address(merkleBase) }); - emit Clawback({ admin: users.admin, to: to, amount: clawbackAmount }); + emit Clawback({ admin: users.campaignOwner, to: to, amount: clawbackAmount }); merkleBase.clawback({ to: to, amount: clawbackAmount }); } } diff --git a/test/periphery/integration/merkle-campaign/shared/clawback/clawback.tree b/test/periphery/integration/merkle-campaign/shared/clawback/clawback.tree index 4828678e3..92db26f83 100644 --- a/test/periphery/integration/merkle-campaign/shared/clawback/clawback.tree +++ b/test/periphery/integration/merkle-campaign/shared/clawback/clawback.tree @@ -1,7 +1,7 @@ Clawback_Integration_Test -├── when caller not admin +├── when caller not campaign owner │ └── it should revert -└── when caller admin +└── when caller campaig owner ├── when first claim not made │ ├── it should perform the ERC-20 transfer │ └── it should emit a {Clawback} event diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 9e391a94f..3ca9e8d16 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -447,11 +447,11 @@ contract Defaults is Constants, Merkle { //////////////////////////////////////////////////////////////////////////*/ function baseParams() public view returns (MerkleBase.ConstructorParams memory) { - return baseParams(users.admin, asset, EXPIRATION, MERKLE_ROOT); + return baseParams(users.campaignOwner, asset, EXPIRATION, MERKLE_ROOT); } function baseParams( - address admin, + address campaignOwner, IERC20 asset_, uint40 expiration, bytes32 merkleRoot @@ -463,7 +463,7 @@ contract Defaults is Constants, Merkle { return MerkleBase.ConstructorParams({ asset: asset_, expiration: expiration, - initialAdmin: admin, + initialAdmin: campaignOwner, ipfsCID: IPFS_CID, merkleRoot: merkleRoot, name: NAME diff --git a/test/utils/Types.sol b/test/utils/Types.sol index ed5aa2454..f30f7348f 100644 --- a/test/utils/Types.sol +++ b/test/utils/Types.sol @@ -8,6 +8,8 @@ struct Users { address payable alice; // Default stream broker. address payable broker; + // Default campaign owner. + address payable campaignOwner; // Malicious user. address payable eve; // Default NFT operator. From 6ec11429e6e45bc63d74b40109b480af5c0df978 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 11 Sep 2024 17:21:28 +0100 Subject: [PATCH 12/21] test: custom sablier fee for users --- src/periphery/SablierMerkleFactory.sol | 4 +- .../interfaces/ISablierMerkleFactory.sol | 8 +- .../merkle-campaign/MerkleCampaign.t.sol | 67 +++++++++++++++-- .../createMerkleInstant.t.sol | 72 ++++++++++++++++-- .../createMerkleInstant.tree | 10 ++- .../create-merkle-ll/createMerkleLL.t.sol | 72 ++++++++++++++++-- .../create-merkle-ll/createMerkleLL.tree | 10 ++- .../create-merkle-lt/createMerkleLT.t.sol | 73 +++++++++++++++++-- .../create-merkle-lt/createMerkleLT.tree | 10 ++- .../resetSablierFeeByUser.t.sol | 53 ++++++++++++++ .../resetSablierFeeByUser.tree | 12 +++ .../set-fee-by-user/setSablierFeeByUser.t.sol | 53 ++++++++++++++ .../set-fee-by-user/setSablierFeeByUser.tree | 11 +++ test/utils/Events.sol | 4 + 14 files changed, 427 insertions(+), 32 deletions(-) create mode 100644 test/periphery/integration/merkle-campaign/factory/reset-fee-by-user/resetSablierFeeByUser.t.sol create mode 100644 test/periphery/integration/merkle-campaign/factory/reset-fee-by-user/resetSablierFeeByUser.tree create mode 100644 test/periphery/integration/merkle-campaign/factory/set-fee-by-user/setSablierFeeByUser.t.sol create mode 100644 test/periphery/integration/merkle-campaign/factory/set-fee-by-user/setSablierFeeByUser.tree diff --git a/src/periphery/SablierMerkleFactory.sol b/src/periphery/SablierMerkleFactory.sol index ed0c35d92..86660a8ae 100644 --- a/src/periphery/SablierMerkleFactory.sol +++ b/src/periphery/SablierMerkleFactory.sol @@ -81,7 +81,7 @@ contract SablierMerkleFactory is delete _sablierFeeByUser[campaignCreator]; // Log the reset. - emit ResetSablierFeeFor({ admin: msg.sender, user: campaignCreator }); + emit ResetSablierFee({ admin: msg.sender, campaignCreator: campaignCreator }); } /// @inheritdoc ISablierMerkleFactory @@ -103,7 +103,7 @@ contract SablierMerkleFactory is feeByUser.fee = fee; // Log the update. - emit UpdateSablierFeeFor({ admin: msg.sender, user: campaignCreator, sablierFee: fee }); + emit SetSablierFee({ admin: msg.sender, campaignCreator: campaignCreator, sablierFee: fee }); } /// @inheritdoc ISablierMerkleFactory diff --git a/src/periphery/interfaces/ISablierMerkleFactory.sol b/src/periphery/interfaces/ISablierMerkleFactory.sol index 7633a517b..133025558 100644 --- a/src/periphery/interfaces/ISablierMerkleFactory.sol +++ b/src/periphery/interfaces/ISablierMerkleFactory.sol @@ -58,13 +58,13 @@ interface ISablierMerkleFactory is IAdminable { ); /// @notice Emitted when the admin resets Sablier fee to default for a specific user. - event ResetSablierFeeFor(address indexed admin, address indexed user); + event ResetSablierFee(address indexed admin, address indexed campaignCreator); /// @notice Emitted when the default Sablier fee is set by the admin. event SetDefaultSablierFee(address indexed admin, uint256 defaultSablierFee); /// @notice Emitted when the admin sets Sablier fee for a specific user. - event UpdateSablierFeeFor(address indexed admin, address indexed user, uint256 sablierFee); + event SetSablierFee(address indexed admin, address indexed campaignCreator, uint256 sablierFee); /// @notice Emitted when the sablier fees are claimed by the sablier admin. event WithdrawSablierFees( @@ -182,7 +182,7 @@ interface ISablierMerkleFactory is IAdminable { returns (ISablierMerkleLT merkleLT); /// @notice Resets the Sablier fee to default. - /// @dev Emits a {ResetSablierFeeFor} event. + /// @dev Emits a {ResetSablierFee} event. /// /// Notes: /// - The default fee will only be applied to the future campaigns. @@ -194,7 +194,7 @@ interface ISablierMerkleFactory is IAdminable { function resetSablierFeeByUser(address campaignCreator) external; /// @notice Sets the custom Sablier fee for a campaign creator. - /// @dev Emits a {UpdateSablierFeeFor} event. + /// @dev Emits a {SetSablierFee} event. /// /// Notes: /// - The new fee will only be applied to the future campaigns. diff --git a/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol index fd4f8d9f9..d2a03bda3 100644 --- a/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol +++ b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol @@ -15,8 +15,8 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { function setUp() public virtual override { Periphery_Test.setUp(); - // Make Alice the caller. - resetPrank(users.alice); + // Make campaign owner the caller. + resetPrank(users.campaignOwner); // Create the default Merkle contracts. merkleInstant = createMerkleInstant(); @@ -51,6 +51,18 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { ); } + function computeMerkleInstantAddress( + address campaignOwner, + uint40 expiration, + uint256 sablierFee + ) + internal + view + returns (address) + { + return computeMerkleInstantAddress(campaignOwner, defaults.MERKLE_ROOT(), expiration, sablierFee); + } + function computeMerkleInstantAddress(address campaignOwner, bytes32 merkleRoot) internal view returns (address) { return computeMerkleInstantAddress( campaignOwner, merkleRoot, defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE() @@ -67,7 +79,14 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { view returns (address) { - return computeMerkleInstantAddress(users.alice, campaignOwner, dai, merkleRoot, expiration, sablierFee); + return computeMerkleInstantAddress({ + caller: users.campaignOwner, + campaignOwner: campaignOwner, + asset_: dai, + merkleRoot: merkleRoot, + expiration: expiration, + sablierFee: sablierFee + }); } function createMerkleInstant() internal returns (ISablierMerkleInstant) { @@ -110,6 +129,18 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { return computeMerkleLLAddress(campaignOwner, defaults.MERKLE_ROOT(), expiration, defaults.DEFAULT_SABLIER_FEE()); } + function computeMerkleLLAddress( + address campaignOwner, + uint40 expiration, + uint256 sablierFee + ) + internal + view + returns (address) + { + return computeMerkleLLAddress(campaignOwner, defaults.MERKLE_ROOT(), expiration, sablierFee); + } + function computeMerkleLLAddress(address campaignOwner, bytes32 merkleRoot) internal view returns (address) { return computeMerkleLLAddress(campaignOwner, merkleRoot, defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE()); } @@ -124,7 +155,14 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { view returns (address) { - return computeMerkleLLAddress(users.alice, campaignOwner, dai, merkleRoot, expiration, sablierFee); + return computeMerkleLLAddress({ + caller: users.campaignOwner, + campaignOwner: campaignOwner, + asset_: dai, + merkleRoot: merkleRoot, + expiration: expiration, + sablierFee: sablierFee + }); } function createMerkleLL() internal returns (ISablierMerkleLL) { @@ -171,6 +209,18 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { return computeMerkleLTAddress(campaignOwner, defaults.MERKLE_ROOT(), expiration, defaults.DEFAULT_SABLIER_FEE()); } + function computeMerkleLTAddress( + address campaignOwner, + uint40 expiration, + uint256 sablierFee + ) + internal + view + returns (address) + { + return computeMerkleLTAddress(campaignOwner, defaults.MERKLE_ROOT(), expiration, sablierFee); + } + function computeMerkleLTAddress(address campaignOwner, bytes32 merkleRoot) internal view returns (address) { return computeMerkleLTAddress(campaignOwner, merkleRoot, defaults.EXPIRATION(), defaults.DEFAULT_SABLIER_FEE()); } @@ -185,7 +235,14 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { view returns (address) { - return computeMerkleLTAddress(users.alice, campaignOwner, dai, merkleRoot, expiration, sablierFee); + return computeMerkleLTAddress({ + caller: users.campaignOwner, + campaignOwner: campaignOwner, + asset_: dai, + merkleRoot: merkleRoot, + expiration: expiration, + sablierFee: sablierFee + }); } function createMerkleLT() internal returns (ISablierMerkleLT) { diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol b/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol index 8fa1df962..f6e1c36b3 100644 --- a/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol @@ -47,8 +47,62 @@ contract CreateMerkleInstant_Integration_Test is MerkleCampaign_Integration_Test }); } - function test_GivenCampaignNotExists(address campaignOwner, uint40 expiration) external whenNameNotTooLong { - vm.assume(campaignOwner != users.campaignOwner); + modifier givenCampaignNotExists() { + _; + } + + function test_GivenCustomFeeSet( + address campaignOwner, + uint40 expiration, + uint256 customFee + ) + external + whenNameNotTooLong + givenCampaignNotExists + { + // Set the Sablier fee to 0 for this test. + resetPrank(users.admin); + merkleFactory.setSablierFeeByUser(users.campaignOwner, customFee); + + resetPrank(users.campaignOwner); + address expectedMerkleInstant = computeMerkleInstantAddress(campaignOwner, expiration, customFee); + + MerkleBase.ConstructorParams memory baseParams = defaults.baseParams({ + campaignOwner: campaignOwner, + asset_: dai, + merkleRoot: defaults.MERKLE_ROOT(), + expiration: expiration + }); + + // It should emit a {CreateMerkleInstant} event. + vm.expectEmit({ emitter: address(merkleFactory) }); + emit CreateMerkleInstant({ + merkleInstant: ISablierMerkleInstant(expectedMerkleInstant), + baseParams: baseParams, + aggregateAmount: defaults.AGGREGATE_AMOUNT(), + recipientCount: defaults.RECIPIENT_COUNT() + }); + + ISablierMerkleInstant actualInstant = createMerkleInstant(campaignOwner, expiration); + assertGt(address(actualInstant).code.length, 0, "MerkleInstant contract not created"); + assertEq( + address(actualInstant), expectedMerkleInstant, "MerkleInstant contract does not match computed address" + ); + + // It should create the campaign with custom fee. + assertEq(actualInstant.SABLIER_FEE(), customFee, "sablier fee"); + // It should set the current factory address. + assertEq(actualInstant.FACTORY(), address(merkleFactory), "factory"); + } + + function test_GivenCustomFeeNotSet( + address campaignOwner, + uint40 expiration + ) + external + whenNameNotTooLong + givenCampaignNotExists + { address expectedMerkleInstant = computeMerkleInstantAddress(campaignOwner, expiration); MerkleBase.ConstructorParams memory baseParams = defaults.baseParams({ @@ -58,6 +112,7 @@ contract CreateMerkleInstant_Integration_Test is MerkleCampaign_Integration_Test expiration: expiration }); + // It should emit a {CreateMerkleInstant} event. vm.expectEmit({ emitter: address(merkleFactory) }); emit CreateMerkleInstant({ merkleInstant: ISablierMerkleInstant(expectedMerkleInstant), @@ -66,8 +121,15 @@ contract CreateMerkleInstant_Integration_Test is MerkleCampaign_Integration_Test recipientCount: defaults.RECIPIENT_COUNT() }); - address actualInstant = address(createMerkleInstant(campaignOwner, expiration)); - assertGt(actualInstant.code.length, 0, "MerkleInstant contract not created"); - assertEq(actualInstant, expectedMerkleInstant, "MerkleInstant contract does not match computed address"); + ISablierMerkleInstant actualInstant = createMerkleInstant(campaignOwner, expiration); + assertGt(address(actualInstant).code.length, 0, "MerkleInstant contract not created"); + assertEq( + address(actualInstant), expectedMerkleInstant, "MerkleInstant contract does not match computed address" + ); + + // It should create the campaign with custom fee. + assertEq(actualInstant.SABLIER_FEE(), defaults.DEFAULT_SABLIER_FEE(), "default sablier fee"); + // It should set the current factory address. + assertEq(actualInstant.FACTORY(), address(merkleFactory), "factory"); } } diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.tree b/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.tree index 047964d0f..7ccf9b6af 100644 --- a/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.tree +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.tree @@ -5,5 +5,11 @@ CreateMerkleInstant_Integration_Test ├── given campaign already exists │ └── it should revert └── given campaign not exists - ├── it should create the campaign - └── it should emit a {CreateMerkleInstant} event + ├── given custom fee set + │ ├── it should create the campaign with custom fee + │ ├── it should set the current factory address + │ └── it should emit a {CreateMerkleInstant} event + └── given custom fee not set + ├── it should create the campaign with default fee + ├── it should set the current factory address + └── it should emit a {CreateMerkleInstant} event diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol b/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol index 64a213c5d..096803efa 100644 --- a/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol @@ -61,8 +61,64 @@ contract CreateMerkleLL_Integration_Test is MerkleCampaign_Integration_Test { }); } - function test_GivenCampaignNotExists(address campaignOwner, uint40 expiration) external whenNameNotTooLong { - vm.assume(campaignOwner != users.campaignOwner); + modifier givenCampaignNotExists() { + _; + } + + function test_GivenCustomFeeSet( + address campaignOwner, + uint40 expiration, + uint256 customFee + ) + external + whenNameNotTooLong + givenCampaignNotExists + { + // Set the Sablier fee to 0 for this test. + resetPrank(users.admin); + merkleFactory.setSablierFeeByUser(users.campaignOwner, customFee); + + resetPrank(users.campaignOwner); + address expectedLL = computeMerkleLLAddress(campaignOwner, expiration, customFee); + + MerkleBase.ConstructorParams memory baseParams = defaults.baseParams({ + campaignOwner: campaignOwner, + asset_: dai, + merkleRoot: defaults.MERKLE_ROOT(), + expiration: expiration + }); + + // It should emit a {CreateMerkleLL} event. + vm.expectEmit({ emitter: address(merkleFactory) }); + emit CreateMerkleLL({ + merkleLL: ISablierMerkleLL(expectedLL), + baseParams: baseParams, + lockupLinear: lockupLinear, + cancelable: defaults.CANCELABLE(), + transferable: defaults.TRANSFERABLE(), + schedule: defaults.schedule(), + aggregateAmount: defaults.AGGREGATE_AMOUNT(), + recipientCount: defaults.RECIPIENT_COUNT() + }); + + ISablierMerkleLL actualLL = createMerkleLL(campaignOwner, expiration); + assertGt(address(actualLL).code.length, 0, "MerkleLL contract not created"); + assertEq(address(actualLL), expectedLL, "MerkleLL contract does not match computed address"); + + // It should create the campaign with custom fee. + assertEq(actualLL.SABLIER_FEE(), customFee, "sablier fee"); + // It should set the current factory address. + assertEq(actualLL.FACTORY(), address(merkleFactory), "factory"); + } + + function test_GivenCustomFeeNotSet( + address campaignOwner, + uint40 expiration + ) + external + whenNameNotTooLong + givenCampaignNotExists + { address expectedLL = computeMerkleLLAddress(campaignOwner, expiration); MerkleBase.ConstructorParams memory baseParams = defaults.baseParams({ @@ -72,6 +128,7 @@ contract CreateMerkleLL_Integration_Test is MerkleCampaign_Integration_Test { expiration: expiration }); + // It should emit a {CreateMerkleInstant} event. vm.expectEmit({ emitter: address(merkleFactory) }); emit CreateMerkleLL({ merkleLL: ISablierMerkleLL(expectedLL), @@ -84,8 +141,13 @@ contract CreateMerkleLL_Integration_Test is MerkleCampaign_Integration_Test { recipientCount: defaults.RECIPIENT_COUNT() }); - address actualLL = address(createMerkleLL(campaignOwner, expiration)); - assertGt(actualLL.code.length, 0, "MerkleLL contract not created"); - assertEq(actualLL, expectedLL, "MerkleLL contract does not match computed address"); + ISablierMerkleLL actualLL = createMerkleLL(campaignOwner, expiration); + assertGt(address(actualLL).code.length, 0, "MerkleLL contract not created"); + assertEq(address(actualLL), expectedLL, "MerkleLL contract does not match computed address"); + + // It should create the campaign with custom fee. + assertEq(actualLL.SABLIER_FEE(), defaults.DEFAULT_SABLIER_FEE(), "default sablier fee"); + // It should set the current factory address. + assertEq(actualLL.FACTORY(), address(merkleFactory), "factory"); } } diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.tree b/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.tree index d41547b61..e6350cf9d 100644 --- a/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.tree +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.tree @@ -5,5 +5,11 @@ CreateMerkleLL_Integration_Test ├── given campaign already exists │ └── it should revert └── given campaign not exists - ├── it should create the campaign - └── it should emit a {CreateMerkleLL} event + ├── given custom fee set + │ ├── it should create the campaign with custom fee + │ ├── it should set the current factory address + │ └── it should emit a {CreateMerkleLL} event + └── given custom fee not set + ├── it should create the campaign with default fee + ├── it should set the current factory address + └── it should emit a {CreateMerkleLL} event diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol b/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol index fe5dc19da..d7841d9e0 100644 --- a/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol @@ -65,8 +65,66 @@ contract CreateMerkleLT_Integration_Test is MerkleCampaign_Integration_Test { ); } - function test_GivenCampaignNotExists(address campaignOwner, uint40 expiration) external whenNameNotTooLong { - vm.assume(campaignOwner != users.campaignOwner); + modifier givenCampaignNotExists() { + _; + } + + function test_GivenCustomFeeSet( + address campaignOwner, + uint40 expiration, + uint256 customFee + ) + external + whenNameNotTooLong + givenCampaignNotExists + { + // Set the Sablier fee to 0 for this test. + resetPrank(users.admin); + merkleFactory.setSablierFeeByUser(users.campaignOwner, customFee); + + resetPrank(users.campaignOwner); + address expectedLT = computeMerkleLTAddress(campaignOwner, expiration, customFee); + + MerkleBase.ConstructorParams memory baseParams = defaults.baseParams({ + campaignOwner: campaignOwner, + asset_: dai, + merkleRoot: defaults.MERKLE_ROOT(), + expiration: expiration + }); + + // It should emit a {CreateMerkleLT} event. + vm.expectEmit({ emitter: address(merkleFactory) }); + emit CreateMerkleLT({ + merkleLT: ISablierMerkleLT(expectedLT), + baseParams: baseParams, + lockupTranched: lockupTranched, + cancelable: defaults.CANCELABLE(), + transferable: defaults.TRANSFERABLE(), + streamStartTime: defaults.STREAM_START_TIME_ZERO(), + tranchesWithPercentages: defaults.tranchesWithPercentages(), + totalDuration: defaults.TOTAL_DURATION(), + aggregateAmount: defaults.AGGREGATE_AMOUNT(), + recipientCount: defaults.RECIPIENT_COUNT() + }); + + ISablierMerkleLT actualLT = createMerkleLT(campaignOwner, expiration); + assertGt(address(actualLT).code.length, 0, "MerkleLT contract not created"); + assertEq(address(actualLT), expectedLT, "MerkleLT contract does not match computed address"); + + // It should create the campaign with custom fee. + assertEq(actualLT.SABLIER_FEE(), customFee, "sablier fee"); + // It should set the current factory address. + assertEq(actualLT.FACTORY(), address(merkleFactory), "factory"); + } + + function test_GivenCustomFeeNotSet( + address campaignOwner, + uint40 expiration + ) + external + whenNameNotTooLong + givenCampaignNotExists + { address expectedLT = computeMerkleLTAddress(campaignOwner, expiration); MerkleBase.ConstructorParams memory baseParams = defaults.baseParams({ @@ -90,8 +148,13 @@ contract CreateMerkleLT_Integration_Test is MerkleCampaign_Integration_Test { recipientCount: defaults.RECIPIENT_COUNT() }); - address actualLT = address(createMerkleLT(campaignOwner, expiration)); - assertGt(actualLT.code.length, 0, "MerkleLT contract not created"); - assertEq(actualLT, expectedLT, "MerkleLT contract does not match computed address"); + ISablierMerkleLT actualLT = createMerkleLT(campaignOwner, expiration); + assertGt(address(actualLT).code.length, 0, "MerkleLT contract not created"); + assertEq(address(actualLT), expectedLT, "MerkleLT contract does not match computed address"); + + // It should create the campaign with custom fee. + assertEq(actualLT.SABLIER_FEE(), defaults.DEFAULT_SABLIER_FEE(), "default sablier fee"); + // It should set the current factory address. + assertEq(actualLT.FACTORY(), address(merkleFactory), "factory"); } } diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.tree b/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.tree index 7ea208a25..9ccdea759 100644 --- a/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.tree +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.tree @@ -5,5 +5,11 @@ CreateMerkleLT_Integration_Test ├── given campaign already exists │ └── it should revert └── given campaign not exists - ├── it should create the campaign - └── it should emit a {CreateMerkleLT} event + ├── given custom fee set + │ ├── it should create the campaign with custom fee + │ ├── it should set the current factory address + │ └── it should emit a {CreateMerkleLT} event + └── given custom fee not set + ├── it should create the campaign with default fee + ├── it should set the current factory address + └── it should emit a {CreateMerkleLT} event diff --git a/test/periphery/integration/merkle-campaign/factory/reset-fee-by-user/resetSablierFeeByUser.t.sol b/test/periphery/integration/merkle-campaign/factory/reset-fee-by-user/resetSablierFeeByUser.t.sol new file mode 100644 index 000000000..fe92993ce --- /dev/null +++ b/test/periphery/integration/merkle-campaign/factory/reset-fee-by-user/resetSablierFeeByUser.t.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; + +import { MerkleFactory } from "src/periphery/types/DataTypes.sol"; + +import { MerkleCampaign_Integration_Shared_Test } from "../../shared/MerkleCampaign.t.sol"; + +contract ResetSablierFeeByUser_Integration_Test is MerkleCampaign_Integration_Shared_Test { + function test_RevertWhen_CallerNotAdmin() external { + resetPrank({ msgSender: users.eve }); + vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); + merkleFactory.resetSablierFeeByUser({ campaignCreator: users.campaignOwner }); + } + + function test_WhenNotEnabled() external whenCallerAdmin { + // It should emit a {ResetSablierFee} event. + vm.expectEmit({ emitter: address(merkleFactory) }); + emit ResetSablierFee({ admin: users.admin, campaignCreator: users.campaignOwner }); + + // Reset the Sablier fee. + merkleFactory.resetSablierFeeByUser({ campaignCreator: users.campaignOwner }); + + MerkleFactory.SablierFee memory sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); + // It should return false. + assertFalse(sablierFee.enabled, "enabled"); + // It should return 0 for the Sablier fee. + assertEq(sablierFee.fee, 0, "fee"); + } + + function test_WhenEnabled() external whenCallerAdmin { + // Enable the Sablier fee. + merkleFactory.setSablierFeeByUser({ campaignCreator: users.campaignOwner, fee: 1 ether }); + // Check that its enabled. + MerkleFactory.SablierFee memory sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); + assertTrue(sablierFee.enabled, "enabled"); + assertEq(sablierFee.fee, 1 ether, "fee"); + + // It should emit a {ResetSablierFee} event. + vm.expectEmit({ emitter: address(merkleFactory) }); + emit ResetSablierFee({ admin: users.admin, campaignCreator: users.campaignOwner }); + + // Reset the Sablier fee. + merkleFactory.resetSablierFeeByUser({ campaignCreator: users.campaignOwner }); + + sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); + // it should disable the Sablier fee + assertFalse(sablierFee.enabled, "enabled"); + // it should set the Sablier fee to 0 + assertEq(sablierFee.fee, 0, "fee"); + } +} diff --git a/test/periphery/integration/merkle-campaign/factory/reset-fee-by-user/resetSablierFeeByUser.tree b/test/periphery/integration/merkle-campaign/factory/reset-fee-by-user/resetSablierFeeByUser.tree new file mode 100644 index 000000000..623e29345 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/factory/reset-fee-by-user/resetSablierFeeByUser.tree @@ -0,0 +1,12 @@ +ResetSablierFeeByUser_Integration_Test +├── when caller not admin +│ └── it should revert +└── when caller admin + ├── when not enabled + │ ├── it should return false + │ ├── it should return 0 for the Sablier fee + │ └── it should emit a {ResetSablierFee} event + └── when enabled + ├── it should disable the Sablier fee + ├── it should set the Sablier fee to 0 + └── it should emit a {ResetSablierFee} event diff --git a/test/periphery/integration/merkle-campaign/factory/set-fee-by-user/setSablierFeeByUser.t.sol b/test/periphery/integration/merkle-campaign/factory/set-fee-by-user/setSablierFeeByUser.t.sol new file mode 100644 index 000000000..109efeba0 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/factory/set-fee-by-user/setSablierFeeByUser.t.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; + +import { MerkleFactory } from "src/periphery/types/DataTypes.sol"; + +import { MerkleCampaign_Integration_Shared_Test } from "../../shared/MerkleCampaign.t.sol"; + +contract SetSablierFeeByUser_Integration_Test is MerkleCampaign_Integration_Shared_Test { + function test_RevertWhen_CallerNotAdmin() external { + resetPrank({ msgSender: users.eve }); + vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); + merkleFactory.setSablierFeeByUser({ campaignCreator: users.campaignOwner, fee: 0 }); + } + + function test_WhenNotEnabled() external whenCallerAdmin { + // It should emit a {SetSablierFee} event. + vm.expectEmit({ emitter: address(merkleFactory) }); + emit SetSablierFee({ admin: users.admin, campaignCreator: users.campaignOwner, sablierFee: 0 }); + + // Set the Sablier fee. + merkleFactory.setSablierFeeByUser({ campaignCreator: users.campaignOwner, fee: 0 }); + + MerkleFactory.SablierFee memory sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); + // It should enable the Sablier fee. + assertTrue(sablierFee.enabled, "enabled"); + // It should set the Sablier fee. + assertEq(sablierFee.fee, 0, "fee"); + } + + function test_WhenEnabled() external whenCallerAdmin { + // Enable the Sablier fee. + merkleFactory.setSablierFeeByUser({ campaignCreator: users.campaignOwner, fee: 0.001 ether }); + // Check that its enabled. + MerkleFactory.SablierFee memory sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); + assertTrue(sablierFee.enabled, "enabled"); + assertEq(sablierFee.fee, 0.001 ether, "fee"); + + // It should emit a {SetSablierFee} event. + vm.expectEmit({ emitter: address(merkleFactory) }); + emit SetSablierFee({ admin: users.admin, campaignCreator: users.campaignOwner, sablierFee: 1 ether }); + + // Now set it to another fee. + merkleFactory.setSablierFeeByUser({ campaignCreator: users.campaignOwner, fee: 1 ether }); + + sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); + // It should enable the Sablier fee. + assertTrue(sablierFee.enabled, "enabled"); + // It should set the Sablier fee. + assertEq(sablierFee.fee, 1 ether, "fee"); + } +} diff --git a/test/periphery/integration/merkle-campaign/factory/set-fee-by-user/setSablierFeeByUser.tree b/test/periphery/integration/merkle-campaign/factory/set-fee-by-user/setSablierFeeByUser.tree new file mode 100644 index 000000000..9c29fd57c --- /dev/null +++ b/test/periphery/integration/merkle-campaign/factory/set-fee-by-user/setSablierFeeByUser.tree @@ -0,0 +1,11 @@ +SetSablierFeeByUser_Integration_Test +├── when caller not admin +│ └── it should revert +└── when caller admin + ├── when not enabled + │ ├── it should enable the Sablier fee + │ ├── it should set the Sablier fee + │ └── it should emit a {SetSablierFee} event + └── when enabled + ├── it should set the Sablier fee + └── it should emit a {SetSablierFee} event diff --git a/test/utils/Events.sol b/test/utils/Events.sol index 7bcf22616..b09b16b32 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -139,8 +139,12 @@ abstract contract Events { uint256 recipientCount ); + event ResetSablierFee(address indexed admin, address indexed campaignCreator); + event SetDefaultSablierFee(address indexed admin, uint256 sablierFee); + event SetSablierFee(address indexed admin, address indexed campaignCreator, uint256 sablierFee); + event WithdrawSablierFees( address indexed admin, ISablierMerkleBase indexed merkleLockup, address to, uint256 sablierFees ); From bc77b3cbff5c06a459ba8dcf02d5defb7fe8f771 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 11 Sep 2024 17:29:19 +0100 Subject: [PATCH 13/21] style: fix import --- .lintstagedrc.yml | 2 +- src/periphery/SablierMerkleFactory.sol | 2 +- .../merkle-campaign/instant/MerkleInstant.t.sol | 13 ++++++------- .../integration/merkle-campaign/ll/MerkleLL.t.sol | 13 ++++++------- .../integration/merkle-campaign/lt/MerkleLT.t.sol | 13 ++++++------- 5 files changed, 20 insertions(+), 23 deletions(-) diff --git a/.lintstagedrc.yml b/.lintstagedrc.yml index 3b310bf20..2353f3772 100644 --- a/.lintstagedrc.yml +++ b/.lintstagedrc.yml @@ -1,4 +1,4 @@ "*.{json,md,svg,yml}": "prettier --write" "*.sol": - - "bun solhint --fix --noPrompt" + - "bun solhint {benchmark,precompiles,script,src,test}/**/*.sol --fix --noPrompt" - "forge fmt" diff --git a/src/periphery/SablierMerkleFactory.sol b/src/periphery/SablierMerkleFactory.sol index 86660a8ae..925106339 100644 --- a/src/periphery/SablierMerkleFactory.sol +++ b/src/periphery/SablierMerkleFactory.sol @@ -31,7 +31,7 @@ contract SablierMerkleFactory is uint256 public defaultSablierFee; /// @dev A mapping of custom Sablier fees by user. - mapping(address campaignCreator => MerkleFactory.SablierFee) private _sablierFeeByUser; + mapping(address campaignCreator => MerkleFactory.SablierFee customFee) private _sablierFeeByUser; /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR diff --git a/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol b/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol index 1d9ea9749..04cbac465 100644 --- a/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol +++ b/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol @@ -2,13 +2,12 @@ pragma solidity >=0.8.22 <0.9.0; import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; - -import { Clawback_Integration_Test } from "../shared/clawback/clawback.t.sol"; -import { GetFirstClaimTime_Integration_Test } from "../shared/get-first-claim-time/getFirstClaimTime.t.sol"; -import { HasClaimed_Integration_Test } from "../shared/has-claimed/hasClaimed.t.sol"; -import { HasExpired_Integration_Test } from "../shared/has-expired/hasExpired.t.sol"; -import { WithdrawFees_Integration_Test } from "../shared/withdraw-fees/withdrawFees.t.sol"; -import { MerkleCampaign_Integration_Shared_Test } from "../shared/MerkleCampaign.t.sol"; +import { Clawback_Integration_Test } from "./../shared/clawback/clawback.t.sol"; +import { GetFirstClaimTime_Integration_Test } from "./../shared/get-first-claim-time/getFirstClaimTime.t.sol"; +import { HasClaimed_Integration_Test } from "./../shared/has-claimed/hasClaimed.t.sol"; +import { HasExpired_Integration_Test } from "./../shared/has-expired/hasExpired.t.sol"; +import { MerkleCampaign_Integration_Shared_Test } from "./../shared/MerkleCampaign.t.sol"; +import { WithdrawFees_Integration_Test } from "./../shared/withdraw-fees/withdrawFees.t.sol"; /*////////////////////////////////////////////////////////////////////////// NON-SHARED TESTS diff --git a/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol b/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol index 69774c03b..63e1e5d84 100644 --- a/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol @@ -2,13 +2,12 @@ pragma solidity >=0.8.22 <0.9.0; import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; - -import { Clawback_Integration_Test } from "../shared/clawback/clawback.t.sol"; -import { GetFirstClaimTime_Integration_Test } from "../shared/get-first-claim-time/getFirstClaimTime.t.sol"; -import { HasClaimed_Integration_Test } from "../shared/has-claimed/hasClaimed.t.sol"; -import { HasExpired_Integration_Test } from "../shared/has-expired/hasExpired.t.sol"; -import { WithdrawFees_Integration_Test } from "../shared/withdraw-fees/withdrawFees.t.sol"; -import { MerkleCampaign_Integration_Shared_Test } from "../shared/MerkleCampaign.t.sol"; +import { Clawback_Integration_Test } from "./../shared/clawback/clawback.t.sol"; +import { GetFirstClaimTime_Integration_Test } from "./../shared/get-first-claim-time/getFirstClaimTime.t.sol"; +import { HasClaimed_Integration_Test } from "./../shared/has-claimed/hasClaimed.t.sol"; +import { HasExpired_Integration_Test } from "./../shared/has-expired/hasExpired.t.sol"; +import { MerkleCampaign_Integration_Shared_Test } from "./../shared/MerkleCampaign.t.sol"; +import { WithdrawFees_Integration_Test } from "./../shared/withdraw-fees/withdrawFees.t.sol"; /*////////////////////////////////////////////////////////////////////////// NON-SHARED TESTS diff --git a/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol b/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol index d53c6f740..c3f3b035c 100644 --- a/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol @@ -2,13 +2,12 @@ pragma solidity >=0.8.22 <0.9.0; import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; - -import { Clawback_Integration_Test } from "../shared/clawback/clawback.t.sol"; -import { GetFirstClaimTime_Integration_Test } from "../shared/get-first-claim-time/getFirstClaimTime.t.sol"; -import { HasClaimed_Integration_Test } from "../shared/has-claimed/hasClaimed.t.sol"; -import { HasExpired_Integration_Test } from "../shared/has-expired/hasExpired.t.sol"; -import { WithdrawFees_Integration_Test } from "../shared/withdraw-fees/withdrawFees.t.sol"; -import { MerkleCampaign_Integration_Shared_Test } from "../shared/MerkleCampaign.t.sol"; +import { Clawback_Integration_Test } from "./../shared/clawback/clawback.t.sol"; +import { GetFirstClaimTime_Integration_Test } from "./../shared/get-first-claim-time/getFirstClaimTime.t.sol"; +import { HasClaimed_Integration_Test } from "./../shared/has-claimed/hasClaimed.t.sol"; +import { HasExpired_Integration_Test } from "./../shared/has-expired/hasExpired.t.sol"; +import { MerkleCampaign_Integration_Shared_Test } from "./../shared/MerkleCampaign.t.sol"; +import { WithdrawFees_Integration_Test } from "./../shared/withdraw-fees/withdrawFees.t.sol"; /*////////////////////////////////////////////////////////////////////////// NON-SHARED TESTS From 253866815ec7928217628f18315ecad2113bf688 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Fri, 11 Oct 2024 07:37:54 +0100 Subject: [PATCH 14/21] style: lint code --- script/protocol/DeployDeterministicProtocol.s.sol | 2 +- script/protocol/DeployProtocol.s.sol | 2 +- script/protocol/DeploymentLogger.s.sol | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/script/protocol/DeployDeterministicProtocol.s.sol b/script/protocol/DeployDeterministicProtocol.s.sol index 75744af23..5bb83108d 100644 --- a/script/protocol/DeployDeterministicProtocol.s.sol +++ b/script/protocol/DeployDeterministicProtocol.s.sol @@ -5,8 +5,8 @@ import { LockupNFTDescriptor } from "../../src/core/LockupNFTDescriptor.sol"; import { SablierLockupDynamic } from "../../src/core/SablierLockupDynamic.sol"; import { SablierLockupLinear } from "../../src/core/SablierLockupLinear.sol"; import { SablierLockupTranched } from "../../src/core/SablierLockupTranched.sol"; -import { SablierMerkleFactory } from "../../src/periphery/SablierMerkleFactory.sol"; import { SablierBatchLockup } from "../../src/periphery/SablierBatchLockup.sol"; +import { SablierMerkleFactory } from "../../src/periphery/SablierMerkleFactory.sol"; import { DeploymentLogger } from "./DeploymentLogger.s.sol"; diff --git a/script/protocol/DeployProtocol.s.sol b/script/protocol/DeployProtocol.s.sol index 0419d1f94..77906c74c 100644 --- a/script/protocol/DeployProtocol.s.sol +++ b/script/protocol/DeployProtocol.s.sol @@ -5,8 +5,8 @@ import { LockupNFTDescriptor } from "../../src/core/LockupNFTDescriptor.sol"; import { SablierLockupDynamic } from "../../src/core/SablierLockupDynamic.sol"; import { SablierLockupLinear } from "../../src/core/SablierLockupLinear.sol"; import { SablierLockupTranched } from "../../src/core/SablierLockupTranched.sol"; -import { SablierMerkleFactory } from "../../src/periphery/SablierMerkleFactory.sol"; import { SablierBatchLockup } from "../../src/periphery/SablierBatchLockup.sol"; +import { SablierMerkleFactory } from "../../src/periphery/SablierMerkleFactory.sol"; import { DeploymentLogger } from "./DeploymentLogger.s.sol"; diff --git a/script/protocol/DeploymentLogger.s.sol b/script/protocol/DeploymentLogger.s.sol index 3b2496b98..a989ebcb9 100644 --- a/script/protocol/DeploymentLogger.s.sol +++ b/script/protocol/DeploymentLogger.s.sol @@ -2,7 +2,6 @@ pragma solidity >=0.8.22 <0.9.0; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { stdJson } from "forge-std/src/StdJson.sol"; import { BaseScript } from "../Base.s.sol"; From 952406952b2de58c9b0db77963006da16cf8fb2c Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Sun, 13 Oct 2024 00:44:52 +0100 Subject: [PATCH 15/21] refactor: add constructor to Adminable contract refactor: use plural in mapping names refactor: DRY'ify through _computeSablierFeeForUser function refactor: adds missing override refactor: rename SetSablierFee to SetSablierFeeForUser feat: add non-zero check for to address in withdrawFees docs: polish natspecs fix: typos Co-authored-by: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> --- precompiles/Precompiles.sol | 18 +++--- src/core/abstracts/Adminable.sol | 11 ++++ src/core/abstracts/SablierLockup.sol | 4 +- src/periphery/SablierMerkleFactory.sol | 55 ++++++++++--------- src/periphery/abstracts/SablierMerkleBase.sol | 14 ++--- .../interfaces/ISablierMerkleBase.sol | 4 +- .../interfaces/ISablierMerkleFactory.sol | 39 ++++++------- src/periphery/interfaces/ISablierMerkleLT.sol | 2 +- src/periphery/libraries/Errors.sol | 6 ++ src/periphery/types/DataTypes.sol | 2 +- test/mocks/AdminableMock.sol | 6 +- .../fork/merkle-campaign/MerkleInstant.t.sol | 4 +- .../fork/merkle-campaign/MerkleLL.t.sol | 4 +- .../fork/merkle-campaign/MerkleLT.t.sol | 4 +- .../resetSablierFeeByUser.t.sol | 4 +- .../set-fee-by-user/setSablierFeeByUser.t.sol | 8 +-- .../factory/withdraw-fees/withdrawFees.t.sol | 15 ++++- .../factory/withdraw-fees/withdrawFees.tree | 29 +++++----- test/utils/Events.sol | 4 +- 19 files changed, 127 insertions(+), 106 deletions(-) diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index f0faabfbf..691814156 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -23,15 +23,15 @@ contract Precompiles { bytes public constant BYTECODE_BATCH_LOCKUP = hex"60808060405234601557611b67908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c806337266dd31461108957806349a32c4014610d7b578063606ef87514610a635780639e743f291461072b578063a514f83e146103e85763f7ca34eb1461005b575f80fd5b3461032a57610069366113d4565b91909282156103c0575f905f5b84811061039557506001600160a01b036100939116918383611827565b61009c83611584565b926001600160a01b035f9316925b8181106100c357604051806100bf878261142b565b0390f35b6100ce8183886117e1565b6100d7906115b6565b90826100e482828a6117e1565b6020016100f0906115b6565b6100fb83838b6117e1565b604001610107906114b0565b93896101148585836117e1565b606001610120906115ca565b61012b8686846117e1565b608001610137906115ca565b6101428787856117e1565b60a00161014e90611804565b918761015b8189876117e1565b60c081016101689161170e565b986101749291966117e1565b60e001936040519561018587611511565b6001600160a01b0316865260208601966001600160a01b0316875260408601996001600160801b03168a5260608601978d895260808701921515835260a08701931515845260c087019464ffffffffff16855236906101e392611744565b9360e08601948552366101f5916116b0565b966101008601978852604051998a977f31df3d480000000000000000000000000000000000000000000000000000000089526004890160209052610164890197516001600160a01b031660248a0152516001600160a01b03166044890152516001600160801b03166064880152516001600160a01b0316608487015251151560a486015251151560c48501525164ffffffffff1660e48401525190610104830161014090528151809152610184830191602001905f905b808210610341575050925180516001600160a01b03166101248401526020908101516101448401529250819003815f885af18015610336575f90610300575b600192506102f982886116e9565b52016100aa565b506020823d821161032e575b816103196020938361154a565b8101031261032a57600191516102eb565b5f80fd5b3d915061030c565b6040513d5f823e3d90fd5b91949350916020606082610386600194895164ffffffffff604080926001600160801b03815116855267ffffffffffffffff6020820151166020860152015116910152565b019501920186939492916102ac565b916001906001600160801b036103b760406103b1878a8c6117e1565b016114b0565b16019201610076565b7f36186274000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461032a57606036600319011261032a57610401611464565b61040961138d565b906044359167ffffffffffffffff831161032a573660238401121561032a5782600401359267ffffffffffffffff841161032a57602481019060243691610140870201011161032a5783156103c05790915f9190825b85811061070257506001600160a01b0361047c9116928484611827565b61048584611584565b926001600160a01b03165f5b8581106104a657604051806100bf878261142b565b6104b96104b4828886611816565b6115b6565b906104d060206104ca838a88611816565b016115b6565b87856104e260406103b1868585611816565b6104f860606104f2878686611816565b016115ca565b906101006105228761051b818861051560806104f284848d611816565b98611816565b968c611816565b01906001600160a01b03604051986105398a6114c4565b1688526001600160a01b0360208901961686526001600160801b036040890191168152606088019189835260808901931515845260a0890194151585526060609f19873603011261032a57604051956105918761152e565b61059d60a08201611621565b87526105ab60c08201611621565b602088015260e0016105bc90611621565b604087015260c08901958652366105d2916116b0565b9560e08901968752604051987f53b15727000000000000000000000000000000000000000000000000000000008a52516001600160a01b031660048a0152516001600160a01b03166024890152516001600160801b03166044880152516001600160a01b03166064870152511515608486015251151560a485015251805164ffffffffff1660c4850152602081015164ffffffffff1660e48501526040015164ffffffffff166101048401525161012483016106a091602080916001600160a01b0381511684520151910152565b8180865a925f61016492602095f18015610336575f906106d0575b600192506106c982886116e9565b5201610491565b506020823d82116106fa575b816106e96020938361154a565b8101031261032a57600191516106bb565b3d91506106dc565b93926001906001600160801b0361071f60406103b1898b89611816565b1601940193929361045f565b3461032a57610739366113d4565b91909282156103c0575f905f5b848110610a3e57506001600160a01b036107639116918383611827565b61076c83611584565b926001600160a01b035f9316925b81811061078f57604051806100bf878261142b565b61079a8183886117e1565b6107a3906115b6565b90826107b082828a6117e1565b6020016107bc906115b6565b6107c783838b6117e1565b6040016107d3906114b0565b93896107e08585836117e1565b6060016107ec906115ca565b6107f78686846117e1565b608001610803906115ca565b61080e8787856117e1565b60a00161081a90611804565b91876108278189876117e1565b60c08101610834916115d7565b986108409291966117e1565b60e001936040519561085187611511565b6001600160a01b0316865260208601966001600160a01b0316875260408601996001600160801b03168a5260608601978d895260808701921515835260a08701931515845260c087019464ffffffffff16855236906108af92611633565b9360e08601948552366108c1916116b0565b966101008601978852604051998a977f32fbe22b0000000000000000000000000000000000000000000000000000000089526004890160209052610164890197516001600160a01b031660248a0152516001600160a01b03166044890152516001600160801b03166064880152516001600160a01b0316608487015251151560a486015251151560c48501525164ffffffffff1660e48401525190610104830161014090528151809152610184830191602001905f905b8082106109fe575050925180516001600160a01b03166101248401526020908101516101448401529250819003815f885af18015610336575f906109cc575b600192506109c582886116e9565b520161077a565b506020823d82116109f6575b816109e56020938361154a565b8101031261032a57600191516109b7565b3d91506109d8565b91949350916020604082610a2f600194895164ffffffffff602080926001600160801b038151168552015116910152565b01950192018693949291610978565b916001906001600160801b03610a5a60406103b1878a8c6117e1565b16019201610746565b3461032a57610a71366113d4565b91909282156103c0575f905f5b848110610d5657506001600160a01b03610a9b9116918383611827565b610aa483611584565b926001600160a01b035f9316925b818110610ac757604051806100bf878261142b565b610ad281838861147a565b610adb906115b6565b9082610ae882828a61147a565b602001610af4906115b6565b610aff83838b61147a565b604001610b0b906114b0565b9389610b1885858361147a565b606001610b24906115ca565b610b2f86868461147a565b608001610b3b906115ca565b9086610b4881888661147a565b60a08101610b559161170e565b97610b6192919561147a565b60c0019260405194610b72866114c4565b6001600160a01b0316855260208501956001600160a01b0316865260408501986001600160801b0316895260608501968c885260808601921515835260a0860193151584523690610bc292611744565b9260c0850193845236610bd4916116b0565b9560e085019687526040519889967f54c022920000000000000000000000000000000000000000000000000000000088526004880160209052610144880196516001600160a01b03166024890152516001600160a01b03166044880152516001600160801b03166064870152516001600160a01b0316608486015251151560a485015251151560c4840152519060e4830161012090528151809152610164830191602001905f905b808210610d02575050925180516001600160a01b03166101048401526020908101516101248401529250819003815f885af18015610336575f90610cd0575b60019250610cc982886116e9565b5201610ab2565b506020823d8211610cfa575b81610ce96020938361154a565b8101031261032a5760019151610cbb565b3d9150610cdc565b91949350916020606082610d47600194895164ffffffffff604080926001600160801b03815116855267ffffffffffffffff6020820151166020860152015116910152565b01950192018693949291610c7c565b916001906001600160801b03610d7260406103b1878a8c61147a565b16019201610a7e565b3461032a57606036600319011261032a57610d94611464565b610d9c61138d565b906044359167ffffffffffffffff831161032a573660238401121561032a5782600401359267ffffffffffffffff841161032a57602481019060243691610120870201011161032a5783156103c05790915f9190825b85811061106057506001600160a01b03610e0f9116928484611827565b610e1884611584565b926001600160a01b03165f5b858110610e3957604051806100bf878261142b565b610e476104b48288866116fd565b90610e5860206104ca838a886116fd565b8785610e6a60406103b18685856116fd565b610e7a60606104f28786866116fd565b9060e0610ea387610e9c8188610e9660806104f284848d6116fd565b986116fd565b968c6116fd565b01906001600160a01b0360405198610eba8a6114c4565b1688526001600160a01b0360208901961686526001600160801b036040890191168152606088019189835260808901931515845260a0890194151585526040609f19873603011261032a5760405195610f12876114f5565b610f1e60a08201611621565b875260c001610f2c90611621565b602087015260c0890195865236610f42916116b0565b9560e08901968752604051987fab167ccc000000000000000000000000000000000000000000000000000000008a52516001600160a01b031660048a0152516001600160a01b03166024890152516001600160801b03166044880152516001600160a01b03166064870152511515608486015251151560a485015251805164ffffffffff1660c48501526020015164ffffffffff1660e4840152516101048301610ffe91602080916001600160a01b0381511684520151910152565b8180865a925f61014492602095f18015610336575f9061102e575b6001925061102782886116e9565b5201610e24565b506020823d8211611058575b816110476020938361154a565b8101031261032a5760019151611019565b3d915061103a565b93926001906001600160801b0361107d60406103b1898b896116fd565b16019401939293610df2565b3461032a57611097366113d4565b91909282156103c0575f905f5b84811061136857506001600160a01b036110c19116918383611827565b6110ca83611584565b926001600160a01b035f9316925b8181106110ed57604051806100bf878261142b565b6110f881838861147a565b611101906115b6565b908261110e82828a61147a565b60200161111a906115b6565b61112583838b61147a565b604001611131906114b0565b938961113e85858361147a565b60600161114a906115ca565b61115586868461147a565b608001611161906115ca565b908661116e81888661147a565b60a0810161117b916115d7565b9761118792919561147a565b60c0019260405194611198866114c4565b6001600160a01b0316855260208501956001600160a01b0316865260408501986001600160801b0316895260608501968c885260808601921515835260a08601931515845236906111e892611633565b9260c08501938452366111fa916116b0565b9560e085019687526040519889967f897f362b0000000000000000000000000000000000000000000000000000000088526004880160209052610144880196516001600160a01b03166024890152516001600160a01b03166044880152516001600160801b03166064870152516001600160a01b0316608486015251151560a485015251151560c4840152519060e4830161012090528151809152610164830191602001905f905b808210611328575050925180516001600160a01b03166101048401526020908101516101248401529250819003815f885af18015610336575f906112f6575b600192506112ef82886116e9565b52016110d8565b506020823d8211611320575b8161130f6020938361154a565b8101031261032a57600191516112e1565b3d9150611302565b91949350916020604082611359600194895164ffffffffff602080926001600160801b038151168552015116910152565b019501920186939492916112a2565b916001906001600160801b0361138460406103b1878a8c61147a565b160192016110a4565b602435906001600160a01b038216820361032a57565b9181601f8401121561032a5782359167ffffffffffffffff831161032a576020808501948460051b01011161032a57565b606060031982011261032a576004356001600160a01b038116810361032a57916024356001600160a01b038116810361032a57916044359067ffffffffffffffff821161032a57611427916004016113a3565b9091565b60206040818301928281528451809452019201905f5b81811061144e5750505090565b8251845260209384019390920191600101611441565b600435906001600160a01b038216820361032a57565b919081101561149c5760051b8101359060fe198136030182121561032a570190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b038116810361032a5790565b610100810190811067ffffffffffffffff8211176114e157604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff8211176114e157604052565b610120810190811067ffffffffffffffff8211176114e157604052565b6060810190811067ffffffffffffffff8211176114e157604052565b90601f8019910116810190811067ffffffffffffffff8211176114e157604052565b67ffffffffffffffff81116114e15760051b60200190565b9061158e8261156c565b61159b604051918261154a565b82815280926115ac601f199161156c565b0190602036910137565b356001600160a01b038116810361032a5790565b35801515810361032a5790565b903590601e198136030182121561032a570180359067ffffffffffffffff821161032a57602001918160061b3603831361032a57565b35906001600160801b038216820361032a57565b359064ffffffffff8216820361032a57565b92919261163f8261156c565b9361164d604051958661154a565b602085848152019260061b82019181831161032a57925b8284106116715750505050565b60408483031261032a576020604091825161168b816114f5565b6116948761160d565b81526116a1838801611621565b83820152815201930192611664565b919082604091031261032a576040516116c8816114f5565b809280356001600160a01b038116810361032a578252602090810135910152565b805182101561149c5760209160051b010190565b919081101561149c57610120020190565b903590601e198136030182121561032a570180359067ffffffffffffffff821161032a5760200191606082023603831361032a57565b9291926117508261156c565b9361175e604051958661154a565b606060208685815201930282019181831161032a57925b8284106117825750505050565b60608483031261032a57604051906117998261152e565b6117a28561160d565b825260208501359067ffffffffffffffff8216820361032a57826020928360609501526117d160408801611621565b6040820152815201930192611775565b919081101561149c5760051b8101359061011e198136030182121561032a570190565b3564ffffffffff8116810361032a5790565b919081101561149c57610140020190565b919061187c6040517f23b872dd0000000000000000000000000000000000000000000000000000000060208201523360248201523060448201528360648201526064815261187660848261154a565b82611a0a565b6001600160a01b0381166001600160a01b03604051947fdd62ed3e0000000000000000000000000000000000000000000000000000000086523060048701521693846024820152602081604481855afa80156103365784915f916119bd575b50106118e8575b50505050565b5f8060405194602086019063095ea7b360e01b825287602488015260448701526044865261191760648761154a565b85519082855af190611927611a8f565b8261198b575b5081611980575b5015611941575b806118e2565b611973611978936040519063095ea7b360e01b602083015260248201525f60448201526044815261187660648261154a565b611a0a565b5f808061193b565b90503b15155f611934565b805191925081159182156119a3575b5050905f61192d565b6119b692506020809183010191016119f2565b5f8061199a565b9150506020813d6020116119ea575b816119d96020938361154a565b8101031261032a578390515f6118db565b3d91506119cc565b9081602091031261032a5751801515810361032a5790565b5f806001600160a01b03611a3393169360208151910182865af1611a2c611a8f565b9083611ace565b8051908115159182611a74575b5050611a495750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b611a8792506020809183010191016119f2565b155f80611a40565b3d15611ac9573d9067ffffffffffffffff82116114e15760405191611abe601f8201601f19166020018461154a565b82523d5f602084013e565b606090565b90611b0b5750805115611ae357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611b51575b611b1c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15611b1456fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c0604052346103e157615a406060813803918261001c816103e5565b9384928339810103126103e15780516001600160a01b038116908190036103e15760208201516001600160a01b03811692908390036103e1576040015161006360406103e5565b92601a84527f5361626c696572204c6f636b75702044796e616d6963204e4654000000000000602085015261009860406103e5565b600e81526d29a0a116a627a1a5aaa816a22ca760911b602082015230608052845190946001600160401b0382116102e45760015490600182811c921680156103d7575b60208310146102c65781601f849311610369575b50602090601f8311600114610303575f926102f8575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e457600254600181811c911680156102da575b60208210146102c657601f8111610263575b50602094601f8211600114610200579481929394955f926101f5575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755615635908161040b82396080518161393a015260a051818181610bcc0152613a140152f35b015190505f80610169565b601f1982169560025f52805f20915f5b88811061024b57508360019596979810610233575b505050811b0160025561017e565b01515f1960f88460031b161c191690555f8080610225565b91926020600181928685015181550194019201610210565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bc575b601f0160051c01905b8181106102b1575061014d565b5f81556001016102a4565b909150819061029b565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013b565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610105565b60015f9081528281209350601f198516905b8181106103515750908460019594939210610339575b505050811b0160015561011a565b01515f1960f88460031b161c191690555f808061032b565b92936020600181928786015181550195019301610315565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103cd575b90601f859493920160051c01905b8181106103bf57506100ef565b5f81558493506001016103b2565b90915081906103a4565b91607f16916100db565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e45760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146127c957508063027b6744146127a757806306fdde03146126ec578063081812fc146126ce578063095ea7b3146125c95780631400ecec146125185780631c1cdd4c146124b45780631e99d5691461249757806323b872dd14612480578063303acc851461244357806331df3d4814612330578063406887cb146121c157806340e58ee514611ea8578063425d30dd14611e5857806342842e0e14611e2f57806342966c6814611c6b5780634426757014611c455780634857501f14611bd45780634869e12d14611b9a5780634cc55e1114611aa257806354c02292146117f157806357404b12146117635780636352211e146117345780636d0cee751461173457806370a08231146116ca57806375829def1461165c5780637cad6cd11461156b5780637de6b1db146113ec5780638659c27014610fed578063894e9a0d14610cbe5780638f69b99314610c3e5780639067b67714610bef5780639188ec8414610bb557806395d89b4114610aad578063a22cb465146109f9578063a80fc071146109a8578063ad35efd414610949578063b2564569146108f9578063b637b865146108a0578063b88d4fde14610818578063b8a3be66146107e3578063b971302a14610795578063bc2be1be14610746578063c156a11d1461060f578063c87b56dd146104f9578063d4dbd20b146104a8578063d511609f1461045d578063d975dfed14610423578063e985e9c5146103ca578063ea5ead1914610386578063eac8f5b814610335578063f590c176146102d9578063f851a440146102b45763fdd46d601461026e575f80fd5b346102b05760603660031901126102b0576102876128f6565b6044356001600160801b03811681036102b0576102ae916102a6613930565b6004356133e3565b005b5f80fd5b346102b0575f3660031901126102b05760206001600160a01b035f5416604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346102b05760403660031901126102b05760206004356103b96103a76128f6565b916103b1816141f9565b928391613085565b6001600160801b0360405191168152f35b346102b05760403660031901126102b0576103e36128e0565b6001600160a01b036103f36128f6565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b96020916141f9565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a6020526020600260405f20015460801c604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346102b05760203660031901126102b057600435610516816136b2565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa8015610604575f90610587575b610583906040519182916020835260208301906128bb565b0390f35b503d805f833e6105978183612a79565b8101906020818303126102b05780519067ffffffffffffffff82116102b057019080601f830112156102b0578151916105cf83612a9b565b916105dd6040519384612a79565b838352602084830101116102b057610583926105ff916020808501910161289a565b61056b565b6040513d5f823e3d90fd5b346102b05760403660031901126102b05760043561062b6128f6565b610633613930565b815f52600a60205260ff600160405f20015460a81c161561073357815f5260036020526001600160a01b0360405f2054169081330361071357610675836141f9565b6001600160801b0381169182610703575b6001600160a01b038116156106f0576106a7856001600160a01b03926137f6565b1692836106c15784637e27328960e01b5f5260045260245ffd5b80859185036106d557602084604051908152f35b8492506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b61070e828587613085565b610686565b82632082501160e01b5f526004526001600160a01b03331660245260445ffd5b5063699d2de960e01b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b0360405f205416604051908152f35b346102b05760203660031901126102b0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346102b05760803660031901126102b0576108316128e0565b6108396128f6565b6064359167ffffffffffffffff83116102b057366023840112156102b05782600401359161086683612a9b565b926108746040519485612a79565b80845236602482870101116102b0576020815f9260246102ae9801838801378501015260443591612f95565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600b6020526105836108e560405f20612f0e565b60405191829160208352602083019061298b565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c16156103235761098190613762565b6040516005821015610994576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346102b05760403660031901126102b057610a126128e0565b602435908115158092036102b0576001600160a01b0316908115610a8157335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0575f3660031901126102b0576040515f6002548060011c90600181168015610bab575b602083108114610b9757828552908115610b735750600114610b15575b61058383610b0181850382612a79565b6040519182916020835260208301906128bb565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210610b5957509091508101602001610b01610af1565b919260018160209254838588010152019101909291610b41565b60ff191660208086019190915291151560051b84019091019150610b019050610af1565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ad4565b346102b0575f3660031901126102b05760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610c7690613762565b6005811015806109945760028214908115610cb2575b8115610ca0575b6020826040519015158152f35b90506109945760046020911482610c93565b5050600381145f610c8c565b346102b05760203660031901126102b057600435604051610180810181811067ffffffffffffffff821117610fd957606091610160916040525f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152610d39612ebe565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260405f20604051610d7481612a5c565b8154906001600160a01b0382168152602081019264ffffffffff8360a01c1684526040820164ffffffffff8460c81c168152606083019160ff8560f01c1615158352608084019460f81c1515855260018101549160a08501946001600160a01b038416865260c0810160ff8560a01c1615158152610e13600260e084019560ff8860a81c161515875260ff61010086019860b01c161515885201612edc565b61012083019081526002610e268c613762565b610e2f816129fd565b14610fd1575b5196516001600160a01b0316925164ffffffffff1695511515905115159351151594511515958a5f52600360205260405f20546001600160a01b03169a5f52600b60205260405f2092516001600160a01b0316995164ffffffffff1698511515926040519a610ea66101808d612a79565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610efa90612f0e565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e082016105839161298b565b5f8752610e35565b634e487b7160e01b5f52604160045260245ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761101e90369060040161295a565b90611027613930565b5f915b80831061103357005b61103e838284612e4d565b3592611048613930565b835f52600a60205260ff600160405f20015460a81c16156113d857835f52600a60205260ff600160405f20015460a01c165f1461109257836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c6113c6576110c7815f52600a6020526001600160a01b0360405f205416331490565b156113b0576110d5816136d3565b90805f52600a6020526110ed600260405f2001612edc565b916001600160801b038351166001600160801b038216101561139c57815f52600a60205260ff60405f205460f01c161561138857806001600160801b03602081611141948188511603169501511690612aed565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611363575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061125c6001600160a01b03600160405f2001541694611234888588614653565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a160ff6112a6866001600160a01b03165f52600960205260405f2090565b54166112bc575b5050505050600101919061102a565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060457630d4af11f60e31b916001600160e01b0319915f91611335575b50160361131957808080806112ad565b636ade251160e01b5f526001600160a01b03602491166004525ffd5b611356915060203d811161135c575b61134e8183612a79565b810190613692565b87611309565b503d611344565b825f52600a602052600160405f2001600160a01b60ff60a01b1982541617905561118b565b50635dd950cb60e11b5f526024906004525ffd5b506308aca53f60e21b5f526024906004525ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f526024906004525ffd5b346102b05760203660031901126102b057600435611408613930565b805f52600a60205260ff600160405f20015460a81c16156103235761142c81613762565b611435816129fd565b6004810361145057506315efa0f360e11b5f5260045260245ffd5b611459816129fd565b60038103611474575063d0a172b360e01b5f5260045260245ffd5b600290611480816129fd565b14611559576114a3815f52600a6020526001600160a01b0360405f205416331490565b1561153a57805f52600a60205260ff60405f205460f01c1615611528576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b632082501160e01b5f526004526001600160a01b03331660245260445ffd5b6308aca53f60e21b5f5260045260245ffd5b346102b05760203660031901126102b0576004356001600160a01b0381168091036102b0576001600160a01b035f5416338103611646575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116325760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b0576116756128e0565b5f546001600160a01b03811633810361164657506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346102b05760203660031901126102b0576001600160a01b036116eb6128e0565b168015611708575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346102b05760203660031901126102b05760206117526004356136b2565b6001600160a01b0360405191168152f35b346102b05760203660031901126102b05760043561177f612ea6565b50805f52600a60205260ff600160405f20015460a81c1615610323575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166117c983612a40565b825260208201526117ef8251809264ffffffffff60208092828151168552015116910152565bf35b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b0578036036101206003198201126102b05761182c613930565b60c482013590602219018112156102b057810160048101359067ffffffffffffffff82116102b05760240160608202360381136102b05761186e913691612d69565b9081519161187b83612d51565b926118896040519485612a79565b808452601f1961189882612d51565b015f5b818110611a8b57505064ffffffffff4216916001600160801b036118be8261398a565b51511667ffffffffffffffff60206118d58461398a565b5101511664ffffffffff8060406118eb8661398a565b51015116860116906040519261190084612a24565b8352602083015260408201526119158661398a565b5261191f8561398a565b5060015b8281106119f75750505061193982600401612e85565b9261194660248401612e85565b9261195360448201612e71565b916064820135936001600160a01b0385168095036102b0576020966119ef966119af966001600160801b036119e4976001600160a01b0361199660848a01612e99565b94816119a460a48c01612e99565b976040519d8e612a07565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612e06565b6101008201526139ab565b604051908152f35b806001600160801b03611a0c60019385613997565b51511667ffffffffffffffff6020611a248487613997565b5101511664ffffffffff806040611a3e5f1987018d613997565b51015116816040611a4f878a613997565b5101511601169060405192611a6384612a24565b835260208301526040820152611a798289613997565b52611a848188613997565b5001611923565b602090611a96612ebe565b8282890101520161189b565b346102b05760403660031901126102b05760043567ffffffffffffffff81116102b057611ad390369060040161295a565b9060243567ffffffffffffffff81116102b057611af490369060040161295a565b9091611afe613930565b818403611b6a575f5b848110611b1057005b80611b64611b216001938886612e4d565b35611b2d838987612e4d565b355f5260036020526001600160a01b0360405f205416611b56611b5185898b612e4d565b612e71565b91611b5f613930565b6133e3565b01611b07565b50827fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b9602091614149565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f611c0d82613762565b600581101561099457600203611c2b575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16611c1e565b346102b0575f3660031901126102b05760206001600160a01b0360085416604051908152f35b346102b05760203660031901126102b057600435611c87613930565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c1615611e0457611cc6816140d7565b156113b057805f5260036020526001600160a01b0360405f205416151580611dfd575b80611de0575b611dce577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115611d97575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611d8557005b637e27328960e01b5f5260045260245ffd5b611db6835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055611d3d565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615611cef565b505f611ce9565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0576102ae611e4036612920565b9060405192611e50602085612a79565b5f8452612f95565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346102b05760203660031901126102b057600435611ec4613930565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c165f14611f0d576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c6113c657611f3f815f52600a6020526001600160a01b0360405f205416331490565b1561153a57611f4d816136d3565b90805f52600a602052611f65600260405f2001612edc565b916001600160801b038351166001600160801b03821610156121ae57815f52600a60205260ff60405f205460f01c161561219b57806001600160801b03602081611fb9948188511603169501511690612aed565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612176575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506120ac6001600160a01b03600160405f2001541694611234888588614653565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f2054166120ef57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060457630d4af11f60e31b916001600160e01b0319915f91612157575b50160361214557005b636ade251160e01b5f5260045260245ffd5b612170915060203d60201161135c5761134e8183612a79565b8461213c565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612003565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b346102b05760203660031901126102b0576121da6128e0565b6001600160a01b035f54169033820361231957806001600160a01b03913b156122ed57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa908115610604575f916122be575b501561229357805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6122e0915060203d6020116122e6575b6122d88183612a79565b810190612e35565b82612248565b503d6122ce565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761014060031982360301126102b05761236a613930565b6040519061237782612a07565b6123838160040161290c565b82526123916024820161290c565b60208301526123a260448201612ab7565b604083015260648101356001600160a01b03811681036102b05760608301526123cd608482016129f0565b60808301526123de60a482016129f0565b60a08301526123ef60c48201612d3f565b60c083015260e481013567ffffffffffffffff81116102b057810191366023840112156102b0576119e46119ef926124336020953690602460048201359101612d69565b60e0840152610104369101612e06565b346102b05760203660031901126102b0576001600160a01b036124646128e0565b165f526009602052602060ff60405f2054166040519015158152f35b346102b0576102ae61249136612920565b91612b0d565b346102b0575f3660031901126102b0576020600754604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576124ec90613762565b600581101561099457806020911590811561250d575b506040519015158152f35b600191501482612502565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576020905f90805f52600a835260ff60405f205460f01c16806125ad575b61257b575b506001600160801b0360405191168152f35b6125a79150805f52600a83526125a16001600160801b03600260405f20015416916136d3565b90612aed565b82612569565b50805f52600a835260ff600160405f20015460a01c1615612564565b346102b05760403660031901126102b0576125e26128e0565b6024356125ee816136b2565b331515806126bb575b80612688575b61265c5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156125fd565b50336001600160a01b03821614156125f7565b346102b05760203660031901126102b0576020611752600435612acb565b346102b0575f3660031901126102b0576040515f6001548060011c9060018116801561279d575b602083108114610b9757828552908115610b73575060011461273f5761058383610b0181850382612a79565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061278357509091508101602001610b01610af1565b91926001816020925483858801015201910190929161276b565b91607f1691612713565b346102b0575f3660031901126102b057602060405167016345785d8a00008152f35b346102b05760203660031901126102b057600435906001600160e01b031982168092036102b057817f490649060000000000000000000000000000000000000000000000000000000060209314908115612825575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115612870575b811561285f575b508361281e565b6301ffc9a760e01b91501483612858565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612851565b5f5b8381106128ab5750505f910152565b818101518382015260200161289c565b906020916128d48151809281855285808601910161289a565b601f01601f1916010190565b600435906001600160a01b03821682036102b057565b602435906001600160a01b03821682036102b057565b35906001600160a01b03821682036102b057565b60609060031901126102b0576004356001600160a01b03811681036102b057906024356001600160a01b03811681036102b0579060443590565b9181601f840112156102b05782359167ffffffffffffffff83116102b0576020808501948460051b0101116102b057565b90602080835192838152019201905f5b8181106129a85750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff8682015116868501520151166040820152019401910191909161299b565b359081151582036102b057565b6005111561099457565b610120810190811067ffffffffffffffff821117610fd957604052565b6060810190811067ffffffffffffffff821117610fd957604052565b6040810190811067ffffffffffffffff821117610fd957604052565b610140810190811067ffffffffffffffff821117610fd957604052565b90601f8019910116810190811067ffffffffffffffff821117610fd957604052565b67ffffffffffffffff8111610fd957601f01601f191660200190565b35906001600160801b03821682036102b057565b612ad4816136b2565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161163257565b91906001600160a01b031680156106f057815f5260036020526001600160a01b0360405f205416151580612d37575b80612d1a575b612d07577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612c52575b6001600160a01b03935085612c1b575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303612c0357505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b612c3a825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612ba2565b9192905080612cb0575b15612c6957828291612b92565b8284612c8157637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612cde575b80612c5c5750825f526005602052336001600160a01b0360405f20541614612c5c565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612cbb565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615612b42565b506001612b3c565b359064ffffffffff821682036102b057565b67ffffffffffffffff8111610fd95760051b60200190565b929192612d7582612d51565b93612d836040519586612a79565b60606020868581520193028201918183116102b057925b828410612da75750505050565b6060848303126102b05760405190612dbe82612a24565b612dc785612ab7565b825260208501359067ffffffffffffffff821682036102b05782602092836060950152612df660408801612d3f565b6040820152815201930192612d9a565b91908260409103126102b057604051612e1e81612a40565b6020808294612e2c8161290c565b84520135910152565b908160209103126102b0575180151581036102b05790565b9190811015612e5d5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036102b05790565b356001600160a01b03811681036102b05790565b3580151581036102b05790565b60405190612eb382612a40565b5f6020838281520152565b60405190612ecb82612a24565b5f6040838281528260208201520152565b90604051612ee981612a24565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612f1a81612d51565b92612f286040519485612a79565b81845260208401905f5260205f205f915b838310612f465750505050565b600160208192604051612f5881612a24565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612f39565b90612fa1838284612b0d565b803b612fae575b50505050565b602091612ff46001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906128bb565b03815f865af15f9181613064575b5061303057506130106141ca565b8051908161302b5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361305257505f808080612fa8565b633250574960e11b5f5260045260245ffd5b61307e91925060203d60201161135c5761134e8183612a79565b905f613002565b909161308f613930565b815f52600a60205260ff600160405f20015460a81c161561073357815f52600a60205260ff600160405f20015460a01c166133d0576001600160a01b03831680156133a457825f5260036020526001600160a01b0360405f205416938482141580613394575b613360576001600160801b038316928315613334576001600160801b0361311b866141f9565b16808511613301575061314090855f52600a602052600260405f20015460801c61421f565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff191691909117815561318390612edc565b6001600160801b036131a78160208401511692826040818351169201511690612aed565b1611156132cf575b835f52600a6020526131d3836001600160a01b03600160405f200154169283614653565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806132b9575b61323d5750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610604576392b9102b60e01b916001600160e01b0319915f9161329a575b50160361214557808080612fa8565b6132b3915060203d60201161135c5761134e8183612a79565b5f61328b565b50835f52600960205260ff60405f205416613233565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556131af565b84867f066920d7000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b847fb2ae7633000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50827f6a166406000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b5061339e846140d7565b156130f5565b827f2da33e5b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b506315efa0f360e11b5f5260045260245ffd5b9091815f52600a60205260ff600160405f20015460a81c161561073357815f52600a60205260ff600160405f20015460a01c166133d0576001600160a01b03831680156133a457825f5260036020526001600160a01b0360405f205416938482141580613682575b613360576001600160801b038316928315613334576001600160801b03613471866141f9565b16808511613301575061349690855f52600a602052600260405f20015460801c61421f565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff19169190911781556134d990612edc565b6001600160801b036134fd8160208401511692826040818351169201511690612aed565b161115613650575b835f52600a602052613529836001600160a01b03600160405f200154169283614653565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a1833314158061362b575b6135935750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610604576392b9102b60e01b916001600160e01b0319915f9161360c575b5016036135f057808080612fa8565b6001600160a01b0390636ade251160e01b5f521660045260245ffd5b613625915060203d60201161135c5761134e8183612a79565b5f6135e1565b5060ff613649856001600160a01b03165f52600960205260405f2090565b5416613589565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055613505565b5061368c846140d7565b1561344b565b908160209103126102b057516001600160e01b0319811681036102b05790565b805f5260036020526001600160a01b0360405f205416908115611d85575090565b64ffffffffff4216815f52600a6020528064ffffffffff60405f205460a01c16101561375c57815f52600a60205264ffffffffff60405f205460c81c16111561374157805f52600b602052600160405f2054115f1461373857613735906142ff565b90565b6137359061423f565b5f52600a6020526001600160801b03600260405f2001541690565b50505f90565b805f52600a60205260ff600160405f20015460a01c165f146137845750600490565b805f52600a60205260405f205460f81c6137f057805f52600a60205264ffffffffff60405f205460a01c1642106137eb576137be816136d3565b905f52600a6020526001600160801b0380600260405f200154169116105f146137e657600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f20541615158061391e575b80613901575b611dce577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836138ca575b16806138b2575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f206001815401905561386e565b6138e9835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613867565b50805f52600a60205260ff600160405f20015460b01c161561381b565b506001600160a01b0382161515613815565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361396257565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612e5d5760200190565b8051821015612e5d5760209160051b010190565b906139cd6001600160801b036040840151166020610100850151015190614515565b916001600160a01b03815116906001600160801b0384511660e082015160c083019364ffffffffff85511690156140af57821561408757801561405f5781518015614037577f0000000000000000000000000000000000000000000000000000000000000000811161400c575064ffffffffff6040613a4b8461398a565b51015116811015613fc857505f809180515f915b818310613f45575050506001600160801b0391501690818103613f1757505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c1f8751975f19890190613997565b51015160c81b169360a01b169116171785555f5b818110613e09575050600187016007556001600160a01b0360208301511680156106f057613c69886001600160a01b03926137f6565b16613ddd578682613cb76001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b0385511690309033906145f2565b6001600160801b0360208401511680613dad575b506001600160a01b0381511694613da2613d846001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613d298b612a40565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c087015261014086019061298b565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613dd7906001600160a01b036060840151166001600160a01b0361010085015151169033906145f2565b5f613ccb565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f2090613e248160e0870151613997565b51825468010000000000000000811015610fd95760018101808555811015612e5d576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613c33565b7f0fa99c11000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b909192613f67906001600160801b03613f5e8685613997565b5151169061421f565b9364ffffffffff806040613f7b8786613997565b51015116911680821115613f96575093926001019190613a5f565b847f4b90504d000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff6040613fd98461398a565b51015116907f93c315e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f099c714b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f5fbab612000000000000000000000000000000000000000000000000000000005f5260045ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6d004a9e000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561411d575b508115614104575090565b90506001600160a01b036141183392612acb565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f6140f9565b805f52600a602052614160600260405f2001612edc565b90805f52600a60205260ff600160405f20015460a01c165f1461418e5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6141ad5750613735906136d3565b61373591506001600160801b036040818351169201511690612aed565b3d156141f4573d906141db82612a9b565b916141e96040519384612a79565b82523d5f602084013e565b606090565b6137359061420681614149565b905f52600a602052600260405f20015460801c90612aed565b906001600160801b03809116911601906001600160801b03821161163257565b5f818152600a60205260409020546142769064ffffffffff60a082901c811660c89290921c811682900381169142821603166146a3565b90805f52600b60205260405f20805415612e5d575f526142cb67ffffffffffffffff60205f205460801c1692825f52600a6020526142c66001600160801b03600260405f20015416948592614783565b6147f6565b9182136142e857506142e46001600160801b03916148d1565b1690565b90505f52600a602052600260405f20015460801c90565b9064ffffffffff421691805f52600a60205260405f20906040519061432382612a5c565b6101206143b660028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612edc565b92019182525f52600b6020526143ce60405f20612f0e565b915f9264ffffffffff60406143e28361398a565b510151168664ffffffffff5f925b16106144d6578161446764ffffffffff9697988784816001600160801b0361441f6142c69861446c9b9a613997565b5151169a8b9867ffffffffffffffff602061443a868b613997565b510151169782604061444c8784613997565b5101511694806144b9575050511680925b03169203166146a3565b614783565b91821361448d5750906001600160801b0361448781936148d1565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f146144b4575090565b905090565b60409250906144cb915f190190613997565b51015116809261445d565b936001600160801b03600191816144ed8886613997565b51511601169401958064ffffffffff8060406145098b87613997565b510151169892986143f0565b91909160405161452481612a40565b5f81525f6020820152926001600160801b0382169081156145d55767016345785d8a0000811161459e576145606001600160801b0391836154ee565b166020850191818352111561458a576001600160801b03918261458592511690612aed565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516145e681612a40565b5f81525f602082015290565b9091926001600160a01b036146519481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261464c608483612a79565b614906565b565b614651926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261464c606483612a79565b600160ff1b81148015614776575b61474e575f811215614745576146d5815f035b5f84121561473e57835f039061498b565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161470f575f199118131561470a5790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b839061498b565b6146d5816146c4565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b82146146b1565b8061479d575061479957670de0b6b3a764000090565b5f90565b90670de0b6b3a764000082146147e857806147c0575050670de0b6b3a764000090565b670de0b6b3a764000081146147e4576147df906142c661373593614a91565b614be8565b5090565b5050670de0b6b3a764000090565b600160ff1b811480156148c4575b61489c575f81121561489357614828815f035b5f84121561488c57835f03906154ee565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161485d575f199118131561470a5790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b83906154ee565b61482881614817565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b8214614804565b5f81126148db5790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b0361492f93169360208151910182865af16149286141ca565b908361559c565b8051908115159182614970575b50506149455750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6149839250602080918301019101612e35565b155f8061493c565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614a565781841015614a1c57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614a63570490565b634e487b7160e01b5f52601260045260245ffd5b8015614a63576ec097ce7bc90715b34b9f10000000000590565b805f811315614bbd57670de0b6b3a76400008112614b9d57506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614b8a57506706f05b59d3b20000905b5f8213614b545750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614b7c575b60011d90614b47565b809192019160011d90614b73565b9050670de0b6b3a7640000929150020290565b5f1991508015614a63576ec097ce7bc90715b34b9f100000000005614aae565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614c155768033dd1780914b971141981126137eb57614c0c905f03614be8565b61373590614a77565b680a688906bd8affffff81136154c357670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff00000000000000821661538e575b670de0b6b3a76400009066ff000000000000831661527e575b65ff00000000008316615176575b64ff000000008316615076575b63ff0000008316614f7e575b62ff00008316614e8e575b61ff008316614da6575b60ff8316614cc6575b029060401c60bf031c90565b60808316614d93575b60408316614d80575b60208316614d6d575b60108316614d5a575b60088316614d47575b60048316614d34575b60028316614d21575b6001831615614cba57680100000000000000010260401c614cba565b680100000000000000010260401c614d05565b680100000000000000030260401c614cfc565b680100000000000000060260401c614cf3565b6801000000000000000b0260401c614cea565b680100000000000000160260401c614ce1565b6801000000000000002c0260401c614cd8565b680100000000000000590260401c614ccf565b6180008316614e7b575b6140008316614e68575b6120008316614e55575b6110008316614e42575b6108008316614e2f575b6104008316614e1c575b6102008316614e09575b610100831615614cb157680100000000000000b10260401c614cb1565b680100000000000001630260401c614dec565b680100000000000002c60260401c614de2565b6801000000000000058c0260401c614dd8565b68010000000000000b170260401c614dce565b6801000000000000162e0260401c614dc4565b68010000000000002c5d0260401c614dba565b680100000000000058b90260401c614db0565b628000008316614f6b575b624000008316614f58575b622000008316614f45575b621000008316614f32575b620800008316614f1f575b620400008316614f0c575b620200008316614ef9575b62010000831615614ca7576801000000000000b1720260401c614ca7565b680100000000000162e40260401c614edb565b6801000000000002c5c80260401c614ed0565b68010000000000058b910260401c614ec5565b680100000000000b17210260401c614eba565b68010000000000162e430260401c614eaf565b680100000000002c5c860260401c614ea4565b6801000000000058b90c0260401c614e99565b63800000008316615063575b63400000008316615050575b6320000000831661503d575b6310000000831661502a575b63080000008316615017575b63040000008316615004575b63020000008316614ff1575b6301000000831615614c9c5768010000000000b172180260401c614c9c565b6801000000000162e4300260401c614fd2565b68010000000002c5c8600260401c614fc6565b680100000000058b90c00260401c614fba565b6801000000000b17217f0260401c614fae565b680100000000162e42ff0260401c614fa2565b6801000000002c5c85fe0260401c614f96565b68010000000058b90bfc0260401c614f8a565b6480000000008316615163575b6440000000008316615150575b642000000000831661513d575b641000000000831661512a575b6408000000008316615117575b6404000000008316615104575b64020000000083166150f1575b640100000000831615614c9057680100000000b17217f80260401c614c90565b68010000000162e42ff10260401c6150d1565b680100000002c5c85fe30260401c6150c4565b6801000000058b90bfce0260401c6150b7565b68010000000b17217fbb0260401c6150aa565b6801000000162e42fff00260401c61509d565b68010000002c5c8601cc0260401c615090565b680100000058b90c0b490260401c615083565b65800000000000831661526b575b654000000000008316615258575b652000000000008316615245575b651000000000008316615232575b65080000000000831661521f575b65040000000000831661520c575b6502000000000083166151f9575b65010000000000831615614c83576801000000b1721835510260401c614c83565b680100000162e430e5a20260401c6151d8565b6801000002c5c863b73f0260401c6151ca565b68010000058b90cf1e6e0260401c6151bc565b680100000b1721bcfc9a0260401c6151ae565b68010000162e43f4f8310260401c6151a0565b680100002c5c89d5ec6d0260401c615192565b6801000058b91b5bc9ae0260401c615184565b6680000000000000831661537b575b66400000000000008316615368575b66200000000000008316615355575b66100000000000008316615342575b6608000000000000831661532f575b6604000000000000831661531c575b66020000000000008316615309575b6601000000000000831615614c755768010000b17255775c040260401c614c75565b6801000162e525ee05470260401c6152e7565b68010002c5cc37da94920260401c6152d8565b680100058ba01fb9f96d0260401c6152c9565b6801000b175effdc76ba0260401c6152ba565b680100162f3904051fa10260401c6152ab565b6801002c605e2e8cec500260401c61529c565b68010058c86da1c09ea20260401c61528d565b67800000000000000082166154a4575b670de0b6b3a7640000906740000000000000008316615491575b672000000000000000831661547e575b671000000000000000831661546b575b6708000000000000008316615458575b6704000000000000008316615445575b6702000000000000008316615432575b670100000000000000831661541f575b9050614c5c565b680100b1afa5abcbed610260401c615418565b68010163da9fb33356d80260401c615408565b680102c9a3e778060ee70260401c6153f8565b6801059b0d31585743ae0260401c6153e8565b68010b5586cf9890f62a0260401c6153d8565b6801172b83c7d517adce0260401c6153c8565b6801306fe0a31b7152df0260401c6153b8565b5077b504f333f9de64848000000000000000000000000000000061539e565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461558b57670de0b6b3a764000082101561555b577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906155d957508051156155b157805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061561f575b6155ea575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156155e256fea164736f6c634300081a000a"; + hex"60c0604052346103e157615a506060813803918261001c816103e5565b9384928339810103126103e15780516001600160a01b038116908190036103e15760208201516001600160a01b03811692908390036103e1576040015161006360406103e5565b92601a84527f5361626c696572204c6f636b75702044796e616d6963204e4654000000000000602085015261009860406103e5565b600e81526d29a0a116a627a1a5aaa816a22ca760911b602082015230608052845190946001600160401b0382116102e45760015490600182811c921680156103d7575b60208310146102c65781601f849311610369575b50602090601f8311600114610303575f926102f8575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e457600254600181811c911680156102da575b60208210146102c657601f8111610263575b50602094601f8211600114610200579481929394955f926101f5575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755615645908161040b823960805181613938015260a051818181610bcc0152613a020152f35b015190505f80610169565b601f1982169560025f52805f20915f5b88811061024b57508360019596979810610233575b505050811b0160025561017e565b01515f1960f88460031b161c191690555f8080610225565b91926020600181928685015181550194019201610210565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bc575b601f0160051c01905b8181106102b1575061014d565b5f81556001016102a4565b909150819061029b565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013b565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610105565b60015f9081528281209350601f198516905b8181106103515750908460019594939210610339575b505050811b0160015561011a565b01515f1960f88460031b161c191690555f808061032b565b92936020600181928786015181550195019301610315565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103cd575b90601f859493920160051c01905b8181106103bf57506100ef565b5f81558493506001016103b2565b90915081906103a4565b91607f16916100db565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e45760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146127c957508063027b6744146127a757806306fdde03146126ec578063081812fc146126ce578063095ea7b3146125c95780631400ecec146125185780631c1cdd4c146124b45780631e99d5691461249757806323b872dd14612480578063303acc851461244357806331df3d4814612330578063406887cb146121c157806340e58ee514611ea8578063425d30dd14611e5857806342842e0e14611e2f57806342966c6814611c6b5780634426757014611c455780634857501f14611bd45780634869e12d14611b9a5780634cc55e1114611aa257806354c02292146117f157806357404b12146117635780636352211e146117345780636d0cee751461173457806370a08231146116ca57806375829def1461165c5780637cad6cd11461156b5780637de6b1db146113ec5780638659c27014610fed578063894e9a0d14610cbe5780638f69b99314610c3e5780639067b67714610bef5780639188ec8414610bb557806395d89b4114610aad578063a22cb465146109f9578063a80fc071146109a8578063ad35efd414610949578063b2564569146108f9578063b637b865146108a0578063b88d4fde14610818578063b8a3be66146107e3578063b971302a14610795578063bc2be1be14610746578063c156a11d1461060f578063c87b56dd146104f9578063d4dbd20b146104a8578063d511609f1461045d578063d975dfed14610423578063e985e9c5146103ca578063ea5ead1914610386578063eac8f5b814610335578063f590c176146102d9578063f851a440146102b45763fdd46d601461026e575f80fd5b346102b05760603660031901126102b0576102876128f6565b6044356001600160801b03811681036102b0576102ae916102a661392e565b6004356133e2565b005b5f80fd5b346102b0575f3660031901126102b05760206001600160a01b035f5416604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346102b05760403660031901126102b05760206004356103b96103a76128f6565b916103b181614209565b928391613085565b6001600160801b0360405191168152f35b346102b05760403660031901126102b0576103e36128e0565b6001600160a01b036103f36128f6565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b9602091614209565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a6020526020600260405f20015460801c604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346102b05760203660031901126102b057600435610516816136b0565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa8015610604575f90610587575b610583906040519182916020835260208301906128bb565b0390f35b503d805f833e6105978183612a79565b8101906020818303126102b05780519067ffffffffffffffff82116102b057019080601f830112156102b0578151916105cf83612a9b565b916105dd6040519384612a79565b838352602084830101116102b057610583926105ff916020808501910161289a565b61056b565b6040513d5f823e3d90fd5b346102b05760403660031901126102b05760043561062b6128f6565b61063361392e565b815f52600a60205260ff600160405f20015460a81c161561073357815f5260036020526001600160a01b0360405f205416908133036107135761067583614209565b6001600160801b0381169182610703575b6001600160a01b038116156106f0576106a7856001600160a01b03926137f4565b1692836106c15784637e27328960e01b5f5260045260245ffd5b80859185036106d557602084604051908152f35b8492506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b61070e828587613085565b610686565b82632082501160e01b5f526004526001600160a01b03331660245260445ffd5b5063699d2de960e01b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b0360405f205416604051908152f35b346102b05760203660031901126102b0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346102b05760803660031901126102b0576108316128e0565b6108396128f6565b6064359167ffffffffffffffff83116102b057366023840112156102b05782600401359161086683612a9b565b926108746040519485612a79565b80845236602482870101116102b0576020815f9260246102ae9801838801378501015260443591612f95565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600b6020526105836108e560405f20612f0e565b60405191829160208352602083019061298b565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c16156103235761098190613760565b6040516005821015610994576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346102b05760403660031901126102b057610a126128e0565b602435908115158092036102b0576001600160a01b0316908115610a8157335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0575f3660031901126102b0576040515f6002548060011c90600181168015610bab575b602083108114610b9757828552908115610b735750600114610b15575b61058383610b0181850382612a79565b6040519182916020835260208301906128bb565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210610b5957509091508101602001610b01610af1565b919260018160209254838588010152019101909291610b41565b60ff191660208086019190915291151560051b84019091019150610b019050610af1565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ad4565b346102b0575f3660031901126102b05760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610c7690613760565b6005811015806109945760028214908115610cb2575b8115610ca0575b6020826040519015158152f35b90506109945760046020911482610c93565b5050600381145f610c8c565b346102b05760203660031901126102b057600435604051610180810181811067ffffffffffffffff821117610fd957606091610160916040525f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152610d39612ebe565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260405f20604051610d7481612a5c565b8154906001600160a01b0382168152602081019264ffffffffff8360a01c1684526040820164ffffffffff8460c81c168152606083019160ff8560f01c1615158352608084019460f81c1515855260018101549160a08501946001600160a01b038416865260c0810160ff8560a01c1615158152610e13600260e084019560ff8860a81c161515875260ff61010086019860b01c161515885201612edc565b61012083019081526002610e268c613760565b610e2f816129fd565b14610fd1575b5196516001600160a01b0316925164ffffffffff1695511515905115159351151594511515958a5f52600360205260405f20546001600160a01b03169a5f52600b60205260405f2092516001600160a01b0316995164ffffffffff1698511515926040519a610ea66101808d612a79565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610efa90612f0e565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e082016105839161298b565b5f8752610e35565b634e487b7160e01b5f52604160045260245ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761101e90369060040161295a565b9061102761392e565b5f915b80831061103357005b61103e838284612e4d565b359261104861392e565b835f52600a60205260ff600160405f20015460a81c16156113d857835f52600a60205260ff600160405f20015460a01c165f1461109257836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c6113c6576110c7815f52600a6020526001600160a01b0360405f205416331490565b156113b0576110d5816136d1565b90805f52600a6020526110ed600260405f2001612edc565b916001600160801b038351166001600160801b038216101561139c57815f52600a60205260ff60405f205460f01c161561138857806001600160801b03602081611141948188511603169501511690612aed565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611363575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061125c6001600160a01b03600160405f2001541694611234888588614663565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a160ff6112a6866001600160a01b03165f52600960205260405f2090565b54166112bc575b5050505050600101919061102a565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060457630d4af11f60e31b916001600160e01b0319915f91611335575b50160361131957808080806112ad565b636ade251160e01b5f526001600160a01b03602491166004525ffd5b611356915060203d811161135c575b61134e8183612a79565b810190613690565b87611309565b503d611344565b825f52600a602052600160405f2001600160a01b60ff60a01b1982541617905561118b565b50635dd950cb60e11b5f526024906004525ffd5b506308aca53f60e21b5f526024906004525ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f526024906004525ffd5b346102b05760203660031901126102b05760043561140861392e565b805f52600a60205260ff600160405f20015460a81c16156103235761142c81613760565b611435816129fd565b6004810361145057506315efa0f360e11b5f5260045260245ffd5b611459816129fd565b60038103611474575063d0a172b360e01b5f5260045260245ffd5b600290611480816129fd565b14611559576114a3815f52600a6020526001600160a01b0360405f205416331490565b1561153a57805f52600a60205260ff60405f205460f01c1615611528576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b632082501160e01b5f526004526001600160a01b03331660245260445ffd5b6308aca53f60e21b5f5260045260245ffd5b346102b05760203660031901126102b0576004356001600160a01b0381168091036102b0576001600160a01b035f5416338103611646575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116325760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b0576116756128e0565b5f546001600160a01b03811633810361164657506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346102b05760203660031901126102b0576001600160a01b036116eb6128e0565b168015611708575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346102b05760203660031901126102b05760206117526004356136b0565b6001600160a01b0360405191168152f35b346102b05760203660031901126102b05760043561177f612ea6565b50805f52600a60205260ff600160405f20015460a81c1615610323575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166117c983612a40565b825260208201526117ef8251809264ffffffffff60208092828151168552015116910152565bf35b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b0578036036101206003198201126102b05761182c61392e565b60c482013590602219018112156102b057810160048101359067ffffffffffffffff82116102b05760240160608202360381136102b05761186e913691612d69565b9081519161187b83612d51565b926118896040519485612a79565b808452601f1961189882612d51565b015f5b818110611a8b57505064ffffffffff4216916001600160801b036118be82613988565b51511667ffffffffffffffff60206118d584613988565b5101511664ffffffffff8060406118eb86613988565b51015116860116906040519261190084612a24565b83526020830152604082015261191586613988565b5261191f85613988565b5060015b8281106119f75750505061193982600401612e85565b9261194660248401612e85565b9261195360448201612e71565b916064820135936001600160a01b0385168095036102b0576020966119ef966119af966001600160801b036119e4976001600160a01b0361199660848a01612e99565b94816119a460a48c01612e99565b976040519d8e612a07565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612e06565b6101008201526139a9565b604051908152f35b806001600160801b03611a0c60019385613995565b51511667ffffffffffffffff6020611a248487613995565b5101511664ffffffffff806040611a3e5f1987018d613995565b51015116816040611a4f878a613995565b5101511601169060405192611a6384612a24565b835260208301526040820152611a798289613995565b52611a848188613995565b5001611923565b602090611a96612ebe565b8282890101520161189b565b346102b05760403660031901126102b05760043567ffffffffffffffff81116102b057611ad390369060040161295a565b9060243567ffffffffffffffff81116102b057611af490369060040161295a565b9091611afe61392e565b818403611b6a575f5b848110611b1057005b80611b64611b216001938886612e4d565b35611b2d838987612e4d565b355f5260036020526001600160a01b0360405f205416611b56611b5185898b612e4d565b612e71565b91611b5f61392e565b6133e2565b01611b07565b50827fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b9602091614159565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f611c0d82613760565b600581101561099457600203611c2b575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16611c1e565b346102b0575f3660031901126102b05760206001600160a01b0360085416604051908152f35b346102b05760203660031901126102b057600435611c8761392e565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c1615611e0457611cc6816140e7565b156113b057805f5260036020526001600160a01b0360405f205416151580611dfd575b80611de0575b611dce577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115611d97575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611d8557005b637e27328960e01b5f5260045260245ffd5b611db6835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055611d3d565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615611cef565b505f611ce9565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0576102ae611e4036612920565b9060405192611e50602085612a79565b5f8452612f95565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346102b05760203660031901126102b057600435611ec461392e565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c165f14611f0d576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c6113c657611f3f815f52600a6020526001600160a01b0360405f205416331490565b1561153a57611f4d816136d1565b90805f52600a602052611f65600260405f2001612edc565b916001600160801b038351166001600160801b03821610156121ae57815f52600a60205260ff60405f205460f01c161561219b57806001600160801b03602081611fb9948188511603169501511690612aed565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612176575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506120ac6001600160a01b03600160405f2001541694611234888588614663565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f2054166120ef57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060457630d4af11f60e31b916001600160e01b0319915f91612157575b50160361214557005b636ade251160e01b5f5260045260245ffd5b612170915060203d60201161135c5761134e8183612a79565b8461213c565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612003565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b346102b05760203660031901126102b0576121da6128e0565b6001600160a01b035f54169033820361231957806001600160a01b03913b156122ed57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa908115610604575f916122be575b501561229357805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6122e0915060203d6020116122e6575b6122d88183612a79565b810190612e35565b82612248565b503d6122ce565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761014060031982360301126102b05761236a61392e565b6040519061237782612a07565b6123838160040161290c565b82526123916024820161290c565b60208301526123a260448201612ab7565b604083015260648101356001600160a01b03811681036102b05760608301526123cd608482016129f0565b60808301526123de60a482016129f0565b60a08301526123ef60c48201612d3f565b60c083015260e481013567ffffffffffffffff81116102b057810191366023840112156102b0576119e46119ef926124336020953690602460048201359101612d69565b60e0840152610104369101612e06565b346102b05760203660031901126102b0576001600160a01b036124646128e0565b165f526009602052602060ff60405f2054166040519015158152f35b346102b0576102ae61249136612920565b91612b0d565b346102b0575f3660031901126102b0576020600754604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576124ec90613760565b600581101561099457806020911590811561250d575b506040519015158152f35b600191501482612502565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576020905f90805f52600a835260ff60405f205460f01c16806125ad575b61257b575b506001600160801b0360405191168152f35b6125a79150805f52600a83526125a16001600160801b03600260405f20015416916136d1565b90612aed565b82612569565b50805f52600a835260ff600160405f20015460a01c1615612564565b346102b05760403660031901126102b0576125e26128e0565b6024356125ee816136b0565b331515806126bb575b80612688575b61265c5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156125fd565b50336001600160a01b03821614156125f7565b346102b05760203660031901126102b0576020611752600435612acb565b346102b0575f3660031901126102b0576040515f6001548060011c9060018116801561279d575b602083108114610b9757828552908115610b73575060011461273f5761058383610b0181850382612a79565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061278357509091508101602001610b01610af1565b91926001816020925483858801015201910190929161276b565b91607f1691612713565b346102b0575f3660031901126102b057602060405167016345785d8a00008152f35b346102b05760203660031901126102b057600435906001600160e01b031982168092036102b057817f490649060000000000000000000000000000000000000000000000000000000060209314908115612825575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115612870575b811561285f575b508361281e565b6301ffc9a760e01b91501483612858565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612851565b5f5b8381106128ab5750505f910152565b818101518382015260200161289c565b906020916128d48151809281855285808601910161289a565b601f01601f1916010190565b600435906001600160a01b03821682036102b057565b602435906001600160a01b03821682036102b057565b35906001600160a01b03821682036102b057565b60609060031901126102b0576004356001600160a01b03811681036102b057906024356001600160a01b03811681036102b0579060443590565b9181601f840112156102b05782359167ffffffffffffffff83116102b0576020808501948460051b0101116102b057565b90602080835192838152019201905f5b8181106129a85750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff8682015116868501520151166040820152019401910191909161299b565b359081151582036102b057565b6005111561099457565b610120810190811067ffffffffffffffff821117610fd957604052565b6060810190811067ffffffffffffffff821117610fd957604052565b6040810190811067ffffffffffffffff821117610fd957604052565b610140810190811067ffffffffffffffff821117610fd957604052565b90601f8019910116810190811067ffffffffffffffff821117610fd957604052565b67ffffffffffffffff8111610fd957601f01601f191660200190565b35906001600160801b03821682036102b057565b612ad4816136b0565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161163257565b91906001600160a01b031680156106f057815f5260036020526001600160a01b0360405f205416151580612d37575b80612d1a575b612d07577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612c52575b6001600160a01b03935085612c1b575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303612c0357505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b612c3a825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612ba2565b9192905080612cb0575b15612c6957828291612b92565b8284612c8157637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612cde575b80612c5c5750825f526005602052336001600160a01b0360405f20541614612c5c565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612cbb565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615612b42565b506001612b3c565b359064ffffffffff821682036102b057565b67ffffffffffffffff8111610fd95760051b60200190565b929192612d7582612d51565b93612d836040519586612a79565b60606020868581520193028201918183116102b057925b828410612da75750505050565b6060848303126102b05760405190612dbe82612a24565b612dc785612ab7565b825260208501359067ffffffffffffffff821682036102b05782602092836060950152612df660408801612d3f565b6040820152815201930192612d9a565b91908260409103126102b057604051612e1e81612a40565b6020808294612e2c8161290c565b84520135910152565b908160209103126102b0575180151581036102b05790565b9190811015612e5d5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036102b05790565b356001600160a01b03811681036102b05790565b3580151581036102b05790565b60405190612eb382612a40565b5f6020838281520152565b60405190612ecb82612a24565b5f6040838281528260208201520152565b90604051612ee981612a24565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612f1a81612d51565b92612f286040519485612a79565b81845260208401905f5260205f205f915b838310612f465750505050565b600160208192604051612f5881612a24565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612f39565b90612fa1838284612b0d565b803b612fae575b50505050565b602091612ff46001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906128bb565b03815f865af15f9181613064575b5061303057506130106141da565b8051908161302b5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361305257505f808080612fa8565b633250574960e11b5f5260045260245ffd5b61307e91925060203d60201161135c5761134e8183612a79565b905f613002565b9061308e61392e565b815f52600a60205260ff600160405f20015460a81c161561073357815f52600a60205260ff600160405f20015460a01c166133cf576001600160a01b03811680156133a3576001600160801b03841691821561337757835f5260036020526001600160a01b0360405f205416948583141580613367575b613333576001600160801b0361311a86614209565b16808511613300575061313f90855f52600a602052600260405f20015460801c61422f565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff191691909117815561318290612edc565b6001600160801b036131a68160208401511692826040818351169201511690612aed565b1611156132ce575b835f52600a6020526131d2836001600160a01b03600160405f200154169283614663565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806132b8575b61323c5750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610604576392b9102b60e01b916001600160e01b0319915f91613299575b50160361214557808080612fa8565b6132b2915060203d60201161135c5761134e8183612a79565b5f61328a565b50835f52600960205260ff60405f205416613232565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556131ae565b84867f066920d7000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b82857f6a166406000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b50613371856140e7565b15613105565b837fb2ae7633000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b827f2da33e5b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b506315efa0f360e11b5f5260045260245ffd5b90815f52600a60205260ff600160405f20015460a81c161561073357815f52600a60205260ff600160405f20015460a01c166133cf576001600160a01b03811680156133a3576001600160801b03841691821561337757835f5260036020526001600160a01b0360405f205416948583141580613680575b613333576001600160801b0361346f86614209565b16808511613300575061349490855f52600a602052600260405f20015460801c61422f565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff19169190911781556134d790612edc565b6001600160801b036134fb8160208401511692826040818351169201511690612aed565b16111561364e575b835f52600a602052613527836001600160a01b03600160405f200154169283614663565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613629575b6135915750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610604576392b9102b60e01b916001600160e01b0319915f9161360a575b5016036135ee57808080612fa8565b6001600160a01b0390636ade251160e01b5f521660045260245ffd5b613623915060203d60201161135c5761134e8183612a79565b5f6135df565b5060ff613647856001600160a01b03165f52600960205260405f2090565b5416613587565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055613503565b5061368a856140e7565b1561345a565b908160209103126102b057516001600160e01b0319811681036102b05790565b805f5260036020526001600160a01b0360405f205416908115611d85575090565b64ffffffffff4216815f52600a6020528064ffffffffff60405f205460a01c16101561375a57815f52600a60205264ffffffffff60405f205460c81c16111561373f57805f52600b602052600160405f2054115f14613736576137339061430f565b90565b6137339061424f565b5f52600a6020526001600160801b03600260405f2001541690565b50505f90565b805f52600a60205260ff600160405f20015460a01c165f146137825750600490565b805f52600a60205260405f205460f81c6137ee57805f52600a60205264ffffffffff60405f205460a01c1642106137e9576137bc816136d1565b905f52600a6020526001600160801b0380600260405f200154169116105f146137e457600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f20541615158061391c575b806138ff575b611dce577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836138c8575b16806138b0575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f206001815401905561386c565b6138e7835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613865565b50805f52600a60205260ff600160405f20015460b01c1615613819565b506001600160a01b0382161515613813565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361396057565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612e5d5760200190565b8051821015612e5d5760209160051b010190565b906139cb6001600160801b036040840151166020610100850151015190614525565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156140bf578015614097578151801561406f577f00000000000000000000000000000000000000000000000000000000000000008111614044575064ffffffffff6040613a3984613988565b5101511681101561400057505f905f905f81515f905b808210613f78575050505064ffffffffff80421691169081811015613f4a5750506001600160801b031690818103613f1c57505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c248751975f19890190613995565b51015160c81b169360a01b169116171785555f5b818110613e0e575050600187016007556001600160a01b0360208301511680156106f057613c6e886001600160a01b03926137f4565b16613de2578682613cbc6001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b038551169030903390614602565b6001600160801b0360208401511680613db2575b506001600160a01b0381511694613da7613d896001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613d2e8b612a40565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c087015261014086019061298b565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613ddc906001600160a01b036060840151166001600160a01b036101008501515116903390614602565b5f613cd0565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f2090613e298160e0870151613995565b51825468010000000000000000811015610fd95760018101808555811015612e5d576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613c38565b7f0fa99c11000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f879842de000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193613f9c906001600160801b03613f938588613995565b5151169061422f565b9364ffffffffff806040613fb08685613995565b51015116941680851115613fcc57506001849301909291613a4f565b8490847f4b90504d000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff604061401184613988565b51015116907f93c315e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f099c714b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f5fbab612000000000000000000000000000000000000000000000000000000005f5260045ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561412d575b508115614114575090565b90506001600160a01b036141283392612acb565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614109565b805f52600a602052614170600260405f2001612edc565b90805f52600a60205260ff600160405f20015460a01c165f1461419e5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6141bd5750613733906136d1565b61373391506001600160801b036040818351169201511690612aed565b3d15614204573d906141eb82612a9b565b916141f96040519384612a79565b82523d5f602084013e565b606090565b6137339061421681614159565b905f52600a602052600260405f20015460801c90612aed565b906001600160801b03809116911601906001600160801b03821161163257565b5f818152600a60205260409020546142869064ffffffffff60a082901c811660c89290921c811682900381169142821603166146b3565b90805f52600b60205260405f20805415612e5d575f526142db67ffffffffffffffff60205f205460801c1692825f52600a6020526142d66001600160801b03600260405f20015416948592614793565b614806565b9182136142f857506142f46001600160801b03916148e1565b1690565b90505f52600a602052600260405f20015460801c90565b9064ffffffffff421691805f52600a60205260405f20906040519061433382612a5c565b6101206143c660028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612edc565b92019182525f52600b6020526143de60405f20612f0e565b915f9264ffffffffff60406143f283613988565b510151168664ffffffffff5f925b16106144e6578161447764ffffffffff9697988784816001600160801b0361442f6142d69861447c9b9a613995565b5151169a8b9867ffffffffffffffff602061444a868b613995565b510151169782604061445c8784613995565b5101511694806144c9575050511680925b03169203166146b3565b614793565b91821361449d5750906001600160801b0361449781936148e1565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f146144c4575090565b905090565b60409250906144db915f190190613995565b51015116809261446d565b936001600160801b03600191816144fd8886613995565b51511601169401958064ffffffffff8060406145198b87613995565b51015116989298614400565b91909160405161453481612a40565b5f81525f6020820152926001600160801b0382169081156145e55767016345785d8a000081116145ae576145706001600160801b0391836154fe565b166020850191818352111561459a576001600160801b03918261459592511690612aed565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516145f681612a40565b5f81525f602082015290565b9091926001600160a01b036146619481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261465c608483612a79565b614916565b565b614661926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261465c606483612a79565b600160ff1b81148015614786575b61475e575f811215614755576146e5815f035b5f84121561474e57835f039061499b565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161471f575f199118131561471a5790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b839061499b565b6146e5816146d4565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b82146146c1565b806147ad57506147a957670de0b6b3a764000090565b5f90565b90670de0b6b3a764000082146147f857806147d0575050670de0b6b3a764000090565b670de0b6b3a764000081146147f4576147ef906142d661373393614aa1565b614bf8565b5090565b5050670de0b6b3a764000090565b600160ff1b811480156148d4575b6148ac575f8112156148a357614838815f035b5f84121561489c57835f03906154fe565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161486d575f199118131561471a5790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b83906154fe565b61483881614827565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b8214614814565b5f81126148eb5790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b0361493f93169360208151910182865af16149386141da565b90836155ac565b8051908115159182614980575b50506149555750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6149939250602080918301019101612e35565b155f8061494c565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614a665781841015614a2c57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614a73570490565b634e487b7160e01b5f52601260045260245ffd5b8015614a73576ec097ce7bc90715b34b9f10000000000590565b805f811315614bcd57670de0b6b3a76400008112614bad57506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614b9a57506706f05b59d3b20000905b5f8213614b645750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614b8c575b60011d90614b57565b809192019160011d90614b83565b9050670de0b6b3a7640000929150020290565b5f1991508015614a73576ec097ce7bc90715b34b9f100000000005614abe565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614c255768033dd1780914b971141981126137e957614c1c905f03614bf8565b61373390614a87565b680a688906bd8affffff81136154d357670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff00000000000000821661539e575b670de0b6b3a76400009066ff000000000000831661528e575b65ff00000000008316615186575b64ff000000008316615086575b63ff0000008316614f8e575b62ff00008316614e9e575b61ff008316614db6575b60ff8316614cd6575b029060401c60bf031c90565b60808316614da3575b60408316614d90575b60208316614d7d575b60108316614d6a575b60088316614d57575b60048316614d44575b60028316614d31575b6001831615614cca57680100000000000000010260401c614cca565b680100000000000000010260401c614d15565b680100000000000000030260401c614d0c565b680100000000000000060260401c614d03565b6801000000000000000b0260401c614cfa565b680100000000000000160260401c614cf1565b6801000000000000002c0260401c614ce8565b680100000000000000590260401c614cdf565b6180008316614e8b575b6140008316614e78575b6120008316614e65575b6110008316614e52575b6108008316614e3f575b6104008316614e2c575b6102008316614e19575b610100831615614cc157680100000000000000b10260401c614cc1565b680100000000000001630260401c614dfc565b680100000000000002c60260401c614df2565b6801000000000000058c0260401c614de8565b68010000000000000b170260401c614dde565b6801000000000000162e0260401c614dd4565b68010000000000002c5d0260401c614dca565b680100000000000058b90260401c614dc0565b628000008316614f7b575b624000008316614f68575b622000008316614f55575b621000008316614f42575b620800008316614f2f575b620400008316614f1c575b620200008316614f09575b62010000831615614cb7576801000000000000b1720260401c614cb7565b680100000000000162e40260401c614eeb565b6801000000000002c5c80260401c614ee0565b68010000000000058b910260401c614ed5565b680100000000000b17210260401c614eca565b68010000000000162e430260401c614ebf565b680100000000002c5c860260401c614eb4565b6801000000000058b90c0260401c614ea9565b63800000008316615073575b63400000008316615060575b6320000000831661504d575b6310000000831661503a575b63080000008316615027575b63040000008316615014575b63020000008316615001575b6301000000831615614cac5768010000000000b172180260401c614cac565b6801000000000162e4300260401c614fe2565b68010000000002c5c8600260401c614fd6565b680100000000058b90c00260401c614fca565b6801000000000b17217f0260401c614fbe565b680100000000162e42ff0260401c614fb2565b6801000000002c5c85fe0260401c614fa6565b68010000000058b90bfc0260401c614f9a565b6480000000008316615173575b6440000000008316615160575b642000000000831661514d575b641000000000831661513a575b6408000000008316615127575b6404000000008316615114575b6402000000008316615101575b640100000000831615614ca057680100000000b17217f80260401c614ca0565b68010000000162e42ff10260401c6150e1565b680100000002c5c85fe30260401c6150d4565b6801000000058b90bfce0260401c6150c7565b68010000000b17217fbb0260401c6150ba565b6801000000162e42fff00260401c6150ad565b68010000002c5c8601cc0260401c6150a0565b680100000058b90c0b490260401c615093565b65800000000000831661527b575b654000000000008316615268575b652000000000008316615255575b651000000000008316615242575b65080000000000831661522f575b65040000000000831661521c575b650200000000008316615209575b65010000000000831615614c93576801000000b1721835510260401c614c93565b680100000162e430e5a20260401c6151e8565b6801000002c5c863b73f0260401c6151da565b68010000058b90cf1e6e0260401c6151cc565b680100000b1721bcfc9a0260401c6151be565b68010000162e43f4f8310260401c6151b0565b680100002c5c89d5ec6d0260401c6151a2565b6801000058b91b5bc9ae0260401c615194565b6680000000000000831661538b575b66400000000000008316615378575b66200000000000008316615365575b66100000000000008316615352575b6608000000000000831661533f575b6604000000000000831661532c575b66020000000000008316615319575b6601000000000000831615614c855768010000b17255775c040260401c614c85565b6801000162e525ee05470260401c6152f7565b68010002c5cc37da94920260401c6152e8565b680100058ba01fb9f96d0260401c6152d9565b6801000b175effdc76ba0260401c6152ca565b680100162f3904051fa10260401c6152bb565b6801002c605e2e8cec500260401c6152ac565b68010058c86da1c09ea20260401c61529d565b67800000000000000082166154b4575b670de0b6b3a76400009067400000000000000083166154a1575b672000000000000000831661548e575b671000000000000000831661547b575b6708000000000000008316615468575b6704000000000000008316615455575b6702000000000000008316615442575b670100000000000000831661542f575b9050614c6c565b680100b1afa5abcbed610260401c615428565b68010163da9fb33356d80260401c615418565b680102c9a3e778060ee70260401c615408565b6801059b0d31585743ae0260401c6153f8565b68010b5586cf9890f62a0260401c6153e8565b6801172b83c7d517adce0260401c6153d8565b6801306fe0a31b7152df0260401c6153c8565b5077b504f333f9de6484800000000000000000000000000000006153ae565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461559b57670de0b6b3a764000082101561556b577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906155e957508051156155c157805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061562f575b6155fa575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156155f256fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a0604052346103bc57614b5c6040813803918261001c816103c0565b9384928339810103126103bc5780516001600160a01b03811691908290036103bc57602001516001600160a01b038116908190036103bc5761005e60406103c0565b91601983527f5361626c696572204c6f636b7570204c696e656172204e465400000000000000602084015261009360406103c0565b600e81526d29a0a116a627a1a5aaa816a624a760911b60208201523060805283519092906001600160401b0381116102cd57600154600181811c911680156103b2575b60208210146102af57601f811161034f575b50602094601f82116001146102ec579481929394955f926102e1575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102cd57600254600181811c911680156102c3575b60208210146102af57601f811161024c575b506020601f82116001146101e957819293945f926101de575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3600160075561477690816103e6823960805181613ade0152f35b015190505f80610165565b601f1982169060025f52805f20915f5b8181106102345750958360019596971061021c575b505050811b0160025561017a565b01515f1960f88460031b161c191690555f808061020e565b9192602060018192868b0151815501940192016101f9565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a5575b601f0160051c01905b81811061029a575061014c565b5f815560010161028d565b9091508190610284565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013a565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610104565b601f1982169560015f52805f20915f5b8881106103375750836001959697981061031f575b505050811b01600155610119565b01515f1960f88460031b161c191690555f8080610311565b919260206001819286850151815501940192016102fc565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103a8575b601f0160051c01905b81811061039d57506100e8565b5f8155600101610390565b9091508190610387565b90607f16906100d6565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102cd5760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461313a57508063027b67441461311857806306fdde031461305d578063081812fc1461303f578063095ea7b314612f3a5780631400ecec14612e895780631c1cdd4c14612e255780631e99d56914612e0857806323b872dd14612df1578063303acc8514612db4578063406887cb14612c4557806340e58ee51461296e578063425d30dd1461291e57806342842e0e146128f557806342966c6814612731578063442675701461270b5780634857501f1461269a5780634869e12d146126605780634cc55e11146122b957806353b157271461218e57806357404b12146120c85780636352211e146120995780636d0cee751461209957806370a082311461202f57806375829def14611fc1578063780a82c814611f755780637cad6cd114611e985780637de6b1db14611d4b5780638659c27014611993578063894e9a0d146116ab5780638f69b9931461162b5780639067b677146115dc57806395d89b41146114d4578063a22cb46514611420578063a80fc071146113cf578063ab167ccc1461125e578063ad35efd4146111ff578063b2564569146111af578063b88d4fde14611125578063b8a3be66146110f0578063b971302a146110a2578063bc2be1be14611053578063c156a11d14610c3c578063c87b56dd14610b31578063d4dbd20b14610ae0578063d511609f14610a95578063d975dfed14610a4a578063e985e9c5146109f1578063ea5ead19146106ae578063eac8f5b81461065d578063f590c17614610601578063f851a440146105dc5763fdd46d6014610263575f80fd5b346105d85760603660031901126105d85760043561027f613267565b906102886133c9565b91610291613ad4565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b2576001600160a01b038116801561059f57825f5260036020526001600160a01b0360405f20541693848214158061058f575b610574576001600160801b0316918215610561576001600160801b0361031c8561430a565b168084116105475750835f52600a60205282600260405f20015460801c016001600160801b0381116105335761037b90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610392600260405f20016136ad565b6001600160801b036103b68160208401511692826040818351169201511690613401565b161115610501575b835f52600a6020526103e2836001600160a01b03600160405f200154169283614330565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104eb575b61044857005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f916104b1575b50160361049f57005b636ade251160e01b5f5260045260245ffd5b6104d3915060203d6020116104d9575b6104cb818361338b565b8101906137e3565b5f610496565b503d6104c1565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f205416610442565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103be565b634e487b7160e01b5f52601160045260245ffd5b838563066920d760e01b5f5260045260245260445260645ffd5b8363b2ae763360e01b5f5260045260245ffd5b508263350b320360e11b5f526004523360245260445260645ffd5b5061059984613b2e565b156102f7565b82632da33e5b60e01b5f5260045260245ffd5b506315efa0f360e11b5f5260045260245ffd5b5063699d2de960e01b5f5260045260245ffd5b5f80fd5b346105d8575f3660031901126105d85760206001600160a01b035f5416604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105d85760403660031901126105d8576004356106ca613267565b6106d38261430a565b916106dc613ad4565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c166109df576001600160a01b03821680156109cc57815f5260036020526001600160a01b0360405f2054169384821415806109bc575b6109a1576001600160801b031692831561098e576001600160801b036107678461430a565b168085116109745750825f52600a60205283600260405f20015460801c016001600160801b038111610533576107c690845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526107dd600260405f20016136ad565b6001600160801b036108018160208401511692826040818351169201511690613401565b161115610942575b825f52600a60205261082d846001600160a01b03600160405f200154169283614330565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1833314158061092c575b61089d575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104e0576392b9102b60e01b916001600160e01b0319915f9161090d575b5016036108fa578180610892565b50636ade251160e01b5f5260045260245ffd5b610926915060203d6020116104d9576104cb818361338b565b856108ec565b50835f52600960205260ff60405f20541661088d565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610809565b848463066920d760e01b5f5260045260245260445260645ffd5b8263b2ae763360e01b5f5260045260245ffd5b509063350b320360e11b5f526004523360245260445260645ffd5b506109c683613b2e565b15610742565b50632da33e5b60e01b5f5260045260245ffd5b6315efa0f360e11b5f5260045260245ffd5b346105d85760403660031901126105d857610a0a613251565b6001600160a01b03610a1a613267565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57610a8460209161430a565b6001600160801b0360405191168152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a6020526020600260405f20015460801c604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105d85760203660031901126105d857600435610b4e81613803565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104e0575f90610bbf575b610bbb9060405191829160208352602083019061322c565b0390f35b503d805f833e610bcf818361338b565b8101906020818303126105d85780519067ffffffffffffffff82116105d857019080601f830112156105d857815191610c07836133ad565b91610c15604051938461338b565b838352602084830101116105d857610bbb92610c37916020808501910161320b565b610ba3565b346105d85760403660031901126105d857600435610c58613267565b610c60613ad4565b815f52600a60205260ff600160405f20015460a81c16156105c557815f5260036020526001600160a01b0360405f2054169081330361103c576001600160801b03610caa8461430a565b169081158015610d33575b506001600160a01b03811615610d2057610cd7846001600160a01b039261399a565b169182610cf15783637e27328960e01b5f5260045260245ffd5b8084918403610d0557602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d3b613ad4565b845f52600a60205260ff600160405f20015460a81c161561102957845f52600a60205260ff600160405f20015460a01c1661101657831561100357845f5260036020526001600160a01b0360405f205416908185141580610ff3575b610fd857610fc5576001600160801b03610db08661430a565b16808411610fab5750845f52600a60205282600260405f20015460801c016001600160801b03811161053357610e0f90865f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b845f52600a602052610e26600260405f20016136ad565b6001600160801b03610e4a8160208401511692826040818351169201511690613401565b161115610f79575b845f52600a6020526001600160a01b03600160405f20015416610e76848683614330565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f63575b15610cb5576040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91610f44575b501614610cb557636ade251160e01b5f5260045260245ffd5b610f5d915060203d6020116104d9576104cb818361338b565b88610f2b565b50805f52600960205260ff60405f205416610ed6565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e52565b838663066920d760e01b5f5260045260245260445260645ffd5b8463b2ae763360e01b5f5260045260245ffd5b848663350b320360e11b5f526004523360245260445260645ffd5b50610ffd86613b2e565b15610d97565b84632da33e5b60e01b5f5260045260245ffd5b846315efa0f360e11b5f5260045260245ffd5b8463699d2de960e01b5f5260045260245ffd5b82632082501160e01b5f526004523360245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105d85760203660031901126105d8576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105d85760803660031901126105d85761113e613251565b611146613267565b6064359167ffffffffffffffff83116105d857366023840112156105d857826004013591611173836133ad565b92611181604051948561338b565b80845236602482870101116105d8576020815f9260246111ad98018388013785010152604435916136f3565b005b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b5761123790613906565b604051600582101561124a576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105d8576101403660031901126105d857611278613ad4565b61128061368f565b64ffffffffff421680825264ffffffffff6112996136df565b166113b4575b60e43564ffffffffff811681036105d85764ffffffffff9101166040820152600435906001600160a01b038216918281036105d857506024356001600160a01b038116908181036105d857506044356001600160801b038116908181036105d857506064356001600160a01b0381168091036105d85760843591821515928381036105d8575060a43593841515948581036105d8575060405196611342886132e8565b8752602087015260408601526060850152608084015260a083015260c08201526040610103193601126105d8576040519061137c8261336f565b61010435906001600160a01b03821682036105d857826113ac9260209452610124358482015260e0820152613c24565b604051908152f35b64ffffffffff6113c26136df565b820116602083015261129f565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105d85760403660031901126105d857611439613251565b602435908115158092036105d8576001600160a01b03169081156114a857335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d8575f3660031901126105d8576040515f6002548060011c906001811680156115d2575b6020831081146115be5782855290811561159a575060011461153c575b610bbb836115288185038261338b565b60405191829160208352602083019061322c565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b80821061158057509091508101602001611528611518565b919260018160209254838588010152019101909291611568565b60ff191660208086019190915291151560051b840190910191506115289050611518565b634e487b7160e01b5f52602260045260245ffd5b91607f16916114fb565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b5761166390613906565b60058110158061124a576002821490811561169f575b811561168d575b6020826040519015158152f35b905061124a5760046020911482611680565b5050600381145f611679565b346105d85760203660031901126105d8576004355f6101606040516116cf81613335565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201528261012082015261171261368f565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260405f2060405161174d81613352565b81546001600160a01b0381168252602082019364ffffffffff8260a01c168552604083019364ffffffffff8360c81c1685526060840160ff8460f01c1615158152608085019360f81c1515845260018201549360a08601956001600160a01b038616875260c081019560ff8160a01c16151587526117ec600260e084019660ff8460a81c161515885260ff61010086019460b01c1615158452016136ad565b61012083019081526117fd87613906565b600581101561124a5760021461198b575b5197516001600160a01b031692865f52600b60205260405f205464ffffffffff16995164ffffffffff1694511515915115159751151595511515965f52600360205260405f20546001600160a01b031692516001600160a01b03169a5164ffffffffff16905115159260405161188381613335565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b5f855261180e565b346105d85760203660031901126105d85760043567ffffffffffffffff81116105d8576119c49036906004016132b7565b906119cd613ad4565b5f915b8083106119d957005b6119e483828461366b565b35926119ee613ad4565b835f52600a60205260ff600160405f20015460a81c1615611d3857835f52600a60205260ff600160405f20015460a01c165f14611a3857836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611d2657611a6d815f52600a6020526001600160a01b0360405f205416331490565b15611d1057611a7b81613824565b90805f52600a602052611a93600260405f20016136ad565b916001600160801b038351166001600160801b0382161015611cfd57815f52600a60205260ff60405f205460f01c1615611cea57806001600160801b03602081611ae7948188511603169501511690613401565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611cc5575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611bf96001600160a01b03600160405f2001541694611bd1888588614330565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611c4a575b505050505060010191906119d0565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91611ca7575b50160361049f5780808080611c3b565b611cbf915060203d81116104d9576104cb818361338b565b87611c97565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611b31565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f5260045260245ffd5b346105d85760203660031901126105d857600435611d67613ad4565b805f52600a60205260ff600160405f20015460a81c161561064b57611d8b81613906565b600581101561124a5760048103611daf57506315efa0f360e11b5f5260045260245ffd5b60038103611dca575063d0a172b360e01b5f5260045260245ffd5b600214611e8657611def815f52600a6020526001600160a01b0360405f205416331490565b15611d1057805f52600a60205260ff60405f205460f01c1615611e74576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b6308aca53f60e21b5f5260045260245ffd5b346105d85760203660031901126105d8576004356001600160a01b0381168091036105d8576001600160a01b035f5416338103611f5f575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116105335760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600b602052602064ffffffffff60405f205416604051908152f35b346105d85760203660031901126105d857611fda613251565b5f546001600160a01b038116338103611f5f57506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105d85760203660031901126105d8576001600160a01b03612050613251565b16801561206d575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105d85760203660031901126105d85760206120b7600435613803565b6001600160a01b0360405191168152f35b346105d85760203660031901126105d8576004356120e461368f565b50805f52600a60205260ff600160405f20015460a81c161561064b57806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c16906040519261215484613319565b83526020830152604082015261218c604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b346105d8576101603660031901126105d8576121a8613ad4565b6040516121b4816132e8565b6121bc613251565b81526121c6613267565b60208201526121d36133c9565b60408201526064356001600160a01b03811681036105d857606082015260843580151581036105d857608082015260a43580151581036105d85760a082015260603660c31901126105d85760405161222a81613319565b60c43564ffffffffff811681036105d857815260e43564ffffffffff811681036105d85760208201526101043564ffffffffff811681036105d857604082015260c08201526040610123193601126105d857604051906122898261336f565b61012435906001600160a01b03821682036105d857826113ac9260209452610144358482015260e0820152613c24565b346105d85760403660031901126105d85760043567ffffffffffffffff81116105d8576122ea9036906004016132b7565b60243567ffffffffffffffff81116105d85761230a9036906004016132b7565b612315939193613ad4565b808303612631575f5b83811061232757005b61233281858561366b565b3561233e82868661366b565b355f5260036020526001600160a01b0360405f2054169061236083858961366b565b356001600160801b038116908181036105d8575061237c613ad4565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b25782156109cc57815f5260036020526001600160a01b0360405f205416928381141580612621575b61260757811561098e576001600160801b036123f38461430a565b168083116125ed5750825f52600a60205281600260405f20015460801c016001600160801b0381116105335761245290845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a602052612469600260405f20016136ad565b6001600160801b0361248d8160208401511692826040818351169201511690613401565b1611156125bb575b825f52600a6020526001600160a01b03600160405f200154166124b9838383614330565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125a5575b61252a575b5050505060010161231e565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91612587575b50160361049f5780808061251e565b61259f915060203d81116104d9576104cb818361338b565b89612578565b50835f52600960205260ff60405f205416612519565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612495565b828463066920d760e01b5f5260045260245260445260645ffd5b8263350b320360e11b5f526004523360245260445260645ffd5b5061262b83613b2e565b156123d8565b827fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57610a84602091613ba0565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f6126d382613906565b600581101561124a576002036126f1575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c166126e4565b346105d8575f3660031901126105d85760206001600160a01b0360085416604051908152f35b346105d85760203660031901126105d85760043561274d613ad4565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c16156128ca5761278c81613b2e565b15611d1057805f5260036020526001600160a01b0360405f2054161515806128c3575b806128a6575b612894577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f205416801590811561285d575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061284b57005b637e27328960e01b5f5260045260245ffd5b61287c835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612803565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127b5565b505f6127af565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d8576111ad6129063661327d565b906040519261291660208561338b565b5f84526136f3565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105d85760203660031901126105d85760043561298a613ad4565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c165f146129d3576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c611d2657612a05815f52600a6020526001600160a01b0360405f205416331490565b15611d1057612a1381613824565b90805f52600a602052612a2b600260405f20016136ad565b916001600160801b038351166001600160801b0382161015611cfd57815f52600a60205260ff60405f205460f01c1615611cea57806001600160801b03602081612a7f948188511603169501511690613401565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c20575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612b696001600160a01b03600160405f2001541694611bd1888588614330565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612bac57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91612c015750160361049f57005b612c1a915060203d6020116104d9576104cb818361338b565b84610496565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612ac9565b346105d85760203660031901126105d857612c5e613251565b6001600160a01b035f541690338203612d9d57806001600160a01b03913b15612d7157166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104e0575f91612d42575b5015612d1757805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612d64915060203d602011612d6a575b612d5c818361338b565b810190613653565b82612ccc565b503d612d52565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105d85760203660031901126105d8576001600160a01b03612dd5613251565b165f526009602052602060ff60405f2054166040519015158152f35b346105d8576111ad612e023661327d565b91613421565b346105d8575f3660031901126105d8576020600754604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57612e5d90613906565b600581101561124a578060209115908115612e7e575b506040519015158152f35b600191501482612e73565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b576020905f90805f52600a835260ff60405f205460f01c1680612f1e575b612eec575b506001600160801b0360405191168152f35b612f189150805f52600a8352612f126001600160801b03600260405f2001541691613824565b90613401565b82612eda565b50805f52600a835260ff600160405f20015460a01c1615612ed5565b346105d85760403660031901126105d857612f53613251565b602435612f5f81613803565b3315158061302c575b80612ff9575b612fcd5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612f6e565b50336001600160a01b0382161415612f68565b346105d85760203660031901126105d85760206120b76004356133df565b346105d8575f3660031901126105d8576040515f6001548060011c9060018116801561310e575b6020831081146115be5782855290811561159a57506001146130b057610bbb836115288185038261338b565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106130f457509091508101602001611528611518565b9192600181602092548385880101520191019092916130dc565b91607f1691613084565b346105d8575f3660031901126105d857602060405167016345785d8a00008152f35b346105d85760203660031901126105d857600435906001600160e01b031982168092036105d857817f490649060000000000000000000000000000000000000000000000000000000060209314908115613196575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156131e1575b81156131d0575b508361318f565b6301ffc9a760e01b915014836131c9565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506131c2565b5f5b83811061321c5750505f910152565b818101518382015260200161320d565b906020916132458151809281855285808601910161320b565b601f01601f1916010190565b600435906001600160a01b03821682036105d857565b602435906001600160a01b03821682036105d857565b60609060031901126105d8576004356001600160a01b03811681036105d857906024356001600160a01b03811681036105d8579060443590565b9181601f840112156105d85782359167ffffffffffffffff83116105d8576020808501948460051b0101116105d857565b610100810190811067ffffffffffffffff82111761330557604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761330557604052565b610180810190811067ffffffffffffffff82111761330557604052565b610140810190811067ffffffffffffffff82111761330557604052565b6040810190811067ffffffffffffffff82111761330557604052565b90601f8019910116810190811067ffffffffffffffff82111761330557604052565b67ffffffffffffffff811161330557601f01601f191660200190565b604435906001600160801b03821682036105d857565b6133e881613803565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161053357565b91906001600160a01b03168015610d2057815f5260036020526001600160a01b0360405f20541615158061364b575b8061362e575b61361b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613566575b6001600160a01b0393508561352f575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361351757505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b61354e825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556134b6565b91929050806135c4575b1561357d578282916134a6565b828461359557637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b5033841480156135f2575b806135705750825f526005602052336001600160a01b0360405f20541614613570565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166135cf565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615613456565b506001613450565b908160209103126105d8575180151581036105d85790565b919081101561367b5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b6040519061369c82613319565b5f6040838281528260208201520152565b906040516136ba81613319565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff811681036105d85790565b906136ff838284613421565b803b61370c575b50505050565b6020916137526001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061322c565b03815f865af15f91816137c2575b5061378e575061376e6142db565b805190816137895782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b9116036137b057505f808080613706565b633250574960e11b5f5260045260245ffd5b6137dc91925060203d6020116104d9576104cb818361338b565b905f613760565b908160209103126105d857516001600160e01b0319811681036105d85790565b805f5260036020526001600160a01b0360405f20541690811561284b575090565b805f52600b60205264ffffffffff60405f205416815f52600a60205264ffffffffff60405f205460a01c1690421080156138fc575b6138f657815f52600a60205264ffffffffff60405f205460c81c1690814210156138d9578061388b92039042036144be565b815f52600a6020526138ae6001600160801b03600260405f2001541680926145aa565b9081116138c3576001600160801b0391501690565b505f52600a602052600260405f20015460801c90565b50505f52600a6020526001600160801b03600260405f2001541690565b50505f90565b5042811015613859565b805f52600a60205260ff600160405f20015460a01c165f146139285750600490565b805f52600a60205260405f205460f81c61399457805f52600a60205264ffffffffff60405f205460a01c16421061398f5761396281613824565b905f52600a6020526001600160801b0380600260405f200154169116105f1461398a57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613ac2575b80613aa5575b612894577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613a6e575b1680613a56575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613a12565b613a8d835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613a0b565b50805f52600a60205260ff600160405f20015460b01c16156139bf565b506001600160a01b03821615156139b9565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613b0657565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613b74575b508115613b5b575090565b90506001600160a01b03613b6f33926133df565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613b50565b805f52600a602052613bb7600260405f20016136ad565b90805f52600a60205260ff600160405f20015460a01c165f14613be55750602001516001600160801b031690565b90815f52600a60205260405f205460f81c613c075750613c0490613824565b90565b613c0491506001600160801b036040818351169201511690613401565b90613c456001600160801b03604084015116602060e0850151015190614387565b916001600160a01b038151166001600160801b0384511660c083015191156142b3571561428b5764ffffffffff81511615614263576020810164ffffffffff815116806141d7575b505064ffffffffff6040818351169201511690818110156141a95750506007549280516001600160801b03169160405192613cc784613319565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613d2d89613352565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600a60205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613fad91906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff1680614189575b50600185016007556001600160a01b036020820151168015610d205761401b866001600160a01b039261399a565b1661415d576140466001600160a01b036060830151166001600160801b038451169030903390614464565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b038651168061412e575b506141256001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b614157906001600160a01b036060880151166001600160a01b0360e08901515116903390614464565b5f614081565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600b60205260405f209064ffffffffff198254161790555f613fed565b7f9e7fd91f000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff8351168181101561423557505064ffffffffff90511664ffffffffff60408301511690818110613c8d577f87d966a0000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f84fe0623000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6d004a9e000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d15614305573d906142ec826133ad565b916142fa604051938461338b565b82523d5f602084013e565b606090565b613c049061431781613ba0565b905f52600a602052600260405f20015460801c90613401565b614385926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261438060648361338b565b614658565b565b9190916040516143968161336f565b5f81525f6020820152926001600160801b0382169081156144475767016345785d8a00008111614410576143d26001600160801b0391836145aa565b16602085019181835211156143fc576001600160801b0391826143f792511690613401565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516144588161336f565b5f81525f602082015290565b9091926001600160a01b036143859481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261438060848361338b565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614589578184101561454f57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614596570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f198382098382029182808310920391808303921461464757670de0b6b3a7640000821015614617577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b0361468193169360208151910182865af161467a6142db565b90836146dd565b80519081151591826146c2575b50506146975750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6146d59250602080918301019101613653565b155f8061468e565b9061471a57508051156146f257805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614760575b61472b575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561472356fea164736f6c634300081a000a"; + hex"60a0604052346103bc57614b716040813803918261001c816103c0565b9384928339810103126103bc5780516001600160a01b03811691908290036103bc57602001516001600160a01b038116908190036103bc5761005e60406103c0565b91601983527f5361626c696572204c6f636b7570204c696e656172204e465400000000000000602084015261009360406103c0565b600e81526d29a0a116a627a1a5aaa816a624a760911b60208201523060805283519092906001600160401b0381116102cd57600154600181811c911680156103b2575b60208210146102af57601f811161034f575b50602094601f82116001146102ec579481929394955f926102e1575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102cd57600254600181811c911680156102c3575b60208210146102af57601f811161024c575b506020601f82116001146101e957819293945f926101de575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3600160075561478b90816103e6823960805181613adf0152f35b015190505f80610165565b601f1982169060025f52805f20915f5b8181106102345750958360019596971061021c575b505050811b0160025561017a565b01515f1960f88460031b161c191690555f808061020e565b9192602060018192868b0151815501940192016101f9565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a5575b601f0160051c01905b81811061029a575061014c565b5f815560010161028d565b9091508190610284565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013a565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610104565b601f1982169560015f52805f20915f5b8881106103375750836001959697981061031f575b505050811b01600155610119565b01515f1960f88460031b161c191690555f8080610311565b919260206001819286850151815501940192016102fc565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103a8575b601f0160051c01905b81811061039d57506100e8565b5f8155600101610390565b9091508190610387565b90607f16906100d6565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102cd5760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461313b57508063027b67441461311957806306fdde031461305e578063081812fc14613040578063095ea7b314612f3b5780631400ecec14612e8a5780631c1cdd4c14612e265780631e99d56914612e0957806323b872dd14612df2578063303acc8514612db5578063406887cb14612c4657806340e58ee51461296f578063425d30dd1461291f57806342842e0e146128f657806342966c6814612732578063442675701461270c5780634857501f1461269b5780634869e12d146126615780634cc55e11146122ba57806353b157271461218f57806357404b12146120c95780636352211e1461209a5780636d0cee751461209a57806370a082311461203057806375829def14611fc2578063780a82c814611f765780637cad6cd114611e995780637de6b1db14611d4c5780638659c27014611994578063894e9a0d146116ac5780638f69b9931461162c5780639067b677146115dd57806395d89b41146114d5578063a22cb46514611421578063a80fc071146113d0578063ab167ccc1461125f578063ad35efd414611200578063b2564569146111b0578063b88d4fde14611126578063b8a3be66146110f1578063b971302a146110a3578063bc2be1be14611054578063c156a11d14610c3e578063c87b56dd14610b33578063d4dbd20b14610ae2578063d511609f14610a97578063d975dfed14610a4c578063e985e9c5146109f3578063ea5ead19146106ae578063eac8f5b81461065d578063f590c17614610601578063f851a440146105dc5763fdd46d6014610263575f80fd5b346105d85760603660031901126105d85760043561027f613268565b906102886133ca565b610290613ad5565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b2576001600160a01b03831690811561059f576001600160801b031690811561058c57825f5260036020526001600160a01b0360405f20541693848214158061057c575b610561576001600160801b0361031c8561431f565b168084116105475750835f52600a60205282600260405f20015460801c016001600160801b0381116105335761037b90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610392600260405f20016136ae565b6001600160801b036103b68160208401511692826040818351169201511690613402565b161115610501575b835f52600a6020526103e2836001600160a01b03600160405f200154169283614345565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104eb575b61044857005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f916104b1575b50160361049f57005b636ade251160e01b5f5260045260245ffd5b6104d3915060203d6020116104d9575b6104cb818361338c565b8101906137e4565b5f610496565b503d6104c1565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f205416610442565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103be565b634e487b7160e01b5f52601160045260245ffd5b838563066920d760e01b5f5260045260245260445260645ffd5b508263350b320360e11b5f526004523360245260445260645ffd5b5061058684613b2f565b15610307565b8263b2ae763360e01b5f5260045260245ffd5b82632da33e5b60e01b5f5260045260245ffd5b506315efa0f360e11b5f5260045260245ffd5b5063699d2de960e01b5f5260045260245ffd5b5f80fd5b346105d8575f3660031901126105d85760206001600160a01b035f5416604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105d85760403660031901126105d8576004356106ca613268565b906106d48161431f565b906106dd613ad5565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c166109e1576001600160a01b0383169182156109ce576001600160801b03169182156109bb57815f5260036020526001600160a01b0360405f2054169384821415806109ab575b610990576001600160801b036107698461431f565b168085116109765750825f52600a60205283600260405f20015460801c016001600160801b038111610533576107c890845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526107df600260405f20016136ae565b6001600160801b036108038160208401511692826040818351169201511690613402565b161115610944575b825f52600a60205261082f846001600160a01b03600160405f200154169283614345565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1833314158061092e575b61089f575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104e0576392b9102b60e01b916001600160e01b0319915f9161090f575b5016036108fc578180610894565b50636ade251160e01b5f5260045260245ffd5b610928915060203d6020116104d9576104cb818361338c565b856108ee565b50835f52600960205260ff60405f20541661088f565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b1916905561080b565b848463066920d760e01b5f5260045260245260445260645ffd5b509063350b320360e11b5f526004523360245260445260645ffd5b506109b583613b2f565b15610754565b5063b2ae763360e01b5f5260045260245ffd5b50632da33e5b60e01b5f5260045260245ffd5b6315efa0f360e11b5f5260045260245ffd5b346105d85760403660031901126105d857610a0c613252565b6001600160a01b03610a1c613268565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57610a8660209161431f565b6001600160801b0360405191168152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a6020526020600260405f20015460801c604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105d85760203660031901126105d857600435610b5081613804565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104e0575f90610bc1575b610bbd9060405191829160208352602083019061322d565b0390f35b503d805f833e610bd1818361338c565b8101906020818303126105d85780519067ffffffffffffffff82116105d857019080601f830112156105d857815191610c09836133ae565b91610c17604051938461338c565b838352602084830101116105d857610bbd92610c39916020808501910161320c565b610ba5565b346105d85760403660031901126105d857600435610c5a613268565b610c62613ad5565b815f52600a60205260ff600160405f20015460a81c16156105c557815f5260036020526001600160a01b0360405f2054169081330361103d576001600160801b03610cac8461431f565b169081158015610d35575b506001600160a01b03811615610d2257610cd9846001600160a01b039261399b565b169182610cf35783637e27328960e01b5f5260045260245ffd5b8084918403610d0757602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d3d613ad5565b845f52600a60205260ff600160405f20015460a81c161561102a57845f52600a60205260ff600160405f20015460a01c1661101757831561100457610ff157835f5260036020526001600160a01b0360405f2054168084141580610fe1575b610fc6576001600160801b03610db18661431f565b16808411610fac5750845f52600a60205282600260405f20015460801c016001600160801b03811161053357610e1090865f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b845f52600a602052610e27600260405f20016136ae565b6001600160801b03610e4b8160208401511692826040818351169201511690613402565b161115610f7a575b845f52600a6020526001600160a01b03600160405f20015416610e77848683614345565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f64575b15610cb7576040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91610f45575b501614610cb757636ade251160e01b5f5260045260245ffd5b610f5e915060203d6020116104d9576104cb818361338c565b88610f2c565b50805f52600960205260ff60405f205416610ed7565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e53565b838663066920d760e01b5f5260045260245260445260645ffd5b838563350b320360e11b5f526004523360245260445260645ffd5b50610feb85613b2f565b15610d9c565b8363b2ae763360e01b5f5260045260245ffd5b84632da33e5b60e01b5f5260045260245ffd5b846315efa0f360e11b5f5260045260245ffd5b8463699d2de960e01b5f5260045260245ffd5b82632082501160e01b5f526004523360245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105d85760203660031901126105d8576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105d85760803660031901126105d85761113f613252565b611147613268565b6064359167ffffffffffffffff83116105d857366023840112156105d857826004013591611174836133ae565b92611182604051948561338c565b80845236602482870101116105d8576020815f9260246111ae98018388013785010152604435916136f4565b005b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b5761123890613907565b604051600582101561124b576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105d8576101403660031901126105d857611279613ad5565b611281613690565b64ffffffffff421680825264ffffffffff61129a6136e0565b166113b5575b60e43564ffffffffff811681036105d85764ffffffffff9101166040820152600435906001600160a01b038216918281036105d857506024356001600160a01b038116908181036105d857506044356001600160801b038116908181036105d857506064356001600160a01b0381168091036105d85760843591821515928381036105d8575060a43593841515948581036105d8575060405196611343886132e9565b8752602087015260408601526060850152608084015260a083015260c08201526040610103193601126105d8576040519061137d82613370565b61010435906001600160a01b03821682036105d857826113ad9260209452610124358482015260e0820152613c25565b604051908152f35b64ffffffffff6113c36136e0565b82011660208301526112a0565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105d85760403660031901126105d85761143a613252565b602435908115158092036105d8576001600160a01b03169081156114a957335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d8575f3660031901126105d8576040515f6002548060011c906001811680156115d3575b6020831081146115bf5782855290811561159b575060011461153d575b610bbd836115298185038261338c565b60405191829160208352602083019061322d565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b80821061158157509091508101602001611529611519565b919260018160209254838588010152019101909291611569565b60ff191660208086019190915291151560051b840190910191506115299050611519565b634e487b7160e01b5f52602260045260245ffd5b91607f16916114fc565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b5761166490613907565b60058110158061124b57600282149081156116a0575b811561168e575b6020826040519015158152f35b905061124b5760046020911482611681565b5050600381145f61167a565b346105d85760203660031901126105d8576004355f6101606040516116d081613336565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152611713613690565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260405f2060405161174e81613353565b81546001600160a01b0381168252602082019364ffffffffff8260a01c168552604083019364ffffffffff8360c81c1685526060840160ff8460f01c1615158152608085019360f81c1515845260018201549360a08601956001600160a01b038616875260c081019560ff8160a01c16151587526117ed600260e084019660ff8460a81c161515885260ff61010086019460b01c1615158452016136ae565b61012083019081526117fe87613907565b600581101561124b5760021461198c575b5197516001600160a01b031692865f52600b60205260405f205464ffffffffff16995164ffffffffff1694511515915115159751151595511515965f52600360205260405f20546001600160a01b031692516001600160a01b03169a5164ffffffffff16905115159260405161188481613336565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b5f855261180f565b346105d85760203660031901126105d85760043567ffffffffffffffff81116105d8576119c59036906004016132b8565b906119ce613ad5565b5f915b8083106119da57005b6119e583828461366c565b35926119ef613ad5565b835f52600a60205260ff600160405f20015460a81c1615611d3957835f52600a60205260ff600160405f20015460a01c165f14611a3957836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611d2757611a6e815f52600a6020526001600160a01b0360405f205416331490565b15611d1157611a7c81613825565b90805f52600a602052611a94600260405f20016136ae565b916001600160801b038351166001600160801b0382161015611cfe57815f52600a60205260ff60405f205460f01c1615611ceb57806001600160801b03602081611ae8948188511603169501511690613402565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611cc6575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611bfa6001600160a01b03600160405f2001541694611bd2888588614345565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611c4b575b505050505060010191906119d1565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91611ca8575b50160361049f5780808080611c3c565b611cc0915060203d81116104d9576104cb818361338c565b87611c98565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611b32565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f5260045260245ffd5b346105d85760203660031901126105d857600435611d68613ad5565b805f52600a60205260ff600160405f20015460a81c161561064b57611d8c81613907565b600581101561124b5760048103611db057506315efa0f360e11b5f5260045260245ffd5b60038103611dcb575063d0a172b360e01b5f5260045260245ffd5b600214611e8757611df0815f52600a6020526001600160a01b0360405f205416331490565b15611d1157805f52600a60205260ff60405f205460f01c1615611e75576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b6308aca53f60e21b5f5260045260245ffd5b346105d85760203660031901126105d8576004356001600160a01b0381168091036105d8576001600160a01b035f5416338103611f60575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116105335760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600b602052602064ffffffffff60405f205416604051908152f35b346105d85760203660031901126105d857611fdb613252565b5f546001600160a01b038116338103611f6057506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105d85760203660031901126105d8576001600160a01b03612051613252565b16801561206e575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105d85760203660031901126105d85760206120b8600435613804565b6001600160a01b0360405191168152f35b346105d85760203660031901126105d8576004356120e5613690565b50805f52600a60205260ff600160405f20015460a81c161561064b57806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c1690604051926121558461331a565b83526020830152604082015261218d604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b346105d8576101603660031901126105d8576121a9613ad5565b6040516121b5816132e9565b6121bd613252565b81526121c7613268565b60208201526121d46133ca565b60408201526064356001600160a01b03811681036105d857606082015260843580151581036105d857608082015260a43580151581036105d85760a082015260603660c31901126105d85760405161222b8161331a565b60c43564ffffffffff811681036105d857815260e43564ffffffffff811681036105d85760208201526101043564ffffffffff811681036105d857604082015260c08201526040610123193601126105d8576040519061228a82613370565b61012435906001600160a01b03821682036105d857826113ad9260209452610144358482015260e0820152613c25565b346105d85760403660031901126105d85760043567ffffffffffffffff81116105d8576122eb9036906004016132b8565b60243567ffffffffffffffff81116105d85761230b9036906004016132b8565b612316939193613ad5565b808303612632575f5b83811061232857005b61233381858561366c565b3561233f82868661366c565b355f5260036020526001600160a01b0360405f2054169061236183858961366c565b356001600160801b038116908181036105d8575061237d613ad5565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b25782156109ce5780156109bb57815f5260036020526001600160a01b0360405f205416928381141580612622575b612608576001600160801b036123f48461431f565b168083116125ee5750825f52600a60205281600260405f20015460801c016001600160801b0381116105335761245390845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a60205261246a600260405f20016136ae565b6001600160801b0361248e8160208401511692826040818351169201511690613402565b1611156125bc575b825f52600a6020526001600160a01b03600160405f200154166124ba838383614345565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125a6575b61252b575b5050505060010161231f565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91612588575b50160361049f5780808061251f565b6125a0915060203d81116104d9576104cb818361338c565b89612579565b50835f52600960205260ff60405f20541661251a565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612496565b828463066920d760e01b5f5260045260245260445260645ffd5b8263350b320360e11b5f526004523360245260445260645ffd5b5061262c83613b2f565b156123df565b827fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57610a86602091613ba1565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f6126d482613907565b600581101561124b576002036126f2575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c166126e5565b346105d8575f3660031901126105d85760206001600160a01b0360085416604051908152f35b346105d85760203660031901126105d85760043561274e613ad5565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c16156128cb5761278d81613b2f565b15611d1157805f5260036020526001600160a01b0360405f2054161515806128c4575b806128a7575b612895577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f205416801590811561285e575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061284c57005b637e27328960e01b5f5260045260245ffd5b61287d835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612804565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127b6565b505f6127b0565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d8576111ae6129073661327e565b906040519261291760208561338c565b5f84526136f4565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105d85760203660031901126105d85760043561298b613ad5565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c165f146129d4576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c611d2757612a06815f52600a6020526001600160a01b0360405f205416331490565b15611d1157612a1481613825565b90805f52600a602052612a2c600260405f20016136ae565b916001600160801b038351166001600160801b0382161015611cfe57815f52600a60205260ff60405f205460f01c1615611ceb57806001600160801b03602081612a80948188511603169501511690613402565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c21575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612b6a6001600160a01b03600160405f2001541694611bd2888588614345565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612bad57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91612c025750160361049f57005b612c1b915060203d6020116104d9576104cb818361338c565b84610496565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612aca565b346105d85760203660031901126105d857612c5f613252565b6001600160a01b035f541690338203612d9e57806001600160a01b03913b15612d7257166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104e0575f91612d43575b5015612d1857805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612d65915060203d602011612d6b575b612d5d818361338c565b810190613654565b82612ccd565b503d612d53565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105d85760203660031901126105d8576001600160a01b03612dd6613252565b165f526009602052602060ff60405f2054166040519015158152f35b346105d8576111ae612e033661327e565b91613422565b346105d8575f3660031901126105d8576020600754604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57612e5e90613907565b600581101561124b578060209115908115612e7f575b506040519015158152f35b600191501482612e74565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b576020905f90805f52600a835260ff60405f205460f01c1680612f1f575b612eed575b506001600160801b0360405191168152f35b612f199150805f52600a8352612f136001600160801b03600260405f2001541691613825565b90613402565b82612edb565b50805f52600a835260ff600160405f20015460a01c1615612ed6565b346105d85760403660031901126105d857612f54613252565b602435612f6081613804565b3315158061302d575b80612ffa575b612fce5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612f6f565b50336001600160a01b0382161415612f69565b346105d85760203660031901126105d85760206120b86004356133e0565b346105d8575f3660031901126105d8576040515f6001548060011c9060018116801561310f575b6020831081146115bf5782855290811561159b57506001146130b157610bbd836115298185038261338c565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106130f557509091508101602001611529611519565b9192600181602092548385880101520191019092916130dd565b91607f1691613085565b346105d8575f3660031901126105d857602060405167016345785d8a00008152f35b346105d85760203660031901126105d857600435906001600160e01b031982168092036105d857817f490649060000000000000000000000000000000000000000000000000000000060209314908115613197575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156131e2575b81156131d1575b5083613190565b6301ffc9a760e01b915014836131ca565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506131c3565b5f5b83811061321d5750505f910152565b818101518382015260200161320e565b906020916132468151809281855285808601910161320c565b601f01601f1916010190565b600435906001600160a01b03821682036105d857565b602435906001600160a01b03821682036105d857565b60609060031901126105d8576004356001600160a01b03811681036105d857906024356001600160a01b03811681036105d8579060443590565b9181601f840112156105d85782359167ffffffffffffffff83116105d8576020808501948460051b0101116105d857565b610100810190811067ffffffffffffffff82111761330657604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761330657604052565b610180810190811067ffffffffffffffff82111761330657604052565b610140810190811067ffffffffffffffff82111761330657604052565b6040810190811067ffffffffffffffff82111761330657604052565b90601f8019910116810190811067ffffffffffffffff82111761330657604052565b67ffffffffffffffff811161330657601f01601f191660200190565b604435906001600160801b03821682036105d857565b6133e981613804565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161053357565b91906001600160a01b03168015610d2257815f5260036020526001600160a01b0360405f20541615158061364c575b8061362f575b61361c577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613567575b6001600160a01b03935085613530575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361351857505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b61354f825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556134b7565b91929050806135c5575b1561357e578282916134a7565b828461359657637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b5033841480156135f3575b806135715750825f526005602052336001600160a01b0360405f20541614613571565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166135d0565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615613457565b506001613451565b908160209103126105d8575180151581036105d85790565b919081101561367c5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b6040519061369d8261331a565b5f6040838281528260208201520152565b906040516136bb8161331a565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff811681036105d85790565b90613700838284613422565b803b61370d575b50505050565b6020916137536001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061322d565b03815f865af15f91816137c3575b5061378f575061376f6142f0565b8051908161378a5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b9116036137b157505f808080613707565b633250574960e11b5f5260045260245ffd5b6137dd91925060203d6020116104d9576104cb818361338c565b905f613761565b908160209103126105d857516001600160e01b0319811681036105d85790565b805f5260036020526001600160a01b0360405f20541690811561284c575090565b805f52600b60205264ffffffffff60405f205416815f52600a60205264ffffffffff60405f205460a01c1690421080156138fd575b6138f757815f52600a60205264ffffffffff60405f205460c81c1690814210156138da578061388c92039042036144d3565b815f52600a6020526138af6001600160801b03600260405f2001541680926145bf565b9081116138c4576001600160801b0391501690565b505f52600a602052600260405f20015460801c90565b50505f52600a6020526001600160801b03600260405f2001541690565b50505f90565b504281101561385a565b805f52600a60205260ff600160405f20015460a01c165f146139295750600490565b805f52600a60205260405f205460f81c61399557805f52600a60205264ffffffffff60405f205460a01c1642106139905761396381613825565b905f52600a6020526001600160801b0380600260405f200154169116105f1461398b57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613ac3575b80613aa6575b612895577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613a6f575b1680613a57575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613a13565b613a8e835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613a0c565b50805f52600a60205260ff600160405f20015460b01c16156139c0565b506001600160a01b03821615156139ba565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613b0757565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613b75575b508115613b5c575090565b90506001600160a01b03613b7033926133e0565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613b51565b805f52600a602052613bb8600260405f20016136ae565b90805f52600a60205260ff600160405f20015460a01c165f14613be65750602001516001600160801b031690565b90815f52600a60205260405f205460f81c613c085750613c0590613825565b90565b613c0591506001600160801b036040818351169201511690613402565b90613c466001600160801b03604084015116602060e085015101519061439c565b916001600160801b0383511660c082015190156142c85764ffffffffff815116156142a0576020810164ffffffffff81511680614214575b5050604064ffffffffff82511691019064ffffffffff82511690818110156141e657505064ffffffffff80421691511690818110156141b85750506007549280516001600160801b03169160405192613cd68461331a565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613d3c89613353565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600a60205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613fbc91906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff1680614198575b50600185016007556001600160a01b036020820151168015610d225761402a866001600160a01b039261399b565b1661416c576140556001600160a01b036060830151166001600160801b038451169030903390614479565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b038651168061413d575b506141346001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b614166906001600160a01b036060880151166001600160a01b0360e08901515116903390614479565b5f614090565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600b60205260405f209064ffffffffff198254161790555f613ffc565b7f879842de000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f9e7fd91f000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff8351168181101561427257505064ffffffffff90511664ffffffffff60408301511690818110613c7e577f87d966a0000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f84fe0623000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d1561431a573d90614301826133ae565b9161430f604051938461338c565b82523d5f602084013e565b606090565b613c059061432c81613ba1565b905f52600a602052600260405f20015460801c90613402565b61439a926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261439560648361338c565b61466d565b565b9190916040516143ab81613370565b5f81525f6020820152926001600160801b03821690811561445c5767016345785d8a00008111614425576143e76001600160801b0391836145bf565b1660208501918183521115614411576001600160801b03918261440c92511690613402565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161446d81613370565b5f81525f602082015290565b9091926001600160a01b0361439a9481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261439560848361338c565b5f19670de0b6b3a7640000820991670de0b6b3a764000082029182808510940393808503941461459e578184101561456457670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156145ab570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f198382098382029182808310920391808303921461465c57670de0b6b3a764000082101561462c577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b0361469693169360208151910182865af161468f6142f0565b90836146f2565b80519081151591826146d7575b50506146ac5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6146ea9250602080918301019101613654565b155f806146a3565b9061472f575080511561470757805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614775575b614740575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561473856fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = - hex"60c0604052346103e157614e1e6060813803918261001c816103e5565b9384928339810103126103e15780516001600160a01b038116908190036103e15760208201516001600160a01b03811692908390036103e1576040015161006360406103e5565b92601b84527f5361626c696572204c6f636b7570205472616e63686564204e46540000000000602085015261009860406103e5565b600e81526d5341422d4c4f434b55502d54524160901b602082015230608052845190946001600160401b0382116102e45760015490600182811c921680156103d7575b60208310146102c65781601f849311610369575b50602090601f8311600114610303575f926102f8575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e457600254600181811c911680156102da575b60208210146102c657601f8111610263575b50602094601f8211600114610200579481929394955f926101f5575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614a13908161040b823960805181613e37015260a051818181612fa60152613ef00152f35b015190505f80610169565b601f1982169560025f52805f20915f5b88811061024b57508360019596979810610233575b505050811b0160025561017e565b01515f1960f88460031b161c191690555f8080610225565b91926020600181928685015181550194019201610210565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bc575b601f0160051c01905b8181106102b1575061014d565b5f81556001016102a4565b909150819061029b565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013b565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610105565b60015f9081528281209350601f198516905b8181106103515750908460019594939210610339575b505050811b0160015561011a565b01515f1960f88460031b161c191690555f808061032b565b92936020600181928786015181550195019301610315565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103cd575b90601f859493920160051c01905b8181106103bf57506100ef565b5f81558493506001016103b2565b90915081906103a4565b91607f16916100db565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e45760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461331257508063027b6744146132f057806306fdde0314613235578063081812fc14613217578063095ea7b3146131125780631400ecec146130615780631c1cdd4c14612ffd5780631e99d56914612fe057806323b872dd14612fc95780632fe4304114612f8f578063303acc8514612f5257806332fbe22b14612df5578063406887cb14612c8657806340e58ee5146129af578063425d30dd1461295f57806342842e0e1461293657806342966c6814612772578063442675701461274c5780634857501f146126db5780634869e12d146126a15780634cc55e11146122fd57806357404b121461226f5780636352211e146122405780636d0cee751461224057806370a08231146121d657806375829def146121685780637cad6cd1146120775780637de6b1db14611f2a5780637f5799f914611ed15780638659c27014611b19578063894e9a0d146117da578063897f362b1461150f5780638f69b9931461148f5780639067b6771461144057806395d89b4114611338578063a22cb46514611284578063a80fc07114611233578063ad35efd4146111d4578063b256456914611184578063b88d4fde146110fa578063b8a3be66146110c5578063b971302a14611077578063bc2be1be14611028578063c156a11d14610c0b578063c87b56dd14610b00578063d4dbd20b14610aaf578063d511609f14610a64578063d975dfed14610a19578063e985e9c5146109c0578063ea5ead1914610692578063eac8f5b814610641578063f590c176146105e5578063f851a440146105c05763fdd46d601461026e575f80fd5b346105bc5760603660031901126105bc5760043561028a61343f565b90604435916001600160801b038316908184036105bc576102a9613e2d565b825f52600a60205260ff600160405f20015460a81c16156105a957825f52600a60205260ff600160405f20015460a01c16610596576001600160a01b03811690811561058357835f5260036020526001600160a01b0360405f205416948583141580610573575b610558578315610545576001600160801b0361032b86614673565b1680851161052b575061035090855f52600a602052600260405f20015460801c614699565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561038a906139d3565b6001600160801b036103ae8160208401511692826040818351169201511690613616565b1611156104f9575b835f52600a6020526103da836001600160a01b03600160405f2001541692836147f7565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104e3575b61044057005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916104a9575b50160361049757005b636ade251160e01b5f5260045260245ffd5b6104cb915060203d6020116104d1575b6104c381836135a2565b810190613b16565b5f61048e565b503d6104b9565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f20541661043a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103b6565b848663066920d760e01b5f5260045260245260445260645ffd5b8463b2ae763360e01b5f5260045260245ffd5b828563350b320360e11b5f526004523360245260445260645ffd5b5061057d8561454e565b15610310565b83632da33e5b60e01b5f5260045260245ffd5b826315efa0f360e11b5f5260045260245ffd5b8263699d2de960e01b5f5260045260245ffd5b5f80fd5b346105bc575f3660031901126105bc5760206001600160a01b035f5416604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105bc5760403660031901126105bc576004356106ae61343f565b906106b881614673565b906106c1613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c166109ae576001600160a01b038316801561099b57815f5260036020526001600160a01b0360405f20541693848214158061098b575b610970576001600160801b03841693841561095d576001600160801b0361074d85614673565b16808611610943575061077290845f52600a602052600260405f20015460801c614699565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b0319169190911781556107ac906139d3565b6001600160801b036107d08160208401511692826040818351169201511690613616565b161115610911575b825f52600a6020526107fc846001600160a01b03600160405f2001541692836147f7565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a183331415806108fb575b61086c575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104d8576392b9102b60e01b916001600160e01b0319915f916108dc575b5016036108c9578180610861565b50636ade251160e01b5f5260045260245ffd5b6108f5915060203d6020116104d1576104c381836135a2565b856108bb565b50835f52600960205260ff60405f20541661085c565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556107d8565b858563066920d760e01b5f5260045260245260445260645ffd5b8363b2ae763360e01b5f5260045260245ffd5b509063350b320360e11b5f526004523360245260445260645ffd5b506109958361454e565b15610727565b50632da33e5b60e01b5f5260045260245ffd5b6315efa0f360e11b5f5260045260245ffd5b346105bc5760403660031901126105bc576109d9613429565b6001600160a01b036109e961343f565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f57610a53602091614673565b6001600160801b0360405191168152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a6020526020600260405f20015460801c604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105bc5760203660031901126105bc57600435610b1d81613b36565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104d8575f90610b8e575b610b8a90604051918291602083526020830190613404565b0390f35b503d805f833e610b9e81836135a2565b8101906020818303126105bc5780519067ffffffffffffffff82116105bc57019080601f830112156105bc57815191610bd6836135c4565b91610be460405193846135a2565b838352602084830101116105bc57610b8a92610c0691602080850191016133e3565b610b72565b346105bc5760403660031901126105bc57600435610c2761343f565b610c2f613e2d565b815f52600a60205260ff600160405f20015460a81c161561101557815f5260036020526001600160a01b0360405f20541690813303610ffe57610c7183614673565b906001600160801b038216918215908115610d06575b50506001600160a01b03811615610cf357610caa846001600160a01b0392613cf3565b169182610cc45783637e27328960e01b5f5260045260245ffd5b8084918403610cd857602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d0e613e2d565b855f52600a60205260ff600160405f20015460a81c1615610feb57855f52600a60205260ff600160405f20015460a01c16610fd8578415610fc557855f5260036020526001600160a01b0360405f205416918286141580610fb5575b610f9a57610f87576001600160801b03610d8387614673565b16808511610f6d5750610da890865f52600a602052600260405f20015460801c614699565b5f868152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155610de2906139d3565b6001600160801b03610e068160208401511692826040818351169201511690613616565b161115610f3b575b845f52600a6020526001600160a01b03600160405f20015416610e328486836147f7565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f25575b610e9d575b80610c87565b6040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f91610f06575b501614610e9757636ade251160e01b5f5260045260245ffd5b610f1f915060203d6020116104d1576104c381836135a2565b88610eed565b50805f52600960205260ff60405f205416610e92565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e0e565b848763066920d760e01b5f5260045260245260445260645ffd5b8563b2ae763360e01b5f5260045260245ffd5b858763350b320360e11b5f526004523360245260445260645ffd5b50610fbf8761454e565b15610d6a565b85632da33e5b60e01b5f5260045260245ffd5b856315efa0f360e11b5f5260045260245ffd5b8563699d2de960e01b5f5260045260245ffd5b82632082501160e01b5f526004523360245260445ffd5b5063699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105bc5760203660031901126105bc576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105bc5760803660031901126105bc57611113613429565b61111b61343f565b6064359167ffffffffffffffff83116105bc57366023840112156105bc57826004013591611148836135c4565b9261115660405194856135a2565b80845236602482870101116105bc576020815f9260246111829801838801378501015260443591613a26565b005b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f5761120c90613c5f565b604051600582101561121f576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105bc5760403660031901126105bc5761129d613429565b602435908115158092036105bc576001600160a01b031690811561130c57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bc575f3660031901126105bc576040515f6002548060011c90600181168015611436575b602083108114611422578285529081156113fe57506001146113a0575b610b8a8361138c818503826135a2565b604051918291602083526020830190613404565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106113e45750909150810160200161138c61137c565b9192600181602092548385880101520191019092916113cc565b60ff191660208086019190915291151560051b8401909101915061138c905061137c565b634e487b7160e01b5f52602260045260245ffd5b91607f169161135f565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f576114c790613c5f565b60058110158061121f5760028214908115611503575b81156114f1575b6020826040519015158152f35b905061121f57600460209114826114e4565b5050600381145f6114dd565b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc578036036101206003198201126105bc5761154a613e2d565b60c482013590602219018112156105bc5781019060048201359167ffffffffffffffff83116105bc5760248101908360061b80360383136105bc5760046020916115938761387a565b966115a160405198896135a2565b875282870193010101913683116105bc57905b8282106117c0575050508151916115ca8361387a565b926115d860405194856135a2565b808452601f196115e78261387a565b015f5b81811061179d57505064ffffffffff4216916001600160801b0361160d82613b57565b51511664ffffffffff80602061162285613b57565b51015116850116604051916116368361354d565b8252602082015261164686613b57565b5261165085613b57565b5060015b8281106117285750505061166a82600401613a05565b9261167760248401613a05565b9261168460448201613933565b916064820135936001600160a01b0385168095036105bc57602096611720966116e0966001600160801b03611715976001600160a01b036116c760848a01613a19565b94816116d560a48c01613a19565b976040519d8e613530565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e43691016138c8565b610100820152613e87565b604051908152f35b806001600160801b0361173d60019385613b64565b51511664ffffffffff8060206117565f1986018c613b64565b510151168160206117678689613b64565b5101511601166040519161177a8361354d565b8252602082015261178b8289613b64565b526117968188613b64565b5001611654565b6020906040516117ac8161354d565b5f81525f83820152828289010152016115ea565b60206040916117cf3685613892565b8152019101906115b4565b346105bc5760203660031901126105bc5760043560606101606040516117ff81613569565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f61012082015260405161184581613586565b5f81525f60208201525f60408201526101408201520152805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260405f2060405191610140830183811067ffffffffffffffff821117611b05576040528154916001600160a01b0383168452602084019264ffffffffff8160a01c168452604085019064ffffffffff8160c81c16825285606081019260ff8360f01c1615158452608082019260f81c1515835260018501549260a08301956001600160a01b0385168752611942600260c086019260ff8860a01c161515845260ff61010060e0890198828b60a81c1615158a52019860b01c1615158852016139d3565b6101208b0190815261195389613c5f565b600581101561121f57600214611afd575b5196516001600160a01b0316925164ffffffffff169551151590511515935115159451151595885f52600360205260405f20546001600160a01b03169a516001600160a01b0316995164ffffffffff16985f52600b60205260405f2092511515926040519a6119d28c613569565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952611a269061395f565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e08201610b8a916134d4565b5f8752611964565b634e487b7160e01b5f52604160045260245ffd5b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc57611b4a9036906004016134a3565b90611b53613e2d565b5f915b808310611b5f57005b611b6a83828461390f565b3592611b74613e2d565b835f52600a60205260ff600160405f20015460a81c1615611ebe57835f52600a60205260ff600160405f20015460a01c165f14611bbe57836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611eac57611bf3815f52600a6020526001600160a01b0360405f205416331490565b15611e9657611c0181613b78565b90805f52600a602052611c19600260405f20016139d3565b916001600160801b038351166001600160801b0382161015611e8357815f52600a60205260ff60405f205460f01c1615611e7057806001600160801b03602081611c6d948188511603169501511690613616565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611e4b575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611d7f6001600160a01b03600160405f2001541694611d578885886147f7565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611dd0575b50505050506001019190611b56565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91611e2d575b5016036104975780808080611dc1565b611e45915060203d81116104d1576104c381836135a2565b87611e1d565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611cb7565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600b602052610b8a611f1660405f2061395f565b6040519182916020835260208301906134d4565b346105bc5760203660031901126105bc57600435611f46613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57611f6a81613c5f565b600581101561121f5760048103611f8e57506315efa0f360e11b5f5260045260245ffd5b60038103611fa9575063d0a172b360e01b5f5260045260245ffd5b60021461206557611fce815f52600a6020526001600160a01b0360405f205416331490565b15611e9657805f52600a60205260ff60405f205460f01c1615612053576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b6308aca53f60e21b5f5260045260245ffd5b346105bc5760203660031901126105bc576004356001600160a01b0381168091036105bc576001600160a01b035f5416338103612152575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161213e5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346105bc5760203660031901126105bc57612181613429565b5f546001600160a01b03811633810361215257506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105bc5760203660031901126105bc576001600160a01b036121f7613429565b168015612214575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105bc5760203660031901126105bc57602061225e600435613b36565b6001600160a01b0360405191168152f35b346105bc5760203660031901126105bc5760043561228b613947565b50805f52600a60205260ff600160405f20015460a81c161561062f575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166122d58361354d565b825260208201526122fb8251809264ffffffffff60208092828151168552015116910152565bf35b346105bc5760403660031901126105bc5760043567ffffffffffffffff81116105bc5761232e9036906004016134a3565b9060243567ffffffffffffffff81116105bc5761234f9036906004016134a3565b91909261235a613e2d565b828103612671575f5b81811061236c57005b61237781838561390f565b3561238382848661390f565b355f5260036020526001600160a01b0360405f205416906123ad6123a884888a61390f565b613933565b6123b5613e2d565b815f52600a60205260ff600160405f20015460a81c161561101557815f52600a60205260ff600160405f20015460a01c1661265e57821561099b57815f5260036020526001600160a01b0360405f20541692838114158061264e575b612634576001600160801b03821691821561095d576001600160801b0361243785614673565b1680841161261a575061245c90845f52600a602052600260405f20015460801c614699565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155612496906139d3565b6001600160801b036124ba8160208401511692826040818351169201511690613616565b1611156125e8575b825f52600a6020526001600160a01b03600160405f200154166124e68383836147f7565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125d2575b612557575b50505050600101612363565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916125b4575b5016036104975780808061254b565b6125cc915060203d81116104d1576104c381836135a2565b896125a5565b50835f52600960205260ff60405f205416612546565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556124c2565b838563066920d760e01b5f5260045260245260445260645ffd5b8263350b320360e11b5f526004523360245260445260645ffd5b506126588361454e565b15612411565b506315efa0f360e11b5f5260045260245ffd5b90507fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f57610a536020916145c0565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f61271482613c5f565b600581101561121f57600203612732575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16612725565b346105bc575f3660031901126105bc5760206001600160a01b0360085416604051908152f35b346105bc5760203660031901126105bc5760043561278e613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c161561290b576127cd8161454e565b15611e9657805f5260036020526001600160a01b0360405f205416151580612904575b806128e7575b6128d5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f205416801590811561289e575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061288c57005b637e27328960e01b5f5260045260245ffd5b6128bd835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612844565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127f6565b505f6127f0565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bc5761118261294736613469565b90604051926129576020856135a2565b5f8452613a26565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105bc5760203660031901126105bc576004356129cb613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c165f14612a14576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c611eac57612a46815f52600a6020526001600160a01b0360405f205416331490565b15611e9657612a5481613b78565b90805f52600a602052612a6c600260405f20016139d3565b916001600160801b038351166001600160801b0382161015611e8357815f52600a60205260ff60405f205460f01c1615611e7057806001600160801b03602081612ac0948188511603169501511690613616565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c61575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612baa6001600160a01b03600160405f2001541694611d578885886147f7565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612bed57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91612c425750160361049757005b612c5b915060203d6020116104d1576104c381836135a2565b8461048e565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612b0a565b346105bc5760203660031901126105bc57612c9f613429565b6001600160a01b035f541690338203612dde57806001600160a01b03913b15612db257166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104d8575f91612d83575b5015612d5857805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612da5915060203d602011612dab575b612d9d81836135a2565b8101906138f7565b82612d0d565b503d612d93565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc5761014060031982360301126105bc57612e2f613e2d565b604051612e3b81613530565b612e4782600401613455565b8152612e5560248301613455565b6020820152612e66604483016135e0565b604082015260648201356001600160a01b03811681036105bc576060820152612e9160848301613523565b6080820152612ea260a48301613523565b60a0820152612eb360c48301613868565b60c082015260e482013567ffffffffffffffff81116105bc57820191366023840112156105bc57600483013592612ee98461387a565b90612ef760405192836135a2565b848252602060048184019660061b83010101903682116105bc57602401945b818610612f3857602061172086611715878760e08401526101043691016138c8565b6020604091612f473689613892565b815201950194612f16565b346105bc5760203660031901126105bc576001600160a01b03612f73613429565b165f526009602052602060ff60405f2054166040519015158152f35b346105bc575f3660031901126105bc5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346105bc57611182612fda36613469565b91613636565b346105bc575f3660031901126105bc576020600754604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f5761303590613c5f565b600581101561121f578060209115908115613056575b506040519015158152f35b60019150148261304b565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f576020905f90805f52600a835260ff60405f205460f01c16806130f6575b6130c4575b506001600160801b0360405191168152f35b6130f09150805f52600a83526130ea6001600160801b03600260405f2001541691613b78565b90613616565b826130b2565b50805f52600a835260ff600160405f20015460a01c16156130ad565b346105bc5760403660031901126105bc5761312b613429565b60243561313781613b36565b33151580613204575b806131d1575b6131a55781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615613146565b50336001600160a01b0382161415613140565b346105bc5760203660031901126105bc57602061225e6004356135f4565b346105bc575f3660031901126105bc576040515f6001548060011c906001811680156132e6575b602083108114611422578285529081156113fe575060011461328857610b8a8361138c818503826135a2565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106132cc5750909150810160200161138c61137c565b9192600181602092548385880101520191019092916132b4565b91607f169161325c565b346105bc575f3660031901126105bc57602060405167016345785d8a00008152f35b346105bc5760203660031901126105bc57600435906001600160e01b031982168092036105bc57817f49064906000000000000000000000000000000000000000000000000000000006020931490811561336e575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156133b9575b81156133a8575b5083613367565b6301ffc9a760e01b915014836133a1565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061339a565b5f5b8381106133f45750505f910152565b81810151838201526020016133e5565b9060209161341d815180928185528580860191016133e3565b601f01601f1916010190565b600435906001600160a01b03821682036105bc57565b602435906001600160a01b03821682036105bc57565b35906001600160a01b03821682036105bc57565b60609060031901126105bc576004356001600160a01b03811681036105bc57906024356001600160a01b03811681036105bc579060443590565b9181601f840112156105bc5782359167ffffffffffffffff83116105bc576020808501948460051b0101116105bc57565b90602080835192838152019201905f5b8181106134f15750505090565b825180516001600160801b0316855260209081015164ffffffffff1681860152604090940193909201916001016134e4565b359081151582036105bc57565b610120810190811067ffffffffffffffff821117611b0557604052565b6040810190811067ffffffffffffffff821117611b0557604052565b610180810190811067ffffffffffffffff821117611b0557604052565b6060810190811067ffffffffffffffff821117611b0557604052565b90601f8019910116810190811067ffffffffffffffff821117611b0557604052565b67ffffffffffffffff8111611b0557601f01601f191660200190565b35906001600160801b03821682036105bc57565b6135fd81613b36565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161213e57565b91906001600160a01b03168015610cf357815f5260036020526001600160a01b0360405f205416151580613860575b80613843575b613830577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f2054169282331515928361377b575b6001600160a01b03935085613744575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361372c57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b613763825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556136cb565b91929050806137d9575b15613792578282916136bb565b82846137aa57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613807575b806137855750825f526005602052336001600160a01b0360405f20541614613785565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166137e4565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c161561366b565b506001613665565b359064ffffffffff821682036105bc57565b67ffffffffffffffff8111611b055760051b60200190565b91908260409103126105bc576040516138aa8161354d565b60206138c38183956138bb816135e0565b855201613868565b910152565b91908260409103126105bc576040516138e08161354d565b60208082946138ee81613455565b84520135910152565b908160209103126105bc575180151581036105bc5790565b919081101561391f5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036105bc5790565b604051906139548261354d565b5f6020838281520152565b90815461396b8161387a565b9261397960405194856135a2565b81845260208401905f5260205f205f915b8383106139975750505050565b6001602081926040516139a98161354d565b64ffffffffff86546001600160801b038116835260801c168382015281520192019201919061398a565b906040516139e081613586565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b03811681036105bc5790565b3580151581036105bc5790565b90613a32838284613636565b803b613a3f575b50505050565b602091613a856001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613404565b03815f865af15f9181613af5575b50613ac15750613aa1614644565b80519081613abc5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b911603613ae357505f808080613a39565b633250574960e11b5f5260045260245ffd5b613b0f91925060203d6020116104d1576104c381836135a2565b905f613a93565b908160209103126105bc57516001600160e01b0319811681036105bc5790565b805f5260036020526001600160a01b0360405f20541690811561288c575090565b80511561391f5760200190565b805182101561391f5760209160051b010190565b9064ffffffffff421691805f52600b602052613b9660405f2061395f565b908364ffffffffff6020613ba985613b57565b5101511611613c5857805f52600a6020528364ffffffffff60405f205460c81c161115613c3957506001600160801b03613be282613b57565b515116916001925b8251841015613c32578464ffffffffff6020613c068787613b64565b5101511611613c32576001600160801b0360019181613c258787613b64565b5151160116930192613bea565b9350915050565b919250505f52600a6020526001600160801b03600260405f2001541690565b505f925050565b805f52600a60205260ff600160405f20015460a01c165f14613c815750600490565b805f52600a60205260405f205460f81c613ced57805f52600a60205264ffffffffff60405f205460a01c164210613ce857613cbb81613b78565b905f52600a6020526001600160801b0380600260405f200154169116105f14613ce357600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613e1b575b80613dfe575b6128d5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613dc7575b1680613daf575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613d6b565b613de6835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613d64565b50805f52600a60205260ff600160405f20015460b01c1615613d18565b506001600160a01b0382161515613d12565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e5f57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613ea96001600160801b0360408401511660206101008501510151906146b9565b916001600160a01b03815116906001600160801b0384511660e082015160c083019364ffffffffff85511690156145265782156144fe5780156144d657815180156144ae577f00000000000000000000000000000000000000000000000000000000000000008111614483575064ffffffffff6020613f2784613b57565b5101511681101561443f57505f809180515f915b8183106143bc575050506001600160801b039150169081810361438e57505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140f28751975f19890190613b64565b51015160c81b169360a01b169116171785555f5b8181106142dc575050600187016007556001600160a01b036020830151168015610cf35761413c886001600160a01b0392613cf3565b166142b057868261418a6001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b038551169030903390614796565b6001600160801b0360208401511680614280575b506001600160a01b03815116946142756142576001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996141fc8b61354d565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c08701526101408601906134d4565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b6142aa906001600160a01b036060840151166001600160a01b036101008501515116903390614796565b5f61419e565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f20906142f78160e0870151613b64565b5182549268010000000000000000841015611b05576001840180825584101561391f576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b16911617905501614106565b7fa4cdf853000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9091926143de906001600160801b036143d58685613b64565b51511690614699565b9364ffffffffff8060206143f28786613b64565b5101511691168082111561440d575093926001019190613f3b565b847fbfc5f2fa000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff602061445084613b57565b51015116907fab900963000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f76d9c284000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f814426ed000000000000000000000000000000000000000000000000000000005f5260045ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6d004a9e000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215614594575b50811561457b575090565b90506001600160a01b0361458f33926135f4565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614570565b805f52600a6020526145d7600260405f20016139d3565b90805f52600a60205260ff600160405f20015460a01c165f146146055750602001516001600160801b031690565b90815f52600a60205260405f205460f81c614627575061462490613b78565b90565b61462491506001600160801b036040818351169201511690613616565b3d1561466e573d90614655826135c4565b9161466360405193846135a2565b82523d5f602084013e565b606090565b61462490614680816145c0565b905f52600a602052600260405f20015460801c90613616565b906001600160801b03809116911601906001600160801b03821161213e57565b9190916040516146c88161354d565b5f81525f6020820152926001600160801b0382169081156147795767016345785d8a00008111614742576147046001600160801b0391836148cc565b166020850191818352111561472e576001600160801b03918261472992511690613616565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161478a8161354d565b5f81525f602082015290565b9091926001600160a01b036147f59481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526147f06084836135a2565b614847565b565b6147f5926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526147f06064836135a2565b5f806001600160a01b0361487093169360208151910182865af1614869614644565b908361497a565b80519081151591826148b1575b50506148865750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6148c492506020809183010191016138f7565b155f8061487d565b9091905f198382098382029182808310920391808303921461496957670de0b6b3a7640000821015614939577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906149b7575080511561498f57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806149fd575b6149c8575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156149c056fea164736f6c634300081a000a"; + hex"60c0604052346103e157614e306060813803918261001c816103e5565b9384928339810103126103e15780516001600160a01b038116908190036103e15760208201516001600160a01b03811692908390036103e1576040015161006360406103e5565b92601b84527f5361626c696572204c6f636b7570205472616e63686564204e46540000000000602085015261009860406103e5565b600e81526d5341422d4c4f434b55502d54524160901b602082015230608052845190946001600160401b0382116102e45760015490600182811c921680156103d7575b60208310146102c65781601f849311610369575b50602090601f8311600114610303575f926102f8575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e457600254600181811c911680156102da575b60208210146102c657601f8111610263575b50602094601f8211600114610200579481929394955f926101f5575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614a25908161040b823960805181613e37015260a051818181612fa60152613ee00152f35b015190505f80610169565b601f1982169560025f52805f20915f5b88811061024b57508360019596979810610233575b505050811b0160025561017e565b01515f1960f88460031b161c191690555f8080610225565b91926020600181928685015181550194019201610210565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bc575b601f0160051c01905b8181106102b1575061014d565b5f81556001016102a4565b909150819061029b565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013b565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610105565b60015f9081528281209350601f198516905b8181106103515750908460019594939210610339575b505050811b0160015561011a565b01515f1960f88460031b161c191690555f808061032b565b92936020600181928786015181550195019301610315565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103cd575b90601f859493920160051c01905b8181106103bf57506100ef565b5f81558493506001016103b2565b90915081906103a4565b91607f16916100db565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e45760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461331257508063027b6744146132f057806306fdde0314613235578063081812fc14613217578063095ea7b3146131125780631400ecec146130615780631c1cdd4c14612ffd5780631e99d56914612fe057806323b872dd14612fc95780632fe4304114612f8f578063303acc8514612f5257806332fbe22b14612df5578063406887cb14612c8657806340e58ee5146129af578063425d30dd1461295f57806342842e0e1461293657806342966c6814612772578063442675701461274c5780634857501f146126db5780634869e12d146126a15780634cc55e11146122fb57806357404b121461226d5780636352211e1461223e5780636d0cee751461223e57806370a08231146121d457806375829def146121665780637cad6cd1146120755780637de6b1db14611f285780637f5799f914611ecf5780638659c27014611b17578063894e9a0d146117d8578063897f362b1461150d5780638f69b9931461148d5780639067b6771461143e57806395d89b4114611336578063a22cb46514611282578063a80fc07114611231578063ad35efd4146111d2578063b256456914611182578063b88d4fde146110f8578063b8a3be66146110c3578063b971302a14611075578063bc2be1be14611026578063c156a11d14610c0a578063c87b56dd14610aff578063d4dbd20b14610aae578063d511609f14610a63578063d975dfed14610a18578063e985e9c5146109bf578063ea5ead1914610692578063eac8f5b814610641578063f590c176146105e5578063f851a440146105c05763fdd46d601461026e575f80fd5b346105bc5760603660031901126105bc5760043561028a61343f565b90604435916001600160801b038316908184036105bc576102a9613e2d565b825f52600a60205260ff600160405f20015460a81c16156105a957825f52600a60205260ff600160405f20015460a01c16610596576001600160a01b03811690811561058357821561057057835f5260036020526001600160a01b0360405f205416948583141580610560575b610545576001600160801b0361032b86614685565b1680851161052b575061035090855f52600a602052600260405f20015460801c6146ab565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561038a906139d3565b6001600160801b036103ae8160208401511692826040818351169201511690613616565b1611156104f9575b835f52600a6020526103da836001600160a01b03600160405f200154169283614809565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104e3575b61044057005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916104a9575b50160361049757005b636ade251160e01b5f5260045260245ffd5b6104cb915060203d6020116104d1575b6104c381836135a2565b810190613b16565b5f61048e565b503d6104b9565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f20541661043a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103b6565b848663066920d760e01b5f5260045260245260445260645ffd5b828563350b320360e11b5f526004523360245260445260645ffd5b5061056a85614560565b15610316565b8363b2ae763360e01b5f5260045260245ffd5b83632da33e5b60e01b5f5260045260245ffd5b826315efa0f360e11b5f5260045260245ffd5b8263699d2de960e01b5f5260045260245ffd5b5f80fd5b346105bc575f3660031901126105bc5760206001600160a01b035f5416604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105bc5760403660031901126105bc576004356106ae61343f565b6106b782614685565b916106c0613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c166109ad576001600160a01b038216801561099a576001600160801b03841692831561098757825f5260036020526001600160a01b0360405f205416948583141580610977575b61095c576001600160801b0361074c85614685565b16808611610942575061077190845f52600a602052600260405f20015460801c6146ab565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b0319169190911781556107ab906139d3565b6001600160801b036107cf8160208401511692826040818351169201511690613616565b161115610910575b825f52600a6020526107fb846001600160a01b03600160405f200154169283614809565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a183331415806108fa575b61086b575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104d8576392b9102b60e01b916001600160e01b0319915f916108db575b5016036108c8578180610860565b50636ade251160e01b5f5260045260245ffd5b6108f4915060203d6020116104d1576104c381836135a2565b856108ba565b50835f52600960205260ff60405f20541661085b565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556107d7565b858563066920d760e01b5f5260045260245260445260645ffd5b828463350b320360e11b5f526004523360245260445260645ffd5b5061098184614560565b15610737565b8263b2ae763360e01b5f5260045260245ffd5b50632da33e5b60e01b5f5260045260245ffd5b6315efa0f360e11b5f5260045260245ffd5b346105bc5760403660031901126105bc576109d8613429565b6001600160a01b036109e861343f565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f57610a52602091614685565b6001600160801b0360405191168152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a6020526020600260405f20015460801c604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105bc5760203660031901126105bc57600435610b1c81613b36565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104d8575f90610b8d575b610b8990604051918291602083526020830190613404565b0390f35b503d805f833e610b9d81836135a2565b8101906020818303126105bc5780519067ffffffffffffffff82116105bc57019080601f830112156105bc57815191610bd5836135c4565b91610be360405193846135a2565b838352602084830101116105bc57610b8992610c0591602080850191016133e3565b610b71565b346105bc5760403660031901126105bc57600435610c2661343f565b610c2e613e2d565b815f52600a60205260ff600160405f20015460a81c161561101357815f5260036020526001600160a01b0360405f20541690813303610ffc57610c7083614685565b906001600160801b0382169182158015610d04575b50506001600160a01b03811615610cf157610ca8846001600160a01b0392613cf3565b169182610cc25783637e27328960e01b5f5260045260245ffd5b8084918403610cd657602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d0c613e2d565b855f52600a60205260ff600160405f20015460a81c1615610fe957855f52600a60205260ff600160405f20015460a01c16610fd6578415610fc357610fb057845f5260036020526001600160a01b0360405f205416908185141580610fa0575b610f85576001600160801b03610d8187614685565b16808511610f6b5750610da690865f52600a602052600260405f20015460801c6146ab565b5f868152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155610de0906139d3565b6001600160801b03610e048160208401511692826040818351169201511690613616565b161115610f39575b845f52600a6020526001600160a01b03600160405f20015416610e30848683614809565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f23575b610e9b575b80610c85565b6040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f91610f04575b501614610e9557636ade251160e01b5f5260045260245ffd5b610f1d915060203d6020116104d1576104c381836135a2565b88610eeb565b50805f52600960205260ff60405f205416610e90565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e0c565b848763066920d760e01b5f5260045260245260445260645ffd5b848663350b320360e11b5f526004523360245260445260645ffd5b50610faa86614560565b15610d6c565b8463b2ae763360e01b5f5260045260245ffd5b85632da33e5b60e01b5f5260045260245ffd5b856315efa0f360e11b5f5260045260245ffd5b8563699d2de960e01b5f5260045260245ffd5b82632082501160e01b5f526004523360245260445ffd5b5063699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105bc5760203660031901126105bc576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105bc5760803660031901126105bc57611111613429565b61111961343f565b6064359167ffffffffffffffff83116105bc57366023840112156105bc57826004013591611146836135c4565b9261115460405194856135a2565b80845236602482870101116105bc576020815f9260246111809801838801378501015260443591613a26565b005b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f5761120a90613c5f565b604051600582101561121d576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105bc5760403660031901126105bc5761129b613429565b602435908115158092036105bc576001600160a01b031690811561130a57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bc575f3660031901126105bc576040515f6002548060011c90600181168015611434575b602083108114611420578285529081156113fc575060011461139e575b610b898361138a818503826135a2565b604051918291602083526020830190613404565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106113e25750909150810160200161138a61137a565b9192600181602092548385880101520191019092916113ca565b60ff191660208086019190915291151560051b8401909101915061138a905061137a565b634e487b7160e01b5f52602260045260245ffd5b91607f169161135d565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f576114c590613c5f565b60058110158061121d5760028214908115611501575b81156114ef575b6020826040519015158152f35b905061121d57600460209114826114e2565b5050600381145f6114db565b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc578036036101206003198201126105bc57611548613e2d565b60c482013590602219018112156105bc5781019060048201359167ffffffffffffffff83116105bc5760248101908360061b80360383136105bc5760046020916115918761387a565b9661159f60405198896135a2565b875282870193010101913683116105bc57905b8282106117be575050508151916115c88361387a565b926115d660405194856135a2565b808452601f196115e58261387a565b015f5b81811061179b57505064ffffffffff4216916001600160801b0361160b82613b57565b51511664ffffffffff80602061162085613b57565b51015116850116604051916116348361354d565b8252602082015261164486613b57565b5261164e85613b57565b5060015b8281106117265750505061166882600401613a05565b9261167560248401613a05565b9261168260448201613933565b916064820135936001600160a01b0385168095036105bc5760209661171e966116de966001600160801b03611713976001600160a01b036116c560848a01613a19565b94816116d360a48c01613a19565b976040519d8e613530565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e43691016138c8565b610100820152613e87565b604051908152f35b806001600160801b0361173b60019385613b64565b51511664ffffffffff8060206117545f1986018c613b64565b510151168160206117658689613b64565b510151160116604051916117788361354d565b825260208201526117898289613b64565b526117948188613b64565b5001611652565b6020906040516117aa8161354d565b5f81525f83820152828289010152016115e8565b60206040916117cd3685613892565b8152019101906115b2565b346105bc5760203660031901126105bc5760043560606101606040516117fd81613569565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f61012082015260405161184381613586565b5f81525f60208201525f60408201526101408201520152805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260405f2060405191610140830183811067ffffffffffffffff821117611b03576040528154916001600160a01b0383168452602084019264ffffffffff8160a01c168452604085019064ffffffffff8160c81c16825285606081019260ff8360f01c1615158452608082019260f81c1515835260018501549260a08301956001600160a01b0385168752611940600260c086019260ff8860a01c161515845260ff61010060e0890198828b60a81c1615158a52019860b01c1615158852016139d3565b6101208b0190815261195189613c5f565b600581101561121d57600214611afb575b5196516001600160a01b0316925164ffffffffff169551151590511515935115159451151595885f52600360205260405f20546001600160a01b03169a516001600160a01b0316995164ffffffffff16985f52600b60205260405f2092511515926040519a6119d08c613569565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952611a249061395f565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e08201610b89916134d4565b5f8752611962565b634e487b7160e01b5f52604160045260245ffd5b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc57611b489036906004016134a3565b90611b51613e2d565b5f915b808310611b5d57005b611b6883828461390f565b3592611b72613e2d565b835f52600a60205260ff600160405f20015460a81c1615611ebc57835f52600a60205260ff600160405f20015460a01c165f14611bbc57836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611eaa57611bf1815f52600a6020526001600160a01b0360405f205416331490565b15611e9457611bff81613b78565b90805f52600a602052611c17600260405f20016139d3565b916001600160801b038351166001600160801b0382161015611e8157815f52600a60205260ff60405f205460f01c1615611e6e57806001600160801b03602081611c6b948188511603169501511690613616565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611e49575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611d7d6001600160a01b03600160405f2001541694611d55888588614809565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611dce575b50505050506001019190611b54565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91611e2b575b5016036104975780808080611dbf565b611e43915060203d81116104d1576104c381836135a2565b87611e1b565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611cb5565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600b602052610b89611f1460405f2061395f565b6040519182916020835260208301906134d4565b346105bc5760203660031901126105bc57600435611f44613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57611f6881613c5f565b600581101561121d5760048103611f8c57506315efa0f360e11b5f5260045260245ffd5b60038103611fa7575063d0a172b360e01b5f5260045260245ffd5b60021461206357611fcc815f52600a6020526001600160a01b0360405f205416331490565b15611e9457805f52600a60205260ff60405f205460f01c1615612051576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b6308aca53f60e21b5f5260045260245ffd5b346105bc5760203660031901126105bc576004356001600160a01b0381168091036105bc576001600160a01b035f5416338103612150575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161213c5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346105bc5760203660031901126105bc5761217f613429565b5f546001600160a01b03811633810361215057506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105bc5760203660031901126105bc576001600160a01b036121f5613429565b168015612212575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105bc5760203660031901126105bc57602061225c600435613b36565b6001600160a01b0360405191168152f35b346105bc5760203660031901126105bc57600435612289613947565b50805f52600a60205260ff600160405f20015460a81c161561062f575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166122d38361354d565b825260208201526122f98251809264ffffffffff60208092828151168552015116910152565bf35b346105bc5760403660031901126105bc5760043567ffffffffffffffff81116105bc5761232c9036906004016134a3565b9060243567ffffffffffffffff81116105bc5761234d9036906004016134a3565b919092612358613e2d565b828103612671575f5b81811061236a57005b61237581838561390f565b3561238182848661390f565b355f5260036020526001600160a01b0360405f205416906123ab6123a684888a61390f565b613933565b916123b4613e2d565b815f52600a60205260ff600160405f20015460a81c161561101357815f52600a60205260ff600160405f20015460a01c1661265e57801561099a576001600160801b03831690811561098757825f5260036020526001600160a01b0360405f20541693848214158061264e575b612633576001600160801b0361243685614685565b16808411612619575061245b90845f52600a602052600260405f20015460801c6146ab565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155612495906139d3565b6001600160801b036124b98160208401511692826040818351169201511690613616565b1611156125e7575b825f52600a6020526001600160a01b03600160405f200154166124e5838383614809565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125d1575b612556575b50505050600101612361565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916125b3575b5016036104975780808061254a565b6125cb915060203d81116104d1576104c381836135a2565b896125a4565b50835f52600960205260ff60405f205416612545565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556124c1565b838563066920d760e01b5f5260045260245260445260645ffd5b508263350b320360e11b5f526004523360245260445260645ffd5b5061265884614560565b15612421565b506315efa0f360e11b5f5260045260245ffd5b90507fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f57610a526020916145d2565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f61271482613c5f565b600581101561121d57600203612732575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16612725565b346105bc575f3660031901126105bc5760206001600160a01b0360085416604051908152f35b346105bc5760203660031901126105bc5760043561278e613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c161561290b576127cd81614560565b15611e9457805f5260036020526001600160a01b0360405f205416151580612904575b806128e7575b6128d5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f205416801590811561289e575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061288c57005b637e27328960e01b5f5260045260245ffd5b6128bd835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612844565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127f6565b505f6127f0565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bc5761118061294736613469565b90604051926129576020856135a2565b5f8452613a26565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105bc5760203660031901126105bc576004356129cb613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c165f14612a14576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c611eaa57612a46815f52600a6020526001600160a01b0360405f205416331490565b15611e9457612a5481613b78565b90805f52600a602052612a6c600260405f20016139d3565b916001600160801b038351166001600160801b0382161015611e8157815f52600a60205260ff60405f205460f01c1615611e6e57806001600160801b03602081612ac0948188511603169501511690613616565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c61575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612baa6001600160a01b03600160405f2001541694611d55888588614809565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612bed57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91612c425750160361049757005b612c5b915060203d6020116104d1576104c381836135a2565b8461048e565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612b0a565b346105bc5760203660031901126105bc57612c9f613429565b6001600160a01b035f541690338203612dde57806001600160a01b03913b15612db257166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104d8575f91612d83575b5015612d5857805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612da5915060203d602011612dab575b612d9d81836135a2565b8101906138f7565b82612d0d565b503d612d93565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc5761014060031982360301126105bc57612e2f613e2d565b604051612e3b81613530565b612e4782600401613455565b8152612e5560248301613455565b6020820152612e66604483016135e0565b604082015260648201356001600160a01b03811681036105bc576060820152612e9160848301613523565b6080820152612ea260a48301613523565b60a0820152612eb360c48301613868565b60c082015260e482013567ffffffffffffffff81116105bc57820191366023840112156105bc57600483013592612ee98461387a565b90612ef760405192836135a2565b848252602060048184019660061b83010101903682116105bc57602401945b818610612f3857602061171e86611713878760e08401526101043691016138c8565b6020604091612f473689613892565b815201950194612f16565b346105bc5760203660031901126105bc576001600160a01b03612f73613429565b165f526009602052602060ff60405f2054166040519015158152f35b346105bc575f3660031901126105bc5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346105bc57611180612fda36613469565b91613636565b346105bc575f3660031901126105bc576020600754604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f5761303590613c5f565b600581101561121d578060209115908115613056575b506040519015158152f35b60019150148261304b565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f576020905f90805f52600a835260ff60405f205460f01c16806130f6575b6130c4575b506001600160801b0360405191168152f35b6130f09150805f52600a83526130ea6001600160801b03600260405f2001541691613b78565b90613616565b826130b2565b50805f52600a835260ff600160405f20015460a01c16156130ad565b346105bc5760403660031901126105bc5761312b613429565b60243561313781613b36565b33151580613204575b806131d1575b6131a55781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615613146565b50336001600160a01b0382161415613140565b346105bc5760203660031901126105bc57602061225c6004356135f4565b346105bc575f3660031901126105bc576040515f6001548060011c906001811680156132e6575b602083108114611420578285529081156113fc575060011461328857610b898361138a818503826135a2565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106132cc5750909150810160200161138a61137a565b9192600181602092548385880101520191019092916132b4565b91607f169161325c565b346105bc575f3660031901126105bc57602060405167016345785d8a00008152f35b346105bc5760203660031901126105bc57600435906001600160e01b031982168092036105bc57817f49064906000000000000000000000000000000000000000000000000000000006020931490811561336e575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156133b9575b81156133a8575b5083613367565b6301ffc9a760e01b915014836133a1565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061339a565b5f5b8381106133f45750505f910152565b81810151838201526020016133e5565b9060209161341d815180928185528580860191016133e3565b601f01601f1916010190565b600435906001600160a01b03821682036105bc57565b602435906001600160a01b03821682036105bc57565b35906001600160a01b03821682036105bc57565b60609060031901126105bc576004356001600160a01b03811681036105bc57906024356001600160a01b03811681036105bc579060443590565b9181601f840112156105bc5782359167ffffffffffffffff83116105bc576020808501948460051b0101116105bc57565b90602080835192838152019201905f5b8181106134f15750505090565b825180516001600160801b0316855260209081015164ffffffffff1681860152604090940193909201916001016134e4565b359081151582036105bc57565b610120810190811067ffffffffffffffff821117611b0357604052565b6040810190811067ffffffffffffffff821117611b0357604052565b610180810190811067ffffffffffffffff821117611b0357604052565b6060810190811067ffffffffffffffff821117611b0357604052565b90601f8019910116810190811067ffffffffffffffff821117611b0357604052565b67ffffffffffffffff8111611b0357601f01601f191660200190565b35906001600160801b03821682036105bc57565b6135fd81613b36565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161213c57565b91906001600160a01b03168015610cf157815f5260036020526001600160a01b0360405f205416151580613860575b80613843575b613830577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f2054169282331515928361377b575b6001600160a01b03935085613744575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361372c57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b613763825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556136cb565b91929050806137d9575b15613792578282916136bb565b82846137aa57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613807575b806137855750825f526005602052336001600160a01b0360405f20541614613785565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166137e4565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c161561366b565b506001613665565b359064ffffffffff821682036105bc57565b67ffffffffffffffff8111611b035760051b60200190565b91908260409103126105bc576040516138aa8161354d565b60206138c38183956138bb816135e0565b855201613868565b910152565b91908260409103126105bc576040516138e08161354d565b60208082946138ee81613455565b84520135910152565b908160209103126105bc575180151581036105bc5790565b919081101561391f5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036105bc5790565b604051906139548261354d565b5f6020838281520152565b90815461396b8161387a565b9261397960405194856135a2565b81845260208401905f5260205f205f915b8383106139975750505050565b6001602081926040516139a98161354d565b64ffffffffff86546001600160801b038116835260801c168382015281520192019201919061398a565b906040516139e081613586565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b03811681036105bc5790565b3580151581036105bc5790565b90613a32838284613636565b803b613a3f575b50505050565b602091613a856001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613404565b03815f865af15f9181613af5575b50613ac15750613aa1614656565b80519081613abc5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b911603613ae357505f808080613a39565b633250574960e11b5f5260045260245ffd5b613b0f91925060203d6020116104d1576104c381836135a2565b905f613a93565b908160209103126105bc57516001600160e01b0319811681036105bc5790565b805f5260036020526001600160a01b0360405f20541690811561288c575090565b80511561391f5760200190565b805182101561391f5760209160051b010190565b9064ffffffffff421691805f52600b602052613b9660405f2061395f565b908364ffffffffff6020613ba985613b57565b5101511611613c5857805f52600a6020528364ffffffffff60405f205460c81c161115613c3957506001600160801b03613be282613b57565b515116916001925b8251841015613c32578464ffffffffff6020613c068787613b64565b5101511611613c32576001600160801b0360019181613c258787613b64565b5151160116930192613bea565b9350915050565b919250505f52600a6020526001600160801b03600260405f2001541690565b505f925050565b805f52600a60205260ff600160405f20015460a01c165f14613c815750600490565b805f52600a60205260405f205460f81c613ced57805f52600a60205264ffffffffff60405f205460a01c164210613ce857613cbb81613b78565b905f52600a6020526001600160801b0380600260405f200154169116105f14613ce357600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613e1b575b80613dfe575b6128d5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613dc7575b1680613daf575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613d6b565b613de6835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613d64565b50805f52600a60205260ff600160405f20015460b01c1615613d18565b506001600160a01b0382161515613d12565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e5f57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613ea96001600160801b0360408401511660206101008501510151906146cb565b916001600160801b038351169060e08101519160c082019264ffffffffff845116821561453857801561451057815180156144e8577f000000000000000000000000000000000000000000000000000000000000000081116144bd575064ffffffffff6020613f1784613b57565b5101511681101561447957505f905f905f81515f905b8082106143f1575050505064ffffffffff804216911690818110156143c35750506001600160801b03169081810361439557505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140f98751975f19890190613b64565b51015160c81b169360a01b169116171785555f5b8181106142e3575050600187016007556001600160a01b036020830151168015610cf157614143886001600160a01b0392613cf3565b166142b75786826141916001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b0385511690309033906147a8565b6001600160801b0360208401511680614287575b506001600160a01b038151169461427c61425e6001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996142038b61354d565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c08701526101408601906134d4565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b6142b1906001600160a01b036060840151166001600160a01b0361010085015151169033906147a8565b5f6141a5565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f20906142fe8160e0870151613b64565b5182549268010000000000000000841015611b03576001840180825584101561391f576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b1691161790550161410d565b7fa4cdf853000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f879842de000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193614415906001600160801b0361440c8588613b64565b515116906146ab565b9364ffffffffff8060206144298685613b64565b5101511694168085111561444557506001849301909291613f2d565b8490847fbfc5f2fa000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff602061448a84613b57565b51015116907fab900963000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f76d9c284000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f814426ed000000000000000000000000000000000000000000000000000000005f5260045ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f205416908133149182156145a6575b50811561458d575090565b90506001600160a01b036145a133926135f4565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614582565b805f52600a6020526145e9600260405f20016139d3565b90805f52600a60205260ff600160405f20015460a01c165f146146175750602001516001600160801b031690565b90815f52600a60205260405f205460f81c614639575061463690613b78565b90565b61463691506001600160801b036040818351169201511690613616565b3d15614680573d90614667826135c4565b9161467560405193846135a2565b82523d5f602084013e565b606090565b61463690614692816145d2565b905f52600a602052600260405f20015460801c90613616565b906001600160801b03809116911601906001600160801b03821161213c57565b9190916040516146da8161354d565b5f81525f6020820152926001600160801b03821690811561478b5767016345785d8a00008111614754576147166001600160801b0391836148de565b1660208501918183521115614740576001600160801b03918261473b92511690613616565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161479c8161354d565b5f81525f602082015290565b9091926001600160a01b036148079481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526148026084836135a2565b614859565b565b614807926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526148026064836135a2565b5f806001600160a01b0361488293169360208151910182865af161487b614656565b908361498c565b80519081151591826148c3575b50506148985750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6148d692506020809183010191016138f7565b155f8061488f565b9091905f198382098382029182808310920391808303921461497b57670de0b6b3a764000082101561494b577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906149c957508051156149a157805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614a0f575b6149da575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156149d256fea164736f6c634300081a000a"; bytes public constant BYTECODE_MERKLE_FACTORY = - hex"608034609357601f61577238819003918201601f19168301916001600160401b03831184841017609757808492602094604052833981010312609357516001600160a01b038116908190036093575f80546001600160a01b0319168217815560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36156c690816100ac8239f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c8063070a6b8414610b46578063145e9edb14610b29578063294f73bf14610ad057806345aa93571461075a5780634d7c0f111461068757806375829def14610600578063b3ee17cc146101d2578063f2555278146100a55763f851a4401461007c575f80fd5b346100a1575f3660031901126100a15760206001600160a01b035f5416604051908152f35b5f80fd5b346100a15760403660031901126100a1576004356001600160a01b0381168091036100a1576024356001600160a01b0381168091036100a1576001600160a01b035f54163381036101a3575060205f916024604051809481937f164e68de0000000000000000000000000000000000000000000000000000000083528760048401525af1908115610198575f91610166575b506040519081527f9b5d61c5cfb8ae3875898f5500bd74e04af45a87127b30a4a3d68bf16958047860203392a3005b90506020813d602011610190575b8161018160209383610d24565b810103126100a1575182610137565b3d9150610174565b6040513d5f823e3d90fd5b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100a1576101003660031901126100a15760043567ffffffffffffffff81116100a157610204903690600401610dc2565b6024356001600160a01b038116918282036100a157610221610e83565b610229610e92565b91610232610d46565b9060a4359267ffffffffffffffff84116100a157366023850112156100a157836004013567ffffffffffffffff811161054f576040519461027960208360051b0187610d24565b8186526024602087019260061b820101903682116100a157602401915b8183106105a2575050508351905f915f905b8082106105635750508251906020840151866040860151926060870151906040519b8c80602081019460208652604082016102e291610ec2565b03601f19810182526102f391610d24565b60808901519260a08a015160405181819251908160208401916020019161031992610ea1565b81010380825261032c9060200182610d24565b61033590610ee7565b906040519e8f80602081019860208a526040820161035291610f77565b03601f198101825261036391610d24565b60405198899860208a019b3360601b8d526bffffffffffffffffffffffff199060601b1660348b015260d81b6001600160d81b03191660488a01526bffffffffffffffffffffffff199060601b16604d890152519081606189016103c692610ea1565b860193606185015260818401526bffffffffffffffffffffffff199060601b1660a18301521515998a60f81b60b583015215159a8b60f81b60b683015264ffffffffff89169860d81b6001600160d81b03191660b783015251918260bc830161042e92610ea1565b0160610103605b01601f19810182526104479082610d24565b51902060015460405190611e2e908183019083821067ffffffffffffffff83111761054f57839261388c843960e0825260c06104b08d61048a60e086018b610f09565b9060208601528c60408601528d60608601528a608086015284810360a08601528b610f77565b92015203905ff58015610198576020977f332a019da0fba197fab04e82d49dae180458832766349abd4d0875f255dfedbe9561050c956001600160a01b0361052d9416998a996040519889986101208a526101208a0190610f09565b948d89015260408801526060870152608086015284820360a0860152610f77565b9060c083015260c43560e083015260e4356101008301520390a2604051908152f35b634e487b7160e01b5f52604160045260245ffd5b9092865184101561058e5760019064ffffffffff6020808760051b8b010151015116019301906102a8565b634e487b7160e01b5f52603260045260245ffd5b6040833603126100a157604051906040820182811067ffffffffffffffff82111761054f5760405283359067ffffffffffffffff821682036100a15782602092604094526105f1838701610d5a565b83820152815201920191610296565b346100a15760203660031901126100a1576004356001600160a01b0381168091036100a1575f546001600160a01b0381163381036101a357507fffffffffffffffffffffffff0000000000000000000000000000000000000000829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346100a15760203660031901126100a15760043567ffffffffffffffff81116100a157366023820112156100a15780600401359067ffffffffffffffff82116100a1573660248360061b830101116100a1575f90815b8383101561073b5760248360061b830101359067ffffffffffffffff82168092036100a15767ffffffffffffffff160167ffffffffffffffff8111610727576001909201916106dd565b634e487b7160e01b5f52601160045260245ffd5b602090670de0b6b3a764000067ffffffffffffffff6040519216148152f35b346100a1576101203660031901126100a15760043567ffffffffffffffff81116100a15761078c903690600401610dc2565b6024356001600160a01b038116918282036100a1576107a9610e83565b906107b2610e92565b9160603660831901126100a157604051906060820182811067ffffffffffffffff82111761054f576040526107e5610d46565b825260a43564ffffffffff811681036100a157602083015260c43564ffffffffff811681036100a157604083015282519060208401516040850151916060860151976040519182602081019a60208c526040820161084291610ec2565b03601f19810184526108549084610d24565b60808801519160a089015160405181819251908160208401916020019161087a92610ea1565b81010380825261088d9060200182610d24565b61089690610ee7565b6040519b60208d01956108c8878c64ffffffffff60408092828151168552826020820151166020860152015116910152565b60608e526108d760808f610d24565b60405198899860208a019b3360601b8d526bffffffffffffffffffffffff199060601b1660348b015260d81b6001600160d81b03191660488a01526bffffffffffffffffffffffff199060601b16604d8901525190816061890161093a92610ea1565b860193606185015260818401526bffffffffffffffffffffffff199060601b1660a18301521515978860f81b60b58301521515988960f81b60b683015251918260b7830161098792610ea1565b0160610103605601601f19810182526109a09082610d24565b519020600154604051906117db908183019083821067ffffffffffffffff83111761054f5783926120b18439610100825260e06109e1610100840189610f09565b928b60208201528960408201528a6060820152610a20608082018964ffffffffff60408092828151168552826020820151166020860152015116910152565b015203905ff591821561019857602095610ab3610a7b936001600160a01b037f845a4c1d0848b2ab1afaa55c1dda984f2fecb1007925c78b45b73f557f95325d96169788976040519687966101208852610120880190610f09565b948b87015260408601526060850152608084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b60e43560e0830152610104356101008301520390a2604051908152f35b346100a15760203660031901126100a1576004356001600160a01b035f54163381036101a35750806001556040519081527f7ddad2fcbe59f6ef4aa0bb369d1349aebf41976346ef8dbdc0ff8a92c21bd35860203392a2005b346100a1575f3660031901126100a1576020600154604051908152f35b346100a15760603660031901126100a15760043567ffffffffffffffff81116100a157610b77903690600401610dc2565b80516001600160d81b0319610c7660406061602086015182870151606088015190845191610bc283610bb460208201936020855289830190610ec2565b03601f198101855284610d24565b610c5b60808b015193610c0460a08d0151610bff60208b5183610bee8295518092858086019101610ea1565b81010301601f198101835282610d24565b610ee7565b9388519a8b97602089019d8e3360601b90526bffffffffffffffffffffffff199060601b1660348a015260d81b1660488801526bffffffffffffffffffffffff199060601b16604d87015251809287870190610ea1565b83019184830152608182015203016020810184520182610d24565b519020600154604051906110e9908183019083821067ffffffffffffffff83111761054f578392610fc88439604082526020610cb56040840188610f09565b92015203905ff58015610198576020917f6c8ff1a6e3a223daee8bc86092060b16475c557888c1b051617185a6ebb453256001600160a01b03610d0a9316928392604051918291606083526060830190610f09565b6024358783015260443560408301520390a2604051908152f35b90601f8019910116810190811067ffffffffffffffff82111761054f57604052565b6084359064ffffffffff821682036100a157565b359064ffffffffff821682036100a157565b81601f820112156100a15780359067ffffffffffffffff821161054f5760405192610da1601f8401601f191660200185610d24565b828452602083830101116100a157815f926020809301838601378301015290565b919060c0838203126100a1576040519060c0820182811067ffffffffffffffff82111761054f57604052819380356001600160a01b03811681036100a1578352610e0e60208201610d5a565b602084015260408101356001600160a01b03811681036100a1576040840152606081013567ffffffffffffffff81116100a15782610e4d918301610d6c565b60608401526080810135608084015260a08101359167ffffffffffffffff83116100a15760a092610e7e9201610d6c565b910152565b6044359081151582036100a157565b6064359081151582036100a157565b5f5b838110610eb25750505f910152565b8181015183820152602001610ea3565b90602091610edb81518092818552858086019101610ea1565b601f01601f1916010190565b602081519101519060208110610efb575090565b5f199060200360031b1b1690565b610f74916001600160a01b03825116815264ffffffffff60208301511660208201526001600160a01b03604083015116604082015260a0610f59606084015160c0606085015260c0840190610ec2565b926080810151608084015201519060a0818403910152610ec2565b90565b90602080835192838152019201905f5b818110610f945750505090565b8251805167ffffffffffffffff16855260209081015164ffffffffff168186015260409094019390920191600101610f8756fe61014080604052346103a5576110e9803803809161001d82856103a9565b83398101906040818303126103a55780516001600160401b0381116103a55781019060c0828403126103a5576040519160c083016001600160401b0381118482101761037a5760405280516001600160a01b03811681036103a5578352602081015164ffffffffff811681036103a557602084019081526040820151936001600160a01b03851685036103a5576040810194855260608301516001600160401b0381116103a557866100d09185016103ed565b92606082019384526080810151966080830197885260a082015160018060401b0381116103a55761010192016103ed565b94602060a0830195878752015195516020811161038e5750515f80546001600160a01b0319166001600160a01b039283161790559051166080525164ffffffffff1660a0525180519093906001600160401b03811161037a57600154600181811c91168015610370575b602082101461035c57601f81116102f9575b50602094601f8211600114610296579481929394955f9261028b575b50508160011b915f199060031b1c1916176001555b5160e052516040516101e1602082816101d081830196878151938492016103cc565b81010301601f1981018352826103a9565b519051906020811061027a575b50610100523360c05261012052604051610ca7908161044282396080518181816103f50152818161062a0152610811015260a051818181610181015281816107370152818161089f0152610b07015260c05181818161077e015261093d015260e05181818161028b01526105af015261010051816109fa01526101205181818161014101526104af0152f35b5f199060200360031b1b165f6101ee565b015190505f80610199565b601f1982169560015f52805f20915f5b8881106102e1575083600195969798106102c9575b505050811b016001556101ae565b01515f1960f88460031b161c191690555f80806102bb565b919260206001819286850151815501940192016102a6565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c81019160208410610352575b601f0160051c01905b818110610347575061017d565b5f815560010161033a565b9091508190610331565b634e487b7160e01b5f52602260045260245ffd5b90607f169061016b565b634e487b7160e01b5f52604160045260245ffd5b6371935f2960e11b5f52600452602060245260445ffd5b5f80fd5b601f909101601f19168101906001600160401b0382119082101761037a57604052565b5f5b8381106103dd5750505f910152565b81810151838201526020016103ce565b81601f820112156103a55780516001600160401b03811161037a5760405192610420601f8301601f1916602001856103a9565b818452602082840101116103a55761043e91602080850191016103cc565b9056fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146109e457508063164e68de1461090e5780631686c909146107a25780632dd310001461075f5780633f31ae3f146104195780634800d97f146103d657806349fc73dd146102d25780634e390d3e146102ae57806351e75e8b1461027457806375829def146101bf57806390e64d13146101a5578063bb4b573414610164578063bba72cd31461012a578063ce516507146100ea5763f851a440146100c1575f80fd5b346100e6575f3660031901126100e65760206001600160a01b035f5416604051908152f35b5f80fd5b346100e65760203660031901126100e657602061012060043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100e6575f3660031901126100e65760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100e6575f3660031901126100e657602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100e6575f3660031901126100e6576020610120610aff565b346100e65760203660031901126100e6576101d8610a74565b5f546001600160a01b03811633810361024557506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100e6575f3660031901126100e65760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100e6575f3660031901126100e657602064ffffffffff60035416604051908152f35b346100e6575f3660031901126100e6576040515f6001548060011c906001811680156103cc575b6020831081146103b8578285529081156103945750600114610336575b6103328361032681850382610a8a565b60405191829182610a2d565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061037a57509091508101602001610326610316565b919260018160209254838588010152019101909291610362565b60ff191660208086019190915291151560051b840190910191506103269050610316565b634e487b7160e01b5f52602260045260245ffd5b91607f16916102f9565b346100e6575f3660031901126100e65760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b60803660031901126100e657600435602435906001600160a01b038216918281036100e657604435926fffffffffffffffffffffffffffffffff84168094036100e6576064359367ffffffffffffffff85116100e657366023860112156100e657846004013567ffffffffffffffff81116100e6578060051b95602487820101903682116100e6576104a9610aff565b610708577f00000000000000000000000000000000000000000000000000000000000000008034106106d957506104f78760ff6001918060081c5f526002602052161b60405f205416151590565b6106ad57604051602081019088825286604082015285606082015260608152610521608082610a8a565b519020604051602081019182526020815261053d604082610a8a565b5190209261055160206040519a018a610a8a565b8852602401602088015b82821061069d57505050925f935b86518510156105ab5760208560051b88010151908181105f1461059a575f52602052600160405f205b940193610569565b905f52602052600160405f20610592565b85907f000000000000000000000000000000000000000000000000000000000000000003610675578261064e7f1dcd2362ae467d43bf31cbcac0526c0958b23eb063e011ab49a5179c839ed9a99460409460035464ffffffffff81161561065b575b508460081c5f526002602052855f20600160ff87161b81541790557f0000000000000000000000000000000000000000000000000000000000000000610b3c565b82519182526020820152a2005b64ffffffffff19164264ffffffffff16176003558861060d565b7fb4f06787000000000000000000000000000000000000000000000000000000005f5260045ffd5b813581526020918201910161055b565b867febe6f30d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fa164c6b4000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b7fdf4bae05000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b346100e6575f3660031901126100e65760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100e65760403660031901126100e6576107bb610a74565b602435906fffffffffffffffffffffffffffffffff82168092036100e6576001600160a01b035f5416338103610245575064ffffffffff60035416801515806108d9575b806108ca575b610870575061083582827f0000000000000000000000000000000000000000000000000000000000000000610b3c565b7f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b03805f5416936040519586521693a3005b7fe2e40a0c000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b506108d3610aff565b15610805565b5062093a80810164ffffffffff81116108fa5764ffffffffff1642116107ff565b634e487b7160e01b5f52601160045260245ffd5b346100e65760203660031901126100e6576004356001600160a01b0381168091036100e6576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168033036109b5575047905f80808085855af1610977610ac0565b501561098857602082604051908152f35b7e534073000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e3ddeed000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100e6575f3660031901126100e657610332907f0000000000000000000000000000000000000000000000000000000000000000602082015260208152610326604082610a8a565b9190916020815282518060208301525f5b818110610a5e575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201610a3e565b600435906001600160a01b03821682036100e657565b90601f8019910116810190811067ffffffffffffffff821117610aac57604052565b634e487b7160e01b5f52604160045260245ffd5b3d15610afa573d9067ffffffffffffffff8211610aac5760405191610aef601f8201601f191660200184610a8a565b82523d5f602084013e565b606090565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610b34575090565b905042101590565b5f610ba9926001600160a01b038293604051968260208901947fa9059cbb000000000000000000000000000000000000000000000000000000008652166024890152604488015260448752610b92606488610a8a565b1694519082865af1610ba2610ac0565b9083610c0e565b8051908115159182610bea575b5050610bbf5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100e657602001518015908115036100e6575f80610bb6565b90610c4b5750805115610c2357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580610c91575b610c5c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15610c5456fea164736f6c634300081a000a6101a0806040523461046c576117db803803809161001d82856105aa565b8339810190808203610100811261046c5781516001600160401b03811161046c5782019160c08385031261046c576040519160c083016001600160401b0381118482101761057f5760405283516001600160a01b038116810361046c578352610088602085016105cd565b6020840190815260408501519091906001600160a01b038116810361046c576040850190815260608601516001600160401b03811161046c57876100cd91880161061b565b95606086019687526080810151976080870198895260a082015160018060401b03811161046c576100fe920161061b565b60a0860190815260208501516001600160a01b038116979092909188840361046c5761012c60408801610660565b92606061013a818a01610660565b96607f19011261046c5760405196606088016001600160401b0381118982101761057f5760405261016d60808a016105cd565b885261017b60a08a016105cd565b99602089019a8b5260e061019160c08c016105cd565b9a60408b019b8c52015194845151602081116105935750515f80546001600160a01b0319166001600160a01b039283161790559051166080525164ffffffffff1660a052518051909a906001600160401b03811161057f57600154600181811c91168015610575575b602082101461056157601f81116104fe575b506020601f821160011461048c57819064ffffffffff9a9b9c9d5f92610481575b50508160011b915f199060031b1c1916176001555b5160e052516040516102756020828161026481830196878151938492016105fa565b81010301601f1981018352826105aa565b5190519060208110610470575b50610100523360c0526101205261014052610160526101805251166effffffffff0000000000000000000069ffffffffff0000000000600454945160281b16925160501b169260018060781b03191617171760045560018060a01b0360805116604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526103126064866105aa565b84519082855af161032161066d565b81610435575b508061042b575b156103e6575b60405161106d908161076e823960805181818161049e0152818161076f0152610c4b015260a0518181816101ad01528181610aa201528181610d4b0152610f9f015260c051818181610ae90152610de9015260e051818181610334015261065601526101005181610ea601526101205181818161016d01526105560152610140518181816107a00152610b6001526101605181818161022a01526108c80152610180518181816107ca0152610b240152f35b61041e610423936040519063095ea7b360e01b602083015260248201525f6044820152604481526104186064826105aa565b8261069c565b61069c565b5f8080610334565b50803b151561032e565b805180159250821561044a575b50505f610327565b819250906020918101031261046c5760206104659101610660565b5f80610442565b5f80fd5b5f199060200360031b1b165f610282565b015190505f8061022d565b601f1982169c60015f52815f209d5f5b8181106104e157509164ffffffffff9b9c9d9e918460019594106104c9575b505050811b01600155610242565b01515f1960f88460031b161c191690555f80806104bb565b919e8f60016020928684930151815501940192019e91929e61049c565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c81019160208410610557575b601f0160051c01905b81811061054c575061020c565b5f815560010161053f565b9091508190610536565b634e487b7160e01b5f52602260045260245ffd5b90607f16906101fa565b634e487b7160e01b5f52604160045260245ffd5b6371935f2960e11b5f52600452602060245260445ffd5b601f909101601f19168101906001600160401b0382119082101761057f57604052565b519064ffffffffff8216820361046c57565b6001600160401b03811161057f57601f01601f191660200190565b5f5b83811061060b5750505f910152565b81810151838201526020016105fc565b81601f8201121561046c578051610631816105df565b9261063f60405194856105aa565b8184526020828401011161046c5761065d91602080850191016105fa565b90565b5190811515820361046c57565b3d15610697573d9061067e826105df565b9161068c60405193846105aa565b82523d5f602084013e565b606090565b5f806106c49260018060a01b03169360208151910182865af16106bd61066d565b908361070f565b80519081151591826106ec575b50506106da5750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261046c5760206107079101610660565b155f806106d1565b90610733575080511561072457805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580610764575b610744575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561073c56fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314610e9057508063164e68de14610dba5780631686c90914610b8557806316c3549d14610b495780631bfd681414610b0d5780632dd3100014610aca5780633f31ae3f146104c25780634800d97f1461047f57806349fc73dd1461037b5780634e390d3e1461035757806351e75e8b1461031d57806375829def1461026857806390e64d131461024e5780639e93e5771461020b578063b0604a26146101d1578063bb4b573414610190578063bba72cd314610156578063ce516507146101165763f851a440146100ed575f80fd5b34610112575f3660031901126101125760206001600160a01b035f5416604051908152f35b5f80fd5b3461011257602036600319011261011257602061014c60043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b34610112575f3660031901126101125760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610112575f36600319011261011257602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610112575f36600319011261011257606060045464ffffffffff604051918181168352818160281c16602084015260501c166040820152f35b34610112575f3660031901126101125760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610112575f36600319011261011257602061014c610f97565b3461011257602036600319011261011257610281610f20565b5f546001600160a01b0381163381036102ee57506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610112575f3660031901126101125760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610112575f36600319011261011257602064ffffffffff60035416604051908152f35b34610112575f366003190112610112576040515f6001548060011c90600181168015610475575b6020831081146104615782855290811561043d57506001146103df575b6103db836103cf81850382610f36565b60405191829182610ed9565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b808210610423575090915081016020016103cf6103bf565b91926001816020925483858801015201910190929161040b565b60ff191660208086019190915291151560051b840190910191506103cf90506103bf565b634e487b7160e01b5f52602260045260245ffd5b91607f16916103a2565b34610112575f3660031901126101125760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b608036600319011261011257600435602435906001600160a01b038216809203610112576044356fffffffffffffffffffffffffffffffff8116809103610112576064359067ffffffffffffffff8211610112573660238301121561011257816004013567ffffffffffffffff8111610112578060051b926024848201019036821161011257610550610f97565b610a73577f0000000000000000000000000000000000000000000000000000000000000000803410610a44575061059e8660ff6001918060081c5f526002602052161b60405f205416151590565b610a18576040516020810190878252886040820152856060820152606081526105c8608082610f36565b51902060405160208101918252602081526105e4604082610f36565b519020926105f86020604051970187610f36565b8552602401602085015b828210610a0857505050935f945b83518610156106525760208660051b85010151908181105f14610641575f52602052600160405f205b950194610610565b905f52602052600160405f20610639565b84907f0000000000000000000000000000000000000000000000000000000000000000036109e05760035464ffffffffff8116156109c6575b508060081c5f52600260205260405f20600160ff83161b8154179055604051926060840184811067ffffffffffffffff82111761099b5760405264ffffffffff602085015f81526004549082821680155f146109bf575082421687525b828260281c16806109af575b505081808751169160501c16011660408501526001600160a01b035f541693604051906040820182811067ffffffffffffffff82111761099b576040525f82525f602083015260405195610100870187811067ffffffffffffffff82111761099b5760405286526020860185815260408701848152606088017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815260808901917f00000000000000000000000000000000000000000000000000000000000000001515835260a08a01937f00000000000000000000000000000000000000000000000000000000000000001515855260c08b0195865260e08b019687526040519a7f53b15727000000000000000000000000000000000000000000000000000000008c52516001600160a01b031660048c0152516001600160a01b031660248b0152516fffffffffffffffffffffffffffffffff1660448a0152516001600160a01b03166064890152511515608488015251151560a487015251805164ffffffffff1660c4870152602081015164ffffffffff1660e48701526040015164ffffffffff166101048601525180516001600160a01b03166101248601526020015161014485015283807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165a925f61016492602095f1938415610990575f9461093c575b507f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d9160409182519182526020820152a3005b9093506020813d602011610988575b8161095860209383610f36565b810103126101125751927f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d610909565b3d915061094b565b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b87518416018316905286806106f4565b87526106e8565b64ffffffffff19164264ffffffffff16176003558361068b565b7fb4f06787000000000000000000000000000000000000000000000000000000005f5260045ffd5b8135815260209182019101610602565b857febe6f30d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fa164c6b4000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b7fdf4bae05000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b34610112575f3660031901126101125760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610112575f3660031901126101125760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b34610112575f3660031901126101125760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b3461011257604036600319011261011257610b9e610f20565b6024356fffffffffffffffffffffffffffffffff8116809103610112576001600160a01b035f54163381036102ee575064ffffffffff6003541680151580610d85575b80610d76575b610d1c5750604051610c815f806001600160a01b0360208501967fa9059cbb000000000000000000000000000000000000000000000000000000008852169586602486015285604486015260448552610c41606486610f36565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001694519082865af1610c7a610f58565b9083610fd4565b8051908115159182610cf8575b5050610ccd57507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126101125760200151801590811503610112578480610c8e565b7fe2e40a0c000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b50610d7f610f97565b15610be7565b5062093a80810164ffffffffff8111610da65764ffffffffff164211610be1565b634e487b7160e01b5f52601160045260245ffd5b34610112576020366003190112610112576004356001600160a01b038116809103610112576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803303610e61575047905f80808085855af1610e23610f58565b5015610e3457602082604051908152f35b7e534073000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e3ddeed000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610112575f366003190112610112576103db907f00000000000000000000000000000000000000000000000000000000000000006020820152602081526103cf604082610f36565b9190916020815282518060208301525f5b818110610f0a575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201610eea565b600435906001600160a01b038216820361011257565b90601f8019910116810190811067ffffffffffffffff82111761099b57604052565b3d15610f92573d9067ffffffffffffffff821161099b5760405191610f87601f8201601f191660200184610f36565b82523d5f602084013e565b606090565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610fcc575090565b905042101590565b906110115750805115610fe957805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611057575b611022575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561101a56fea164736f6c634300081a000a6101e0806040523461048c57611e2e803803809161001d82856106ef565b833981019060e08183031261048c5780516001600160401b03811161048c5781019060c08284031261048c576040519160c083016001600160401b038111848210176105465760405280516001600160a01b038116810361048c57835261008660208201610712565b6020840190815260408201516001600160a01b038116810361048c576040850190815260608301516001600160401b03811161048c57866100c8918501610760565b6060860190815260808085015190870190815260a085015191949091906001600160401b03821161048c576100ff91899101610760565b60a087019081526020860151949091906001600160a01b038616860361048c5761012b604088016107a5565b94610138606089016107a5565b9861014560808a01610712565b60a08a01519099906001600160401b03811161048c5781018c601f8201121561048c578051906001600160401b038211610546576040519d8e8360051b60200161018f90826106ef565b8381526020019260061b82016020019181831161048c57602001925b828410610693575050505060c00151958551516020811161067c5750515f80546001600160a01b0319166001600160a01b039283161790559051166080525164ffffffffff1660a052518051906001600160401b0382116105465760015490600182811c92168015610672575b602083101461065e5781601f8493116105f0575b50602090601f831160011461058a575f9261057f575b50508160011b915f199060031b1c1916176001555b5160e0525160405161028a60208281610279818301968781519384920161073f565b81010301601f1981018352826106ef565b519051906020811061056e575b50610100523360c052610120526101405261016052610180526101c0528051905f915f915b81831061049057836101a05260018060a01b036080511660018060a01b03610160511690604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526103106064866106ef565b84519082855af161031f6107c6565b81610455575b508061044b575b15610406575b60405161156790816108c78239608051818181610578015281816109290152610f55015260a0518181816102c001528181610db50152818161105501526112dd015260c051818181610dfc01526110f3015260e05181818161040e015261072e015261010051816111b001526101205181818161028001526106270152610140518181816109590152610e7301526101605181818161014b0152610aa70152610180518181816101cc01526107bc01526101a051818181610304015261078a01526101c0518181816109830152610e370152f35b61043e610443936040519063095ea7b360e01b602083015260248201525f6044820152604481526104386064826106ef565b826107f5565b6107f5565b808080610332565b50803b151561032c565b805180159250821561046a575b505084610325565b819250906020918101031261048c57602061048591016107a5565b8480610462565b5f80fd5b91929091906001600160401b036104a785846107b2565b5151166001600160401b039182160190811161055a57926104c881836107b2565b519060045491680100000000000000008310156105465760018301806004558310156105325760019260045f5260205f200190838060401b038151166cffffffffff00000000000000006020845493015160401b1691858060681b031916171790550191906102bc565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f199060200360031b1b165f610297565b015190505f80610242565b60015f9081528281209350601f198516905b8181106105d857509084600195949392106105c0575b505050811b01600155610257565b01515f1960f88460031b161c191690555f80806105b2565b9293602060018192878601518155019501930161059c565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c81019160208510610654575b90601f859493920160051c01905b818110610646575061022c565b5f8155849350600101610639565b909150819061062b565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610218565b6371935f2960e11b5f52600452602060245260445ffd5b60408483031261048c5760408051919082016001600160401b03811183821017610546576040528451906001600160401b038216820361048c5782602092604094526106e0838801610712565b838201528152019301926101ab565b601f909101601f19168101906001600160401b0382119082101761054657604052565b519064ffffffffff8216820361048c57565b6001600160401b03811161054657601f01601f191660200190565b5f5b8381106107505750505f910152565b8181015183820152602001610741565b81601f8201121561048c57805161077681610724565b9261078460405194856106ef565b8184526020828401011161048c576107a2916020808501910161073f565b90565b5190811515820361048c57565b80518210156105325760209160051b010190565b3d156107f0573d906107d782610724565b916107e560405193846106ef565b82523d5f602084013e565b606090565b5f8061081d9260018060a01b03169360208151910182865af16108166107c6565b9083610868565b8051908115159182610845575b50506108335750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261048c57602061086091016107a5565b155f8061082a565b9061088c575080511561087d57805190602001fd5b630a12f52160e11b5f5260045ffd5b815115806108bd575b61089d575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561089556fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde031461119a57508063164e68de146110c45780631686c90914610e9857806316c3549d14610e5c5780631bfd681414610e205780632dd3100014610ddd5780633f31ae3f1461059c5780634800d97f1461055957806349fc73dd146104555780634e390d3e1461043157806351e75e8b146103f757806375829def1461034257806390e64d1314610328578063936c63d9146102e4578063bb4b5734146102a3578063bba72cd314610269578063bf4ed03f146101f0578063ce36b335146101af578063ce5165071461016f578063da7924681461012c5763f851a44014610103575f80fd5b34610128575f3660031901126101285760206001600160a01b035f5416604051908152f35b5f80fd5b34610128575f3660031901126101285760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346101285760203660031901126101285760206101a560043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b34610128575f36600319011261012857602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f36600319011261012857610208611312565b6040518091602082016020835281518091526020604084019201905f5b818110610233575050500390f35b8251805167ffffffffffffffff16855260209081015164ffffffffff168186015286955060409094019390920191600101610225565b34610128575f3660031901126101285760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610128575f36600319011261012857602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f36600319011261012857602060405167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f3660031901126101285760206101a56112d5565b346101285760203660031901126101285761035b61122a565b5f546001600160a01b0381163381036103c857506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610128575f3660031901126101285760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610128575f36600319011261012857602064ffffffffff60035416604051908152f35b34610128575f366003190112610128576040515f6001548060011c9060018116801561054f575b60208310811461053b5782855290811561051757506001146104b9575b6104b5836104a98185038261125c565b604051918291826111e3565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106104fd575090915081016020016104a9610499565b9192600181602092548385880101520191019092916104e5565b60ff191660208086019190915291151560051b840190910191506104a99050610499565b634e487b7160e01b5f52602260045260245ffd5b91607f169161047c565b34610128575f3660031901126101285760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b608036600319011261012857600435602435906001600160a01b03821680920361012857604435906001600160801b03821691828103610128576064359367ffffffffffffffff851161012857366023860112156101285784600401359467ffffffffffffffff86116101285760248660051b820101368111610128576106216112d5565b610d86577f0000000000000000000000000000000000000000000000000000000000000000803410610d57575061066f8560ff6001918060081c5f526002602052161b60405f205416151590565b610d2b5760405160208101908682528460408201528760608201526060815261069960808261125c565b51902060405160208101918252602081526106b560408261125c565b519020916106c2886112bd565b976106d0604051998a61125c565b8852602401602088015b828210610d1b57505050925f935b865185101561072a576106fb85886113c7565b519081811015610719575f52602052600160405f205b9401936106e8565b905f52602052600160405f20610711565b85907f000000000000000000000000000000000000000000000000000000000000000003610cf35760035464ffffffffff811615610cd9575b508160081c5f52600260205260405f20600160ff84161b815417905567ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016670de0b6b3a76400008103610cae57507f000000000000000000000000000000000000000000000000000000000000000064ffffffffff8116610ca8575064ffffffffff4216935b6107fa611312565b90815191610807836112bd565b92610815604051948561125c565b808452601f19610824826112bd565b015f5b818110610c8557505061085661085167ffffffffffffffff610848856113a6565b51511687611420565b6113db565b64ffffffffff806020610868866113a6565b510151168a0116906001600160801b036040519161088583611240565b16918282526020820152610898866113a6565b526108a2856113a6565b50916001905b828210610bf15750506001600160801b038216858111610bdd578511610bb2575b5050506001600160a01b035f541690604051906108e582611240565b5f82525f602083015260405192610120840184811067ffffffffffffffff821117610b9e5760409492939452815260208101918683526040820197858952606083017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152608084017f00000000000000000000000000000000000000000000000000000000000000001515815260a08501917f00000000000000000000000000000000000000000000000000000000000000001515835260c086019364ffffffffff16845260e0860194855261010086019788526040519b8c977f32fbe22b0000000000000000000000000000000000000000000000000000000089526004890160209052610164890197516001600160a01b031660248a0152516001600160a01b03166044890152516001600160801b03166064880152516001600160a01b0316608487015251151560a486015251151560c48501525164ffffffffff1660e48401525190610104830161014090528151809152610184830191602001905f5b818110610b6957505050819060208094516001600160a01b03815116610124850152015161014483015203815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1938415610b5e575f94610b0a575b507f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d9160409182519182526020820152a3005b9093506020813d602011610b56575b81610b266020938361125c565b810103126101285751927f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d610ad7565b3d9150610b19565b6040513d5f823e3d90fd5b825180516001600160801b0316855260209081015164ffffffffff16818601528a955060409094019390920191600101610a70565b634e487b7160e01b5f52604160045260245ffd5b6001600160801b0391610bc983925f1901866113c7565b5193031681835116011690528580806108c9565b634e487b7160e01b5f52600160045260245ffd5b90926001600160801b03600191610c2061085167ffffffffffffffff610c1789886113c7565b5151168b611420565b9064ffffffffff806020610c375f198b018d6113c7565b51015116816020610c488b8a6113c7565b51015116011660405190610c5b82611240565b84841682526020820152610c6f888b6113c7565b52610c7a878a6113c7565b5001169301906108a8565b602090604051610c9481611240565b5f81525f8382015282828901015201610827565b936107f2565b7f36d385ef000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b64ffffffffff19164264ffffffffff161760035584610763565b7fb4f06787000000000000000000000000000000000000000000000000000000005f5260045ffd5b81358152602091820191016106da565b847febe6f30d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fa164c6b4000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b7fdf4bae05000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b34610128575f3660031901126101285760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f3660031901126101285760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b34610128575f3660031901126101285760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b3461012857604036600319011261012857610eb161122a565b6024356001600160801b038116809103610128576001600160a01b035f54163381036103c8575064ffffffffff600354168015158061108f575b80611080575b6110265750604051610f8b5f806001600160a01b0360208501967fa9059cbb000000000000000000000000000000000000000000000000000000008852169586602486015285604486015260448552610f4b60648661125c565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001694519082865af1610f8461127e565b90836114ce565b8051908115159182611002575b5050610fd757507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126101285760200151801590811503610128578480610f98565b7fe2e40a0c000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b506110896112d5565b15610ef1565b5062093a80810164ffffffffff81116110b05764ffffffffff164211610eeb565b634e487b7160e01b5f52601160045260245ffd5b34610128576020366003190112610128576004356001600160a01b038116809103610128576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001680330361116b575047905f80808085855af161112d61127e565b501561113e57602082604051908152f35b7e534073000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e3ddeed000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610128575f366003190112610128576104b5907f00000000000000000000000000000000000000000000000000000000000000006020820152602081526104a960408261125c565b9190916020815282518060208301525f5b818110611214575060409293505f838284010152601f8019910116010190565b80602080928701015160408286010152016111f4565b600435906001600160a01b038216820361012857565b6040810190811067ffffffffffffffff821117610b9e57604052565b90601f8019910116810190811067ffffffffffffffff821117610b9e57604052565b3d156112b8573d9067ffffffffffffffff8211610b9e57604051916112ad601f8201601f19166020018461125c565b82523d5f602084013e565b606090565b67ffffffffffffffff8111610b9e5760051b60200190565b64ffffffffff7f000000000000000000000000000000000000000000000000000000000000000016801515908161130a575090565b905042101590565b6004549061131f826112bd565b9161132d604051938461125c565b80835260045f9081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b602085015b8383106113695750505050565b60016020819260405161137b81611240565b64ffffffffff865467ffffffffffffffff8116835260401c168382015281520192019201919061135c565b8051156113b35760200190565b634e487b7160e01b5f52603260045260245ffd5b80518210156113b35760209160051b010190565b6001600160801b0381116113f5576001600160801b031690565b7f4916adce000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f19838209838202918280831092039180830392146114bd57670de0b6b3a764000082101561148d577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b9061150b57508051156114e357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611551575b61151c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561151456fea164736f6c634300081a000aa164736f6c634300081a000a"; + hex"60808060405234601557613bb9908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c80631e3238761461044c5780634d7c0f11146103795763769bed201461003a575f80fd5b346103755760c03660031901126103755760043567ffffffffffffffff81116103755761006b9036906004016108c2565b602435906001600160a01b03821691828103610375576040366043190112610375576040519061009a8261080f565b60443564ffffffffff8116810361037557825260643564ffffffffff811681036103755760208301528251906020840151151583604086015192606087015160808801519160405180602081019460208652604082016100f9916109ca565b03601f198101825261010b908261082b565b60a08a01519360c08b0151604051818192519081602084019160200191610131926109a9565b810103808252610144906020018261082b565b61014d906109ef565b9060e08c01511515926040519560208701988961017c9164ffffffffff60208092828151168552015116910152565b6040875261018b60608861082b565b6040519a8b9a60208c019d8e3360601b90526bffffffffffffffffffffffff199060601b1660348d015260f81b60488c015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660498b01526bffffffffffffffffffffffff199060601b16604e8a015251908160628a0161020f926109a9565b8701946062860152608285015260f81b60a28401526bffffffffffffffffffffffff199060601b1660a383015251918260b7830161024c926109a9565b0160620103605501601f1981018252610265908261082b565b51902060405161157280820182811067ffffffffffffffff821117610361578291610ae88339608081526102c260406102a16080840189610a61565b92896020820152018664ffffffffff60208092828151168552015116910152565b03905ff59283156103565761031961033b937f2ba0fe49588281dbb122dd3b7f3e2b3396338f70dbe3c62bf3e3888b4ba7ffb8926001600160a01b036020971695869560405194859460c0865260c0860190610a61565b9289850152604084019064ffffffffff60208092828151168552015116910152565b608435608083015260a43560a08301520390a2604051908152f35b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b346103755760203660031901126103755760043567ffffffffffffffff811161037557366023820112156103755780600401359067ffffffffffffffff8211610375573660248360061b83010111610375575f90815b8383101561042d5760248360061b830101359067ffffffffffffffff82168092036103755767ffffffffffffffff160167ffffffffffffffff8111610419576001909201916103cf565b634e487b7160e01b5f52601160045260245ffd5b602090670de0b6b3a764000067ffffffffffffffff6040519216148152f35b346103755760a03660031901126103755760043567ffffffffffffffff81116103755761047d9036906004016108c2565b6024356001600160a01b03811690818103610375576044359067ffffffffffffffff8211610375573660238301121561037557816004013567ffffffffffffffff811161036157604051926104d860208360051b018561082b565b8184526024602085019260061b8201019036821161037557602401915b8183106107c2575050505f9082515f905b8082106107835750508451906020860151151584604088015192606089015160808a0151916040518060208101946020865260408201610545916109ca565b03601f1981018252610557908261082b565b8b60a08101519460c082015160405181819251908160208401916020019161057e926109a9565b810103808252610591906020018261082b565b61059a906109ef565b9160e001511515926040519586602081019960208b52604082016105bd91610a11565b03601f19810188526105cf908861082b565b6040519a8b9a60208c019d8e3360601b90526bffffffffffffffffffffffff199060601b1660348d015260f81b60488c015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660498b01526bffffffffffffffffffffffff199060601b16604e8a015251908160628a01610653926109a9565b8701946062860152608285015260f81b60a28401526bffffffffffffffffffffffff199060601b1660a383015251918260b78301610690926109a9565b0160620103605501601f19810182526106a9908261082b565b519020604051611b538082019082821067ffffffffffffffff8311176103615782916106fa9161205a8439606081526106e5606082018a610a61565b90886020820152604081830391015286610a11565b03905ff58015610356576020947ffe44018cf74992b2720702385a1728bd329dd136e4f651203176c81c12710a8b926107626001600160a01b03610750941696879660405195869560c0875260c0870190610a61565b918a8601528482036040860152610a11565b906060830152606435608083015260843560a08301520390a2604051908152f35b909284518410156107ae5760019064ffffffffff6020808760051b8901015101511601930190610506565b634e487b7160e01b5f52603260045260245ffd5b60408336031261037557604051906107d98261080f565b83359067ffffffffffffffff8216820361037557826020926040945261080083870161085a565b838201528152019201916104f5565b6040810190811067ffffffffffffffff82111761036157604052565b90601f8019910116810190811067ffffffffffffffff82111761036157604052565b3590811515820361037557565b359064ffffffffff8216820361037557565b81601f820112156103755780359067ffffffffffffffff821161036157604051926108a1601f8401601f19166020018561082b565b8284526020838301011161037557815f926020809301838601378301015290565b919091610100818403126103755760405190610100820182811067ffffffffffffffff82111761036157604052819381356001600160a01b03811681036103755783526109116020830161084d565b60208401526109226040830161085a565b604084015260608201356001600160a01b0381168103610375576060840152608082013567ffffffffffffffff8111610375578161096191840161086c565b608084015260a082013560a084015260c08201359067ffffffffffffffff8211610375578261099960e094926109a49486940161086c565b60c08601520161084d565b910152565b5f5b8381106109ba5750505f910152565b81810151838201526020016109ab565b906020916109e3815180928185528580860191016109a9565b601f01601f1916010190565b602081519101519060208110610a03575090565b5f199060200360031b1b1690565b90602080835192838152019201905f5b818110610a2e5750505090565b8251805167ffffffffffffffff16855260209081015164ffffffffff168186015260409094019390920191600101610a21565b906001600160a01b03825116815260208201511515602082015264ffffffffff60408301511660408201526001600160a01b03606083015116606082015260e080610adc610ac0608086015161010060808701526101008601906109ca565b60a086015160a086015260c086015185820360c08701526109ca565b93015115159101529056fe610160806040523461042857611572803803809161001d8285610560565b833981019080820390608082126104285780516001600160401b03811161042857810190610100828503126104285760405161010081016001600160401b038111828210176105355760405282516001600160a01b038116810361042857815261008960208401610583565b6020820190815261009c60408501610590565b60408301908152606085015194906001600160a01b0386168603610428576060840195865260808201516001600160401b03811161042857886100e09184016105de565b6080850190815260a08381015190860190815260c084015190999192916001600160401b0382116104285761011c60e09161012a9387016105de565b9460c0880195865201610583565b9360e0860194855260208701519560018060a01b038716998a880361042857604090603f1901126104285760408051989089016001600160401b0381118a8210176105355761018d9160609160405261018560408201610590565b8b5201610590565b9860208901998a52855151602081116105495750515f80546001600160a01b0319166001600160a01b0392831617905590511660805251151560a0525164ffffffffff1660c0525180519097906001600160401b03811161053557600154600181811c9116801561052b575b602082101461051757601f81116104b4575b506020601f821160011461044857819064ffffffffff98999a5f9261043d575b50508160011b915f199060031b1c1916176001555b5160e052516040516102736020828161026281830196878151938492016105bd565b81010301601f198101835282610560565b519051906020811061042c575b50610100525115156101205261014052511669ffffffffff0000000000600454925160281b169160018060501b031916171760045560018060a01b0360805116604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526102f0606486610560565b84519082855af16102ff610623565b816103f1575b50806103e7575b156103a2575b604051610e4e90816107248239608051818181610409015281816106440152610ae6015260a05181818161067501526109fe015260c0518181816101520152818161095501528181610c250152610d80015260e05181818161029f015261059d01526101005181610caa01526101205181818161069f01526109c201526101405181818161019501526107b40152f35b6103da6103df936040519063095ea7b360e01b602083015260248201525f6044820152604481526103d4606482610560565b82610652565b610652565b5f8080610312565b50803b151561030c565b8051801592508215610406575b50505f610305565b81925090602091810103126104285760206104219101610583565b5f806103fe565b5f80fd5b5f199060200360031b1b165f610280565b015190505f8061022b565b601f1982169960015f52815f209a5f5b81811061049c57509164ffffffffff999a9b91846001959410610484575b505050811b01600155610240565b01515f1960f88460031b161c191690555f8080610476565b838301518d556001909c019b60209384019301610458565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c8101916020841061050d575b601f0160051c01905b818110610502575061020b565b5f81556001016104f5565b90915081906104ec565b634e487b7160e01b5f52602260045260245ffd5b90607f16906101f9565b634e487b7160e01b5f52604160045260245ffd5b630f39860960e01b5f52600452602060245260445ffd5b601f909101601f19168101906001600160401b0382119082101761053557604052565b5190811515820361042857565b519064ffffffffff8216820361042857565b6001600160401b03811161053557601f01601f191660200190565b5f5b8381106105ce5750505f910152565b81810151838201526020016105bf565b81601f820112156104285780516105f4816105a2565b926106026040519485610560565b818452602082840101116104285761062091602080850191016105bd565b90565b3d1561064d573d90610634826105a2565b916106426040519384610560565b82523d5f602084013e565b606090565b5f8061067a9260018060a01b03169360208151910182865af1610673610623565b90836106c5565b80519081151591826106a2575b50506106905750565b635274afe760e01b5f5260045260245ffd5b81925090602091810103126104285760206106bd9101610583565b155f80610687565b906106e957508051156106da57805190602001fd5b630a12f52160e11b5f5260045ffd5b8151158061071a575b6106fa575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156106f256fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314610c94575080631686c90914610a2357806316c3549d146109e75780631bfd6814146109ab5780633bfe03a81461097d5780633f31ae3f1461042d5780634800d97f146103ea57806349fc73dd146102e65780634e390d3e146102c257806351e75e8b1461028857806375829def146101d357806390e64d13146101b95780639e93e57714610176578063bb4b573414610135578063ce516507146100f55763f851a440146100cc575f80fd5b346100f1575f3660031901126100f15760206001600160a01b035f5416604051908152f35b5f80fd5b346100f15760203660031901126100f157602061012b60043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100f1575f3660031901126100f157602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f1575f3660031901126100f15760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f1575f3660031901126100f157602061012b610d78565b346100f15760203660031901126100f1576101ec610d24565b5f546001600160a01b03811633810361025957506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100f1575f3660031901126100f15760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100f1575f3660031901126100f157602064ffffffffff60035416604051908152f35b346100f1575f3660031901126100f1576040515f6001548060011c906001811680156103e0575b6020831081146103cc578285529081156103a8575060011461034a575b6103468361033a81850382610d56565b60405191829182610cdd565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061038e5750909150810160200161033a61032a565b919260018160209254838588010152019101909291610376565b60ff191660208086019190915291151560051b8401909101915061033a905061032a565b634e487b7160e01b5f52602260045260245ffd5b91607f169161030d565b346100f1575f3660031901126100f15760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f15760803660031901126100f1576004356024356001600160a01b0381168091036100f157604435916fffffffffffffffffffffffffffffffff83168093036100f1576064359067ffffffffffffffff82116100f157366023830112156100f157816004013567ffffffffffffffff81116100f1578060051b92602484820101903682116100f1576040516020810190858252876040820152886060820152606081526104de608082610d56565b51902060405160208101918252602081526104fa604082610d56565b51902092610506610d78565b6109265761052b8560ff6001918060081c5f526002602052161b60405f205416151590565b6108fa5761053f6020604051970187610d56565b8552602401602085015b8282106108ea57505050935f945b83518610156105995760208660051b85010151908181105f14610588575f52602052600160405f205b950194610557565b905f52602052600160405f20610580565b84907f0000000000000000000000000000000000000000000000000000000000000000036108c25760035464ffffffffff8116156108a8575b508260081c5f52600260205260405f20600160ff85161b81541790556001600160a01b035f54169160405161060681610d3a565b5f81525f602082015260405193610100850185811067ffffffffffffffff8211176108945760405284526020840183815260408501838152606086017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815260808701907f00000000000000000000000000000000000000000000000000000000000000001515825260a08801927f000000000000000000000000000000000000000000000000000000000000000015158452604051946106cf86610d3a565b60045464ffffffffff8116875260281c64ffffffffff16602087015260c08a0195865260e08a01968752604051997fab167ccc000000000000000000000000000000000000000000000000000000008b52516001600160a01b031660048b0152516001600160a01b031660248a0152516fffffffffffffffffffffffffffffffff166044890152516001600160a01b03166064880152511515608487015251151560a486015251805164ffffffffff1660c48601526020015164ffffffffff1660e48501525180516001600160a01b03166101048501526020015161012484015282807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165a925f61014492602095f1928315610889575f93610831575b50907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d60406020958594825191825287820152a3604051908152f35b939250906020843d602011610881575b8161084e60209383610d56565b810103126100f15792519192907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d6107f5565b3d9150610841565b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b64ffffffffff19164264ffffffffff1617600355836105d2565b7ffe365d76000000000000000000000000000000000000000000000000000000005f5260045ffd5b8135815260209182019101610549565b847fcd4c86cc000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f99657b41000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b346100f1575f3660031901126100f157604060045464ffffffffff825191818116835260281c166020820152f35b346100f1575f3660031901126100f15760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100f1575f3660031901126100f15760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100f15760403660031901126100f157610a3c610d24565b6024356fffffffffffffffffffffffffffffffff81168091036100f1576001600160a01b035f5416338103610259575064ffffffffff6003541680151580610c5f575b80610c50575b610bf657506040515f806001600160a01b0360208401957fa9059cbb000000000000000000000000000000000000000000000000000000008752169485602485015284604485015260448452610adc606485610d56565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15610bea573d67ffffffffffffffff811161089457610b4f9160405191610b3f6020601f19601f8401160184610d56565b82523d5f602084013e5b83610db5565b8051908115159182610bc6575b5050610b9b57507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100f157602001518015908115036100f1578480610b5c565b610b4f90606090610b49565b7f6df0cfdb000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b50610c59610d78565b15610a85565b5062093a80810164ffffffffff8111610c805764ffffffffff164211610a7f565b634e487b7160e01b5f52601160045260245ffd5b346100f1575f3660031901126100f157610346907f000000000000000000000000000000000000000000000000000000000000000060208201526020815261033a604082610d56565b9190916020815282518060208301525f5b818110610d0e575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201610cee565b600435906001600160a01b03821682036100f157565b6040810190811067ffffffffffffffff82111761089457604052565b90601f8019910116810190811067ffffffffffffffff82111761089457604052565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610dad575090565b905042101590565b90610df25750805115610dca57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580610e38575b610e03575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15610dfb56fea164736f6c634300081a000a610180806040523461044857611b53803803809161001d82856106ab565b83398101906060818303126104485780516001600160401b03811161044857810161010081840312610448576040519061010082016001600160401b038111838210176105025760405280516001600160a01b0381168103610448578252610087602082016106ce565b916020810192835261009b604083016106db565b60408201908152606083015193906001600160a01b0385168503610448576060830194855260808401516001600160401b03811161044857876100df918601610729565b916080840192835260a08501519360a0810194855260c086015160018060401b0381116104485760e06101178b610125938a01610729565b9760c08401988952016106ce565b60e082019081526020890151989097906001600160a01b038a168a03610448576040810151906001600160401b03821161044857018a601f82011215610448578051906001600160401b0382116105025760209b8c6040519d8e61018e828760051b01826106ab565b858152019360061b8301019181831161044857602001925b82841061064f5750505050865151602081116106385750515f80546001600160a01b0319166001600160a01b0392831617905590511660805251151560a0525164ffffffffff1660c052518051906001600160401b0382116105025760015490600182811c9216801561062e575b602083101461061a5781601f8493116105ac575b50602090601f8311600114610546575f9261053b575b50508160011b915f199060031b1c1916176001555b5160e05251604051610286602082816102758183019687815193849201610708565b81010301601f1981018352826106ab565b519051906020811061052a575b506101005251151561012052610140528051905f915f915b81831061044c57836101605260018060a01b036080511660018060a01b03610140511690604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526102ff6064866106ab565b84519082855af161030e610782565b81610411575b5080610407575b156103c2575b6040516112d0908161088382396080518181816105590152818161088e0152610e8e015260a0518181816108b80152610daf015260c0518181816102a101528181610d0901528181610fcd0152611114015260e0518181816103ef01526107260152610100518161103e0152610120518181816108ea0152610d7301526101405181818161011f01526109d00152610160518181816102e5015261060a0152f35b6103fa6103ff936040519063095ea7b360e01b602083015260248201525f6044820152604481526103f46064826106ab565b826107b1565b6107b1565b808080610321565b50803b151561031b565b8051801592508215610426575b505084610314565b819250906020918101031261044857602061044191016106ce565b848061041e565b5f80fd5b91929091906001600160401b03610463858461076e565b5151166001600160401b03918216019081116105165792610484818361076e565b519060045491680100000000000000008310156105025760018301806004558310156104ee5760019260045f5260205f200190838060401b038151166cffffffffff00000000000000006020845493015160401b1691858060681b031916171790550191906102ab565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f199060200360031b1b165f610293565b015190505f8061023e565b60015f9081528281209350601f198516905b818110610594575090846001959493921061057c575b505050811b01600155610253565b01515f1960f88460031b161c191690555f808061056e565b92936020600181928786015181550195019301610558565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c81019160208510610610575b90601f859493920160051c01905b8181106106025750610228565b5f81558493506001016105f5565b90915081906105e7565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610214565b630f39860960e01b5f52600452602060245260445ffd5b6040848303126104485760408051919082016001600160401b03811183821017610502576040528451906001600160401b038216820361044857826020926040945261069c8388016106db565b838201528152019301926101a6565b601f909101601f19168101906001600160401b0382119082101761050257604052565b5190811515820361044857565b519064ffffffffff8216820361044857565b6001600160401b03811161050257601f01601f191660200190565b5f5b8381106107195750505f910152565b818101518382015260200161070a565b81601f8201121561044857805161073f816106ed565b9261074d60405194856106ab565b818452602082840101116104485761076b9160208085019101610708565b90565b80518210156104ee5760209160051b010190565b3d156107ac573d90610793826106ed565b916107a160405193846106ab565b82523d5f602084013e565b606090565b5f806107d99260018060a01b03169360208151910182865af16107d2610782565b9083610824565b8051908115159182610801575b50506107ef5750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261044857602061081c91016106ce565b155f806107e6565b90610848575080511561083957805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580610879575b610859575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561085156fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314611028575080631686c90914610dd457806316c3549d14610d985780631bfd681414610d5c5780633f31ae3f1461057d5780634800d97f1461053a57806349fc73dd146104365780634e390d3e1461041257806351e75e8b146103d857806375829def1461032357806390e64d1314610309578063936c63d9146102c5578063bb4b573414610284578063bf4ed03f14610183578063ce51650714610143578063da792468146101005763f851a440146100d7575f80fd5b346100fc575f3660031901126100fc5760206001600160a01b035f5416604051908152f35b5f80fd5b346100fc575f3660031901126100fc5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fc5760203660031901126100fc57602061017960043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100fc575f3660031901126100fc5760045461019f81611149565b906101ad60405192836110ea565b80825260045f9081526020830191907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b835b838310610247578486604051918291602083019060208452518091526040830191905f5b818110610211575050500390f35b8251805167ffffffffffffffff16855260209081015164ffffffffff168186015286955060409094019390920191600101610203565b600160208192604051610259816110ce565b64ffffffffff865467ffffffffffffffff8116835260401c16838201528152019201920191906101df565b346100fc575f3660031901126100fc57602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fc575f3660031901126100fc57602060405167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fc575f3660031901126100fc57602061017961110c565b346100fc5760203660031901126100fc5761033c6110b8565b5f546001600160a01b0381163381036103a957506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100fc575f3660031901126100fc5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100fc575f3660031901126100fc57602064ffffffffff60035416604051908152f35b346100fc575f3660031901126100fc576040515f6001548060011c90600181168015610530575b60208310811461051c578285529081156104f8575060011461049a575b6104968361048a818503826110ea565b60405191829182611071565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106104de5750909150810160200161048a61047a565b9192600181602092548385880101520191019092916104c6565b60ff191660208086019190915291151560051b8401909101915061048a905061047a565b634e487b7160e01b5f52602260045260245ffd5b91607f169161045d565b346100fc575f3660031901126100fc5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fc5760803660031901126100fc57600435602435906001600160a01b0382168092036100fc57604435916001600160801b038316918284036100fc576064359367ffffffffffffffff85116100fc57366023860112156100fc5784600401359467ffffffffffffffff86116100fc5760248660051b8201013681116100fc5767ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016670de0b6b3a76400008103610d3157506040516020810190858252866040820152876060820152606081526106606080826110ea565b519020604051602081019182526020815261067c6040826110ea565b5190209161068861110c565b610cda576106ad8560ff6001918060081c5f526002602052161b60405f205416151590565b610cae576106ba88611149565b976106c8604051998a6110ea565b8852602401602088015b828210610c9e57505050925f935b8651851015610722576106f38588611161565b519081811015610711575f52602052600160405f205b9401936106e0565b905f52602052600160405f20610709565b85907f000000000000000000000000000000000000000000000000000000000000000003610c765760035464ffffffffff811615610c5c575b506004549261076984611149565b9361077760405195866110ea565b80855260045f9081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b602087015b838310610c1f57505050505f84516107bd81611149565b956107cb60405197886110ea565b818752601f196107da83611149565b015f5b818110610bfc5750505f905b828210610b275750506001600160801b038216848111610b13578411610ae8575b5050508360081c5f52600260205260405f20600160ff86161b81541790556001600160a01b035f541692604051610840816110ce565b5f81525f60208201526040519161010083019583871067ffffffffffffffff881117610ad4576001600160a01b039660409492939452815260208101918583526040820185815260608301887f00000000000000000000000000000000000000000000000000000000000000001681528860808501917f0000000000000000000000000000000000000000000000000000000000000000151583526001600160801b0360a08701947f00000000000000000000000000000000000000000000000000000000000000001515865260c0880196875260e08801998a526040519c8d997f897f362b000000000000000000000000000000000000000000000000000000008b52602060048c0152816101448c019a511660248c0152511660448a0152511660648801525116608486015251151560a485015251151560c4840152519061012060e48401528151809152602061016484019201905f5b818110610a9f57505050819060208094516001600160a01b03815116610104850152015161012483015203815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1928315610a94575f93610a3c575b50907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d60406020958594825191825287820152a3604051908152f35b939250906020843d602011610a8c575b81610a59602093836110ea565b810103126100fc5792519192907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d610a00565b3d9150610a4c565b6040513d5f823e3d90fd5b825180516001600160801b0316855260209081015164ffffffffff168186015289955060409094019390920191600101610999565b634e487b7160e01b5f52604160045260245ffd5b6001600160801b0391610aff83925f190188611161565b51930316818351160116905284808061080a565b634e487b7160e01b5f52600160045260245ffd5b9092610b4867ffffffffffffffff610b3f8685611161565b51511687611189565b6001600160801b038111610bd1576001600160801b038091169164ffffffffff6020610b748887611161565b5101511660405190610b85826110ce565b8482526020820152610b97878c611161565b52610ba2868b611161565b5016016001600160801b038111610bbd5792600101906107e9565b634e487b7160e01b5f52601160045260245ffd5b7f4916adce000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b602090604051610c0b816110ce565b5f81525f8382015282828c010152016107dd565b600160208192604051610c31816110ce565b64ffffffffff865467ffffffffffffffff8116835260401c16838201528152019201920191906107a6565b64ffffffffff19164264ffffffffff16176003558461075b565b7ffe365d76000000000000000000000000000000000000000000000000000000005f5260045ffd5b81358152602091820191016106d2565b847fcd4c86cc000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f99657b41000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b7f36d385ef000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346100fc575f3660031901126100fc5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100fc575f3660031901126100fc5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100fc5760403660031901126100fc57610ded6110b8565b6024356001600160801b0381168091036100fc576001600160a01b035f54163381036103a9575064ffffffffff6003541680151580611007575b80610ff8575b610f9e57506040515f806001600160a01b0360208401957fa9059cbb000000000000000000000000000000000000000000000000000000008752169485602485015284604485015260448452610e846064856110ea565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15610f92573d67ffffffffffffffff8111610ad457610ef79160405191610ee76020601f19601f84011601846110ea565b82523d5f602084013e5b83611237565b8051908115159182610f6e575b5050610f4357507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100fc57602001518015908115036100fc578480610f04565b610ef790606090610ef1565b7f6df0cfdb000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b5061100161110c565b15610e2d565b5062093a80810164ffffffffff8111610bbd5764ffffffffff164211610e27565b346100fc575f3660031901126100fc57610496907f000000000000000000000000000000000000000000000000000000000000000060208201526020815261048a6040826110ea565b9190916020815282518060208301525f5b8181106110a2575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201611082565b600435906001600160a01b03821682036100fc57565b6040810190811067ffffffffffffffff821117610ad457604052565b90601f8019910116810190811067ffffffffffffffff821117610ad457604052565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081611141575090565b905042101590565b67ffffffffffffffff8111610ad45760051b60200190565b80518210156111755760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b9091905f198382098382029182808310920391808303921461122657670de0b6b3a76400008210156111f6577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b90611274575080511561124c57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806112ba575b611285575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561127d56fea164736f6c634300081a000aa164736f6c634300081a000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = - hex"60808060405234601557615f8d908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bc5760403660031901126141bc576001600160a01b036004351680600435036141bc576103e06040525f61024081905260606102608190526102808290526102a08290526102c0819052610300819052610320819052610340819052610360819052610380526103a08190526103c0526102e08190526100b6906100ad600435614824565b61030052614b1e565b610320526102e0516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f91614681575b506001600160a01b0361012791168061024052614c1a565b610260526102e0516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8576fffffffffffffffffffffffffffffffff915f91614662575b5016610280526102e0516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8575f90614625575b6101f59150614dbc565b610360526102e0516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f916145f6575b50610280516fffffffffffffffffffffffffffffffff1680156145e2576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614710565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d166154e9565b9701166154e9565b9801166154e9565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146ca565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146ca565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146ca565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ebc565b1690615022565b9061045a6001600160a01b036102405116614b1e565b906020610240015190602460206001600160a01b0360a0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b8576024915f916145c3575b5060206001600160a01b0360a0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b85764ffffffffff8091610522945f91614589575b50169116615318565b610320516103a051939091906105ac600161054a6064610543818a06615994565b98046154e9565b602060405198826105648b945180928580880191016146ca565b8301610578825180938580850191016146ca565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810188520186614710565b61016061024001519561012061024001519760c061024001519560405161016052610140610160510161016051811067ffffffffffffffff821117614575576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457557604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260e06101605101516108ec6109cb60046007602760586106e3610100610160510151610160515190615a95565b60b76106ee5f615d85565b985f6102205260206102205261071660405161070d6102205182614710565b5f8152846157b3565b1561456b57601b60909a5b61072a8c6154e9565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161077081846102205188019801886146ca565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d382518093604284019061022051016146ca565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146ca565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109868251809361010f84019061022051016146ca565b0101661e17ba32bc3a1f60c91b838201526109ad82518093605f84019061022051016146ca565b0101631e17b39f60e11b838201520301601b19810184520182614710565b6101008301526101208201526101206101605101516108ec610a3960046007602760586040516109fe6102205182614710565b5f815260b7610a0d6001615d85565b98601b6028610a1b8c615e90565b610a2484615f08565b8082111561456457505b019a61072a8c6154e9565b61016083015261018082015260206101605101516108ec610a7a6004600760276058604051610a6b6102205182614710565b5f815260b7610a0d6002615d85565b8252602082015260286080610160510151604051610a9b6102205182614710565b5f81526108ec610ae56004600760276058610ab66003615d85565b9660b7610ac289615e90565b610acb8b615f08565b8082111561455c5750995b601b8c8c019a61072a8c6154e9565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7461010082015161016083015183519060a085015192614fb5565b60608201526101006101208190526040516101a0819052610b959190614710565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf7610200516101e051614710565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d638183614710565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119426118bd6073606b60405196610eec6101c05189614710565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113516101805160a051614710565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193d6014602261140a615a5a565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153f6025603589605e87519561022051890196611480818486018a6146ca565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e382518093609384019061022051016146ca565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614710565b61165685602361154d615a5a565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d6818486018a6146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161f82518093608e84019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614710565b6117e060726023611665615a5a565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f4815180928486019061022051016146ca565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173882609683018a6146ca565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614710565b6117e8615a5a565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119068251809360c484019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614710565b614fb5565b60e052611956611950614d46565b856157b3565b938415614541575b5060c061010081905260405191906119769083614710565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a538160c051614710565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432c57604051611dce6102205182614710565b5f8152955b156141d957604051611de76101e082614710565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b604051926120206107e085614710565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ef9183916032890191016146ca565b840160c051519060328101826102205160c0510191612a0d926146ca565b016032018082518093610220510191612a25926146ca565b018082518093610220510191612a3a926146ca565b018082518093610220510191612a4f926146ca565b01631e17b39f60e11b815203601b1981018452600401612a6f9084614710565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abf926146ca565b60805101815191826026830191610220510191612adb926146ca565b016026018082518093610220510191612af3926146ca565b0160a051519080826102205160a0510191612b0d926146ca565b0160e051519080826102205160e0510191612b27926146ca565b018082518093610220510191612b3c926146ca565b01610140515190808261022051610140510191612b58926146ca565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9a91614710565b6101605160a00151906101605160c00151916101605160400151906101605160600151612bc78583615cd9565b916040958651612bd78882614710565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614710565b612dc891615cd9565b928551612dd58782614710565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614710565b612fc08282615d40565b918651612fcd8882614710565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614710565b6131b791615d40565b9085516131c48782614710565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614710565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146ca565b840181519182604583019161022051019161342b926146ca565b016045018082518093610220510191613443926146ca565b018082518093610220510191613458926146ca565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614710565b610140820151916101a08101519060408101519060e001519361349d906154e9565b916134a7906154e9565b906134b1906154e9565b936134bb906154e9565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146ca565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146ca565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146ca565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146ca565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614710565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146ca565b84016080515190607b810182610220516080510191613855926146ca565b01607b01808251809361022051019161386d926146ca565b0191829151809361387d926146ca565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614710565b610380526102e0518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614710565b515a925f93928493fa61391c614793565b610340819052901580156103c0526141d15761022051818051810103126141bc5761022051015180151581036141bc575b15156102a052610260516102e05182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141c7575f9161417b575b50600360236139be613ad693614b1e565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146ca565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146ca565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146ca565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614710565b6103005161026051610320516102405191939291613afc906001600160a01b0316614b1e565b613b076024356154e9565b6102a051909190156140ef5761010051875190613b249082614710565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c696572204c6f636b757020000000000000009052805190610220518101918060598a0190613c5c91856146ca565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546059918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460798201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609982015284516102205186019691613cea8260b583018a6146ca565b01605901605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146ca565b01605c0190601282016302e3716960e51b905251918260168301613d50926146ca565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146ca565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146ca565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146ca565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146ca565b01600a0103600401601f1981018452613e2f9084614710565b61030051613e3e6024356154e9565b855180916102205182019367029b0b13634b2b9160c51b8552805190816028850191610220510191613e6f926146ca565b8201602881017f2023000000000000000000000000000000000000000000000000000000000000905281519182602a830191610220510191613eb0926146ca565b0160280103600201601f1981018252613ec99082614710565b61038051613ed690615648565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f1d926146ca565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f57926146ca565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fba926146ca565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614024926146ca565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d19810182526002016140679082614710565b6102c081905261407690615648565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bc926146ca565b810103603d01601f19810183526140d39083614710565b5180916102205182526102205182016140eb916146eb565b0390f35b86516140fc608082614710565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c0575b6141968183614710565b816102205191810103126141bc57516001600160a01b03811681036141bc5760036139ad565b5f80fd5b503d61418c565b83513d5f823e3d90fd5b50600161394d565b6040516141e861012082614710565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e00000000000000006101205182015290612010565b60405161433b6101c082614710565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd3565b61455591945061454f614d81565b906157b3565b925f61195e565b905099610ad6565b9050610a2e565b601b60d09a610721565b634e487b7160e01b5f52604160045260245ffd5b6145ab915060203d6020116145b1575b6145a38183614710565b81019061475a565b5f610519565b503d614599565b6040513d5f823e3d90fd5b6145dc915060203d6020116145b1576145a38183614710565b5f6104ba565b634e487b7160e01b5f52601260045260245ffd5b614618915060203d60201161461e575b6146108183614710565b810190614732565b5f61024e565b503d614606565b506020813d60201161465a575b8161463f60209383614710565b810103126141bc575160058110156141bc576101f5906101eb565b3d9150614632565b61467b915060203d60201161461e576146108183614710565b5f610191565b90506020813d6020116146c2575b8161469c60209383614710565b810103126141bc57516001600160a01b03811681036141bc576001600160a01b0361010f565b3d915061468f565b5f5b8381106146db5750505f910152565b81810151838201526020016146cc565b90602091614704815180928185528580860191016146ca565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457557604052565b908160209103126141bc57516fffffffffffffffffffffffffffffffff811681036141bc5790565b908160209103126141bc575164ffffffffff811681036141bc5790565b67ffffffffffffffff811161457557601f01601f191660200190565b3d156147bd573d906147a482614777565b916147b26040519384614710565b82523d5f602084013e565b606090565b6020818303126141bc5780519067ffffffffffffffff82116141bc570181601f820112156141bc5780516147f581614777565b926148036040519485614710565b818452602082840101116141bc5761482191602080850191016146ca565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145b8575f92614afa575b5060409161489483516148648582614710565b600e81527f5341422d4c4f434b55502d4c494e0000000000000000000000000000000000006020820152826157b3565b8015614ab5575b156148db5750506148ae81519182614710565b601581527f5361626c696572204c6f636b7570204c696e6561720000000000000000000000602082015290565b61491a83516148ea8582614710565b600e81527f5341422d4c4f434b55502d44594e0000000000000000000000000000000000006020820152826157b3565b8015614a70575b1561496157505061493481519182614710565b601681527f5361626c696572204c6f636b75702044796e616d696300000000000000000000602082015290565b6149a083516149708582614710565b600e81527f5341422d4c4f434b55502d5452410000000000000000000000000000000000006020820152826157b3565b8015614a2b575b156149e75750506149ba81519182614710565b601781527f5361626c696572204c6f636b7570205472616e63686564000000000000000000602082015290565b614a279083519384937f16ee429d0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146eb565b0390fd5b50614a6b8351614a3b8582614710565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826157b3565b6149a7565b50614ab08351614a808582614710565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826157b3565b614921565b50614af58351614ac58582614710565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826157b3565b61489b565b614b179192503d805f833e614b0f8183614710565b8101906147c2565b905f614851565b6001600160a01b03168060405191614b37606084614710565b602a8352602083016040368237835115614c065760309053825160011015614c06576078602184015360295b60018111614ba45750614b74575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614c06577f3031323334353637383961626364656600000000000000000000000000000000901a614bdf83866157e0565b5360041c908015614bf2575f1901614b63565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614c3e602482614710565b51915afa614c4a614793565b90158015614d3a575b614cfe5780602080614c6a935183010191016147c2565b601e8151115f14614cb15750604051614c84604082614710565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614cba816157f1565b15614cc25790565b50604051614cd1604082614710565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614d0d604082614710565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614c53565b60405190614d55604083614710565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614d90604083614710565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614ea85760048103614dd65750614821614d81565b60038103614e1a5750604051614ded604082614710565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614e5e5750604051614e31604082614710565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614e6d57614821614d46565b604051614e7b604082614710565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614ef9602482614710565b51915afa614f05614793565b9080614f34575b15614f2f576020818051810103126141bc576020015160ff811681036141bc5790565b505f90565b506020815114614f0c565b60405190614f4e604083614710565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614f89604083614710565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614fe09493615011602061502095615003828096816040519c8d8b83829d519485930191016146ca565b8901614ff4825180938580850191016146ca565b010191828151948592016146ca565b0191828151948592016146ca565b0103601f198101845283614710565b565b9081156152f757806152e757505b806001811015615099575050615044614f7a565b614821600260206040518461506282965180928580860191016146ca565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b66038d7ea4c680001115615289576040519060a0820182811067ffffffffffffffff821117614575576040526020916040516150d58482614710565b5f8152815260409182516150e98482614710565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516151228482614710565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161515b8482614710565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516151958482614710565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561526f578451946151df8187614710565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061525c575050600160fd1b602786015250600884526152439061523d90615238602887614710565b6154e9565b91615994565b916005851015614c06576148219460051b015192614fb5565b818101830151878201840152820161520c565b9490915060016103e86064600a85040693049101946151c8565b50615292614f3f565b61482160086020604051846152b082965180928580860191016146ca565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614710565b600a0a9081156145e25704615030565b5050604051615307604082614710565b60018152600360fc1b602082015290565b6201518091030480615382575061532d614f7a565b614821600660206040518461534b82965180928580860191016146ca565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614710565b61270f81116154595760018103615415576148216153d76040516153a7604082614710565b600481527f20446179000000000000000000000000000000000000000000000000000000006020820152926154e9565b602060405193826153f186945180928580880191016146ca565b8301615405825180938580850191016146ca565b010103601f198101835282614710565b6148216153d7604051615429604082614710565b600581527f20446179730000000000000000000000000000000000000000000000000000006020820152926154e9565b50615462614f3f565b614821600a60206040518461548082965180928580860191016146ca565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614710565b906154c182614777565b6154ce6040519182614710565b82815280926154df601f1991614777565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000821015615620575b806d04ee2d6d415b85acef8100000000600a921015615605575b662386f26fc100008110156155f1575b6305f5e1008110156155e0575b6127108110156155d1575b60648110156155c3575b10156155b8575b600a6021615573600185016154b7565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156155b357600a9091615578565b505090565b600190910190615563565b60646002910493019261555c565b61271060049104930192615552565b6305f5e10060089104930192615547565b662386f26fc100006010910493019261553a565b6d04ee2d6d415b85acef81000000006020910493019261552a565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008104615510565b9081511561579d576040519161565f606084614710565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614bf257600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614bf2576156f59060021b6154b7565b90602082019080815182019560208701908151925f83525b88811061574f575050600393949596505251068060011461573d57600214615733575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761570d565b90506040516157ad602082614710565b5f815290565b90815181519081811493846157ca575b5050505090565b602092939450820120920120145f8080806157c3565b908151811015614c06570160200190565b8051905f5b82811061580557505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061583082846157e0565b5116600160fd1b811490600360fc1b8110158061596a575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161593f575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615914575b84156158ea575b5083156158e2575b5082156158da575b5081156158d2575b50156158cb576001016157f6565b5050505f90565b90505f6158bd565b91505f6158b5565b92505f6158ad565b7f2d000000000000000000000000000000000000000000000000000000000000001493505f6158a5565b7f7a00000000000000000000000000000000000000000000000000000000000000811115935061589e565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615873565b507f3900000000000000000000000000000000000000000000000000000000000000811115615848565b806159a857506040516157ad602082614710565b600a811015615a0e576159ba906154e9565b614821602260405180937f2e3000000000000000000000000000000000000000000000000000000000000060208301526159fd81518092602086860191016146ca565b81010301601f198101835282614710565b615a17906154e9565b614821602160405180937f2e0000000000000000000000000000000000000000000000000000000000000060208301526159fd81518092602086860191016146ca565b60405190615a69604083614710565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615cc957615aa3615a5a565b9061271003906127108211614bf257602e6061916050615ac5614821956154e9565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615b52815180926020868a0191016146ca565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615bd982518093602060a7850191016146ca565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615c3a825180936020607e850191016146ca565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614710565b50506040516157ad602082614710565b600d6150209193929360206040519582615cfc88945180928580880191016146ca565b830164010714051160dd1b8382015267029b0b13634b2b9160c51b6025820152615d2f8251809385602d850191016146ca565b01010301601f198101845283614710565b60056150209193929360206040519582615d6388945180928580880191016146ca565b830164010714051160dd1b83820152615d2f82518093856025850191016146ca565b6004811015614ea85780615dcf5750604051615da2604082614710565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615e135750604051615de6604082614710565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615e5557604051615e28604082614710565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615e63604082614710565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156158cb5790600d915f925f925b828410615eb65750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615eea88856157e0565b511614615f00575b820194600101929190615ea3565b859450615ef2565b5f90805180156158cb57906010915f925f925b828410615f2e575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615f6288856157e0565b511614615f78575b820194600101929190615f1b565b859450615f6a56fea164736f6c634300081a000a"; + hex"60808060405234601557615f8d908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bc5760403660031901126141bc576001600160a01b036004351680600435036141bc576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614824565b61032052614b1e565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f91614681575b506001600160a01b0361012791168061024052614c1a565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8576fffffffffffffffffffffffffffffffff915f91614662575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8575f90614625575b6101f59150614dbc565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f916145f6575b50610280516fffffffffffffffffffffffffffffffff1680156145e2576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614710565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d166154e9565b9701166154e9565b9801166154e9565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146ca565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146ca565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146ca565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ebc565b1690615022565b9061045a6001600160a01b036102405116614b1e565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b8576024915f916145c3575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b85764ffffffffff8091610521945f91614589575b50169116615318565b610340516103a05190939091906105ac600161054a6064610543818806615994565b96046154e9565b6020604051968261056489945180928580880191016146ca565b8301610578825180938580850191016146ca565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614710565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614575576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457557604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c0610160510151610160515190615a95565b60b76106ed5f615d85565b985f6102205260206102205261071560405161070c6102205182614710565b5f8152846157b3565b1561456b57601b60909a5b6107298c6154e9565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146ca565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146ca565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146ca565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146ca565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146ca565b0101631e17b39f60e11b838201520301601b19810184520182614710565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614710565b5f815260b7610a0c6001615d85565b98601b6028610a1a8c615e90565b610a2384615f08565b8082111561456457505b019a6107298c6154e9565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614710565b5f815260b7610a0c6002615d85565b8252602082015260286080610160510151604051610a9a6102205182614710565b5f81526108eb610ae46004600760276058610ab56003615d85565b9660b7610ac189615e90565b610aca8b615f08565b8082111561455c5750995b601b8c8c019a6107298c6154e9565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614fb5565b60608201526101006101208190526040516101a0819052610b949190614710565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614710565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614710565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614710565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614710565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c60146022611409615a5a565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146ca565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146ca565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614710565b61165585602361154c615a5a565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614710565b6117df60726023611664615a5a565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146ca565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146ca565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614710565b6117e7615a5a565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614710565b614fb5565b60e05261195561194f614d46565b856157b3565b938415614541575b5060c061010081905260405191906119759083614710565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614710565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432c57604051611dcd6102205182614710565b5f8152955b156141d957604051611de66101e082614710565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614710565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146ca565b840160c051519060328101826102205160c0510191612a0c926146ca565b016032018082518093610220510191612a24926146ca565b018082518093610220510191612a39926146ca565b018082518093610220510191612a4e926146ca565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614710565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146ca565b60805101815191826026830191610220510191612ada926146ca565b016026018082518093610220510191612af2926146ca565b0160a051519080826102205160a0510191612b0c926146ca565b0160e051519080826102205160e0510191612b26926146ca565b018082518093610220510191612b3b926146ca565b01610140515190808261022051610140510191612b57926146ca565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614710565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615cd9565b916040958651612bd78882614710565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614710565b612dc891615cd9565b928551612dd58782614710565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614710565b612fc08282615d40565b918651612fcd8882614710565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614710565b6131b791615d40565b9085516131c48782614710565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614710565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146ca565b840181519182604583019161022051019161342b926146ca565b016045018082518093610220510191613443926146ca565b018082518093610220510191613458926146ca565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614710565b610140820151916101a08101519060408101519060e001519361349d906154e9565b916134a7906154e9565b906134b1906154e9565b936134bb906154e9565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146ca565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146ca565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146ca565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146ca565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614710565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146ca565b84016080515190607b810182610220516080510191613855926146ca565b01607b01808251809361022051019161386d926146ca565b0191829151809361387d926146ca565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614710565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614710565b515a925f93928493fa61391c614793565b6102e0819052901580156103c0526141d15761022051818051810103126141bc5761022051015180151581036141bc575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141c7575f9161417b575b50600360236139be613ad693614b1e565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146ca565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146ca565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146ca565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614710565b6103205161026051610340516102405191939291613afc906001600160a01b0316614b1e565b613b076024356154e9565b6102a051909190156140ef5761010051875190613b249082614710565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c696572204c6f636b757020000000000000009052805190610220518101918060598a0190613c5c91856146ca565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546059918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460798201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609982015284516102205186019691613cea8260b583018a6146ca565b01605901605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146ca565b01605c0190601282016302e3716960e51b905251918260168301613d50926146ca565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146ca565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146ca565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146ca565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146ca565b01600a0103600401601f1981018452613e2f9084614710565b61032051613e3e6024356154e9565b855180916102205182019367029b0b13634b2b9160c51b8552805190816028850191610220510191613e6f926146ca565b8201602881017f2023000000000000000000000000000000000000000000000000000000000000905281519182602a830191610220510191613eb0926146ca565b0160280103600201601f1981018252613ec99082614710565b61038051613ed690615648565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f1d926146ca565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f57926146ca565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fba926146ca565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614024926146ca565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d19810182526002016140679082614710565b6102c081905261407690615648565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bc926146ca565b810103603d01601f19810183526140d39083614710565b5180916102205182526102205182016140eb916146eb565b0390f35b86516140fc608082614710565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c0575b6141968183614710565b816102205191810103126141bc57516001600160a01b03811681036141bc5760036139ad565b5f80fd5b503d61418c565b83513d5f823e3d90fd5b50600161394d565b6040516141e861012082614710565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433b6101c082614710565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b61455591945061454f614d81565b906157b3565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ab915060203d6020116145b1575b6145a38183614710565b81019061475a565b5f610518565b503d614599565b6040513d5f823e3d90fd5b6145dc915060203d6020116145b1576145a38183614710565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b614618915060203d60201161461e575b6146108183614710565b810190614732565b5f61024e565b503d614606565b506020813d60201161465a575b8161463f60209383614710565b810103126141bc575160058110156141bc576101f5906101eb565b3d9150614632565b61467b915060203d60201161461e576146108183614710565b5f610191565b90506020813d6020116146c2575b8161469c60209383614710565b810103126141bc57516001600160a01b03811681036141bc576001600160a01b0361010f565b3d915061468f565b5f5b8381106146db5750505f910152565b81810151838201526020016146cc565b90602091614704815180928185528580860191016146ca565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457557604052565b908160209103126141bc57516fffffffffffffffffffffffffffffffff811681036141bc5790565b908160209103126141bc575164ffffffffff811681036141bc5790565b67ffffffffffffffff811161457557601f01601f191660200190565b3d156147bd573d906147a482614777565b916147b26040519384614710565b82523d5f602084013e565b606090565b6020818303126141bc5780519067ffffffffffffffff82116141bc570181601f820112156141bc5780516147f581614777565b926148036040519485614710565b818452602082840101116141bc5761482191602080850191016146ca565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145b8575f92614afa575b5060409161489483516148648582614710565b600e81527f5341422d4c4f434b55502d4c494e0000000000000000000000000000000000006020820152826157b3565b8015614ab5575b156148db5750506148ae81519182614710565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491a83516148ea8582614710565b600e81527f5341422d4c4f434b55502d44594e0000000000000000000000000000000000006020820152826157b3565b8015614a70575b1561496157505061493481519182614710565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b6149a083516149708582614710565b600e81527f5341422d4c4f434b55502d5452410000000000000000000000000000000000006020820152826157b3565b8015614a2b575b156149e75750506149ba81519182614710565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a279083519384937f7498e3a50000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146eb565b0390fd5b50614a6b8351614a3b8582614710565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826157b3565b6149a7565b50614ab08351614a808582614710565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826157b3565b614921565b50614af58351614ac58582614710565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826157b3565b61489b565b614b179192503d805f833e614b0f8183614710565b8101906147c2565b905f614851565b6001600160a01b03168060405191614b37606084614710565b602a8352602083016040368237835115614c065760309053825160011015614c06576078602184015360295b60018111614ba45750614b74575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614c06577f3031323334353637383961626364656600000000000000000000000000000000901a614bdf83866157e0565b5360041c908015614bf2575f1901614b63565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614c3e602482614710565b51915afa614c4a614793565b90158015614d3a575b614cfe5780602080614c6a935183010191016147c2565b601e8151115f14614cb15750604051614c84604082614710565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614cba816157f1565b15614cc25790565b50604051614cd1604082614710565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614d0d604082614710565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614c53565b60405190614d55604083614710565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614d90604083614710565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614ea85760048103614dd65750614821614d81565b60038103614e1a5750604051614ded604082614710565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614e5e5750604051614e31604082614710565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614e6d57614821614d46565b604051614e7b604082614710565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614ef9602482614710565b51915afa614f05614793565b9080614f34575b15614f2f576020818051810103126141bc576020015160ff811681036141bc5790565b505f90565b506020815114614f0c565b60405190614f4e604083614710565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614f89604083614710565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614fe09493615011602061502095615003828096816040519c8d8b83829d519485930191016146ca565b8901614ff4825180938580850191016146ca565b010191828151948592016146ca565b0191828151948592016146ca565b0103601f198101845283614710565b565b9081156152f757806152e757505b806001811015615099575050615044614f7a565b614821600260206040518461506282965180928580860191016146ca565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b66038d7ea4c680001115615289576040519060a0820182811067ffffffffffffffff821117614575576040526020916040516150d58482614710565b5f8152815260409182516150e98482614710565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516151228482614710565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161515b8482614710565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516151958482614710565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561526f578451946151df8187614710565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061525c575050600160fd1b602786015250600884526152439061523d90615238602887614710565b6154e9565b91615994565b916005851015614c06576148219460051b015192614fb5565b818101830151878201840152820161520c565b9490915060016103e86064600a85040693049101946151c8565b50615292614f3f565b61482160086020604051846152b082965180928580860191016146ca565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614710565b600a0a9081156145e25704615030565b5050604051615307604082614710565b60018152600360fc1b602082015290565b6201518091030480615382575061532d614f7a565b614821600660206040518461534b82965180928580860191016146ca565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614710565b61270f81116154595760018103615415576148216153d76040516153a7604082614710565b600481527f20446179000000000000000000000000000000000000000000000000000000006020820152926154e9565b602060405193826153f186945180928580880191016146ca565b8301615405825180938580850191016146ca565b010103601f198101835282614710565b6148216153d7604051615429604082614710565b600581527f20446179730000000000000000000000000000000000000000000000000000006020820152926154e9565b50615462614f3f565b614821600a60206040518461548082965180928580860191016146ca565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614710565b906154c182614777565b6154ce6040519182614710565b82815280926154df601f1991614777565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000821015615620575b806d04ee2d6d415b85acef8100000000600a921015615605575b662386f26fc100008110156155f1575b6305f5e1008110156155e0575b6127108110156155d1575b60648110156155c3575b10156155b8575b600a6021615573600185016154b7565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156155b357600a9091615578565b505090565b600190910190615563565b60646002910493019261555c565b61271060049104930192615552565b6305f5e10060089104930192615547565b662386f26fc100006010910493019261553a565b6d04ee2d6d415b85acef81000000006020910493019261552a565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008104615510565b9081511561579d576040519161565f606084614710565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614bf257600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614bf2576156f59060021b6154b7565b90602082019080815182019560208701908151925f83525b88811061574f575050600393949596505251068060011461573d57600214615733575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761570d565b90506040516157ad602082614710565b5f815290565b90815181519081811493846157ca575b5050505090565b602092939450820120920120145f8080806157c3565b908151811015614c06570160200190565b8051905f5b82811061580557505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061583082846157e0565b5116600160fd1b811490600360fc1b8110158061596a575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161593f575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615914575b84156158ea575b5083156158e2575b5082156158da575b5081156158d2575b50156158cb576001016157f6565b5050505f90565b90505f6158bd565b91505f6158b5565b92505f6158ad565b7f2d000000000000000000000000000000000000000000000000000000000000001493505f6158a5565b7f7a00000000000000000000000000000000000000000000000000000000000000811115935061589e565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615873565b507f3900000000000000000000000000000000000000000000000000000000000000811115615848565b806159a857506040516157ad602082614710565b600a811015615a0e576159ba906154e9565b614821602260405180937f2e3000000000000000000000000000000000000000000000000000000000000060208301526159fd81518092602086860191016146ca565b81010301601f198101835282614710565b615a17906154e9565b614821602160405180937f2e0000000000000000000000000000000000000000000000000000000000000060208301526159fd81518092602086860191016146ca565b60405190615a69604083614710565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615cc957615aa3615a5a565b9061271003906127108211614bf257602e6061916050615ac5614821956154e9565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615b52815180926020868a0191016146ca565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615bd982518093602060a7850191016146ca565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615c3a825180936020607e850191016146ca565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614710565b50506040516157ad602082614710565b600d6150209193929360206040519582615cfc88945180928580880191016146ca565b830164010714051160dd1b8382015267029b0b13634b2b9160c51b6025820152615d2f8251809385602d850191016146ca565b01010301601f198101845283614710565b60056150209193929360206040519582615d6388945180928580880191016146ca565b830164010714051160dd1b83820152615d2f82518093856025850191016146ca565b6004811015614ea85780615dcf5750604051615da2604082614710565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615e135750604051615de6604082614710565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615e5557604051615e28604082614710565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615e63604082614710565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156158cb5790600d915f925f925b828410615eb65750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615eea88856157e0565b511614615f00575b820194600101929190615ea3565b859450615ef2565b5f90805180156158cb57906010915f925f925b828410615f2e575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615f6288856157e0565b511614615f78575b820194600101929190615f1b565b859450615f6a56fea164736f6c634300081a000a"; uint256 public constant MAX_SEGMENT_COUNT = 500; uint256 public constant MAX_TRANCHE_COUNT = 500; @@ -182,9 +182,7 @@ contract Precompiles { } /// @notice Deploys all Core contracts. - function deployCore( - address initialAdmin - ) + function deployCore(address initialAdmin) public returns ( ILockupNFTDescriptor nftDescriptor, @@ -241,9 +239,7 @@ contract Precompiles { /// 4. {SablierLockupTranched} /// 5. {SablierBatchLockup} /// 6. {SablierMerkleFactory} - function deployProtocol( - address initialAdmin - ) + function deployProtocol(address initialAdmin) public returns ( ILockupNFTDescriptor nftDescriptor, diff --git a/src/core/abstracts/Adminable.sol b/src/core/abstracts/Adminable.sol index add9799a0..30108fb5e 100644 --- a/src/core/abstracts/Adminable.sol +++ b/src/core/abstracts/Adminable.sol @@ -26,6 +26,17 @@ abstract contract Adminable is IAdminable { _; } + /*////////////////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Emits a {TransferAdmin} event. + /// @param initialAdmin The address of the initial admin. + constructor(address initialAdmin) { + admin = initialAdmin; + emit TransferAdmin({ oldAdmin: address(0), newAdmin: initialAdmin }); + } + /*////////////////////////////////////////////////////////////////////////// USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/core/abstracts/SablierLockup.sol b/src/core/abstracts/SablierLockup.sol index 64fccd23f..a33041e87 100644 --- a/src/core/abstracts/SablierLockup.sol +++ b/src/core/abstracts/SablierLockup.sol @@ -51,10 +51,8 @@ abstract contract SablierLockup is /// @dev Emits a {TransferAdmin} event. /// @param initialAdmin The address of the initial contract admin. /// @param initialNFTDescriptor The address of the initial NFT descriptor. - constructor(address initialAdmin, ILockupNFTDescriptor initialNFTDescriptor) { - admin = initialAdmin; + constructor(address initialAdmin, ILockupNFTDescriptor initialNFTDescriptor) Adminable(initialAdmin) { nftDescriptor = initialNFTDescriptor; - emit TransferAdmin({ oldAdmin: address(0), newAdmin: initialAdmin }); } /*////////////////////////////////////////////////////////////////////////// diff --git a/src/periphery/SablierMerkleFactory.sol b/src/periphery/SablierMerkleFactory.sol index 925106339..ac8a20981 100644 --- a/src/periphery/SablierMerkleFactory.sol +++ b/src/periphery/SablierMerkleFactory.sol @@ -12,6 +12,7 @@ import { ISablierMerkleFactory } from "./interfaces/ISablierMerkleFactory.sol"; import { ISablierMerkleInstant } from "./interfaces/ISablierMerkleInstant.sol"; import { ISablierMerkleLL } from "./interfaces/ISablierMerkleLL.sol"; import { ISablierMerkleLT } from "./interfaces/ISablierMerkleLT.sol"; +import { Errors } from "./libraries/Errors.sol"; import { SablierMerkleInstant } from "./SablierMerkleInstant.sol"; import { SablierMerkleLL } from "./SablierMerkleLL.sol"; import { SablierMerkleLT } from "./SablierMerkleLT.sol"; @@ -28,10 +29,10 @@ contract SablierMerkleFactory is //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc ISablierMerkleFactory - uint256 public defaultSablierFee; + uint256 public override defaultSablierFee; /// @dev A mapping of custom Sablier fees by user. - mapping(address campaignCreator => MerkleFactory.SablierFee customFee) private _sablierFeeByUser; + mapping(address campaignCreator => MerkleFactory.SablierFeeByUser customFee) private _sablierFeeByUsers; /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR @@ -39,10 +40,7 @@ contract SablierMerkleFactory is /// @dev Emits a {TransferAdmin} event. /// @param initialAdmin The address of the initial contract admin. - constructor(address initialAdmin) { - admin = initialAdmin; - emit TransferAdmin({ oldAdmin: address(0), newAdmin: initialAdmin }); - } + constructor(address initialAdmin) Adminable(initialAdmin) { } /*////////////////////////////////////////////////////////////////////////// USER-FACING CONSTANT FUNCTIONS @@ -67,9 +65,9 @@ contract SablierMerkleFactory is external view override - returns (MerkleFactory.SablierFee memory) + returns (MerkleFactory.SablierFeeByUser memory) { - return _sablierFeeByUser[campaignCreator]; + return _sablierFeeByUsers[campaignCreator]; } /*////////////////////////////////////////////////////////////////////////// @@ -78,7 +76,7 @@ contract SablierMerkleFactory is /// @inheritdoc ISablierMerkleFactory function resetSablierFeeByUser(address campaignCreator) external override onlyAdmin { - delete _sablierFeeByUser[campaignCreator]; + delete _sablierFeeByUsers[campaignCreator]; // Log the reset. emit ResetSablierFee({ admin: msg.sender, campaignCreator: campaignCreator }); @@ -94,25 +92,30 @@ contract SablierMerkleFactory is /// @inheritdoc ISablierMerkleFactory function setSablierFeeByUser(address campaignCreator, uint256 fee) external override onlyAdmin { - MerkleFactory.SablierFee storage feeByUser = _sablierFeeByUser[campaignCreator]; + MerkleFactory.SablierFeeByUser storage feeByUser = _sablierFeeByUsers[campaignCreator]; - // If user does not belong to the custom fee list. + // Check: if user does not belong to the custom fee list. if (!feeByUser.enabled) feeByUser.enabled = true; // Effect: update the Sablier fee for the given campaign creator. feeByUser.fee = fee; // Log the update. - emit SetSablierFee({ admin: msg.sender, campaignCreator: campaignCreator, sablierFee: fee }); + emit SetSablierFeeForUser({ admin: msg.sender, campaignCreator: campaignCreator, sablierFee: fee }); } /// @inheritdoc ISablierMerkleFactory - function withdrawFees(address payable to, ISablierMerkleBase merkleLockup) external override onlyAdmin { - // Effect: call `withdrawFees` on the MerkleLockup contract. - uint256 fees = merkleLockup.withdrawFees(to); + function withdrawFees(address payable to, ISablierMerkleBase merkleBase) external override onlyAdmin { + // Check: the withdrawal address is not zero. + if (to == address(0)) { + revert Errors.SablierMerkleFactory_WithdrawToZeroAddress(); + } + + // Effect: call `withdrawFees` on the MerkleBase contract. + uint256 fees = merkleBase.withdrawFees(to); // Log the withdrawal. - emit WithdrawSablierFees({ admin: msg.sender, merkleLockup: merkleLockup, to: to, sablierFees: fees }); + emit WithdrawSablierFees({ admin: msg.sender, merkleBase: merkleBase, to: to, sablierFees: fees }); } /*////////////////////////////////////////////////////////////////////////// @@ -142,9 +145,8 @@ contract SablierMerkleFactory is ) ); - // Fetch the Sablier fee for the user, or use the default fee. - uint256 sablierFee = - _sablierFeeByUser[msg.sender].enabled ? _sablierFeeByUser[msg.sender].fee : defaultSablierFee; + // Compute the Sablier fee for the user. + uint256 sablierFee = _computeSablierFeeForUser(msg.sender); // Deploy the MerkleInstant contract with CREATE2. merkleInstant = new SablierMerkleInstant{ salt: salt }(baseParams, sablierFee); @@ -184,9 +186,8 @@ contract SablierMerkleFactory is ) ); - // Fetch the Sablier fee for the user, or use the default fee. - uint256 sablierFee = - _sablierFeeByUser[msg.sender].enabled ? _sablierFeeByUser[msg.sender].fee : defaultSablierFee; + // Compute the Sablier fee for the user. + uint256 sablierFee = _computeSablierFeeForUser(msg.sender); // Deploy the MerkleLL contract with CREATE2. merkleLL = @@ -247,6 +248,11 @@ contract SablierMerkleFactory is INTERNAL NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ + /// @dev Computes the Sablier fee for the user, use the default fee if not enabled. + function _computeSablierFeeForUser(address user) internal view returns (uint256) { + return _sablierFeeByUsers[user].enabled ? _sablierFeeByUsers[user].fee : defaultSablierFee; + } + /// @notice Deploys a new MerkleLT contract with CREATE2. /// @dev We need a separate function to prevent the stack too deep error. function _deployMerkleLT( @@ -278,9 +284,8 @@ contract SablierMerkleFactory is ) ); - // Fetch the Sablier fee for the user, or use the default fee. - uint256 sablierFee = - _sablierFeeByUser[msg.sender].enabled ? _sablierFeeByUser[msg.sender].fee : defaultSablierFee; + // Compute the Sablier fee for the user. + uint256 sablierFee = _computeSablierFeeForUser(msg.sender); // Deploy the MerkleLT contract with CREATE2. merkleLT = new SablierMerkleLT{ salt: salt }( diff --git a/src/periphery/abstracts/SablierMerkleBase.sol b/src/periphery/abstracts/SablierMerkleBase.sol index 10cac68e9..e96c992d0 100644 --- a/src/periphery/abstracts/SablierMerkleBase.sol +++ b/src/periphery/abstracts/SablierMerkleBase.sol @@ -30,7 +30,7 @@ abstract contract SablierMerkleBase is uint40 public immutable override EXPIRATION; /// @inheritdoc ISablierMerkleBase - address public immutable FACTORY; + address public immutable override FACTORY; /// @inheritdoc ISablierMerkleBase bytes32 public immutable override MERKLE_ROOT; @@ -39,10 +39,10 @@ abstract contract SablierMerkleBase is bytes32 internal immutable NAME; /// @inheritdoc ISablierMerkleBase - uint256 public immutable SABLIER_FEE; + uint256 public immutable override SABLIER_FEE; /// @inheritdoc ISablierMerkleBase - string public ipfsCID; + string public override ipfsCID; /// @dev Packed booleans that record the history of claims. BitMaps.BitMap internal _claimedBitMap; @@ -54,14 +54,14 @@ abstract contract SablierMerkleBase is CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - /// @dev Constructs the contract by initializing the immutable state variables. - constructor(MerkleBase.ConstructorParams memory params, uint256 sablierFee) { + /// @notice Constructs the contract by initializing the immutable state variables. + /// @dev Emits a {TransferAdmin} event. + constructor(MerkleBase.ConstructorParams memory params, uint256 sablierFee) Adminable(params.initialAdmin) { // Check: the campaign name is not greater than 32 bytes if (bytes(params.name).length > 32) { revert Errors.SablierMerkleBase_CampaignNameTooLong({ nameLength: bytes(params.name).length, maxLength: 32 }); } - admin = params.initialAdmin; ASSET = params.asset; EXPIRATION = params.expiration; FACTORY = msg.sender; @@ -115,7 +115,7 @@ abstract contract SablierMerkleBase is revert Errors.SablierMerkleBase_CampaignExpired({ blockTimestamp: block.timestamp, expiration: EXPIRATION }); } - // Check: `msg.value` is not less than the sablier fee. + // Check: `msg.value` is not less than the Sablier fee. if (msg.value < SABLIER_FEE) { revert Errors.SablierMerkleBase_InsufficientFeePayment(msg.value, SABLIER_FEE); } diff --git a/src/periphery/interfaces/ISablierMerkleBase.sol b/src/periphery/interfaces/ISablierMerkleBase.sol index d433f4123..bb371a407 100644 --- a/src/periphery/interfaces/ISablierMerkleBase.sol +++ b/src/periphery/interfaces/ISablierMerkleBase.sol @@ -34,7 +34,7 @@ interface ISablierMerkleBase is IAdminable { /// @dev This is an immutable state variable. function MERKLE_ROOT() external returns (bytes32); - /// @notice Retrieves the minimum fee required to claim Airstream, paid in ETH. + /// @notice Retrieves the minimum fee required to claim an Airstream, paid in ETH. function SABLIER_FEE() external view returns (uint256); /// @notice Returns the timestamp when the first claim is made. @@ -95,7 +95,7 @@ interface ISablierMerkleBase is IAdminable { /// receive ETH. /// /// Requirements: - /// - The caller must be the Factory contract. + /// - The caller must be the `FACTORY` contract. /// /// @param to The address to receive the Sablier fees. /// @return feeAmount The amount of ETH transferred to the provided address. diff --git a/src/periphery/interfaces/ISablierMerkleFactory.sol b/src/periphery/interfaces/ISablierMerkleFactory.sol index 133025558..febd001e4 100644 --- a/src/periphery/interfaces/ISablierMerkleFactory.sol +++ b/src/periphery/interfaces/ISablierMerkleFactory.sol @@ -64,11 +64,11 @@ interface ISablierMerkleFactory is IAdminable { event SetDefaultSablierFee(address indexed admin, uint256 defaultSablierFee); /// @notice Emitted when the admin sets Sablier fee for a specific user. - event SetSablierFee(address indexed admin, address indexed campaignCreator, uint256 sablierFee); + event SetSablierFeeForUser(address indexed admin, address indexed campaignCreator, uint256 sablierFee); - /// @notice Emitted when the sablier fees are claimed by the sablier admin. + /// @notice Emitted when the Sablier fees are claimed by the Sablier admin. event WithdrawSablierFees( - address indexed admin, ISablierMerkleBase indexed merkleLockup, address to, uint256 sablierFees + address indexed admin, ISablierMerkleBase indexed merkleBase, address to, uint256 sablierFees ); /*////////////////////////////////////////////////////////////////////////// @@ -84,17 +84,13 @@ interface ISablierMerkleFactory is IAdminable { pure returns (bool result); - /// @notice Retrieves the default sablier fee required to claim an airstream. - /// @dev A minimum of this fee must be paid in ETH during `claim`. + /// @notice Retrieves the default Sablier fee required to claim an airstream. + /// @dev A minimum of this fee must be paid in ETH during {SablierMerkleBase.claim}. function defaultSablierFee() external view returns (uint256); - /// @notice Retrieves the custom sablier fee struct for a specified campaign creator. - /// @dev It return two fields: - /// - `enabled` indicates if the custom fee is enabled. If it is not enabled, the default fee will be used for - /// campaigns. - /// - `fee` is the custom fee set by the admin. - /// @param campaignCreator The user for whom the details are being queried. - function sablierFeeByUser(address campaignCreator) external view returns (MerkleFactory.SablierFee memory); + /// @notice Retrieves the custom Sablier fee struct for a specified campaign creator. + /// @param campaignCreator the address of the user for whom the details are being retrieved. + function sablierFeeByUser(address campaignCreator) external view returns (MerkleFactory.SablierFeeByUser memory); /*////////////////////////////////////////////////////////////////////////// NON-CONSTANT FUNCTIONS @@ -106,7 +102,7 @@ interface ISablierMerkleFactory is IAdminable { /// /// Notes: /// - The MerkleInstant contract is created with CREATE2. - /// - The immutable sablier fee will be set to the default value unless a custom fee is set. + /// - The immutable Sablier fee will be set to the default value unless a custom fee is set. /// /// @param baseParams Struct encapsulating the {SablierMerkleBase} parameters, which are documented in /// {DataTypes}. @@ -127,7 +123,7 @@ interface ISablierMerkleFactory is IAdminable { /// /// Notes: /// - The MerkleLL contract is created with CREATE2. - /// - The immutable sablier fee will be set to the default value unless a custom fee is set. + /// - The immutable Sablier fee will be set to the default value unless a custom fee is set. /// /// @param baseParams Struct encapsulating the {SablierMerkleBase} parameters, which are documented in /// {DataTypes}. @@ -156,14 +152,14 @@ interface ISablierMerkleFactory is IAdminable { /// /// Notes: /// - The MerkleLT contract is created with CREATE2. - /// - The immutable sablier fee will be set to the default value unless a custom fee is set. + /// - The immutable Sablier fee will be set to the default value unless a custom fee is set. /// /// @param baseParams Struct encapsulating the {SablierMerkleBase} parameters, which are documented in /// {DataTypes}. /// @param lockupTranched The address of the {SablierLockupTranched} contract. /// @param cancelable Indicates if the stream will be cancelable after claiming. /// @param transferable Indicates if the stream will be transferable after claiming. - /// @param streamStartTime The start time of the streams created through `claim`. + /// @param streamStartTime The start time of the streams created through {SablierMerkleBase.claim}. /// @param tranchesWithPercentages The tranches with their respective unlock percentages. /// @param aggregateAmount The total amount of ERC-20 assets to be distributed to all recipients. /// @param recipientCount The total number of recipients who are eligible to claim. @@ -187,7 +183,7 @@ interface ISablierMerkleFactory is IAdminable { /// Notes: /// - The default fee will only be applied to the future campaigns. /// - /// Requiurements: + /// Requirements: /// - The caller must be the admin. /// /// @param campaignCreator The user for whom the fee is being reset for. @@ -199,7 +195,7 @@ interface ISablierMerkleFactory is IAdminable { /// Notes: /// - The new fee will only be applied to the future campaigns. /// - /// Requiurements: + /// Requirements: /// - The caller must be the admin. /// /// @param campaignCreator The user for whom the fee is being set. @@ -212,13 +208,13 @@ interface ISablierMerkleFactory is IAdminable { /// Notes: /// - The new default fee will only be applied to the future campaigns. /// - /// Requiurements: + /// Requirements: /// - The caller must be the admin. /// /// @param defaultFee The new detault fee to be set. function setDefaultSablierFee(uint256 defaultFee) external; - /// @notice Withdraws the Sablier fees accrued on `merkleLockup` to the provided address. + /// @notice Withdraws the Sablier fees accrued on `merkleBase` contract. /// @dev Emits a {WithdrawSablierFees} event. /// /// Notes: @@ -227,7 +223,8 @@ interface ISablierMerkleFactory is IAdminable { /// /// Requirements: /// - The caller must be the admin. + /// - `to` must not be the zero address. /// /// @param to The address to receive the Sablier fees. - function withdrawFees(address payable to, ISablierMerkleBase merkleLockup) external; + function withdrawFees(address payable to, ISablierMerkleBase merkleBase) external; } diff --git a/src/periphery/interfaces/ISablierMerkleLT.sol b/src/periphery/interfaces/ISablierMerkleLT.sol index 0290cbbf2..2bdb39bea 100644 --- a/src/periphery/interfaces/ISablierMerkleLT.sol +++ b/src/periphery/interfaces/ISablierMerkleLT.sol @@ -26,7 +26,7 @@ interface ISablierMerkleLT is ISablierMerkleBase { /// @notice The address of the {SablierLockupTranched} contract. function LOCKUP_TRANCHED() external view returns (ISablierLockupTranched); - /// @notice The start time of the streams created through `claim` function. + /// @notice The start time of the streams created through {SablierMerkleBase.claim} function. /// @dev A start time value of zero will be considered as `block.timestamp`. function STREAM_START_TIME() external returns (uint40); diff --git a/src/periphery/libraries/Errors.sol b/src/periphery/libraries/Errors.sol index a0f010e37..813f4aed3 100644 --- a/src/periphery/libraries/Errors.sol +++ b/src/periphery/libraries/Errors.sol @@ -10,6 +10,12 @@ library Errors { error SablierBatchLockup_BatchSizeZero(); + /*////////////////////////////////////////////////////////////////////////// + SABLIER-MERKLE-FACTORY + //////////////////////////////////////////////////////////////////////////*/ + + error SablierMerkleFactory_WithdrawToZeroAddress(); + /*////////////////////////////////////////////////////////////////////////// SABLIER-MERKLE-BASE //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/periphery/types/DataTypes.sol b/src/periphery/types/DataTypes.sol index 016e5822b..5a1db1e3b 100644 --- a/src/periphery/types/DataTypes.sol +++ b/src/periphery/types/DataTypes.sol @@ -105,7 +105,7 @@ library MerkleFactory { /// @param enabled Whether the fee is enabled. If false, the default fee will be applied for campaigns created by /// the given creator. /// @param fee The fee amount. - struct SablierFee { + struct SablierFeeByUser { bool enabled; uint256 fee; } diff --git a/test/mocks/AdminableMock.sol b/test/mocks/AdminableMock.sol index f8359a2b6..1b1d81bb1 100644 --- a/test/mocks/AdminableMock.sol +++ b/test/mocks/AdminableMock.sol @@ -2,11 +2,7 @@ pragma solidity >=0.8.22; import { Adminable } from "src/core/abstracts/Adminable.sol"; -import { IAdminable } from "src/core/interfaces/IAdminable.sol"; contract AdminableMock is Adminable { - constructor(address initialAdmin) { - admin = initialAdmin; - emit IAdminable.TransferAdmin({ oldAdmin: address(0), newAdmin: initialAdmin }); - } + constructor(address initialAdmin) Adminable(initialAdmin) { } } diff --git a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol index cbca6f208..f8e1b15ba 100644 --- a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol @@ -222,11 +222,11 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test { vm.expectEmit({ emitter: address(merkleFactory) }); emit WithdrawSablierFees({ admin: users.admin, - merkleLockup: vars.merkleInstant, + merkleBase: vars.merkleInstant, to: users.admin, sablierFees: sablierFee }); - merkleFactory.withdrawFees({ to: payable(users.admin), merkleLockup: vars.merkleInstant }); + merkleFactory.withdrawFees({ to: payable(users.admin), merkleBase: vars.merkleInstant }); assertEq(address(vars.merkleInstant).balance, 0, "merkle lockup ether balance"); assertEq(users.admin.balance, sablierFee, "admin ether balance"); diff --git a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol index 82ebf6fd1..69d71e538 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol @@ -244,11 +244,11 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { vm.expectEmit({ emitter: address(merkleFactory) }); emit WithdrawSablierFees({ admin: users.admin, - merkleLockup: vars.merkleLL, + merkleBase: vars.merkleLL, to: users.admin, sablierFees: sablierFee }); - merkleFactory.withdrawFees({ to: payable(users.admin), merkleLockup: vars.merkleLL }); + merkleFactory.withdrawFees({ to: payable(users.admin), merkleBase: vars.merkleLL }); assertEq(address(vars.merkleLL).balance, 0, "merkle lockup ether balance"); assertEq(users.admin.balance, sablierFee, "admin ether balance"); diff --git a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol index 099bd5d4c..383e3baa0 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol @@ -251,11 +251,11 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { vm.expectEmit({ emitter: address(merkleFactory) }); emit WithdrawSablierFees({ admin: users.admin, - merkleLockup: vars.merkleLT, + merkleBase: vars.merkleLT, to: users.admin, sablierFees: sablierFee }); - merkleFactory.withdrawFees({ to: payable(users.admin), merkleLockup: vars.merkleLT }); + merkleFactory.withdrawFees({ to: payable(users.admin), merkleBase: vars.merkleLT }); assertEq(address(vars.merkleLT).balance, 0, "merkle lockup ether balance"); assertEq(users.admin.balance, sablierFee, "admin ether balance"); diff --git a/test/periphery/integration/merkle-campaign/factory/reset-fee-by-user/resetSablierFeeByUser.t.sol b/test/periphery/integration/merkle-campaign/factory/reset-fee-by-user/resetSablierFeeByUser.t.sol index fe92993ce..30c952231 100644 --- a/test/periphery/integration/merkle-campaign/factory/reset-fee-by-user/resetSablierFeeByUser.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/reset-fee-by-user/resetSablierFeeByUser.t.sol @@ -22,7 +22,7 @@ contract ResetSablierFeeByUser_Integration_Test is MerkleCampaign_Integration_Sh // Reset the Sablier fee. merkleFactory.resetSablierFeeByUser({ campaignCreator: users.campaignOwner }); - MerkleFactory.SablierFee memory sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); + MerkleFactory.SablierFeeByUser memory sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); // It should return false. assertFalse(sablierFee.enabled, "enabled"); // It should return 0 for the Sablier fee. @@ -33,7 +33,7 @@ contract ResetSablierFeeByUser_Integration_Test is MerkleCampaign_Integration_Sh // Enable the Sablier fee. merkleFactory.setSablierFeeByUser({ campaignCreator: users.campaignOwner, fee: 1 ether }); // Check that its enabled. - MerkleFactory.SablierFee memory sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); + MerkleFactory.SablierFeeByUser memory sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); assertTrue(sablierFee.enabled, "enabled"); assertEq(sablierFee.fee, 1 ether, "fee"); diff --git a/test/periphery/integration/merkle-campaign/factory/set-fee-by-user/setSablierFeeByUser.t.sol b/test/periphery/integration/merkle-campaign/factory/set-fee-by-user/setSablierFeeByUser.t.sol index 109efeba0..11ab7ee8d 100644 --- a/test/periphery/integration/merkle-campaign/factory/set-fee-by-user/setSablierFeeByUser.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/set-fee-by-user/setSablierFeeByUser.t.sol @@ -17,12 +17,12 @@ contract SetSablierFeeByUser_Integration_Test is MerkleCampaign_Integration_Shar function test_WhenNotEnabled() external whenCallerAdmin { // It should emit a {SetSablierFee} event. vm.expectEmit({ emitter: address(merkleFactory) }); - emit SetSablierFee({ admin: users.admin, campaignCreator: users.campaignOwner, sablierFee: 0 }); + emit SetSablierFeeForUser({ admin: users.admin, campaignCreator: users.campaignOwner, sablierFee: 0 }); // Set the Sablier fee. merkleFactory.setSablierFeeByUser({ campaignCreator: users.campaignOwner, fee: 0 }); - MerkleFactory.SablierFee memory sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); + MerkleFactory.SablierFeeByUser memory sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); // It should enable the Sablier fee. assertTrue(sablierFee.enabled, "enabled"); // It should set the Sablier fee. @@ -33,13 +33,13 @@ contract SetSablierFeeByUser_Integration_Test is MerkleCampaign_Integration_Shar // Enable the Sablier fee. merkleFactory.setSablierFeeByUser({ campaignCreator: users.campaignOwner, fee: 0.001 ether }); // Check that its enabled. - MerkleFactory.SablierFee memory sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); + MerkleFactory.SablierFeeByUser memory sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); assertTrue(sablierFee.enabled, "enabled"); assertEq(sablierFee.fee, 0.001 ether, "fee"); // It should emit a {SetSablierFee} event. vm.expectEmit({ emitter: address(merkleFactory) }); - emit SetSablierFee({ admin: users.admin, campaignCreator: users.campaignOwner, sablierFee: 1 ether }); + emit SetSablierFeeForUser({ admin: users.admin, campaignCreator: users.campaignOwner, sablierFee: 1 ether }); // Now set it to another fee. merkleFactory.setSablierFeeByUser({ campaignCreator: users.campaignOwner, fee: 1 ether }); diff --git a/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.t.sol b/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.t.sol index 94649fb45..2df226547 100644 --- a/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.t.sol @@ -26,7 +26,16 @@ contract WithdrawFees_Integration_Test is MerkleCampaign_Integration_Shared_Test merkleFactory.withdrawFees(users.eve, merkleBase); } - function test_RevertWhen_ProvidedMerkleLockupNotValid() external whenCallerAdmin { + function test_RevertWhen_WithdrawalAddressZero() external whenCallerAdmin { + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleFactory_WithdrawToZeroAddress.selector)); + merkleFactory.withdrawFees(payable(address(0)), merkleBase); + } + + modifier whenWithdrawalAddressNotZero() { + _; + } + + function test_RevertWhen_ProvidedMerkleLockupNotValid() external whenCallerAdmin whenWithdrawalAddressNotZero { vm.expectRevert(); merkleFactory.withdrawFees(users.eve, ISablierMerkleBase(users.eve)); } @@ -42,7 +51,7 @@ contract WithdrawFees_Integration_Test is MerkleCampaign_Integration_Shared_Test vm.expectEmit({ emitter: address(merkleFactory) }); emit WithdrawSablierFees({ admin: users.admin, - merkleLockup: merkleBase, + merkleBase: merkleBase, to: users.eve, sablierFees: defaults.DEFAULT_SABLIER_FEE() }); @@ -86,7 +95,7 @@ contract WithdrawFees_Integration_Test is MerkleCampaign_Integration_Shared_Test vm.expectEmit({ emitter: address(merkleFactory) }); emit WithdrawSablierFees({ admin: users.admin, - merkleLockup: merkleBase, + merkleBase: merkleBase, to: receiveEth, sablierFees: defaults.DEFAULT_SABLIER_FEE() }); diff --git a/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.tree b/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.tree index 4f871faaf..e07cc3fba 100644 --- a/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.tree +++ b/test/periphery/integration/merkle-campaign/factory/withdraw-fees/withdrawFees.tree @@ -2,17 +2,20 @@ WithdrawFees_Integration_Test ├── when caller not admin │ └── it should revert └── when caller admin - ├── when provided merkle lockup not valid + ├── when withdrawal address zero │ └── it should revert - └── when provided merkle lockup valid - ├── when provided address not contract - │ ├── it should transfer fee collected in ETH to the provided address - │ ├── it should set the ETH balance to 0 - │ └── it should emit {WithdrawSablierFees} event - └── when provided address contract - ├── when provided address not implement receive eth - │ └── it should revert - └── when provided address implement receive eth - ├── it should transfer fee collected in ETH to the provided address - ├── it should set the ETH balance to 0 - └── it should emit {WithdrawSablierFees} event + └── when withdrawal address not zero + ├── when provided merkle lockup not valid + │ └── it should revert + └── when provided merkle lockup valid + ├── when provided address not contract + │ ├── it should transfer fee collected in ETH to the provided address + │ ├── it should set the ETH balance to 0 + │ └── it should emit {WithdrawSablierFees} event + └── when provided address contract + ├── when provided address not implement receive eth + │ └── it should revert + └── when provided address implement receive eth + ├── it should transfer fee collected in ETH to the provided address + ├── it should set the ETH balance to 0 + └── it should emit {WithdrawSablierFees} event diff --git a/test/utils/Events.sol b/test/utils/Events.sol index b09b16b32..6b1584593 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -143,9 +143,9 @@ abstract contract Events { event SetDefaultSablierFee(address indexed admin, uint256 sablierFee); - event SetSablierFee(address indexed admin, address indexed campaignCreator, uint256 sablierFee); + event SetSablierFeeForUser(address indexed admin, address indexed campaignCreator, uint256 sablierFee); event WithdrawSablierFees( - address indexed admin, ISablierMerkleBase indexed merkleLockup, address to, uint256 sablierFees + address indexed admin, ISablierMerkleBase indexed merkleBase, address to, uint256 sablierFees ); } From 155401cfafa1e2e76c64f4b23a6ec53ede5b91d9 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 16 Oct 2024 11:25:55 +0100 Subject: [PATCH 16/21] docs: replace caller with msg.sender --- src/periphery/abstracts/SablierMerkleBase.sol | 2 +- src/periphery/interfaces/ISablierMerkleBase.sol | 4 ++-- src/periphery/interfaces/ISablierMerkleFactory.sol | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/periphery/abstracts/SablierMerkleBase.sol b/src/periphery/abstracts/SablierMerkleBase.sol index e96c992d0..7c8c8e6a0 100644 --- a/src/periphery/abstracts/SablierMerkleBase.sol +++ b/src/periphery/abstracts/SablierMerkleBase.sol @@ -166,7 +166,7 @@ abstract contract SablierMerkleBase is /// @inheritdoc ISablierMerkleBase function withdrawFees(address payable to) external override returns (uint256 feeAmount) { - // Check: the caller is the factory. + // Check: the msg.sender is the FACTORY. if (msg.sender != FACTORY) { revert Errors.SablierMerkleBase_CallerNotFactory(FACTORY, msg.sender); } diff --git a/src/periphery/interfaces/ISablierMerkleBase.sol b/src/periphery/interfaces/ISablierMerkleBase.sol index bb371a407..63ee9d8f5 100644 --- a/src/periphery/interfaces/ISablierMerkleBase.sol +++ b/src/periphery/interfaces/ISablierMerkleBase.sol @@ -80,7 +80,7 @@ interface ISablierMerkleBase is IAdminable { /// @dev Emits a {Clawback} event. /// /// Requirements: - /// - The caller must be the admin. + /// - msg.sender must be the admin. /// - No claim must be made, OR /// The current timestamp must not exceed 7 days after the first claim, OR /// The campaign must be expired. @@ -95,7 +95,7 @@ interface ISablierMerkleBase is IAdminable { /// receive ETH. /// /// Requirements: - /// - The caller must be the `FACTORY` contract. + /// - msg.sender must be the `FACTORY` contract. /// /// @param to The address to receive the Sablier fees. /// @return feeAmount The amount of ETH transferred to the provided address. diff --git a/src/periphery/interfaces/ISablierMerkleFactory.sol b/src/periphery/interfaces/ISablierMerkleFactory.sol index febd001e4..1df442b9b 100644 --- a/src/periphery/interfaces/ISablierMerkleFactory.sol +++ b/src/periphery/interfaces/ISablierMerkleFactory.sol @@ -184,7 +184,7 @@ interface ISablierMerkleFactory is IAdminable { /// - The default fee will only be applied to the future campaigns. /// /// Requirements: - /// - The caller must be the admin. + /// - msg.sender must be the admin. /// /// @param campaignCreator The user for whom the fee is being reset for. function resetSablierFeeByUser(address campaignCreator) external; @@ -196,7 +196,7 @@ interface ISablierMerkleFactory is IAdminable { /// - The new fee will only be applied to the future campaigns. /// /// Requirements: - /// - The caller must be the admin. + /// - msg.sender must be the admin. /// /// @param campaignCreator The user for whom the fee is being set. /// @param fee The new fee to be set. @@ -209,7 +209,7 @@ interface ISablierMerkleFactory is IAdminable { /// - The new default fee will only be applied to the future campaigns. /// /// Requirements: - /// - The caller must be the admin. + /// - msg.sender must be the admin. /// /// @param defaultFee The new detault fee to be set. function setDefaultSablierFee(uint256 defaultFee) external; @@ -222,7 +222,7 @@ interface ISablierMerkleFactory is IAdminable { /// ETH. /// /// Requirements: - /// - The caller must be the admin. + /// - msg.sender must be the admin. /// - `to` must not be the zero address. /// /// @param to The address to receive the Sablier fees. From cf0990ec2468368758f8e90e500b9e291ff83949 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Wed, 23 Oct 2024 16:22:36 +0300 Subject: [PATCH 17/21] small polishes --- test/Base.t.sol | 32 +++++++++---------- .../createMerkleInstant.t.sol | 2 ++ .../create-merkle-ll/createMerkleLL.t.sol | 2 ++ .../resetSablierFeeByUser.t.sol | 10 ++++-- .../set-fee-by-user/setSablierFeeByUser.t.sol | 4 +++ .../merkle-campaign/shared/claim/claim.tree | 4 +-- 6 files changed, 34 insertions(+), 20 deletions(-) diff --git a/test/Base.t.sol b/test/Base.t.sol index a2835f07d..4c265ab45 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -223,22 +223,6 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi }); } - /*////////////////////////////////////////////////////////////////////////// - CALL EXPECTS - MERKLE LOCKUP - //////////////////////////////////////////////////////////////////////////*/ - - /// @dev Expects a call to {ISablierMerkleBase.claim} with msgValue as `msg.value`. - function expectCallToClaimWithMsgValue(address merkleLockup, uint256 msgValue) internal { - vm.expectCall( - merkleLockup, - msgValue, - abi.encodeCall( - ISablierMerkleBase.claim, - (defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), defaults.index1Proof()) - ) - ); - } - /*////////////////////////////////////////////////////////////////////////// CALL EXPECTS - LOCKUP //////////////////////////////////////////////////////////////////////////*/ @@ -332,4 +316,20 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi data: abi.encodeCall(ISablierLockupTranched.createWithTimestamps, (params)) }); } + + /*////////////////////////////////////////////////////////////////////////// + CALL EXPECTS - MERKLE LOCKUP + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Expects a call to {ISablierMerkleBase.claim} with msgValue as `msg.value`. + function expectCallToClaimWithMsgValue(address merkleLockup, uint256 msgValue) internal { + vm.expectCall( + merkleLockup, + msgValue, + abi.encodeCall( + ISablierMerkleBase.claim, + (defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), defaults.index1Proof()) + ) + ); + } } diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol b/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol index f6e1c36b3..24e34c27e 100644 --- a/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol @@ -91,6 +91,7 @@ contract CreateMerkleInstant_Integration_Test is MerkleCampaign_Integration_Test // It should create the campaign with custom fee. assertEq(actualInstant.SABLIER_FEE(), customFee, "sablier fee"); + // It should set the current factory address. assertEq(actualInstant.FACTORY(), address(merkleFactory), "factory"); } @@ -129,6 +130,7 @@ contract CreateMerkleInstant_Integration_Test is MerkleCampaign_Integration_Test // It should create the campaign with custom fee. assertEq(actualInstant.SABLIER_FEE(), defaults.DEFAULT_SABLIER_FEE(), "default sablier fee"); + // It should set the current factory address. assertEq(actualInstant.FACTORY(), address(merkleFactory), "factory"); } diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol b/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol index 096803efa..4db06a9b8 100644 --- a/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol @@ -107,6 +107,7 @@ contract CreateMerkleLL_Integration_Test is MerkleCampaign_Integration_Test { // It should create the campaign with custom fee. assertEq(actualLL.SABLIER_FEE(), customFee, "sablier fee"); + // It should set the current factory address. assertEq(actualLL.FACTORY(), address(merkleFactory), "factory"); } @@ -147,6 +148,7 @@ contract CreateMerkleLL_Integration_Test is MerkleCampaign_Integration_Test { // It should create the campaign with custom fee. assertEq(actualLL.SABLIER_FEE(), defaults.DEFAULT_SABLIER_FEE(), "default sablier fee"); + // It should set the current factory address. assertEq(actualLL.FACTORY(), address(merkleFactory), "factory"); } diff --git a/test/periphery/integration/merkle-campaign/factory/reset-fee-by-user/resetSablierFeeByUser.t.sol b/test/periphery/integration/merkle-campaign/factory/reset-fee-by-user/resetSablierFeeByUser.t.sol index 30c952231..ba4031e7e 100644 --- a/test/periphery/integration/merkle-campaign/factory/reset-fee-by-user/resetSablierFeeByUser.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/reset-fee-by-user/resetSablierFeeByUser.t.sol @@ -23,8 +23,10 @@ contract ResetSablierFeeByUser_Integration_Test is MerkleCampaign_Integration_Sh merkleFactory.resetSablierFeeByUser({ campaignCreator: users.campaignOwner }); MerkleFactory.SablierFeeByUser memory sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); + // It should return false. assertFalse(sablierFee.enabled, "enabled"); + // It should return 0 for the Sablier fee. assertEq(sablierFee.fee, 0, "fee"); } @@ -32,8 +34,10 @@ contract ResetSablierFeeByUser_Integration_Test is MerkleCampaign_Integration_Sh function test_WhenEnabled() external whenCallerAdmin { // Enable the Sablier fee. merkleFactory.setSablierFeeByUser({ campaignCreator: users.campaignOwner, fee: 1 ether }); + // Check that its enabled. MerkleFactory.SablierFeeByUser memory sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); + assertTrue(sablierFee.enabled, "enabled"); assertEq(sablierFee.fee, 1 ether, "fee"); @@ -45,9 +49,11 @@ contract ResetSablierFeeByUser_Integration_Test is MerkleCampaign_Integration_Sh merkleFactory.resetSablierFeeByUser({ campaignCreator: users.campaignOwner }); sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); - // it should disable the Sablier fee + + // It should disable the Sablier fee assertFalse(sablierFee.enabled, "enabled"); - // it should set the Sablier fee to 0 + + // It should set the Sablier fee to 0 assertEq(sablierFee.fee, 0, "fee"); } } diff --git a/test/periphery/integration/merkle-campaign/factory/set-fee-by-user/setSablierFeeByUser.t.sol b/test/periphery/integration/merkle-campaign/factory/set-fee-by-user/setSablierFeeByUser.t.sol index 11ab7ee8d..ac741d61d 100644 --- a/test/periphery/integration/merkle-campaign/factory/set-fee-by-user/setSablierFeeByUser.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/set-fee-by-user/setSablierFeeByUser.t.sol @@ -23,8 +23,10 @@ contract SetSablierFeeByUser_Integration_Test is MerkleCampaign_Integration_Shar merkleFactory.setSablierFeeByUser({ campaignCreator: users.campaignOwner, fee: 0 }); MerkleFactory.SablierFeeByUser memory sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); + // It should enable the Sablier fee. assertTrue(sablierFee.enabled, "enabled"); + // It should set the Sablier fee. assertEq(sablierFee.fee, 0, "fee"); } @@ -45,8 +47,10 @@ contract SetSablierFeeByUser_Integration_Test is MerkleCampaign_Integration_Shar merkleFactory.setSablierFeeByUser({ campaignCreator: users.campaignOwner, fee: 1 ether }); sablierFee = merkleFactory.sablierFeeByUser(users.campaignOwner); + // It should enable the Sablier fee. assertTrue(sablierFee.enabled, "enabled"); + // It should set the Sablier fee. assertEq(sablierFee.fee, 1 ether, "fee"); } diff --git a/test/periphery/integration/merkle-campaign/shared/claim/claim.tree b/test/periphery/integration/merkle-campaign/shared/claim/claim.tree index 849cf9e49..c93188b3d 100644 --- a/test/periphery/integration/merkle-campaign/shared/claim/claim.tree +++ b/test/periphery/integration/merkle-campaign/shared/claim/claim.tree @@ -2,9 +2,9 @@ Claim_Integration_Test ├── given campaign expired │ └── it should revert └── given campaign not expired - ├── given msg value less than sablier fee + ├── given msg value less than Sablier fee │ └── it should revert - └── given msg value not less than sablier fee + └── given msg value not less than Sablier fee ├── given recipient claimed │ └── it should revert └── given recipient not claimed From ce35add0e51a934348f5f917460d126f8645506a Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Thu, 24 Oct 2024 15:10:40 +0100 Subject: [PATCH 18/21] test: dry'ify vm.expectCall docs: polish natspecs over setDefaultSablierFee chore: change visibility to private for internal functions in Factory --- src/periphery/SablierMerkleFactory.sol | 6 ++--- .../interfaces/ISablierMerkleFactory.sol | 3 ++- test/Base.t.sol | 16 +++++++++++++ .../fork/merkle-campaign/MerkleInstant.t.sol | 23 +++++++------------ .../fork/merkle-campaign/MerkleLL.t.sol | 23 +++++++------------ .../fork/merkle-campaign/MerkleLT.t.sol | 23 +++++++------------ 6 files changed, 45 insertions(+), 49 deletions(-) diff --git a/src/periphery/SablierMerkleFactory.sol b/src/periphery/SablierMerkleFactory.sol index ac8a20981..a6626ff7a 100644 --- a/src/periphery/SablierMerkleFactory.sol +++ b/src/periphery/SablierMerkleFactory.sol @@ -245,11 +245,11 @@ contract SablierMerkleFactory is } /*////////////////////////////////////////////////////////////////////////// - INTERNAL NON-CONSTANT FUNCTIONS + PRIVATE NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /// @dev Computes the Sablier fee for the user, use the default fee if not enabled. - function _computeSablierFeeForUser(address user) internal view returns (uint256) { + function _computeSablierFeeForUser(address user) private view returns (uint256) { return _sablierFeeByUsers[user].enabled ? _sablierFeeByUsers[user].fee : defaultSablierFee; } @@ -263,7 +263,7 @@ contract SablierMerkleFactory is uint40 streamStartTime, MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages ) - internal + private returns (ISablierMerkleLT merkleLT) { // Hash the parameters to generate a salt. diff --git a/src/periphery/interfaces/ISablierMerkleFactory.sol b/src/periphery/interfaces/ISablierMerkleFactory.sol index 1df442b9b..b422eb283 100644 --- a/src/periphery/interfaces/ISablierMerkleFactory.sol +++ b/src/periphery/interfaces/ISablierMerkleFactory.sol @@ -206,7 +206,8 @@ interface ISablierMerkleFactory is IAdminable { /// @dev Emits a {SetDefaultSablierFee} event. /// /// Notes: - /// - The new default fee will only be applied to the future campaigns. + /// - The new default fee will only be applied to the future campaigns and will not affect the ones already + /// deployed. /// /// Requirements: /// - msg.sender must be the admin. diff --git a/test/Base.t.sol b/test/Base.t.sol index 4c265ab45..db0157ca9 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -321,6 +321,22 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi CALL EXPECTS - MERKLE LOCKUP //////////////////////////////////////////////////////////////////////////*/ + /// @dev Expects a call to {ISablierMerkleBase.claim} with data provided. + function expectCallToClaimWithData( + address merkleLockup, + uint256 sablierFee, + uint256 index, + address recipient, + uint128 amount, + bytes32[] memory merkleProof + ) + internal + { + vm.expectCall( + merkleLockup, sablierFee, abi.encodeCall(ISablierMerkleBase.claim, (index, recipient, amount, merkleProof)) + ); + } + /// @dev Expects a call to {ISablierMerkleBase.claim} with msgValue as `msg.value`. function expectCallToClaimWithMsgValue(address merkleLockup, uint256 msgValue) internal { vm.expectCall( diff --git a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol index f8e1b15ba..139bbd651 100644 --- a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol @@ -3,7 +3,6 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; -import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; import { ISablierMerkleInstant } from "src/periphery/interfaces/ISablierMerkleInstant.sol"; import { MerkleBase } from "src/periphery/types/DataTypes.sol"; import { MerkleBuilder } from "./../../../utils/MerkleBuilder.sol"; @@ -165,20 +164,14 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test { vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); } - // Expect call to `claim` with `sablierFee` as msg.value on the merkleInstant contract. - vm.expectCall( - address(vars.merkleInstant), - sablierFee, - abi.encodeCall( - ISablierMerkleBase.claim, - ( - vars.indexes[params.posBeforeSort], - vars.recipients[params.posBeforeSort], - vars.amounts[params.posBeforeSort], - vars.merkleProof - ) - ) - ); + expectCallToClaimWithData({ + merkleLockup: address(vars.merkleInstant), + sablierFee: sablierFee, + index: vars.indexes[params.posBeforeSort], + recipient: vars.recipients[params.posBeforeSort], + amount: vars.amounts[params.posBeforeSort], + merkleProof: vars.merkleProof + }); expectCallToTransfer({ asset: FORK_ASSET, diff --git a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol index 69d71e538..84eae5f6f 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol @@ -4,7 +4,6 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; import { Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; -import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; import { MerkleBase } from "src/periphery/types/DataTypes.sol"; import { MerkleBuilder } from "./../../../utils/MerkleBuilder.sol"; @@ -176,20 +175,14 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); } - // Expect call to `claim` with `sablierFee` as msg.value on the merkleLL contract. - vm.expectCall( - address(vars.merkleLL), - sablierFee, - abi.encodeCall( - ISablierMerkleBase.claim, - ( - vars.indexes[params.posBeforeSort], - vars.recipients[params.posBeforeSort], - vars.amounts[params.posBeforeSort], - vars.merkleProof - ) - ) - ); + expectCallToClaimWithData({ + merkleLockup: address(vars.merkleLL), + sablierFee: sablierFee, + index: vars.indexes[params.posBeforeSort], + recipient: vars.recipients[params.posBeforeSort], + amount: vars.amounts[params.posBeforeSort], + merkleProof: vars.merkleProof + }); vars.merkleLL.claim{ value: sablierFee }({ index: vars.indexes[params.posBeforeSort], diff --git a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol index 383e3baa0..25539c54d 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol @@ -4,7 +4,6 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; -import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; import { MerkleBase } from "src/periphery/types/DataTypes.sol"; import { MerkleBuilder } from "./../../../utils/MerkleBuilder.sol"; @@ -179,20 +178,14 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); } - // Expect call to `claim` with `sablierFee` as msg.value on the merkleLL contract. - vm.expectCall( - address(vars.merkleLT), - sablierFee, - abi.encodeCall( - ISablierMerkleBase.claim, - ( - vars.indexes[params.posBeforeSort], - vars.recipients[params.posBeforeSort], - vars.amounts[params.posBeforeSort], - vars.merkleProof - ) - ) - ); + expectCallToClaimWithData({ + merkleLockup: address(vars.merkleLT), + sablierFee: sablierFee, + index: vars.indexes[params.posBeforeSort], + recipient: vars.recipients[params.posBeforeSort], + amount: vars.amounts[params.posBeforeSort], + merkleProof: vars.merkleProof + }); vars.merkleLT.claim{ value: sablierFee }({ index: vars.indexes[params.posBeforeSort], From 37c7caf9ff6002fb9073177afbb81d8589055364 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Thu, 24 Oct 2024 15:46:50 +0100 Subject: [PATCH 19/21] feat: emit sablierFee in CreateMerkle events --- src/periphery/SablierMerkleFactory.sol | 26 +++++++++++++------ .../interfaces/ISablierMerkleFactory.sol | 9 ++++--- .../fork/merkle-campaign/MerkleInstant.t.sol | 3 ++- .../fork/merkle-campaign/MerkleLL.t.sol | 3 ++- .../fork/merkle-campaign/MerkleLT.t.sol | 3 ++- .../createMerkleInstant.t.sol | 6 +++-- .../create-merkle-ll/createMerkleLL.t.sol | 6 +++-- .../create-merkle-lt/createMerkleLT.t.sol | 6 +++-- test/utils/Events.sol | 9 ++++--- 9 files changed, 48 insertions(+), 23 deletions(-) diff --git a/src/periphery/SablierMerkleFactory.sol b/src/periphery/SablierMerkleFactory.sol index a6626ff7a..685ce00b3 100644 --- a/src/periphery/SablierMerkleFactory.sol +++ b/src/periphery/SablierMerkleFactory.sol @@ -152,7 +152,7 @@ contract SablierMerkleFactory is merkleInstant = new SablierMerkleInstant{ salt: salt }(baseParams, sablierFee); // Log the creation of the MerkleInstant contract, including some metadata that is not stored on-chain. - emit CreateMerkleInstant(merkleInstant, baseParams, aggregateAmount, recipientCount); + emit CreateMerkleInstant(merkleInstant, baseParams, aggregateAmount, recipientCount, sablierFee); } /// @inheritdoc ISablierMerkleFactory @@ -195,7 +195,15 @@ contract SablierMerkleFactory is // Log the creation of the MerkleLL contract, including some metadata that is not stored on-chain. emit CreateMerkleLL( - merkleLL, baseParams, lockupLinear, cancelable, transferable, schedule, aggregateAmount, recipientCount + merkleLL, + baseParams, + lockupLinear, + cancelable, + transferable, + schedule, + aggregateAmount, + recipientCount, + sablierFee ); } @@ -224,9 +232,12 @@ contract SablierMerkleFactory is } } + // Compute the Sablier fee for the user. + uint256 sablierFee = _computeSablierFeeForUser(msg.sender); + // Deploy the MerkleLT contract. merkleLT = _deployMerkleLT( - baseParams, lockupTranched, cancelable, transferable, streamStartTime, tranchesWithPercentages + baseParams, lockupTranched, cancelable, transferable, streamStartTime, tranchesWithPercentages, sablierFee ); // Log the creation of the MerkleLT contract, including some metadata that is not stored on-chain. @@ -240,7 +251,8 @@ contract SablierMerkleFactory is tranchesWithPercentages, totalDuration, aggregateAmount, - recipientCount + recipientCount, + sablierFee ); } @@ -261,7 +273,8 @@ contract SablierMerkleFactory is bool cancelable, bool transferable, uint40 streamStartTime, - MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages + MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages, + uint256 sablierFee ) private returns (ISablierMerkleLT merkleLT) @@ -284,9 +297,6 @@ contract SablierMerkleFactory is ) ); - // Compute the Sablier fee for the user. - uint256 sablierFee = _computeSablierFeeForUser(msg.sender); - // Deploy the MerkleLT contract with CREATE2. merkleLT = new SablierMerkleLT{ salt: salt }( baseParams, lockupTranched, cancelable, transferable, streamStartTime, tranchesWithPercentages, sablierFee diff --git a/src/periphery/interfaces/ISablierMerkleFactory.sol b/src/periphery/interfaces/ISablierMerkleFactory.sol index b422eb283..304648996 100644 --- a/src/periphery/interfaces/ISablierMerkleFactory.sol +++ b/src/periphery/interfaces/ISablierMerkleFactory.sol @@ -28,7 +28,8 @@ interface ISablierMerkleFactory is IAdminable { ISablierMerkleInstant indexed merkleInstant, MerkleBase.ConstructorParams baseParams, uint256 aggregateAmount, - uint256 recipientCount + uint256 recipientCount, + uint256 sablierFee ); /// @notice Emitted when a {SablierMerkleLL} campaign is created. @@ -40,7 +41,8 @@ interface ISablierMerkleFactory is IAdminable { bool transferable, MerkleLL.Schedule schedule, uint256 aggregateAmount, - uint256 recipientCount + uint256 recipientCount, + uint256 sablierFee ); /// @notice Emitted when a {SablierMerkleLT} campaign is created. @@ -54,7 +56,8 @@ interface ISablierMerkleFactory is IAdminable { MerkleLT.TrancheWithPercentage[] tranchesWithPercentages, uint256 totalDuration, uint256 aggregateAmount, - uint256 recipientCount + uint256 recipientCount, + uint256 sablierFee ); /// @notice Emitted when the admin resets Sablier fee to default for a specific user. diff --git a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol index 139bbd651..ab6f326ac 100644 --- a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol @@ -113,7 +113,8 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test { merkleInstant: ISablierMerkleInstant(vars.expectedMerkleInstant), baseParams: vars.baseParams, aggregateAmount: vars.aggregateAmount, - recipientCount: vars.recipientCount + recipientCount: vars.recipientCount, + sablierFee: sablierFee }); vars.merkleInstant = merkleFactory.createMerkleInstant({ diff --git a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol index 84eae5f6f..89889423c 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol @@ -121,7 +121,8 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { transferable: defaults.TRANSFERABLE(), schedule: defaults.schedule(), aggregateAmount: vars.aggregateAmount, - recipientCount: vars.recipientCount + recipientCount: vars.recipientCount, + sablierFee: sablierFee }); vars.merkleLL = merkleFactory.createMerkleLL({ diff --git a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol index 25539c54d..7ba8777a2 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol @@ -124,7 +124,8 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { tranchesWithPercentages: defaults.tranchesWithPercentages(), totalDuration: defaults.TOTAL_DURATION(), aggregateAmount: vars.aggregateAmount, - recipientCount: vars.recipientCount + recipientCount: vars.recipientCount, + sablierFee: sablierFee }); vars.merkleLT = merkleFactory.createMerkleLT({ diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol b/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol index 24e34c27e..bd2f6c9c5 100644 --- a/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol @@ -80,7 +80,8 @@ contract CreateMerkleInstant_Integration_Test is MerkleCampaign_Integration_Test merkleInstant: ISablierMerkleInstant(expectedMerkleInstant), baseParams: baseParams, aggregateAmount: defaults.AGGREGATE_AMOUNT(), - recipientCount: defaults.RECIPIENT_COUNT() + recipientCount: defaults.RECIPIENT_COUNT(), + sablierFee: customFee }); ISablierMerkleInstant actualInstant = createMerkleInstant(campaignOwner, expiration); @@ -119,7 +120,8 @@ contract CreateMerkleInstant_Integration_Test is MerkleCampaign_Integration_Test merkleInstant: ISablierMerkleInstant(expectedMerkleInstant), baseParams: baseParams, aggregateAmount: defaults.AGGREGATE_AMOUNT(), - recipientCount: defaults.RECIPIENT_COUNT() + recipientCount: defaults.RECIPIENT_COUNT(), + sablierFee: defaults.DEFAULT_SABLIER_FEE() }); ISablierMerkleInstant actualInstant = createMerkleInstant(campaignOwner, expiration); diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol b/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol index 4db06a9b8..1a893c91b 100644 --- a/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol @@ -98,7 +98,8 @@ contract CreateMerkleLL_Integration_Test is MerkleCampaign_Integration_Test { transferable: defaults.TRANSFERABLE(), schedule: defaults.schedule(), aggregateAmount: defaults.AGGREGATE_AMOUNT(), - recipientCount: defaults.RECIPIENT_COUNT() + recipientCount: defaults.RECIPIENT_COUNT(), + sablierFee: customFee }); ISablierMerkleLL actualLL = createMerkleLL(campaignOwner, expiration); @@ -139,7 +140,8 @@ contract CreateMerkleLL_Integration_Test is MerkleCampaign_Integration_Test { transferable: defaults.TRANSFERABLE(), schedule: defaults.schedule(), aggregateAmount: defaults.AGGREGATE_AMOUNT(), - recipientCount: defaults.RECIPIENT_COUNT() + recipientCount: defaults.RECIPIENT_COUNT(), + sablierFee: defaults.DEFAULT_SABLIER_FEE() }); ISablierMerkleLL actualLL = createMerkleLL(campaignOwner, expiration); diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol b/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol index d7841d9e0..be86887af 100644 --- a/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol @@ -104,7 +104,8 @@ contract CreateMerkleLT_Integration_Test is MerkleCampaign_Integration_Test { tranchesWithPercentages: defaults.tranchesWithPercentages(), totalDuration: defaults.TOTAL_DURATION(), aggregateAmount: defaults.AGGREGATE_AMOUNT(), - recipientCount: defaults.RECIPIENT_COUNT() + recipientCount: defaults.RECIPIENT_COUNT(), + sablierFee: customFee }); ISablierMerkleLT actualLT = createMerkleLT(campaignOwner, expiration); @@ -145,7 +146,8 @@ contract CreateMerkleLT_Integration_Test is MerkleCampaign_Integration_Test { tranchesWithPercentages: defaults.tranchesWithPercentages(), totalDuration: defaults.TOTAL_DURATION(), aggregateAmount: defaults.AGGREGATE_AMOUNT(), - recipientCount: defaults.RECIPIENT_COUNT() + recipientCount: defaults.RECIPIENT_COUNT(), + sablierFee: defaults.DEFAULT_SABLIER_FEE() }); ISablierMerkleLT actualLT = createMerkleLT(campaignOwner, expiration); diff --git a/test/utils/Events.sol b/test/utils/Events.sol index 6b1584593..9304df388 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -112,7 +112,8 @@ abstract contract Events { ISablierMerkleInstant indexed merkleInstant, MerkleBase.ConstructorParams baseParams, uint256 aggregateAmount, - uint256 recipientCount + uint256 recipientCount, + uint256 sablierFee ); event CreateMerkleLL( @@ -123,7 +124,8 @@ abstract contract Events { bool transferable, MerkleLL.Schedule schedule, uint256 aggregateAmount, - uint256 recipientCount + uint256 recipientCount, + uint256 sablierFee ); event CreateMerkleLT( @@ -136,7 +138,8 @@ abstract contract Events { MerkleLT.TrancheWithPercentage[] tranchesWithPercentages, uint256 totalDuration, uint256 aggregateAmount, - uint256 recipientCount + uint256 recipientCount, + uint256 sablierFee ); event ResetSablierFee(address indexed admin, address indexed campaignCreator); From 72af0c3e3b35c65e46bd1b5c5d301540d868f275 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Thu, 24 Oct 2024 15:53:47 +0100 Subject: [PATCH 20/21] test: move periphery related helpers to Periphery base contract --- test/Base.t.sol | 128 -------------------------------- test/periphery/Periphery.t.sol | 132 +++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 128 deletions(-) diff --git a/test/Base.t.sol b/test/Base.t.sol index db0157ca9..c8bbb5807 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -10,9 +10,7 @@ import { LockupNFTDescriptor } from "src/core/LockupNFTDescriptor.sol"; import { SablierLockupDynamic } from "src/core/SablierLockupDynamic.sol"; import { SablierLockupLinear } from "src/core/SablierLockupLinear.sol"; import { SablierLockupTranched } from "src/core/SablierLockupTranched.sol"; -import { LockupDynamic, LockupLinear, LockupTranched } from "src/core/types/DataTypes.sol"; import { ISablierBatchLockup } from "src/periphery/interfaces/ISablierBatchLockup.sol"; -import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; import { ISablierMerkleFactory } from "src/periphery/interfaces/ISablierMerkleFactory.sol"; import { ISablierMerkleInstant } from "src/periphery/interfaces/ISablierMerkleInstant.sol"; import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; @@ -222,130 +220,4 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi data: abi.encodeCall(IERC20.transferFrom, (from, to, value)) }); } - - /*////////////////////////////////////////////////////////////////////////// - CALL EXPECTS - LOCKUP - //////////////////////////////////////////////////////////////////////////*/ - - /// @dev Expects multiple calls to {ISablierLockupDynamic.createWithDurations}, each with the specified - /// `params`. - function expectMultipleCallsToCreateWithDurationsLD( - uint64 count, - LockupDynamic.CreateWithDurations memory params - ) - internal - { - vm.expectCall({ - callee: address(lockupDynamic), - count: count, - data: abi.encodeCall(ISablierLockupDynamic.createWithDurations, (params)) - }); - } - - /// @dev Expects multiple calls to {ISablierLockupLinear.createWithDurations}, each with the specified - /// `params`. - function expectMultipleCallsToCreateWithDurationsLL( - uint64 count, - LockupLinear.CreateWithDurations memory params - ) - internal - { - vm.expectCall({ - callee: address(lockupLinear), - count: count, - data: abi.encodeCall(ISablierLockupLinear.createWithDurations, (params)) - }); - } - - /// @dev Expects multiple calls to {ISablierLockupTranched.createWithDurations}, each with the specified - /// `params`. - function expectMultipleCallsToCreateWithDurationsLT( - uint64 count, - LockupTranched.CreateWithDurations memory params - ) - internal - { - vm.expectCall({ - callee: address(lockupTranched), - count: count, - data: abi.encodeCall(ISablierLockupTranched.createWithDurations, (params)) - }); - } - - /// @dev Expects multiple calls to {ISablierLockupDynamic.createWithTimestamps}, each with the specified - /// `params`. - function expectMultipleCallsToCreateWithTimestampsLD( - uint64 count, - LockupDynamic.CreateWithTimestamps memory params - ) - internal - { - vm.expectCall({ - callee: address(lockupDynamic), - count: count, - data: abi.encodeCall(ISablierLockupDynamic.createWithTimestamps, (params)) - }); - } - - /// @dev Expects multiple calls to {ISablierLockupLinear.createWithTimestamps}, each with the specified - /// `params`. - function expectMultipleCallsToCreateWithTimestampsLL( - uint64 count, - LockupLinear.CreateWithTimestamps memory params - ) - internal - { - vm.expectCall({ - callee: address(lockupLinear), - count: count, - data: abi.encodeCall(ISablierLockupLinear.createWithTimestamps, (params)) - }); - } - - /// @dev Expects multiple calls to {ISablierLockupTranched.createWithTimestamps}, each with the specified - /// `params`. - function expectMultipleCallsToCreateWithTimestampsLT( - uint64 count, - LockupTranched.CreateWithTimestamps memory params - ) - internal - { - vm.expectCall({ - callee: address(lockupTranched), - count: count, - data: abi.encodeCall(ISablierLockupTranched.createWithTimestamps, (params)) - }); - } - - /*////////////////////////////////////////////////////////////////////////// - CALL EXPECTS - MERKLE LOCKUP - //////////////////////////////////////////////////////////////////////////*/ - - /// @dev Expects a call to {ISablierMerkleBase.claim} with data provided. - function expectCallToClaimWithData( - address merkleLockup, - uint256 sablierFee, - uint256 index, - address recipient, - uint128 amount, - bytes32[] memory merkleProof - ) - internal - { - vm.expectCall( - merkleLockup, sablierFee, abi.encodeCall(ISablierMerkleBase.claim, (index, recipient, amount, merkleProof)) - ); - } - - /// @dev Expects a call to {ISablierMerkleBase.claim} with msgValue as `msg.value`. - function expectCallToClaimWithMsgValue(address merkleLockup, uint256 msgValue) internal { - vm.expectCall( - merkleLockup, - msgValue, - abi.encodeCall( - ISablierMerkleBase.claim, - (defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), defaults.index1Proof()) - ) - ); - } } diff --git a/test/periphery/Periphery.t.sol b/test/periphery/Periphery.t.sol index 9cc4127be..5f8ae5ea8 100644 --- a/test/periphery/Periphery.t.sol +++ b/test/periphery/Periphery.t.sol @@ -3,6 +3,12 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; +import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; +import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; +import { LockupDynamic, LockupLinear, LockupTranched } from "src/core/types/DataTypes.sol"; + +import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; import { SablierMerkleInstant } from "src/periphery/SablierMerkleInstant.sol"; import { SablierMerkleLL } from "src/periphery/SablierMerkleLL.sol"; import { SablierMerkleLT } from "src/periphery/SablierMerkleLT.sol"; @@ -31,6 +37,132 @@ contract Periphery_Test is Base_Test { vm.label({ account: address(contractWithReceiveEth), newLabel: "Contract With Receive Eth" }); } + /*////////////////////////////////////////////////////////////////////////// + CALL EXPECTS - LOCKUP + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Expects multiple calls to {ISablierLockupDynamic.createWithDurations}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithDurationsLD( + uint64 count, + LockupDynamic.CreateWithDurations memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupDynamic), + count: count, + data: abi.encodeCall(ISablierLockupDynamic.createWithDurations, (params)) + }); + } + + /// @dev Expects multiple calls to {ISablierLockupLinear.createWithDurations}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithDurationsLL( + uint64 count, + LockupLinear.CreateWithDurations memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupLinear), + count: count, + data: abi.encodeCall(ISablierLockupLinear.createWithDurations, (params)) + }); + } + + /// @dev Expects multiple calls to {ISablierLockupTranched.createWithDurations}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithDurationsLT( + uint64 count, + LockupTranched.CreateWithDurations memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupTranched), + count: count, + data: abi.encodeCall(ISablierLockupTranched.createWithDurations, (params)) + }); + } + + /// @dev Expects multiple calls to {ISablierLockupDynamic.createWithTimestamps}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithTimestampsLD( + uint64 count, + LockupDynamic.CreateWithTimestamps memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupDynamic), + count: count, + data: abi.encodeCall(ISablierLockupDynamic.createWithTimestamps, (params)) + }); + } + + /// @dev Expects multiple calls to {ISablierLockupLinear.createWithTimestamps}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithTimestampsLL( + uint64 count, + LockupLinear.CreateWithTimestamps memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupLinear), + count: count, + data: abi.encodeCall(ISablierLockupLinear.createWithTimestamps, (params)) + }); + } + + /// @dev Expects multiple calls to {ISablierLockupTranched.createWithTimestamps}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithTimestampsLT( + uint64 count, + LockupTranched.CreateWithTimestamps memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupTranched), + count: count, + data: abi.encodeCall(ISablierLockupTranched.createWithTimestamps, (params)) + }); + } + + /*////////////////////////////////////////////////////////////////////////// + CALL EXPECTS - MERKLE LOCKUP + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Expects a call to {ISablierMerkleBase.claim} with data provided. + function expectCallToClaimWithData( + address merkleLockup, + uint256 sablierFee, + uint256 index, + address recipient, + uint128 amount, + bytes32[] memory merkleProof + ) + internal + { + vm.expectCall( + merkleLockup, sablierFee, abi.encodeCall(ISablierMerkleBase.claim, (index, recipient, amount, merkleProof)) + ); + } + + /// @dev Expects a call to {ISablierMerkleBase.claim} with msgValue as `msg.value`. + function expectCallToClaimWithMsgValue(address merkleLockup, uint256 msgValue) internal { + vm.expectCall( + merkleLockup, + msgValue, + abi.encodeCall( + ISablierMerkleBase.claim, + (defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), defaults.index1Proof()) + ) + ); + } + /*////////////////////////////////////////////////////////////////////////// MERKLE-BASE //////////////////////////////////////////////////////////////////////////*/ From 5b24e38af6dbbd3ce876bd1b776fb9e7bdd06cf4 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Thu, 24 Oct 2024 15:59:23 +0100 Subject: [PATCH 21/21] docs: remove redundant comment from constructors --- src/core/SablierLockupDynamic.sol | 1 - src/core/SablierLockupLinear.sol | 1 - src/core/SablierLockupTranched.sol | 1 - src/core/abstracts/SablierLockup.sol | 1 - src/periphery/SablierMerkleFactory.sol | 1 - src/periphery/abstracts/SablierMerkleBase.sol | 1 - 6 files changed, 6 deletions(-) diff --git a/src/core/SablierLockupDynamic.sol b/src/core/SablierLockupDynamic.sol index 13373e6ae..7f03a3c1a 100644 --- a/src/core/SablierLockupDynamic.sol +++ b/src/core/SablierLockupDynamic.sol @@ -56,7 +56,6 @@ contract SablierLockupDynamic is CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - /// @dev Emits a {TransferAdmin} event. /// @param initialAdmin The address of the initial contract admin. /// @param initialNFTDescriptor The address of the NFT descriptor contract. /// @param maxSegmentCount The maximum number of segments allowed in a stream. diff --git a/src/core/SablierLockupLinear.sol b/src/core/SablierLockupLinear.sol index 8de760dff..ecce05b21 100644 --- a/src/core/SablierLockupLinear.sol +++ b/src/core/SablierLockupLinear.sol @@ -50,7 +50,6 @@ contract SablierLockupLinear is CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - /// @dev Emits a {TransferAdmin} event. /// @param initialAdmin The address of the initial contract admin. /// @param initialNFTDescriptor The address of the initial NFT descriptor. constructor( diff --git a/src/core/SablierLockupTranched.sol b/src/core/SablierLockupTranched.sol index 1a998d69a..8f6e03ebd 100644 --- a/src/core/SablierLockupTranched.sol +++ b/src/core/SablierLockupTranched.sol @@ -51,7 +51,6 @@ contract SablierLockupTranched is CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - /// @dev Emits a {TransferAdmin} event. /// @param initialAdmin The address of the initial contract admin. /// @param initialNFTDescriptor The address of the NFT descriptor contract. /// @param maxTrancheCount The maximum number of tranches allowed in a stream. diff --git a/src/core/abstracts/SablierLockup.sol b/src/core/abstracts/SablierLockup.sol index a33041e87..69febc245 100644 --- a/src/core/abstracts/SablierLockup.sol +++ b/src/core/abstracts/SablierLockup.sol @@ -48,7 +48,6 @@ abstract contract SablierLockup is CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - /// @dev Emits a {TransferAdmin} event. /// @param initialAdmin The address of the initial contract admin. /// @param initialNFTDescriptor The address of the initial NFT descriptor. constructor(address initialAdmin, ILockupNFTDescriptor initialNFTDescriptor) Adminable(initialAdmin) { diff --git a/src/periphery/SablierMerkleFactory.sol b/src/periphery/SablierMerkleFactory.sol index 685ce00b3..ecc82b88c 100644 --- a/src/periphery/SablierMerkleFactory.sol +++ b/src/periphery/SablierMerkleFactory.sol @@ -38,7 +38,6 @@ contract SablierMerkleFactory is CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - /// @dev Emits a {TransferAdmin} event. /// @param initialAdmin The address of the initial contract admin. constructor(address initialAdmin) Adminable(initialAdmin) { } diff --git a/src/periphery/abstracts/SablierMerkleBase.sol b/src/periphery/abstracts/SablierMerkleBase.sol index 7c8c8e6a0..87f7dbe7d 100644 --- a/src/periphery/abstracts/SablierMerkleBase.sol +++ b/src/periphery/abstracts/SablierMerkleBase.sol @@ -55,7 +55,6 @@ abstract contract SablierMerkleBase is //////////////////////////////////////////////////////////////////////////*/ /// @notice Constructs the contract by initializing the immutable state variables. - /// @dev Emits a {TransferAdmin} event. constructor(MerkleBase.ConstructorParams memory params, uint256 sablierFee) Adminable(params.initialAdmin) { // Check: the campaign name is not greater than 32 bytes if (bytes(params.name).length > 32) {