Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- LayerCake
- Optimization enabled
- true
- Compiler version
- v0.8.20+commit.a1b79de6
- Optimization runs
- 200
- EVM Version
- london
- Verified at
- 2023-07-12T19:23:34.472547Z
Constructor Arguments
0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000072000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004d2000000000000000000000000000000000000000000000000000000000000162e000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad00000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000052b7d2dcc80cd2e40000000000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000052b7d2dcc80cd2e40000000000000000000000000000000000000000000000000000000000000000dead1c00000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000008546573745745544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000087465737457455448000000000000000000000000000000000000000000000000
Contract source code
// SPDX-License-Identifier: BUSL-1.1 // Copyright (c) 2023, Flare Mainnet Holdings Ltd. // All rights reserved. pragma solidity ^0.8.13; // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } } // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); } // Copyright (c) 2023, Flare Mainnet Holdings Ltd. // All rights reserved. // Copyright (c) 2023, Flare Mainnet Holdings Ltd. // All rights reserved. contract LayerCakeExecutionProof { struct Operations { uint256 nonce; uint256 amount; uint256 fee; address sender; address recipient; uint256 executionTime; uint256 callDataGasLimit; bytes callData; bool cancel; uint256 cancellationFeeRefund; address negatedBandwidthProvider; bool initialNegation; bytes32 invalidExecutionProofId; } struct ExecutionProof { Operations operations; uint256 partialAmount; uint8 v; bytes32 r; bytes32 s; } } contract LayerCakeTools is LayerCakeExecutionProof { // ================================================================================= // STRUCTS // ================================================================================= struct ConstructorParams { bool isDestinationChain; uint256 thisChainId; uint256 oppositeChainId; uint256 assetId; uint256 contractId; address tokenAddress; string tokenName; string tokenSymbol; uint256 depositCap; uint256 reorgAssumption; uint256 bandwidthDepositDenominator; uint256 defaultNegationCost; address forwardedFeeRecipient; uint256 forwardedFeeDenominator; } // ================================================================================= // EVENTS // ================================================================================= event OperationsStored(bytes32 executionId, Operations operations); event OperationsExecuted( bytes32 executionId, address bandwidthProvider, ExecutionProof executionProof, bool executionPrepared ); event BandwidthChanged(address bandwidthProvider, bool added, uint256 amount); // ================================================================================= // FUNCTIONS // ================================================================================= function getPathwayId(uint256 _originChainId, uint256 _destinationChainId, uint256 _assetId, uint256 _contractId) public pure returns (bytes32 pathwayId) { pathwayId = keccak256(abi.encode("layercakePathwayId", _originChainId, _destinationChainId, _assetId, _contractId)); } function getExecutionId(bytes32 _pathwayId, Operations memory _operations) public pure returns (bytes32 executionId) { executionId = keccak256(abi.encode("layercakeExecutionId", _pathwayId, _operations)); } function getInvalidExecutionProofId(ExecutionProof memory _invalidExecutionProof) public pure returns (bytes32 invalidExecutionProofId) { invalidExecutionProofId = keccak256(abi.encode("layercakeInvalidExecutionProofId", _invalidExecutionProof)); } function recoverSigner(bytes32 _hash, ExecutionProof memory _executionProof) public pure returns (address) { bytes memory prefix = "\x19Ethereum Signed Message:\n32"; bytes32 prefixedHashMessage = keccak256(abi.encodePacked(prefix, _hash)); address signer = ecrecover(prefixedHashMessage, _executionProof.v, _executionProof.r, _executionProof.s); return signer; } } // Copyright (c) 2023, Flare Mainnet Holdings Ltd. // All rights reserved. contract LayerCakeBandwidthManager { struct BandwidthProvider { bool negated; uint256 startTime; uint256 timeLastActive; uint256 timeLastNegated; uint256 negationCounter; bytes32 prevInvalidExecutionProofId; uint256 currentTotalBandwidth; uint256 currentUsedBandwidth; } event BpSuggestedFeeUpdated(address bandwidthProvider, uint256 amount); address public immutable layerCakeContract; uint256 public immutable reorgAssumption; uint256 public immutable bandwidthPeriod; uint256 public immutable bandwidthDepositDenominator; uint256 public immutable defaultNegationCost; uint256 public immutable negationCounterReset; uint256 public immutable negationCostResetPeriod; uint256 public immutable negationRewardDenominator; constructor( address _layerCakeContract, uint256 _reorgAssumption, uint256 _bandwidthDepositDenominator, uint256 _defaultNegationCost ) { layerCakeContract = _layerCakeContract; reorgAssumption = _reorgAssumption; bandwidthPeriod = 2 * reorgAssumption; bandwidthDepositDenominator = _bandwidthDepositDenominator; defaultNegationCost = _defaultNegationCost; negationCounterReset = bandwidthDepositDenominator; negationCostResetPeriod = negationCounterReset * bandwidthPeriod; negationRewardDenominator = 2 * bandwidthDepositDenominator; } mapping(address => BandwidthProvider) public bpInfo; mapping(address => uint256) public bpSuggestedFee; modifier layerCakeOnly() { require(msg.sender == layerCakeContract, "LCO1"); _; } // ================== // BP parameter functions // ================== function proveBandwidth(address _bandwidthProvider, uint256 _amount) external layerCakeOnly { proveBandwidthPrivate(_bandwidthProvider, _amount, true); } function proveBandwidthPrivate(address _bandwidthProvider, uint256 _amount, bool _addToUsedBandwidth) private { // Prove that the bandwidth provider calling this function has free bandwidth >= _amount BandwidthProvider memory bp = bpInfo[_bandwidthProvider]; require(!bp.negated && block.timestamp - bp.timeLastNegated > bandwidthPeriod, "PBP1"); if ((block.timestamp - bp.startTime) / bandwidthPeriod > (bp.timeLastActive - bp.startTime) / bandwidthPeriod) { // New bandwidth period if (_amount > bp.currentTotalBandwidth - bp.currentUsedBandwidth) { require(block.timestamp - bp.timeLastActive > reorgAssumption, "PBP2"); } bp.currentUsedBandwidth = 0; } require(bp.currentTotalBandwidth - bp.currentUsedBandwidth >= _amount, "PBP3"); bp.timeLastActive = block.timestamp; bp.negationCounter = 0; if (_addToUsedBandwidth) { bp.currentUsedBandwidth = bp.currentUsedBandwidth + _amount; } bpInfo[_bandwidthProvider] = bp; } function addBandwidth(address _bandwidthProvider, uint256 _bandwidthAmount) external layerCakeOnly returns (uint256 _depositedAmount) { BandwidthProvider memory bp = bpInfo[_bandwidthProvider]; bp.timeLastActive = block.timestamp; require(!bp.negated, "AB1"); if (bp.startTime == 0) { // This is a new BP bp.startTime = bp.timeLastActive; } // Require that the added bandwidth is divisible by BANDWIDTH_DEPOSIT_DENOMINATOR without a remainder require(_bandwidthAmount % bandwidthDepositDenominator == 0, "AB2"); _depositedAmount = _bandwidthAmount + (_bandwidthAmount / bandwidthDepositDenominator); bp.currentTotalBandwidth = bp.currentTotalBandwidth + _bandwidthAmount; bp.negationCounter = 0; bpInfo[_bandwidthProvider] = bp; } function subtractBandwidth(address _bandwidthProvider, uint256 _bandwidthAmount) external layerCakeOnly returns (uint256 _withdrawnAmount) { proveBandwidthPrivate(_bandwidthProvider, _bandwidthAmount, false); BandwidthProvider memory bp = bpInfo[_bandwidthProvider]; require(_bandwidthAmount <= bp.currentTotalBandwidth, "SB1"); // Require that the subtracted bandwidth is divisible by bandwidthDepositDenominator without a remainder require(_bandwidthAmount % bandwidthDepositDenominator == 0, "SB2"); _withdrawnAmount = _bandwidthAmount + (_bandwidthAmount / bandwidthDepositDenominator); bp.currentTotalBandwidth = bp.currentTotalBandwidth - _bandwidthAmount; bpInfo[_bandwidthProvider] = bp; } function negateBp( address _bandwidthProvider, uint256 _depositedAmount, uint256 _fee, bool _initialNegation, bytes32 _invalidExecutionProofId ) external layerCakeOnly returns (uint256 executionAmount) { BandwidthProvider memory bp = bpInfo[_bandwidthProvider]; if (bp.negated && bp.prevInvalidExecutionProofId != 0x0) { require(bp.prevInvalidExecutionProofId == _invalidExecutionProofId, "NB1"); } if (!bp.negated) { if ( bp.timeLastNegated > bp.timeLastActive && block.timestamp - bp.timeLastActive >= negationCostResetPeriod && bp.negationCounter > negationCounterReset && block.timestamp - bp.timeLastNegated < 2 * bandwidthPeriod ) { require(_depositedAmount - _fee == bp.currentTotalBandwidth, "NB2"); bp.negationCounter = 0; } else { require(_depositedAmount - _fee == defaultNegationCost, "NB3"); } bp.negationCounter = bp.negationCounter + 1; executionAmount = _depositedAmount + (bp.currentTotalBandwidth / negationRewardDenominator); } else { require(_depositedAmount - _fee == bp.currentTotalBandwidth, "NB4"); executionAmount = _depositedAmount + defaultNegationCost; } bp.negated = !bp.negated; require(_initialNegation == bp.negated, "NB5"); bp.timeLastNegated = block.timestamp; bp.prevInvalidExecutionProofId = _invalidExecutionProofId; bpInfo[_bandwidthProvider] = bp; return executionAmount; } function updateBpSuggestedFee(uint256 _amount) external { BandwidthProvider memory bp = bpInfo[msg.sender]; require(bp.currentTotalBandwidth > 0, "UBF1"); bpSuggestedFee[msg.sender] = _amount; emit BpSuggestedFeeUpdated(msg.sender, _amount); } } // Copyright (c) 2023, Flare Mainnet Holdings Ltd. // All rights reserved. // Copyright (c) 2023, Flare Mainnet Holdings Ltd. // All rights reserved. contract LayerCakeStorageSlot is LayerCakeExecutionProof { struct ExecutionPreparation { bool executionPrepared; uint256 totalPrepared; uint256 feeIncrease; uint256 feesPaid; } address public immutable storageManager; uint256 public immutable storageStartTime; uint256 public immutable storageEndTime; mapping(bytes32 => bool) public openedExecutionIds; mapping(bytes32 => ExecutionPreparation) public preparedExecutionIds; uint256 public totalStored; uint256 public totalPrepared; mapping(address => uint256) public totalStoredPerAddress; mapping(address => uint256) public totalPreparedPerAddress; constructor(address _storageManager, uint256 _startTime, uint256 _storageEndTime) { storageManager = _storageManager; storageStartTime = _startTime; storageEndTime = _storageEndTime; } modifier storageManagerOnly() { require(msg.sender == storageManager, "SMO1"); _; } // ================================================================================= // FUNCTIONS // ================================================================================= // ================== // View Storage functions // ================== function getExecutionIdStored(bytes32 _executionId) external view returns (bool) { return openedExecutionIds[_executionId]; } function getExecutionIdPrepared(bytes32 _executionId) public view returns (bool, uint256) { return (preparedExecutionIds[_executionId].executionPrepared, preparedExecutionIds[_executionId].totalPrepared); } // ================== // Set Storage functions // ================== function storeExecutionId(bytes32 _executionId, address _sender, uint256 _amount) external storageManagerOnly { openedExecutionIds[_executionId] = true; totalStored = totalStored + _amount; totalStoredPerAddress[_sender] = totalStoredPerAddress[_sender] + _amount; } function prepareExecutionId(bytes32 _executionId, address _preparer, ExecutionProof memory _executionProof) external storageManagerOnly returns (uint256, uint256, bool) { ExecutionPreparation memory executionIdInfo = preparedExecutionIds[_executionId]; uint256 remainingAmount = _executionProof.operations.amount - executionIdInfo.totalPrepared; require(remainingAmount > 0, "PEIP1"); if (_executionProof.partialAmount >= remainingAmount) { executionIdInfo.executionPrepared = true; _executionProof.partialAmount = remainingAmount; } uint256 remainingFees = _executionProof.operations.fee + executionIdInfo.feeIncrease - executionIdInfo.feesPaid; uint256 partialFee = (_executionProof.partialAmount * remainingFees) / remainingAmount; uint256 newRemainingAmount = remainingAmount - _executionProof.partialAmount; uint256 newRemainingFees = remainingFees - partialFee; if (newRemainingAmount > 0 && remainingFees > 0) { require(newRemainingFees > 0, "PEIP2"); } executionIdInfo.totalPrepared = executionIdInfo.totalPrepared + _executionProof.partialAmount; executionIdInfo.feesPaid = executionIdInfo.feesPaid + partialFee; preparedExecutionIds[_executionId] = executionIdInfo; if (_preparer != _executionProof.operations.sender) { totalPreparedPerAddress[_preparer] = totalPreparedPerAddress[_preparer] + _executionProof.partialAmount; totalPrepared = totalPrepared + _executionProof.partialAmount; } return (partialFee, _executionProof.partialAmount, executionIdInfo.executionPrepared); } function increaseFee(bytes32 _executionId, uint256 _amount) external storageManagerOnly { preparedExecutionIds[_executionId].feeIncrease = preparedExecutionIds[_executionId].feeIncrease + _amount; } } contract LayerCakeStorageManager is LayerCakeExecutionProof { uint256 public constant STORAGE_TIME = 365 days; uint256 public constant STORAGE_SLOTS = 100; address public immutable layerCakeContract; uint256 public immutable layerCakeDeployTime; // Each slot lasts for STORAGE_TIME, and a new storage contract is automatically deployed every STORAGE_TIME, // overwriting slots from STORAGE_SLOTS many slots ago. address[STORAGE_SLOTS] public layerCakeStorageSlots; uint256 public storageEpoch; constructor(address _layerCakeContract) { layerCakeContract = _layerCakeContract; layerCakeDeployTime = block.timestamp; LayerCakeStorageSlot newLayerCakeStorageSlot = new LayerCakeStorageSlot( address(this), block.timestamp, block.timestamp + STORAGE_TIME ); layerCakeStorageSlots[0] = address(newLayerCakeStorageSlot); } modifier layerCakeOnly() { require(msg.sender == layerCakeContract, "LCO1"); _; } // ================================================================================= // FUNCTIONS // ================================================================================= function _getStorageSlot(uint256 _timestamp) private view returns (uint256 thisStorageSlot, uint256 latestStorageEpoch, uint256 thisStorageEpoch, bool newSlotRequired) { // If a new storage time block is entered, deploy a new contract and self destruct the old one from a year ago thisStorageEpoch = (_timestamp - layerCakeDeployTime) / STORAGE_TIME; latestStorageEpoch = (block.timestamp - layerCakeDeployTime) / STORAGE_TIME; require(latestStorageEpoch - thisStorageEpoch < STORAGE_SLOTS, "GSS1"); thisStorageSlot = thisStorageEpoch % STORAGE_SLOTS; if (thisStorageEpoch > storageEpoch) { newSlotRequired = true; } } function _checkCreateStorageSlot(uint256 _timestamp) private returns (uint256 storageSlot) { uint256 thisStorageSlot; uint256 latestStorageEpoch; uint256 thisStorageEpoch; bool newSlotRequired; (thisStorageSlot, latestStorageEpoch, thisStorageEpoch, newSlotRequired) = _getStorageSlot(_timestamp); require(latestStorageEpoch - thisStorageEpoch < STORAGE_SLOTS / 2, "CCSS1"); if (newSlotRequired) { // Deploy new contract LayerCakeStorageSlot newLayerCakeStorageSlot = new LayerCakeStorageSlot( address(this), layerCakeDeployTime + (thisStorageEpoch * STORAGE_TIME), layerCakeDeployTime + ((thisStorageEpoch + 1) * STORAGE_TIME) ); layerCakeStorageSlots[thisStorageSlot] = address(newLayerCakeStorageSlot); storageEpoch = thisStorageEpoch; } require( _timestamp >= LayerCakeStorageSlot(layerCakeStorageSlots[thisStorageSlot]).storageStartTime() && _timestamp < LayerCakeStorageSlot(layerCakeStorageSlots[thisStorageSlot]).storageEndTime(), "CCSS2" ); return thisStorageSlot; } // ================== // View Storage functions // ================== function getExecutionIdStored(uint256 _executionTime, bytes32 _executionId) external view returns (bool) { uint256 storageSlot; bool newSlotRequired; (storageSlot,,, newSlotRequired) = _getStorageSlot(_executionTime); if (newSlotRequired) { return false; } return LayerCakeStorageSlot(layerCakeStorageSlots[storageSlot]).getExecutionIdStored(_executionId); } function getExecutionIdPrepared(uint256 _executionTime, bytes32 _executionId) public view returns (bool, uint256) { uint256 storageSlot; bool newSlotRequired; (storageSlot,,, newSlotRequired) = _getStorageSlot(_executionTime); if (newSlotRequired) { return (false, 0); } return LayerCakeStorageSlot(layerCakeStorageSlots[storageSlot]).getExecutionIdPrepared(_executionId); } // ================== // Set Storage functions // ================== function storeExecutionId(uint256 _executionTime, bytes32 _executionId, address _sender, uint256 _amount) external layerCakeOnly { LayerCakeStorageSlot(layerCakeStorageSlots[_checkCreateStorageSlot(_executionTime)]).storeExecutionId( _executionId, _sender, _amount ); } function prepareExecutionId(bytes32 _executionId, address _preparer, ExecutionProof memory _executionProof) external layerCakeOnly returns (uint256, uint256, bool) { return LayerCakeStorageSlot( layerCakeStorageSlots[_checkCreateStorageSlot(_executionProof.operations.executionTime)] ).prepareExecutionId(_executionId, _preparer, _executionProof); } function increaseFee(uint256 _executionTime, bytes32 _executionId, uint256 _amount) external layerCakeOnly { LayerCakeStorageSlot(layerCakeStorageSlots[_checkCreateStorageSlot(_executionTime)]).increaseFee( _executionId, _amount ); } } // Copyright (c) 2023, Flare Mainnet Holdings Ltd. // All rights reserved. contract LayerCakeCalldataInterface is ReentrancyGuard { function execute(address _recipient, bytes memory _callData) external nonReentrant { (bool success, bytes memory result) = address(_recipient).call(_callData); if (!success) { if (result.length < 68) revert("E1"); assembly { result := add(result, 0x04) } revert(abi.decode(result, (string))); } } } /** * @title LayerCake * @dev An insured-in-transit cross-network composability protocol */ contract LayerCake is ReentrancyGuard, LayerCakeTools { // ================================================================================= // PUBLIC VARIABLES // ================================================================================= bool public immutable isDestinationChain; bytes32 public immutable departingPathwayId; bytes32 public immutable arrivingPathwayId; // On the source chain, `token` is the real token deposited by users. // On the destination chain, `token` represents the wrapped version of this ERC20. // The destination version of the token should be a custom ERC20 with a // maximum deposit capacity. IERC20 public immutable token; uint256 public immutable depositCap; LayerCakeBandwidthManager public immutable bandwidthManager; LayerCakeStorageManager public immutable storageManager; LayerCakeCalldataInterface public immutable calldataInterface; address public immutable forwardedFeeRecipient; uint256 public immutable forwardedFeeDenominator; // ================================================================================= // CONSTRUCTOR // ================================================================================= constructor(ConstructorParams memory _params) { isDestinationChain = _params.isDestinationChain; departingPathwayId = getPathwayId(_params.thisChainId, _params.oppositeChainId, _params.assetId, _params.contractId); arrivingPathwayId = getPathwayId(_params.oppositeChainId, _params.thisChainId, _params.assetId, _params.contractId); token = IERC20(_params.tokenAddress); depositCap = _params.depositCap; forwardedFeeRecipient = _params.forwardedFeeRecipient; forwardedFeeDenominator = _params.forwardedFeeDenominator; bandwidthManager = new LayerCakeBandwidthManager( address(this), _params.reorgAssumption, _params.bandwidthDepositDenominator, _params.defaultNegationCost); storageManager = new LayerCakeStorageManager(address(this)); calldataInterface = new LayerCakeCalldataInterface(); } // ================================================================================= // FUNCTIONS // ================================================================================= // ================= // Proof functions // ================= function getExecutionValidity( address _bandwidthProvider, bytes32 _executionId, ExecutionProof memory _executionProof ) public view returns (bool) { // Check that the signature on _proof matches _bandwidthProvider signing the executionId hash require(recoverSigner(_executionId, _executionProof) == _bandwidthProvider, "GEV1"); return (storageManager.getExecutionIdStored(_executionProof.operations.executionTime, _executionId)); } // ============== // User functions // ============== function storeStandardOperations(Operations memory _operations) external { require(_operations.negatedBandwidthProvider == address(0), "SSO1"); require(!_operations.cancel, "SSO2"); if (forwardedFeeDenominator > 0) { uint256 forwardedFee = _operations.amount / forwardedFeeDenominator; require(forwardedFee > 0, "SSO3"); uint256 forwardedFeeRecipientCurrentBalance = token.balanceOf(forwardedFeeRecipient); token.transferFrom(msg.sender, forwardedFeeRecipient, forwardedFee); require(token.balanceOf(forwardedFeeRecipient) > forwardedFeeRecipientCurrentBalance, "SSO4"); } uint256 thisCurrentBalance = token.balanceOf(address(this)); token.transferFrom(msg.sender, address(this), _operations.amount); _operations.amount = token.balanceOf(address(this)) - thisCurrentBalance; _storeOperations(_operations); } function cancelStandardOperations(Operations memory _operations) external nonReentrant { require(_operations.negatedBandwidthProvider == address(0), "CSO1"); require(!_operations.cancel, "CSO2"); bytes32 executionId = getExecutionId(arrivingPathwayId, _operations); (bool executionPrepared,) = storageManager.getExecutionIdPrepared(_operations.executionTime, executionId); require(!executionPrepared, "CSO3"); ExecutionProof memory cancelExecutionProof = ExecutionProof(_operations, _operations.amount, 0, bytes32(0), bytes32(0)); uint256 partialFee; (partialFee, executionPrepared) = _executeOperations(cancelExecutionProof, true); require(executionPrepared, "CSO4"); _operations.cancel = true; _operations.amount = _operations.amount - _operations.fee + partialFee; _storeOperations(_operations); } function storeNegationOperations(Operations memory _operations) external nonReentrant { require(_operations.negatedBandwidthProvider != address(0), "SNO1"); require(!_operations.cancel, "SNO2"); uint256 currentBalance = token.balanceOf(address(this)); token.transferFrom(msg.sender, address(this), _operations.amount); _operations.amount = token.balanceOf(address(this)) - currentBalance; _operations.amount = bandwidthManager.negateBp( _operations.negatedBandwidthProvider, _operations.amount, _operations.fee, _operations.initialNegation, _operations.invalidExecutionProofId ); _storeOperations(_operations); } function addBandwidth(uint256 _bandwidthAmount) external { uint256 depositedAmount = bandwidthManager.addBandwidth(msg.sender, _bandwidthAmount); token.transferFrom(msg.sender, address(this), depositedAmount); require(token.balanceOf(address(this)) <= depositCap, "AB1"); emit BandwidthChanged(msg.sender, true, _bandwidthAmount); } function subtractBandwidth(uint256 _bandwidthAmount) external nonReentrant { uint256 withdrawnAmount = bandwidthManager.subtractBandwidth(msg.sender, _bandwidthAmount); token.transfer(msg.sender, withdrawnAmount); emit BandwidthChanged(msg.sender, false, _bandwidthAmount); } function increaseFee(bytes32 _executionId, uint256 _executionTime, uint256 _addedFee) external nonReentrant { require(block.timestamp >= _executionTime, "IF1"); token.transferFrom(msg.sender, address(this), _addedFee); require(token.balanceOf(address(this)) <= depositCap, "IF2"); storageManager.increaseFee(_executionTime, _executionId, _addedFee); } // ============== // Bandwidth Provider functions // ============== function executeStandardOperations(ExecutionProof memory _executionProof) external { require(_executionProof.operations.negatedBandwidthProvider == address(0), "ESO1"); require(!_executionProof.operations.cancel, "ESO2"); require(_executionProof.operations.cancellationFeeRefund == 0, "ESO3"); (, bool executionPrepared) = _executeOperations(_executionProof, false); if (!executionPrepared) { return; } token.transfer( _executionProof.operations.recipient, _executionProof.operations.amount - _executionProof.operations.fee ); if (_executionProof.operations.callData.length > 1) { uint256 currentBalance = token.balanceOf(address(calldataInterface)); uint256 initialGasLeft = gasleft(); calldataInterface.execute(_executionProof.operations.recipient, _executionProof.operations.callData); require(_executionProof.operations.callDataGasLimit >= initialGasLeft - gasleft(), "ESO4"); require(token.balanceOf(address(calldataInterface)) == currentBalance, "ESO5"); } } function executeCancelStandardOperations(ExecutionProof memory _executionProof) external nonReentrant { require(_executionProof.operations.negatedBandwidthProvider == address(0), "ECSO1"); require(_executionProof.operations.cancel, "ECSO2"); require(_executionProof.operations.cancellationFeeRefund <= _executionProof.operations.fee, "ECSO3"); // Check that these operations were originally stored on this chain uint256 feeRefund = _executionProof.operations.cancellationFeeRefund; _executionProof.operations.cancel = false; _executionProof.operations.amount = _executionProof.operations.amount + _executionProof.operations.fee - feeRefund; _executionProof.operations.cancellationFeeRefund = 0; bytes32 executionId = getExecutionId(departingPathwayId, _executionProof.operations); require(storageManager.getExecutionIdStored(_executionProof.operations.executionTime, executionId), "ECSO4"); // Execute the operations _executionProof.operations.cancel = true; _executionProof.operations.amount = _executionProof.operations.amount - _executionProof.operations.fee + feeRefund; _executionProof.operations.cancellationFeeRefund = feeRefund; (, bool executionPrepared) = _executeOperations(_executionProof, false); if (!executionPrepared) { return; } token.transfer( _executionProof.operations.sender, _executionProof.operations.amount - _executionProof.operations.fee ); } function executeNegationOperations( ExecutionProof memory _negationExecutionProof, ExecutionProof memory _invalidExecutionProof ) external nonReentrant { require(_negationExecutionProof.operations.negatedBandwidthProvider != address(0), "ENO1"); require(!_negationExecutionProof.operations.cancel, "ENO2"); require(_negationExecutionProof.operations.cancellationFeeRefund == 0, "ENO3"); bytes32 invalidExecutionProofId = getInvalidExecutionProofId(_invalidExecutionProof); require(invalidExecutionProofId == _negationExecutionProof.operations.invalidExecutionProofId, "ENO4"); bytes32 invalidExecutionId = getExecutionId(departingPathwayId, _invalidExecutionProof.operations); bool executionValidity = getExecutionValidity( _negationExecutionProof.operations.negatedBandwidthProvider, invalidExecutionId, _invalidExecutionProof ); require(_negationExecutionProof.operations.initialNegation != executionValidity, "ENO5"); (, bool executionPrepared) = _executeOperations(_negationExecutionProof, false); if (!executionPrepared) { return; } token.transfer( _negationExecutionProof.operations.recipient, _negationExecutionProof.operations.amount - _negationExecutionProof.operations.fee ); } // ============== // Private functions // ============== function _storeOperations(Operations memory _operations) private { require(_operations.recipient != address(0), "SO1"); require(_operations.sender == msg.sender, "SO2"); if (!_operations.cancel) { require(_operations.amount >= 2 * _operations.fee, "SO3"); } else { require(_operations.amount >= _operations.fee, "SO4"); } require(token.balanceOf(address(this)) <= depositCap, "SO5"); _operations.executionTime = block.timestamp; bytes32 executionId = getExecutionId(departingPathwayId, _operations); require(!storageManager.getExecutionIdStored(_operations.executionTime, executionId), "SO6"); storageManager.storeExecutionId(_operations.executionTime, executionId, _operations.sender, _operations.amount); emit OperationsStored(executionId, _operations); } function _executeOperations(ExecutionProof memory _executionProof, bool _cancel) internal returns (uint256, bool) { require(_executionProof.operations.recipient != address(0), "EO1"); require(block.timestamp >= _executionProof.operations.executionTime, "EO2"); bytes32 executionId = getExecutionId(arrivingPathwayId, _executionProof.operations); (uint256 partialFee, uint256 bandwidthUsed, bool executionPrepared) = storageManager.prepareExecutionId(executionId, msg.sender, _executionProof); if (!_cancel) { require(recoverSigner(executionId, _executionProof) == msg.sender, "EO3"); bandwidthManager.proveBandwidth(msg.sender, bandwidthUsed); token.transfer(msg.sender, partialFee); } emit OperationsExecuted(executionId, msg.sender, _executionProof, executionPrepared); return (partialFee, executionPrepared); } }
Contract ABI
[{"type":"constructor","inputs":[{"type":"tuple","name":"_params","internalType":"struct LayerCakeTools.ConstructorParams","components":[{"type":"bool"},{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"address"},{"type":"string"},{"type":"string"},{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"address"},{"type":"uint256"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addBandwidth","inputs":[{"type":"uint256","name":"_bandwidthAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"arrivingPathwayId","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract LayerCakeBandwidthManager"}],"name":"bandwidthManager","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract LayerCakeCalldataInterface"}],"name":"calldataInterface","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelStandardOperations","inputs":[{"type":"tuple","name":"_operations","internalType":"struct LayerCakeExecutionProof.Operations","components":[{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"address"},{"type":"address"},{"type":"uint256"},{"type":"uint256"},{"type":"bytes"},{"type":"bool"},{"type":"uint256"},{"type":"address"},{"type":"bool"},{"type":"bytes32"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"departingPathwayId","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"depositCap","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeCancelStandardOperations","inputs":[{"type":"tuple","name":"_executionProof","internalType":"struct LayerCakeExecutionProof.ExecutionProof","components":[{"type":"tuple","components":[{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"address"},{"type":"address"},{"type":"uint256"},{"type":"uint256"},{"type":"bytes"},{"type":"bool"},{"type":"uint256"},{"type":"address"},{"type":"bool"},{"type":"bytes32"}]},{"type":"uint256"},{"type":"uint8"},{"type":"bytes32"},{"type":"bytes32"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeNegationOperations","inputs":[{"type":"tuple","name":"_negationExecutionProof","internalType":"struct LayerCakeExecutionProof.ExecutionProof","components":[{"type":"tuple","components":[{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"address"},{"type":"address"},{"type":"uint256"},{"type":"uint256"},{"type":"bytes"},{"type":"bool"},{"type":"uint256"},{"type":"address"},{"type":"bool"},{"type":"bytes32"}]},{"type":"uint256"},{"type":"uint8"},{"type":"bytes32"},{"type":"bytes32"}]},{"type":"tuple","name":"_invalidExecutionProof","internalType":"struct LayerCakeExecutionProof.ExecutionProof","components":[{"type":"tuple","components":[{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"address"},{"type":"address"},{"type":"uint256"},{"type":"uint256"},{"type":"bytes"},{"type":"bool"},{"type":"uint256"},{"type":"address"},{"type":"bool"},{"type":"bytes32"}]},{"type":"uint256"},{"type":"uint8"},{"type":"bytes32"},{"type":"bytes32"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeStandardOperations","inputs":[{"type":"tuple","name":"_executionProof","internalType":"struct LayerCakeExecutionProof.ExecutionProof","components":[{"type":"tuple","components":[{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"address"},{"type":"address"},{"type":"uint256"},{"type":"uint256"},{"type":"bytes"},{"type":"bool"},{"type":"uint256"},{"type":"address"},{"type":"bool"},{"type":"bytes32"}]},{"type":"uint256"},{"type":"uint8"},{"type":"bytes32"},{"type":"bytes32"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"forwardedFeeDenominator","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"forwardedFeeRecipient","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes32","name":"executionId","internalType":"bytes32"}],"name":"getExecutionId","inputs":[{"type":"bytes32","name":"_pathwayId","internalType":"bytes32"},{"type":"tuple","name":"_operations","internalType":"struct LayerCakeExecutionProof.Operations","components":[{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"address"},{"type":"address"},{"type":"uint256"},{"type":"uint256"},{"type":"bytes"},{"type":"bool"},{"type":"uint256"},{"type":"address"},{"type":"bool"},{"type":"bytes32"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"getExecutionValidity","inputs":[{"type":"address","name":"_bandwidthProvider","internalType":"address"},{"type":"bytes32","name":"_executionId","internalType":"bytes32"},{"type":"tuple","name":"_executionProof","internalType":"struct LayerCakeExecutionProof.ExecutionProof","components":[{"type":"tuple","components":[{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"address"},{"type":"address"},{"type":"uint256"},{"type":"uint256"},{"type":"bytes"},{"type":"bool"},{"type":"uint256"},{"type":"address"},{"type":"bool"},{"type":"bytes32"}]},{"type":"uint256"},{"type":"uint8"},{"type":"bytes32"},{"type":"bytes32"}]}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes32","name":"invalidExecutionProofId","internalType":"bytes32"}],"name":"getInvalidExecutionProofId","inputs":[{"type":"tuple","name":"_invalidExecutionProof","internalType":"struct LayerCakeExecutionProof.ExecutionProof","components":[{"type":"tuple","components":[{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"address"},{"type":"address"},{"type":"uint256"},{"type":"uint256"},{"type":"bytes"},{"type":"bool"},{"type":"uint256"},{"type":"address"},{"type":"bool"},{"type":"bytes32"}]},{"type":"uint256"},{"type":"uint8"},{"type":"bytes32"},{"type":"bytes32"}]}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes32","name":"pathwayId","internalType":"bytes32"}],"name":"getPathwayId","inputs":[{"type":"uint256","name":"_originChainId","internalType":"uint256"},{"type":"uint256","name":"_destinationChainId","internalType":"uint256"},{"type":"uint256","name":"_assetId","internalType":"uint256"},{"type":"uint256","name":"_contractId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"increaseFee","inputs":[{"type":"bytes32","name":"_executionId","internalType":"bytes32"},{"type":"uint256","name":"_executionTime","internalType":"uint256"},{"type":"uint256","name":"_addedFee","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isDestinationChain","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"recoverSigner","inputs":[{"type":"bytes32","name":"_hash","internalType":"bytes32"},{"type":"tuple","name":"_executionProof","internalType":"struct LayerCakeExecutionProof.ExecutionProof","components":[{"type":"tuple","components":[{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"address"},{"type":"address"},{"type":"uint256"},{"type":"uint256"},{"type":"bytes"},{"type":"bool"},{"type":"uint256"},{"type":"address"},{"type":"bool"},{"type":"bytes32"}]},{"type":"uint256"},{"type":"uint8"},{"type":"bytes32"},{"type":"bytes32"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract LayerCakeStorageManager"}],"name":"storageManager","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"storeNegationOperations","inputs":[{"type":"tuple","name":"_operations","internalType":"struct LayerCakeExecutionProof.Operations","components":[{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"address"},{"type":"address"},{"type":"uint256"},{"type":"uint256"},{"type":"bytes"},{"type":"bool"},{"type":"uint256"},{"type":"address"},{"type":"bool"},{"type":"bytes32"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"storeStandardOperations","inputs":[{"type":"tuple","name":"_operations","internalType":"struct LayerCakeExecutionProof.Operations","components":[{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"address"},{"type":"address"},{"type":"uint256"},{"type":"uint256"},{"type":"bytes"},{"type":"bool"},{"type":"uint256"},{"type":"address"},{"type":"bool"},{"type":"bytes32"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"subtractBandwidth","inputs":[{"type":"uint256","name":"_bandwidthAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"token","inputs":[]},{"type":"event","name":"BandwidthChanged","inputs":[{"type":"address","name":"bandwidthProvider","indexed":false},{"type":"bool","name":"added","indexed":false},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false},{"type":"event","name":"OperationsExecuted","inputs":[{"type":"bytes32","name":"executionId","indexed":false},{"type":"address","name":"bandwidthProvider","indexed":false},{"type":"tuple","name":"executionProof","indexed":false,"components":[{"type":"tuple","components":[{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"address"},{"type":"address"},{"type":"uint256"},{"type":"uint256"},{"type":"bytes"},{"type":"bool"},{"type":"uint256"},{"type":"address"},{"type":"bool"},{"type":"bytes32"}]},{"type":"uint256"},{"type":"uint8"},{"type":"bytes32"},{"type":"bytes32"}]},{"type":"bool","name":"executionPrepared","indexed":false}],"anonymous":false},{"type":"event","name":"OperationsStored","inputs":[{"type":"bytes32","name":"executionId","indexed":false},{"type":"tuple","name":"operations","indexed":false,"components":[{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"address"},{"type":"address"},{"type":"uint256"},{"type":"uint256"},{"type":"bytes"},{"type":"bool"},{"type":"uint256"},{"type":"address"},{"type":"bool"},{"type":"bytes32"}]}],"anonymous":false}]
Contract Creation Code
0x6101c06040523480156200001257600080fd5b5060405162007970380380620079708339810160408190526200003591620003bc565b600160005580511515608090815260208083015160408085015160608087015186880151845160a0818901819052601260c0830152711b185e595c98d85ad954185d1a1dd85e525960721b60e08084019190915282880198909852938101949094529683015281019490945280518085039092018252610100909301909252815191012060a090815260408281015160208085015160608087015160808089015187518087018a9052601260c0820152711b185e595c98d85ad954185d1a1dd85e525960721b60e080830191909152818a0198909852938401949094528201529485015282518085039092018252610100909301909152805191012060c05260a08101516001600160a01b0390811660e0526101008083015190526101808083015190911690526101a080820151905261012081015161014082015161016083015160405130939291906200018a9062000262565b6001600160a01b039094168452602084019290925260408301526060820152608001604051809103906000f080158015620001c9573d6000803e3d6000fd5b506001600160a01b0316610120526040513090620001e79062000270565b6001600160a01b039091168152602001604051809103906000f08015801562000214573d6000803e3d6000fd5b506001600160a01b03166101405260405162000230906200027e565b604051809103906000f0801580156200024d573d6000803e3d6000fd5b506001600160a01b03166101605250620004f7565b611394806200381183390190565b6129ec8062004ba583390190565b6103df806200759183390190565b634e487b7160e01b600052604160045260246000fd5b6040516101c081016001600160401b0381118282101715620002c857620002c86200028c565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620002f957620002f96200028c565b604052919050565b805180151581146200031257600080fd5b919050565b80516001600160a01b03811681146200031257600080fd5b600082601f8301126200034157600080fd5b81516001600160401b038111156200035d576200035d6200028c565b602062000373601f8301601f19168201620002ce565b82815285828487010111156200038857600080fd5b60005b83811015620003a85785810183015182820184015282016200038b565b506000928101909101919091529392505050565b600060208284031215620003cf57600080fd5b81516001600160401b0380821115620003e757600080fd5b908301906101c08286031215620003fd57600080fd5b62000407620002a2565b620004128362000301565b8152602083015160208201526040830151604082015260608301516060820152608083015160808201526200044a60a0840162000317565b60a082015260c0830151828111156200046257600080fd5b62000470878286016200032f565b60c08301525060e0830151828111156200048957600080fd5b62000497878286016200032f565b60e08301525061010083810151908201526101208084015190820152610140808401519082015261016080840151908201526101809150620004db82840162000317565b918101919091526101a091820151918101919091529392505050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a05161314e620006c36000396000818161027201528181611c4a0152611c720152600081816102fa01528181611cf201528181611dd30152611e580152600081816102d30152818161065b0152818161071f01526107e501526000818161032101528181610d5601528181611016015281816111db0152818161142a0152818161220c015281816126ed01526127e1015260008181610299015281816108d801528181611737015281816117e4015261230b015260008181610439015281816109f90152818161133d01526125d301526000818161047301528181610593015281816106860152818161080f0152818161096701528181610a1b01528181610e7d015281816112ab0152818161135f0152818161153d015281816115cf015281816116610152818161187801528181611b1601528181611d1d01528181611da401528181611e8201528181611f4001528181611fd2015281816120640152818161238901526125f50152600081816101e001528181610fc001526121da0152600081816103ff01528181610d1101528181611a5401526126a90152600061024b015261314e6000f3fe608060405234801561001057600080fd5b50600436106101585760003560e01c806393f3dd48116100c3578063b94007901161007c578063b9400790146103e7578063bec24f2d146103fa578063d0f1b18a14610421578063dbd5edc714610434578063e7c09a6b1461045b578063fc0c546a1461046e57600080fd5b806393f3dd48146102ce57806394f37be9146102f55780639cf001fe1461031c578063a527fba614610343578063b68397ae146103c1578063b841972a146103d457600080fd5b80634a7af61b116101155780634a7af61b146102105780634a91f7af146102335780634b4a0874146102465780635b40601f1461026d5780636e3997281461029457806376b355a3146102bb57600080fd5b8063059aa2481461015d578063061c8b9f14610172578063153f91c61461018557806328752944146101b557806334749e1f146101c85780633e7b2e8d146101db575b600080fd5b61017061016b366004612af9565b610495565b005b610170610180366004612b2e565b6108b9565b610198610193366004612b47565b610b08565b6040516001600160a01b0390911681526020015b60405180910390f35b6101706101c3366004612af9565b610bf3565b6101706101d6366004612b8e565b610f30565b6102027f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016101ac565b61022361021e366004612bc3565b611162565b60405190151581526020016101ac565b610170610241366004612c1a565b611256565b6102237f000000000000000000000000000000000000000000000000000000000000000081565b6102027f000000000000000000000000000000000000000000000000000000000000000081565b6101987f000000000000000000000000000000000000000000000000000000000000000081565b6101706102c9366004612b8e565b61149d565b6101987f000000000000000000000000000000000000000000000000000000000000000081565b6101987f000000000000000000000000000000000000000000000000000000000000000081565b6101987f000000000000000000000000000000000000000000000000000000000000000081565b610202610351366004612c46565b6040805160a060208201819052601260c0830152711b185e595c98d85ad954185d1a1dd85e525960721b60e0830152918101869052606081018590526080810184905290810182905260009061010001604051602081830303815290604052805190602001209050949350505050565b6101706103cf366004612b2e565b6117bd565b6101706103e2366004612c78565b61193a565b6101706103f5366004612b8e565b611bc7565b6102027f000000000000000000000000000000000000000000000000000000000000000081565b61020261042f366004612cd2565b6120ef565b6102027f000000000000000000000000000000000000000000000000000000000000000081565b610202610469366004612af9565b612122565b6101987f000000000000000000000000000000000000000000000000000000000000000081565b805161014001516001600160a01b0316156104e45760405162461bcd60e51b81526004016104db9060208082526004908201526345534f3160e01b604082015260600190565b60405180910390fd5b80516101000151156105215760405162461bcd60e51b81526004016104db9060208082526004908201526322a9a79960e11b604082015260600190565b805161012001511561055e5760405162461bcd60e51b81526004016104db9060208082526004908201526345534f3360e01b604082015260600190565b600061056b826000612152565b91505080610577575050565b8151608081015160408201516020909201516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263a9059cbb92916105c59190612d25565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015610610573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106349190612d38565b50815160e0015151600110156108b5576040516370a0823160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526000917f0000000000000000000000000000000000000000000000000000000000000000909116906370a0823190602401602060405180830381865afa1580156106cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f39190612d5c565b905060005a8451608081015160e090910151604051631cff79cd60e01b81529293506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692631cff79cd92610754929091600401612dc5565b600060405180830381600087803b15801561076e57600080fd5b505af1158015610782573d6000803e3d6000fd5b505050505a6107919082612d25565b845160c0015110156107ce5760405162461bcd60e51b81526004016104db906020808252600490820152631154d3cd60e21b604082015260600190565b6040516370a0823160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015283917f0000000000000000000000000000000000000000000000000000000000000000909116906370a0823190602401602060405180830381865afa158015610858573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087c9190612d5c565b146108b25760405162461bcd60e51b81526004016104db9060208082526004908201526345534f3560e01b604082015260600190565b50505b5050565b604051630b7aa9b360e11b8152336004820152602481018290526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906316f55366906044016020604051808303816000875af1158015610929573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094d9190612d5c565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906109a090339030908690600401612de9565b6020604051808303816000875af11580156109bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e39190612d38565b506040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610a6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8e9190612d5c565b1115610ac25760405162461bcd60e51b815260206004820152600360248201526241423160e81b60448201526064016104db565b60408051338152600160208201529081018390527fd41dce42e61c0eaa6604c711b2c0d1bfa41d005d6c2b965aeca8dfac156ce118906060015b60405180910390a15050565b6000806040518060400160405280601c81526020017f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250905060008185604051602001610b58929190612e0d565b604051602081830303815290604052805190602001209050600060018286604001518760600151886080015160405160008152602001604052604051610bba949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015610bdc573d6000803e3d6000fd5b5050604051601f1901519450505050505b92915050565b610bfb61244d565b805161014001516001600160a01b031615610c405760405162461bcd60e51b81526020600482015260056024820152644543534f3160d81b60448201526064016104db565b80516101000151610c7b5760405162461bcd60e51b815260206004820152600560248201526422a1a9a79960d91b60448201526064016104db565b80516040810151610120909101511115610cbf5760405162461bcd60e51b81526020600482015260056024820152644543534f3360d81b60448201526064016104db565b805161012081015160006101009092019190915281516040810151602091909101518291610cec91612e2f565b610cf69190612d25565b825160200152815160006101209091018190528251610d36907f0000000000000000000000000000000000000000000000000000000000000000906120ef565b835160a00151604051636cd7285760e01b81529192506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691636cd7285791610d94918590600401918252602082015260400190565b602060405180830381865afa158015610db1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd59190612d38565b610e095760405162461bcd60e51b81526020600482015260056024820152641150d4d3cd60da1b60448201526064016104db565b8251600161010090910152825160408101516020909101518391610e2c91612d25565b610e369190612e2f565b8351602001528251610120018290526000610e518482612152565b91505080610e6157505050610f23565b8351606081015160408201516020909201516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263a9059cbb9291610eaf9190612d25565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015610efa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1e9190612d38565b505050505b610f2d6001600055565b50565b610f3861244d565b6101408101516001600160a01b031615610f7d5760405162461bcd60e51b81526004016104db9060208082526004908201526343534f3160e01b604082015260600190565b80610100015115610fb95760405162461bcd60e51b81526004016104db9060208082526004908201526321a9a79960e11b604082015260600190565b6000610fe57f0000000000000000000000000000000000000000000000000000000000000000836120ef565b60a083015160405163d9c0e1b960e01b81526004810191909152602481018290529091506000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d9c0e1b9906044016040805180830381865afa15801561105c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110809190612e42565b50905080156110ba5760405162461bcd60e51b81526004016104db9060208082526004908201526343534f3360e01b604082015260600190565b6040805160a0810182528481526020808601519082015260009181018290526060810182905260808101829052906110f3826001612152565b935090508261112d5760405162461bcd60e51b81526004016104db9060208082526004908201526310d4d3cd60e21b604082015260600190565b600161010086015260408501516020860151829161114a91612d25565b6111549190612e2f565b6020860152610f1e856124a6565b6000836001600160a01b03166111788484610b08565b6001600160a01b0316146111b75760405162461bcd60e51b81526004016104db906020808252600490820152634745563160e01b604082015260600190565b815160a00151604051636cd7285760e01b81526004810191909152602481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636cd7285790604401602060405180830381865afa15801561122a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124e9190612d38565b949350505050565b61125e61244d565b814210156112945760405162461bcd60e51b815260206004820152600360248201526249463160e81b60448201526064016104db565b6040516323b872dd60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906112e490339030908690600401612de9565b6020604051808303816000875af1158015611303573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113279190612d38565b506040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156113ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d29190612d5c565b11156114065760405162461bcd60e51b815260206004820152600360248201526224a31960e91b60448201526064016104db565b6040516360f54f2360e01b81526004810183905260248101849052604481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906360f54f2390606401600060405180830381600087803b15801561147657600080fd5b505af115801561148a573d6000803e3d6000fd5b505050506114986001600055565b505050565b6114a561244d565b6101408101516001600160a01b03166114e95760405162461bcd60e51b81526004016104db90602080825260049082015263534e4f3160e01b604082015260600190565b806101000151156115255760405162461bcd60e51b81526004016104db9060208082526004908201526329a7279960e11b604082015260600190565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561158c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b09190612d5c565b60208301516040516323b872dd60e01b81529192506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916323b872dd916116069133913091600401612de9565b6020604051808303816000875af1158015611625573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116499190612d38565b506040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156116b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d49190612d5c565b6116de9190612d25565b6020830181905261014083015160408085015161016086015161018087015192516343fe9b2160e11b81526001600160a01b039485166004820152602481019590955260448501919091521515606484015260848301527f000000000000000000000000000000000000000000000000000000000000000016906387fd36429060a4016020604051808303816000875af1158015611780573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a49190612d5c565b60208301526117b2826124a6565b50610f2d6001600055565b6117c561244d565b604051633718dc9960e21b8152336004820152602481018290526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063dc637264906044016020604051808303816000875af1158015611835573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118599190612d5c565b60405163a9059cbb60e01b8152336004820152602481018290529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303816000875af11580156118c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ed9190612d38565b5060408051338152600060208201529081018390527fd41dce42e61c0eaa6604c711b2c0d1bfa41d005d6c2b965aeca8dfac156ce1189060600160405180910390a150610f2d6001600055565b61194261244d565b815161014001516001600160a01b03166119875760405162461bcd60e51b81526004016104db90602080825260049082015263454e4f3160e01b604082015260600190565b81516101000151156119c45760405162461bcd60e51b81526004016104db9060208082526004908201526322a7279960e11b604082015260600190565b8151610120015115611a015760405162461bcd60e51b81526004016104db90602080825260049082015263454e4f3360e01b604082015260600190565b6000611a0c82612122565b835161018001519091508114611a4d5760405162461bcd60e51b81526004016104db90602080825260049082015263115393cd60e21b604082015260600190565b6000611a7d7f000000000000000000000000000000000000000000000000000000000000000084600001516120ef565b90506000611a95856000015161014001518386611162565b905080151585600001516101600151151503611adc5760405162461bcd60e51b81526004016104db90602080825260049082015263454e4f3560e01b604082015260600190565b6000611ae9866000612152565b91505080611afa5750505050611bbd565b8551608081015160408201516020909201516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263a9059cbb9291611b489190612d25565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015611b93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bb79190612d38565b50505050505b6108b56001600055565b6101408101516001600160a01b031615611c0c5760405162461bcd60e51b81526004016104db9060208082526004908201526353534f3160e01b604082015260600190565b80610100015115611c485760405162461bcd60e51b81526004016104db9060208082526004908201526329a9a79960e11b604082015260600190565b7f000000000000000000000000000000000000000000000000000000000000000015611f285760007f00000000000000000000000000000000000000000000000000000000000000008260200151611ca09190612e70565b905060008111611cdb5760405162461bcd60e51b81526004016104db9060208082526004908201526353534f3360e01b604082015260600190565b6040516370a0823160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526000917f0000000000000000000000000000000000000000000000000000000000000000909116906370a0823190602401602060405180830381865afa158015611d66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d8a9190612d5c565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90611dfd9033907f0000000000000000000000000000000000000000000000000000000000000000908790600401612de9565b6020604051808303816000875af1158015611e1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e409190612d38565b506040516370a0823160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282917f0000000000000000000000000000000000000000000000000000000000000000909116906370a0823190602401602060405180830381865afa158015611ecb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eef9190612d5c565b11611f255760405162461bcd60e51b81526004016104db9060208082526004908201526314d4d3cd60e21b604082015260600190565b50505b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611f8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb39190612d5c565b60208301516040516323b872dd60e01b81529192506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916323b872dd916120099133913091600401612de9565b6020604051808303816000875af1158015612028573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061204c9190612d38565b506040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156120b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d79190612d5c565b6120e19190612d25565b60208301526108b5826124a6565b60008282604051602001612104929190612f68565b60405160208183030381529060405280519060200120905092915050565b6000816040516020016121359190612ff8565b604051602081830303815290604052805190602001209050919050565b81516080015160009081906001600160a01b03166121985760405162461bcd60e51b8152602060048201526003602482015262454f3160e81b60448201526064016104db565b835160a001514210156121d35760405162461bcd60e51b815260206004820152600360248201526222a79960e91b60448201526064016104db565b60006122037f000000000000000000000000000000000000000000000000000000000000000086600001516120ef565b905060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663df38e2c685338b6040518463ffffffff1660e01b815260040161225a9392919061303f565b6060604051808303816000875af1158015612279573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229d9190613072565b9250925092508661240257336122b3858a610b08565b6001600160a01b0316146122ef5760405162461bcd60e51b8152602060048201526003602482015262454f3360e81b60448201526064016104db565b6040516309c9289360e01b8152336004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906309c9289390604401600060405180830381600087803b15801561235757600080fd5b505af115801561236b573d6000803e3d6000fd5b505060405163a9059cbb60e01b8152336004820152602481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316925063a9059cbb91506044016020604051808303816000875af11580156123dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124009190612d38565b505b7fd115da8ce04ecb5f5673d0fa69278738b6d20e036d733108e0412a9c6d7a69a684338a8460405161243794939291906130ab565b60405180910390a1919791965090945050505050565b60026000540361249f5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016104db565b6002600055565b60808101516001600160a01b03166124e65760405162461bcd60e51b8152602060048201526003602482015262534f3160e81b60448201526064016104db565b60608101516001600160a01b031633146125285760405162461bcd60e51b815260206004820152600360248201526229a79960e91b60448201526064016104db565b8061010001516125805760408101516125429060026130e8565b8160200151101561257b5760405162461bcd60e51b8152602060048201526003602482015262534f3360e81b60448201526064016104db565b6125be565b8060400151816020015110156125be5760405162461bcd60e51b815260206004820152600360248201526214d3cd60ea1b60448201526064016104db565b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612644573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126689190612d5c565b111561269c5760405162461bcd60e51b8152602060048201526003602482015262534f3560e81b60448201526064016104db565b4260a082015260006126ce7f0000000000000000000000000000000000000000000000000000000000000000836120ef565b60a0830151604051636cd7285760e01b81529192506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691636cd728579161272b918590600401918252602082015260400190565b602060405180830381865afa158015612748573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061276c9190612d38565b1561279f5760405162461bcd60e51b815260206004820152600360248201526229a79b60e91b60448201526064016104db565b60a08201516060830151602084015160405163af6f128f60e01b81526004810193909352602483018490526001600160a01b03918216604484015260648301527f0000000000000000000000000000000000000000000000000000000000000000169063af6f128f90608401600060405180830381600087803b15801561282557600080fd5b505af1158015612839573d6000803e3d6000fd5b505050507f5815d7d4608a302ed19ea5444fef66f7d12df25625d7571490f234a5fc4ed91a8183604051610afc9291906130ff565b634e487b7160e01b600052604160045260246000fd5b6040516101a0810167ffffffffffffffff811182821017156128a8576128a861286e565b60405290565b80356001600160a01b03811681146128c557600080fd5b919050565b600082601f8301126128db57600080fd5b813567ffffffffffffffff808211156128f6576128f661286e565b604051601f8301601f19908116603f0116810190828211818310171561291e5761291e61286e565b8160405283815286602085880101111561293757600080fd5b836020870160208301376000602085830101528094505050505092915050565b8015158114610f2d57600080fd5b80356128c581612957565b60006101a0828403121561298357600080fd5b61298b612884565b90508135815260208201356020820152604082013560408201526129b1606083016128ae565b60608201526129c2608083016128ae565b608082015260a082013560a082015260c082013560c082015260e082013567ffffffffffffffff8111156129f557600080fd5b612a01848285016128ca565b60e083015250610100612a15818401612965565b908201526101208281013590820152610140612a328184016128ae565b90820152610160612a44838201612965565b818301525061018080830135818301525092915050565b600060a08284031215612a6d57600080fd5b60405160a0810167ffffffffffffffff8282108183111715612a9157612a9161286e565b816040528293508435915080821115612aa957600080fd5b50612ab685828601612970565b82525060208301356020820152604083013560ff81168114612ad757600080fd5b8060408301525060608301356060820152608083013560808201525092915050565b600060208284031215612b0b57600080fd5b813567ffffffffffffffff811115612b2257600080fd5b61124e84828501612a5b565b600060208284031215612b4057600080fd5b5035919050565b60008060408385031215612b5a57600080fd5b82359150602083013567ffffffffffffffff811115612b7857600080fd5b612b8485828601612a5b565b9150509250929050565b600060208284031215612ba057600080fd5b813567ffffffffffffffff811115612bb757600080fd5b61124e84828501612970565b600080600060608486031215612bd857600080fd5b612be1846128ae565b925060208401359150604084013567ffffffffffffffff811115612c0457600080fd5b612c1086828701612a5b565b9150509250925092565b600080600060608486031215612c2f57600080fd5b505081359360208301359350604090920135919050565b60008060008060808587031215612c5c57600080fd5b5050823594602084013594506040840135936060013592509050565b60008060408385031215612c8b57600080fd5b823567ffffffffffffffff80821115612ca357600080fd5b612caf86838701612a5b565b93506020850135915080821115612cc557600080fd5b50612b8485828601612a5b565b60008060408385031215612ce557600080fd5b82359150602083013567ffffffffffffffff811115612d0357600080fd5b612b8485828601612970565b634e487b7160e01b600052601160045260246000fd5b81810381811115610bed57610bed612d0f565b600060208284031215612d4a57600080fd5b8151612d5581612957565b9392505050565b600060208284031215612d6e57600080fd5b5051919050565b60005b83811015612d90578181015183820152602001612d78565b50506000910152565b60008151808452612db1816020860160208601612d75565b601f01601f19169290920160200192915050565b6001600160a01b038316815260406020820181905260009061124e90830184612d99565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60008351612e1f818460208801612d75565b9190910191825250602001919050565b80820180821115610bed57610bed612d0f565b60008060408385031215612e5557600080fd5b8251612e6081612957565b6020939093015192949293505050565b600082612e8d57634e487b7160e01b600052601260045260246000fd5b500490565b60006101a08251845260208301516020850152604083015160408501526060830151612ec960608601826001600160a01b03169052565b506080830151612ee460808601826001600160a01b03169052565b5060a083015160a085015260c083015160c085015260e08301518160e0860152612f1082860182612d99565b91505061010080840151612f278287018215159052565b50506101208381015190850152610140808401516001600160a01b031690850152610160808401511515908501526101809283015192909301919091525090565b6060815260146060820152731b185e595c98d85ad9515e1958dd5d1a5bdb925960621b608082015282602082015260a06040820152600061124e60a0830184612e92565b6000815160a08452612fc160a0850182612e92565b90506020830151602085015260ff604084015116604085015260608301516060850152608083015160808501528091505092915050565b60408152602060408201527f6c6179657263616b65496e76616c6964457865637574696f6e50726f6f6649646060820152608060208201526000612d556080830184612fac565b8381526001600160a01b038316602082015260606040820181905260009061306990830184612fac565b95945050505050565b60008060006060848603121561308757600080fd5b835192506020840151915060408401516130a081612957565b809150509250925092565b8481526001600160a01b03841660208201526080604082018190526000906130d590830185612fac565b9050821515606083015295945050505050565b8082028115828204841417610bed57610bed612d0f565b82815260406020820152600061124e6040830184612e9256fea26469706673582212204220a5600331d0793169219f050cc51edf7d3e39e743b8fd34b3fa96c753183b64736f6c6343000814003361018060405234801561001157600080fd5b5060405162001394380380620013948339810160408190526100329161008f565b6001600160a01b03841660805260a083905261004f8360026100da565b60c081905260e083905261010082905261012083905261006f90836100da565b6101405260e0516100819060026100da565b610160525061010592505050565b600080600080608085870312156100a557600080fd5b84516001600160a01b03811681146100bc57600080fd5b60208601516040870151606090970151919890975090945092505050565b80820281158282048414176100ff57634e487b7160e01b600052601160045260246000fd5b92915050565b60805160a05160c05160e051610100516101205161014051610160516111ab620001e96000396000818161031401526109890152600081816102ed015261081401526000818161034e015261084f0152600081816101ec0152818161090d0152610a0601526000818161023a015281816104dd0152818161053a01528181610bf50152610c520152600081816102130152818161088101528181610d8e01528181610df60152610e350152600081816102870152610e910152600081816102ae0152818161037b015281816103de015281816106f80152610af801526111ab6000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c80637996e51611610097578063bdff0f8511610066578063bdff0f85146102e8578063c164c44f1461030f578063dc63726414610336578063fca4ed171461034957600080fd5b80637996e5161461025c57806387fd36421461026f5780638a44ac4914610282578063abd05e87146102a957600080fd5b80632abce63e116100d35780632abce63e146101c7578063328d363f146101e75780633801f1e11461020e5780636b2668241461023557600080fd5b806309c92893146100fa5780630f2ab70d1461010f57806316f55366146101a6575b600080fd5b61010d610108366004611006565b610370565b005b61016461011d366004611030565b6000602081905290815260409020805460018201546002830154600384015460048501546005860154600687015460079097015460ff909616969495939492939192909188565b6040805198151589526020890197909752958701949094526060860192909252608085015260a084015260c083015260e0820152610100015b60405180910390f35b6101b96101b4366004611006565b6103d1565b60405190815260200161019d565b6101b96101d5366004611030565b60016020526000908152604090205481565b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b61010d61026a366004611052565b6105f6565b6101b961027d36600461106b565b6106eb565b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b6102d07f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161019d565b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b6101b9610344366004611006565b610aeb565b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103c15760405162461bcd60e51b81526004016103b8906110c0565b60405180910390fd5b6103cd82826001610d0c565b5050565b6000336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461041b5760405162461bcd60e51b81526004016103b8906110c0565b6001600160a01b03831660009081526020818152604091829020825161010081018452815460ff1615801582526001830154938201939093526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460e082015242928101929092526104c15760405162461bcd60e51b815260206004820152600360248201526241423160e81b60448201526064016103b8565b80602001516000036104d857604081015160208201525b6105027f0000000000000000000000000000000000000000000000000000000000000000846110f4565b156105355760405162461bcd60e51b815260206004820152600360248201526220a11960e91b60448201526064016103b8565b61055f7f00000000000000000000000000000000000000000000000000000000000000008461111e565b6105699084611132565b9150828160c0015161057b9190611132565b60c082019081526000608083018181526001600160a01b0396909616815260208181526040918290208451815460ff1916901515178155908401516001820155908301516002820155606083015160038201559451600486015560a0820151600586015551600685015560e001516007909301929092555090565b3360009081526020818152604091829020825161010081018452815460ff16151581526001820154928101929092526002810154928201929092526003820154606082015260048201546080820152600582015460a0820152600682015460c0820181905260079092015460e08201529061069c5760405162461bcd60e51b81526004016103b8906020808252600490820152635542463160e01b604082015260600190565b33600081815260016020908152604091829020859055815192835282018490527f0a364aa2b77ceec44513fac6661b16c91d64ba3414db6774a9b21f66bb7ee407910160405180910390a15050565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146107355760405162461bcd60e51b81526004016103b8906110c0565b6001600160a01b03861660009081526020818152604091829020825161010081018452815460ff161580158083526001840154948301949094526002830154948201949094526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460e0820152916107bc575060a081015115155b156107fa57828160a00151146107fa5760405162461bcd60e51b81526020600482015260036024820152624e423160e81b60448201526064016103b8565b80516109bf578060400151816060015111801561084657507f0000000000000000000000000000000000000000000000000000000000000000816040015142610843919061114b565b10155b801561087557507f00000000000000000000000000000000000000000000000000000000000000008160800151115b80156108b857506108a77f0000000000000000000000000000000000000000000000000000000000000000600261115e565b60608201516108b6904261114b565b105b1561090b5760c08101516108cc868861114b565b146108ff5760405162461bcd60e51b815260206004820152600360248201526227211960e91b60448201526064016103b8565b60006080820152610969565b7f0000000000000000000000000000000000000000000000000000000000000000610936868861114b565b146109695760405162461bcd60e51b81526020600482015260036024820152624e423360e81b60448201526064016103b8565b6080810151610979906001611132565b608082015260c08101516109ae907f00000000000000000000000000000000000000000000000000000000000000009061111e565b6109b89087611132565b9150610a2e565b60c08101516109ce868861114b565b14610a015760405162461bcd60e51b815260206004820152600360248201526213908d60ea1b60448201526064016103b8565b610a2b7f000000000000000000000000000000000000000000000000000000000000000087611132565b91505b80511580825284151514610a6a5760405162461bcd60e51b81526020600482015260036024820152624e423560e81b60448201526064016103b8565b426060820190815260a082018481526001600160a01b038916600090815260208181526040918290208551815490151560ff19909116178155908501516001820155908401516002820155915160038301556080830151600483015551600582015560c0820151600682015560e09091015160079091015595945050505050565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610b355760405162461bcd60e51b81526004016103b8906110c0565b610b4183836000610d0c565b6001600160a01b03831660009081526020818152604091829020825161010081018452815460ff16151581526001820154928101929092526002810154928201929092526003820154606082015260048201546080820152600582015460a0820152600682015460c0820181905260079092015460e082015290831115610bf05760405162461bcd60e51b815260206004820152600360248201526253423160e81b60448201526064016103b8565b610c1a7f0000000000000000000000000000000000000000000000000000000000000000846110f4565b15610c4d5760405162461bcd60e51b815260206004820152600360248201526229a11960e91b60448201526064016103b8565b610c777f00000000000000000000000000000000000000000000000000000000000000008461111e565b610c819084611132565b9150828160c00151610c93919061114b565b60c082019081526001600160a01b0394909416600090815260208181526040918290208351815460ff1916901515178155908301516001820155908201516002820155606082015160038201556080820151600482015560a082015160058201559351600685015560e001516007909301929092555090565b6001600160a01b03831660009081526020818152604091829020825161010081018452815460ff161580158083526001840154948301949094526002830154948201949094526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460e08201529190610dbf57507f0000000000000000000000000000000000000000000000000000000000000000816060015142610dbd919061114b565b115b610df45760405162461bcd60e51b81526004016103b8906020808252600490820152635042503160e01b604082015260600190565b7f000000000000000000000000000000000000000000000000000000000000000081602001518260400151610e29919061114b565b610e33919061111e565b7f0000000000000000000000000000000000000000000000000000000000000000826020015142610e64919061114b565b610e6e919061111e565b1115610efe578060e001518160c00151610e88919061114b565b831115610ef6577f0000000000000000000000000000000000000000000000000000000000000000816040015142610ec0919061114b565b11610ef65760405162461bcd60e51b81526004016103b8906020808252600490820152632821281960e11b604082015260600190565b600060e08201525b828160e001518260c00151610f13919061114b565b1015610f4a5760405162461bcd60e51b81526004016103b8906020808252600490820152635042503360e01b604082015260600190565b426040820152600060808201528115610f7357828160e00151610f6d9190611132565b60e08201525b6001600160a01b0393909316600090815260208181526040918290208551815460ff1916901515178155908501516001820155908401516002820155606084015160038201556080840151600482015560a0840151600582015560c0840151600682015560e0909301516007909301929092555050565b80356001600160a01b038116811461100157600080fd5b919050565b6000806040838503121561101957600080fd5b61102283610fea565b946020939093013593505050565b60006020828403121561104257600080fd5b61104b82610fea565b9392505050565b60006020828403121561106457600080fd5b5035919050565b600080600080600060a0868803121561108357600080fd5b61108c86610fea565b94506020860135935060408601359250606086013580151581146110af57600080fd5b949793965091946080013592915050565b6020808252600490820152634c434f3160e01b604082015260600190565b634e487b7160e01b600052601260045260246000fd5b600082611103576111036110de565b500690565b634e487b7160e01b600052601160045260246000fd5b60008261112d5761112d6110de565b500490565b8082018082111561114557611145611108565b92915050565b8181038181111561114557611145611108565b80820281158282048414176111455761114561110856fea2646970667358221220b650c8ef7935cb32106dd3761cc1d5feb14533b0ecf6aa94284a3716dbddf3e464736f6c6343000814003360c060405234801561001057600080fd5b50604051620029ec380380620029ec833981016040819052610031916100d3565b6001600160a01b0381166080524260a081905260009030906100576301e1338082610103565b604051610063906100c5565b6001600160a01b03909316835260208301919091526040820152606001604051809103906000f08015801561009c573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b03929092169190911790555061012a9050565b610c068062001de683390190565b6000602082840312156100e557600080fd5b81516001600160a01b03811681146100fc57600080fd5b9392505050565b8082018082111561012457634e487b7160e01b600052601160045260246000fd5b92915050565b60805160a051611c6562000181600039600081816101d0015281816106a6015281816106ea015281816108fc015261093701526000818161013401528181610226015281816103ad015261053e0152611c656000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063af6f128f11610071578063af6f128f14610156578063bcb25c1f14610169578063d9c0e1b914610171578063df38e2c61461019b578063e7928839146101cb578063e8170b33146101f257600080fd5b80631696ca88146100ae5780633ebba6ed146100cc57806360f54f23146100f75780636cd728571461010c578063abd05e871461012f575b600080fd5b6100b96301e1338081565b6040519081526020015b60405180910390f35b6100df6100da3660046109d9565b6101fb565b6040516001600160a01b0390911681526020016100c3565b61010a6101053660046109f2565b61021b565b005b61011f61011a366004610a1e565b6102f0565b60405190151581526020016100c3565b6100df7f000000000000000000000000000000000000000000000000000000000000000081565b61010a610164366004610a5c565b6103a2565b6100b9606481565b61018461017f366004610a1e565b610477565b6040805192151583526020830191909152016100c3565b6101ae6101a9366004610bb6565b61052f565b6040805193845260208401929092521515908201526060016100c3565b6100b97f000000000000000000000000000000000000000000000000000000000000000081565b6100b960645481565b6000816064811061020b57600080fd5b01546001600160a01b0316905081565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461026c5760405162461bcd60e51b815260040161026390610d47565b60405180910390fd5b600061027784610623565b6064811061028757610287610d65565b015460405163f1a4fa4960e01b815260048101849052602481018390526001600160a01b039091169063f1a4fa4990604401600060405180830381600087803b1580156102d357600080fd5b505af11580156102e7573d6000803e3d6000fd5b50505050505050565b60008060006102fe856108ed565b92945091925050811590506103185760009250505061039c565b6000826064811061032b5761032b610d65565b015460405163f1d8778560e01b8152600481018690526001600160a01b039091169063f1d8778590602401602060405180830381865afa158015610373573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103979190610d7b565b925050505b92915050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103ea5760405162461bcd60e51b815260040161026390610d47565b60006103f585610623565b6064811061040557610405610d65565b0154604051634e54fde760e11b8152600481018590526001600160a01b0384811660248301526044820184905290911690639ca9fbce90606401600060405180830381600087803b15801561045957600080fd5b505af115801561046d573d6000803e3d6000fd5b5050505050505050565b600080600080610486866108ed565b92945091925050811590506104a357600080935093505050610528565b600082606481106104b6576104b6610d65565b01546040516319587bad60e21b8152600481018790526001600160a01b0390911690636561eeb4906024016040805180830381865afa1580156104fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105219190610d9f565b9350935050505b9250929050565b60008080336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461057b5760405162461bcd60e51b815260040161026390610d47565b600061058e856000015160a00151610623565b6064811061059e5761059e610d65565b0154604051636f9c716360e11b81526001600160a01b039091169063df38e2c6906105d190899089908990600401610e13565b6060604051808303816000875af11580156105f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106149190610f46565b92509250925093509350939050565b6000806000806000610634866108ed565b9296509094509250905061064a60026064610fab565b6106548385610fbf565b106106895760405162461bcd60e51b8152602060048201526005602482015264434353533160d81b6044820152606401610263565b8015610790576000306106a06301e1338085610fd2565b6106ca907f0000000000000000000000000000000000000000000000000000000000000000610fe9565b6301e133806106da866001610fe9565b6106e49190610fd2565b61070e907f0000000000000000000000000000000000000000000000000000000000000000610fe9565b60405161071a906109cc565b6001600160a01b03909316835260208301919091526040820152606001604051809103906000f080158015610753573d6000803e3d6000fd5b509050806000866064811061076a5761076a610d65565b0180546001600160a01b0319166001600160a01b03929092169190911790555060648290555b600084606481106107a3576107a3610d65565b0160009054906101000a90046001600160a01b03166001600160a01b031663cf953ab26040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108199190610ffc565b86101580156108af57506000846064811061083657610836610d65565b0160009054906101000a90046001600160a01b03166001600160a01b031663c7df41b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015610888573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ac9190610ffc565b86105b6108e35760405162461bcd60e51b815260206004820152600560248201526421a1a9a99960d91b6044820152606401610263565b5091949350505050565b60008080806301e133806109217f000000000000000000000000000000000000000000000000000000000000000087610fbf565b61092b9190610fab565b91506301e1338061095c7f000000000000000000000000000000000000000000000000000000000000000042610fbf565b6109669190610fab565b925060646109748385610fbf565b106109aa5760405162461bcd60e51b8152600401610263906020808252600490820152634753533160e01b604082015260600190565b6109b5606483611015565b93506064548211156109c5575060015b9193509193565b610c068061102a83390190565b6000602082840312156109eb57600080fd5b5035919050565b600080600060608486031215610a0757600080fd5b505081359360208301359350604090920135919050565b60008060408385031215610a3157600080fd5b50508035926020909101359150565b80356001600160a01b0381168114610a5757600080fd5b919050565b60008060008060808587031215610a7257600080fd5b8435935060208501359250610a8960408601610a40565b9396929550929360600135925050565b634e487b7160e01b600052604160045260246000fd5b60405160a0810167ffffffffffffffff81118282101715610ad257610ad2610a99565b60405290565b6040516101a0810167ffffffffffffffff81118282101715610ad257610ad2610a99565b600082601f830112610b0d57600080fd5b813567ffffffffffffffff80821115610b2857610b28610a99565b604051601f8301601f19908116603f01168101908282118183101715610b5057610b50610a99565b81604052838152866020858801011115610b6957600080fd5b836020870160208301376000602085830101528094505050505092915050565b8015158114610b9757600080fd5b50565b8035610a5781610b89565b803560ff81168114610a5757600080fd5b600080600060608486031215610bcb57600080fd5b83359250610bdb60208501610a40565b9150604084013567ffffffffffffffff80821115610bf857600080fd5b9085019060a08288031215610c0c57600080fd5b610c14610aaf565b823582811115610c2357600080fd5b83016101a0818a031215610c3657600080fd5b610c3e610ad8565b813581526020820135602082015260408201356040820152610c6260608301610a40565b6060820152610c7360808301610a40565b608082015260a082013560a082015260c082013560c082015260e082013584811115610c9e57600080fd5b610caa8b828501610afc565b60e0830152506101009350610cc0848301610b9a565b84820152610120935083820135848201526101409350610ce1848301610a40565b848201526101609350610cf5848301610b9a565b8482015261018093508382013584820152808352505060208301356020820152610d2160408401610ba5565b604082015260608301356060820152608083013560808201528093505050509250925092565b6020808252600490820152634c434f3160e01b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215610d8d57600080fd5b8151610d9881610b89565b9392505050565b60008060408385031215610db257600080fd5b8251610dbd81610b89565b6020939093015192949293505050565b6000815180845260005b81811015610df357602081850181015186830182015201610dd7565b506000602082860101526020601f19601f83011685010191505092915050565b83815260018060a01b0383166020820152606060408201526000610100835160a060608501528051828501526020810151610120818187015260408301519150610140828188015260608401519250610160610e79818901856001600160a01b03169052565b60808501519350610180610e97818a01866001600160a01b03169052565b60a086015194506101a085818b015260c08701516101c08b015260e08701519550806101e08b015250610ece6102a08a0186610dcd565b9686015115156102008a015292850151610220890152908401516001600160a01b0316610240880152830151151561026087015290910151610280850152506020840151608080850191909152604085015160ff1660a0850152606085015160c08501529093015160e0909201919091525092915050565b600080600060608486031215610f5b57600080fd5b83519250602084015191506040840151610f7481610b89565b809150509250925092565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082610fba57610fba610f7f565b500490565b8181038181111561039c5761039c610f95565b808202811582820484141761039c5761039c610f95565b8082018082111561039c5761039c610f95565b60006020828403121561100e57600080fd5b5051919050565b60008261102457611024610f7f565b50069056fe60e060405234801561001057600080fd5b50604051610c06380380610c0683398101604081905261002f91610048565b6001600160a01b0390921660805260a05260c05261008b565b60008060006060848603121561005d57600080fd5b83516001600160a01b038116811461007457600080fd5b602085015160409095015190969495509392505050565b60805160a05160c051610b376100cf6000396000610281015260006102a80152600081816102220152818161033b015281816103ff01526106a50152610b376000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80639cf001fe1161008c578063cf953ab211610066578063cf953ab2146102a3578063df38e2c6146102ca578063f1a4fa49146102fa578063f1d877851461030d57600080fd5b80639cf001fe1461021d578063bb5076381461025c578063c7df41b31461027c57600080fd5b80632eb1ca36116100c85780632eb1ca361461015e5780636561eeb41461016757806366be9d62146101aa5780639ca9fbce1461020857600080fd5b8063149ee6a5146100ef5780631e3f4d7b1461010b57806326a881661461012b575b600080fd5b6100f860035481565b6040519081526020015b60405180910390f35b6100f8610119366004610734565b60046020526000908152604090205481565b61014e610139366004610756565b60006020819052908152604090205460ff1681565b6040519015158152602001610102565b6100f860025481565b610193610175366004610756565b6000908152600160208190526040909120805491015460ff90911691565b604080519215158352602083019190915201610102565b6101e66101b8366004610756565b6001602081905260009182526040909120805491810154600282015460039092015460ff9093169290919084565b6040805194151585526020850193909352918301526060820152608001610102565b61021b61021636600461076f565b610330565b005b6102447f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610102565b6100f861026a366004610734565b60056020526000908152604090205481565b6100f87f000000000000000000000000000000000000000000000000000000000000000081565b6100f87f000000000000000000000000000000000000000000000000000000000000000081565b6102dd6102d83660046108b5565b6103f0565b604080519384526020840192909252151590820152606001610102565b61021b610308366004610a46565b61069a565b61014e61031b366004610756565b60009081526020819052604090205460ff1690565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103815760405162461bcd60e51b815260040161037890610a68565b60405180910390fd5b6000838152602081905260409020805460ff191660011790556002546103a8908290610a9c565b6002556001600160a01b0382166000908152600460205260409020546103cf908290610a9c565b6001600160a01b039092166000908152600460205260409020919091555050565b60008080336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461043c5760405162461bcd60e51b815260040161037890610a68565b60008681526001602081815260408084208151608081018352815460ff1615158152938101548484018190526002820154928501929092526003015460608401528751909101519192916104909190610ab5565b9050600081116104ca5760405162461bcd60e51b8152602060048201526005602482015264504549503160d81b6044820152606401610378565b808660200151106104e15760018252602086018190525b6000826060015183604001518860000151604001516105009190610a9c565b61050a9190610ab5565b905060008282896020015161051f9190610ac8565b6105299190610adf565b9050600088602001518461053d9190610ab5565b9050600061054b8385610ab5565b905060008211801561055d5750600084115b1561059a576000811161059a5760405162461bcd60e51b81526020600482015260056024820152642822a4a81960d91b6044820152606401610378565b896020015186602001516105ae9190610a9c565b602087015260608601516105c3908490610a9c565b606087810191825260008e8152600160208181526040928390208b51815460ff1916901515178155908b01519181019190915590890151600282015591516003909201919091558a5101516001600160a01b03908116908c161461067e576020808b01516001600160a01b038d166000908152600590925260409091205461064b9190610a9c565b6001600160a01b038c166000908152600560209081526040909120919091558a015160035461067a9190610a9c565b6003555b5050602097909701519251969992985095965090945050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146106e25760405162461bcd60e51b815260040161037890610a68565b6000828152600160205260409020600201546106ff908290610a9c565b6000928352600160205260409092206002019190915550565b80356001600160a01b038116811461072f57600080fd5b919050565b60006020828403121561074657600080fd5b61074f82610718565b9392505050565b60006020828403121561076857600080fd5b5035919050565b60008060006060848603121561078457600080fd5b8335925061079460208501610718565b9150604084013590509250925092565b634e487b7160e01b600052604160045260246000fd5b60405160a0810167ffffffffffffffff811182821017156107dd576107dd6107a4565b60405290565b6040516101a0810167ffffffffffffffff811182821017156107dd576107dd6107a4565b600082601f83011261081857600080fd5b813567ffffffffffffffff80821115610833576108336107a4565b604051601f8301601f19908116603f0116810190828211818310171561085b5761085b6107a4565b8160405283815286602085880101111561087457600080fd5b836020870160208301376000602085830101528094505050505092915050565b8035801515811461072f57600080fd5b803560ff8116811461072f57600080fd5b6000806000606084860312156108ca57600080fd5b833592506108da60208501610718565b9150604084013567ffffffffffffffff808211156108f757600080fd5b9085019060a0828803121561090b57600080fd5b6109136107ba565b82358281111561092257600080fd5b83016101a0818a03121561093557600080fd5b61093d6107e3565b81358152602082013560208201526040820135604082015261096160608301610718565b606082015261097260808301610718565b608082015260a082013560a082015260c082013560c082015260e08201358481111561099d57600080fd5b6109a98b828501610807565b60e08301525061010093506109bf848301610894565b848201526101209350838201358482015261014093506109e0848301610718565b8482015261016093506109f4848301610894565b8482015261018093508382013584820152808352505060208301356020820152610a20604084016108a4565b604082015260608301356060820152608083013560808201528093505050509250925092565b60008060408385031215610a5957600080fd5b50508035926020909101359150565b602080825260049082015263534d4f3160e01b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b80820180821115610aaf57610aaf610a86565b92915050565b81810381811115610aaf57610aaf610a86565b8082028115828204841417610aaf57610aaf610a86565b600082610afc57634e487b7160e01b600052601260045260246000fd5b50049056fea2646970667358221220648a543b0d6222ccd2bccd1ae4061814995ebcf8629f087fc9d3fdffdb51db2664736f6c63430008140033a264697066735822122067f6f6f8e5482de510713e2fd4d6bbc84aae8fadd86d8ce7e4c47aacc1882e4464736f6c6343000814003360e060405234801561001057600080fd5b50604051610c06380380610c0683398101604081905261002f91610048565b6001600160a01b0390921660805260a05260c05261008b565b60008060006060848603121561005d57600080fd5b83516001600160a01b038116811461007457600080fd5b602085015160409095015190969495509392505050565b60805160a05160c051610b376100cf6000396000610281015260006102a80152600081816102220152818161033b015281816103ff01526106a50152610b376000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80639cf001fe1161008c578063cf953ab211610066578063cf953ab2146102a3578063df38e2c6146102ca578063f1a4fa49146102fa578063f1d877851461030d57600080fd5b80639cf001fe1461021d578063bb5076381461025c578063c7df41b31461027c57600080fd5b80632eb1ca36116100c85780632eb1ca361461015e5780636561eeb41461016757806366be9d62146101aa5780639ca9fbce1461020857600080fd5b8063149ee6a5146100ef5780631e3f4d7b1461010b57806326a881661461012b575b600080fd5b6100f860035481565b6040519081526020015b60405180910390f35b6100f8610119366004610734565b60046020526000908152604090205481565b61014e610139366004610756565b60006020819052908152604090205460ff1681565b6040519015158152602001610102565b6100f860025481565b610193610175366004610756565b6000908152600160208190526040909120805491015460ff90911691565b604080519215158352602083019190915201610102565b6101e66101b8366004610756565b6001602081905260009182526040909120805491810154600282015460039092015460ff9093169290919084565b6040805194151585526020850193909352918301526060820152608001610102565b61021b61021636600461076f565b610330565b005b6102447f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610102565b6100f861026a366004610734565b60056020526000908152604090205481565b6100f87f000000000000000000000000000000000000000000000000000000000000000081565b6100f87f000000000000000000000000000000000000000000000000000000000000000081565b6102dd6102d83660046108b5565b6103f0565b604080519384526020840192909252151590820152606001610102565b61021b610308366004610a46565b61069a565b61014e61031b366004610756565b60009081526020819052604090205460ff1690565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103815760405162461bcd60e51b815260040161037890610a68565b60405180910390fd5b6000838152602081905260409020805460ff191660011790556002546103a8908290610a9c565b6002556001600160a01b0382166000908152600460205260409020546103cf908290610a9c565b6001600160a01b039092166000908152600460205260409020919091555050565b60008080336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461043c5760405162461bcd60e51b815260040161037890610a68565b60008681526001602081815260408084208151608081018352815460ff1615158152938101548484018190526002820154928501929092526003015460608401528751909101519192916104909190610ab5565b9050600081116104ca5760405162461bcd60e51b8152602060048201526005602482015264504549503160d81b6044820152606401610378565b808660200151106104e15760018252602086018190525b6000826060015183604001518860000151604001516105009190610a9c565b61050a9190610ab5565b905060008282896020015161051f9190610ac8565b6105299190610adf565b9050600088602001518461053d9190610ab5565b9050600061054b8385610ab5565b905060008211801561055d5750600084115b1561059a576000811161059a5760405162461bcd60e51b81526020600482015260056024820152642822a4a81960d91b6044820152606401610378565b896020015186602001516105ae9190610a9c565b602087015260608601516105c3908490610a9c565b606087810191825260008e8152600160208181526040928390208b51815460ff1916901515178155908b01519181019190915590890151600282015591516003909201919091558a5101516001600160a01b03908116908c161461067e576020808b01516001600160a01b038d166000908152600590925260409091205461064b9190610a9c565b6001600160a01b038c166000908152600560209081526040909120919091558a015160035461067a9190610a9c565b6003555b5050602097909701519251969992985095965090945050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146106e25760405162461bcd60e51b815260040161037890610a68565b6000828152600160205260409020600201546106ff908290610a9c565b6000928352600160205260409092206002019190915550565b80356001600160a01b038116811461072f57600080fd5b919050565b60006020828403121561074657600080fd5b61074f82610718565b9392505050565b60006020828403121561076857600080fd5b5035919050565b60008060006060848603121561078457600080fd5b8335925061079460208501610718565b9150604084013590509250925092565b634e487b7160e01b600052604160045260246000fd5b60405160a0810167ffffffffffffffff811182821017156107dd576107dd6107a4565b60405290565b6040516101a0810167ffffffffffffffff811182821017156107dd576107dd6107a4565b600082601f83011261081857600080fd5b813567ffffffffffffffff80821115610833576108336107a4565b604051601f8301601f19908116603f0116810190828211818310171561085b5761085b6107a4565b8160405283815286602085880101111561087457600080fd5b836020870160208301376000602085830101528094505050505092915050565b8035801515811461072f57600080fd5b803560ff8116811461072f57600080fd5b6000806000606084860312156108ca57600080fd5b833592506108da60208501610718565b9150604084013567ffffffffffffffff808211156108f757600080fd5b9085019060a0828803121561090b57600080fd5b6109136107ba565b82358281111561092257600080fd5b83016101a0818a03121561093557600080fd5b61093d6107e3565b81358152602082013560208201526040820135604082015261096160608301610718565b606082015261097260808301610718565b608082015260a082013560a082015260c082013560c082015260e08201358481111561099d57600080fd5b6109a98b828501610807565b60e08301525061010093506109bf848301610894565b848201526101209350838201358482015261014093506109e0848301610718565b8482015261016093506109f4848301610894565b8482015261018093508382013584820152808352505060208301356020820152610a20604084016108a4565b604082015260608301356060820152608083013560808201528093505050509250925092565b60008060408385031215610a5957600080fd5b50508035926020909101359150565b602080825260049082015263534d4f3160e01b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b80820180821115610aaf57610aaf610a86565b92915050565b81810381811115610aaf57610aaf610a86565b8082028115828204841417610aaf57610aaf610a86565b600082610afc57634e487b7160e01b600052601260045260246000fd5b50049056fea2646970667358221220648a543b0d6222ccd2bccd1ae4061814995ebcf8629f087fc9d3fdffdb51db2664736f6c63430008140033608060405234801561001057600080fd5b5060016000556103ba806100256000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80631cff79cd14610030575b600080fd5b61004361003e3660046101fb565b610045565b005b61004d610133565b600080836001600160a01b03168360405161006891906102be565b6000604051808303816000865af19150503d80600081146100a5576040519150601f19603f3d011682016040523d82523d6000602084013e6100aa565b606091505b509150915081610123576044815110156100f05760405162461bcd60e51b8152602060048201526002602482015261453160f01b60448201526064015b60405180910390fd5b6004810190508080602001905181019061010a91906102da565b60405162461bcd60e51b81526004016100e79190610351565b505061012f6001600055565b5050565b6002600054036101855760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016100e7565b6002600055565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156101cb576101cb61018c565b604052919050565b600067ffffffffffffffff8211156101ed576101ed61018c565b50601f01601f191660200190565b6000806040838503121561020e57600080fd5b82356001600160a01b038116811461022557600080fd5b9150602083013567ffffffffffffffff81111561024157600080fd5b8301601f8101851361025257600080fd5b8035610265610260826101d3565b6101a2565b81815286602083850101111561027a57600080fd5b816020840160208301376000602083830101528093505050509250929050565b60005b838110156102b557818101518382015260200161029d565b50506000910152565b600082516102d081846020870161029a565b9190910192915050565b6000602082840312156102ec57600080fd5b815167ffffffffffffffff81111561030357600080fd5b8201601f8101841361031457600080fd5b8051610322610260826101d3565b81815285602083850101111561033757600080fd5b61034882602083016020860161029a565b95945050505050565b602081526000825180602084015261037081604085016020870161029a565b601f01601f1916919091016040019291505056fea26469706673582212200146d6f09e183ebac19e10a3cd0aaa0d634d27edd1fd83be6e6d1da7999d58b964736f6c63430008140033000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000072000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004d2000000000000000000000000000000000000000000000000000000000000162e000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad00000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000052b7d2dcc80cd2e40000000000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000052b7d2dcc80cd2e40000000000000000000000000000000000000000000000000000000000000000dead1c00000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000008546573745745544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000087465737457455448000000000000000000000000000000000000000000000000
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106101585760003560e01c806393f3dd48116100c3578063b94007901161007c578063b9400790146103e7578063bec24f2d146103fa578063d0f1b18a14610421578063dbd5edc714610434578063e7c09a6b1461045b578063fc0c546a1461046e57600080fd5b806393f3dd48146102ce57806394f37be9146102f55780639cf001fe1461031c578063a527fba614610343578063b68397ae146103c1578063b841972a146103d457600080fd5b80634a7af61b116101155780634a7af61b146102105780634a91f7af146102335780634b4a0874146102465780635b40601f1461026d5780636e3997281461029457806376b355a3146102bb57600080fd5b8063059aa2481461015d578063061c8b9f14610172578063153f91c61461018557806328752944146101b557806334749e1f146101c85780633e7b2e8d146101db575b600080fd5b61017061016b366004612af9565b610495565b005b610170610180366004612b2e565b6108b9565b610198610193366004612b47565b610b08565b6040516001600160a01b0390911681526020015b60405180910390f35b6101706101c3366004612af9565b610bf3565b6101706101d6366004612b8e565b610f30565b6102027fbcb94af36cf248542604fdd834ea71f2887fdbb6bf99aec16cb56fa479ab2b3881565b6040519081526020016101ac565b61022361021e366004612bc3565b611162565b60405190151581526020016101ac565b610170610241366004612c1a565b611256565b6102237f000000000000000000000000000000000000000000000000000000000000000081565b6102027f00000000000000000000000000000000000000000000000000000000000003e881565b6101987f000000000000000000000000091c95772c3e61d06910d5593a59a559ca2093c481565b6101706102c9366004612b8e565b61149d565b6101987f0000000000000000000000009c2dac4716560006e7b5b42ed48e29481e577a8581565b6101987f0000000000000000000000000000000000000000000000000000000000dead1c81565b6101987f000000000000000000000000cdcda4258412b6830cac37de84fd49412c4f64cd81565b610202610351366004612c46565b6040805160a060208201819052601260c0830152711b185e595c98d85ad954185d1a1dd85e525960721b60e0830152918101869052606081018590526080810184905290810182905260009061010001604051602081830303815290604052805190602001209050949350505050565b6101706103cf366004612b2e565b6117bd565b6101706103e2366004612c78565b61193a565b6101706103f5366004612b8e565b611bc7565b6102027f7132442aba1d518db9ed268db78cef775223717287fc18557b66d64ef6a206e981565b61020261042f366004612cd2565b6120ef565b6102027f00000000000000000000000000000000000000000052b7d2dcc80cd2e400000081565b610202610469366004612af9565b612122565b6101987f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad81565b805161014001516001600160a01b0316156104e45760405162461bcd60e51b81526004016104db9060208082526004908201526345534f3160e01b604082015260600190565b60405180910390fd5b80516101000151156105215760405162461bcd60e51b81526004016104db9060208082526004908201526322a9a79960e11b604082015260600190565b805161012001511561055e5760405162461bcd60e51b81526004016104db9060208082526004908201526345534f3360e01b604082015260600190565b600061056b826000612152565b91505080610577575050565b8151608081015160408201516020909201516001600160a01b037f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad169263a9059cbb92916105c59190612d25565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015610610573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106349190612d38565b50815160e0015151600110156108b5576040516370a0823160e01b81526001600160a01b037f0000000000000000000000009c2dac4716560006e7b5b42ed48e29481e577a85811660048301526000917f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad909116906370a0823190602401602060405180830381865afa1580156106cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f39190612d5c565b905060005a8451608081015160e090910151604051631cff79cd60e01b81529293506001600160a01b037f0000000000000000000000009c2dac4716560006e7b5b42ed48e29481e577a851692631cff79cd92610754929091600401612dc5565b600060405180830381600087803b15801561076e57600080fd5b505af1158015610782573d6000803e3d6000fd5b505050505a6107919082612d25565b845160c0015110156107ce5760405162461bcd60e51b81526004016104db906020808252600490820152631154d3cd60e21b604082015260600190565b6040516370a0823160e01b81526001600160a01b037f0000000000000000000000009c2dac4716560006e7b5b42ed48e29481e577a858116600483015283917f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad909116906370a0823190602401602060405180830381865afa158015610858573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087c9190612d5c565b146108b25760405162461bcd60e51b81526004016104db9060208082526004908201526345534f3560e01b604082015260600190565b50505b5050565b604051630b7aa9b360e11b8152336004820152602481018290526000907f000000000000000000000000091c95772c3e61d06910d5593a59a559ca2093c46001600160a01b0316906316f55366906044016020604051808303816000875af1158015610929573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094d9190612d5c565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad16906323b872dd906109a090339030908690600401612de9565b6020604051808303816000875af11580156109bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e39190612d38565b506040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000052b7d2dcc80cd2e4000000907f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad6001600160a01b0316906370a0823190602401602060405180830381865afa158015610a6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8e9190612d5c565b1115610ac25760405162461bcd60e51b815260206004820152600360248201526241423160e81b60448201526064016104db565b60408051338152600160208201529081018390527fd41dce42e61c0eaa6604c711b2c0d1bfa41d005d6c2b965aeca8dfac156ce118906060015b60405180910390a15050565b6000806040518060400160405280601c81526020017f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250905060008185604051602001610b58929190612e0d565b604051602081830303815290604052805190602001209050600060018286604001518760600151886080015160405160008152602001604052604051610bba949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015610bdc573d6000803e3d6000fd5b5050604051601f1901519450505050505b92915050565b610bfb61244d565b805161014001516001600160a01b031615610c405760405162461bcd60e51b81526020600482015260056024820152644543534f3160d81b60448201526064016104db565b80516101000151610c7b5760405162461bcd60e51b815260206004820152600560248201526422a1a9a79960d91b60448201526064016104db565b80516040810151610120909101511115610cbf5760405162461bcd60e51b81526020600482015260056024820152644543534f3360d81b60448201526064016104db565b805161012081015160006101009092019190915281516040810151602091909101518291610cec91612e2f565b610cf69190612d25565b825160200152815160006101209091018190528251610d36907f7132442aba1d518db9ed268db78cef775223717287fc18557b66d64ef6a206e9906120ef565b835160a00151604051636cd7285760e01b81529192506001600160a01b037f000000000000000000000000cdcda4258412b6830cac37de84fd49412c4f64cd1691636cd7285791610d94918590600401918252602082015260400190565b602060405180830381865afa158015610db1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd59190612d38565b610e095760405162461bcd60e51b81526020600482015260056024820152641150d4d3cd60da1b60448201526064016104db565b8251600161010090910152825160408101516020909101518391610e2c91612d25565b610e369190612e2f565b8351602001528251610120018290526000610e518482612152565b91505080610e6157505050610f23565b8351606081015160408201516020909201516001600160a01b037f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad169263a9059cbb9291610eaf9190612d25565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015610efa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1e9190612d38565b505050505b610f2d6001600055565b50565b610f3861244d565b6101408101516001600160a01b031615610f7d5760405162461bcd60e51b81526004016104db9060208082526004908201526343534f3160e01b604082015260600190565b80610100015115610fb95760405162461bcd60e51b81526004016104db9060208082526004908201526321a9a79960e11b604082015260600190565b6000610fe57fbcb94af36cf248542604fdd834ea71f2887fdbb6bf99aec16cb56fa479ab2b38836120ef565b60a083015160405163d9c0e1b960e01b81526004810191909152602481018290529091506000906001600160a01b037f000000000000000000000000cdcda4258412b6830cac37de84fd49412c4f64cd169063d9c0e1b9906044016040805180830381865afa15801561105c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110809190612e42565b50905080156110ba5760405162461bcd60e51b81526004016104db9060208082526004908201526343534f3360e01b604082015260600190565b6040805160a0810182528481526020808601519082015260009181018290526060810182905260808101829052906110f3826001612152565b935090508261112d5760405162461bcd60e51b81526004016104db9060208082526004908201526310d4d3cd60e21b604082015260600190565b600161010086015260408501516020860151829161114a91612d25565b6111549190612e2f565b6020860152610f1e856124a6565b6000836001600160a01b03166111788484610b08565b6001600160a01b0316146111b75760405162461bcd60e51b81526004016104db906020808252600490820152634745563160e01b604082015260600190565b815160a00151604051636cd7285760e01b81526004810191909152602481018490527f000000000000000000000000cdcda4258412b6830cac37de84fd49412c4f64cd6001600160a01b031690636cd7285790604401602060405180830381865afa15801561122a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124e9190612d38565b949350505050565b61125e61244d565b814210156112945760405162461bcd60e51b815260206004820152600360248201526249463160e81b60448201526064016104db565b6040516323b872dd60e01b81526001600160a01b037f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad16906323b872dd906112e490339030908690600401612de9565b6020604051808303816000875af1158015611303573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113279190612d38565b506040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000052b7d2dcc80cd2e4000000907f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad6001600160a01b0316906370a0823190602401602060405180830381865afa1580156113ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d29190612d5c565b11156114065760405162461bcd60e51b815260206004820152600360248201526224a31960e91b60448201526064016104db565b6040516360f54f2360e01b81526004810183905260248101849052604481018290527f000000000000000000000000cdcda4258412b6830cac37de84fd49412c4f64cd6001600160a01b0316906360f54f2390606401600060405180830381600087803b15801561147657600080fd5b505af115801561148a573d6000803e3d6000fd5b505050506114986001600055565b505050565b6114a561244d565b6101408101516001600160a01b03166114e95760405162461bcd60e51b81526004016104db90602080825260049082015263534e4f3160e01b604082015260600190565b806101000151156115255760405162461bcd60e51b81526004016104db9060208082526004908201526329a7279960e11b604082015260600190565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad6001600160a01b0316906370a0823190602401602060405180830381865afa15801561158c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b09190612d5c565b60208301516040516323b872dd60e01b81529192506001600160a01b037f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad16916323b872dd916116069133913091600401612de9565b6020604051808303816000875af1158015611625573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116499190612d38565b506040516370a0823160e01b815230600482015281907f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad6001600160a01b0316906370a0823190602401602060405180830381865afa1580156116b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d49190612d5c565b6116de9190612d25565b6020830181905261014083015160408085015161016086015161018087015192516343fe9b2160e11b81526001600160a01b039485166004820152602481019590955260448501919091521515606484015260848301527f000000000000000000000000091c95772c3e61d06910d5593a59a559ca2093c416906387fd36429060a4016020604051808303816000875af1158015611780573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a49190612d5c565b60208301526117b2826124a6565b50610f2d6001600055565b6117c561244d565b604051633718dc9960e21b8152336004820152602481018290526000907f000000000000000000000000091c95772c3e61d06910d5593a59a559ca2093c46001600160a01b03169063dc637264906044016020604051808303816000875af1158015611835573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118599190612d5c565b60405163a9059cbb60e01b8152336004820152602481018290529091507f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad6001600160a01b03169063a9059cbb906044016020604051808303816000875af11580156118c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ed9190612d38565b5060408051338152600060208201529081018390527fd41dce42e61c0eaa6604c711b2c0d1bfa41d005d6c2b965aeca8dfac156ce1189060600160405180910390a150610f2d6001600055565b61194261244d565b815161014001516001600160a01b03166119875760405162461bcd60e51b81526004016104db90602080825260049082015263454e4f3160e01b604082015260600190565b81516101000151156119c45760405162461bcd60e51b81526004016104db9060208082526004908201526322a7279960e11b604082015260600190565b8151610120015115611a015760405162461bcd60e51b81526004016104db90602080825260049082015263454e4f3360e01b604082015260600190565b6000611a0c82612122565b835161018001519091508114611a4d5760405162461bcd60e51b81526004016104db90602080825260049082015263115393cd60e21b604082015260600190565b6000611a7d7f7132442aba1d518db9ed268db78cef775223717287fc18557b66d64ef6a206e984600001516120ef565b90506000611a95856000015161014001518386611162565b905080151585600001516101600151151503611adc5760405162461bcd60e51b81526004016104db90602080825260049082015263454e4f3560e01b604082015260600190565b6000611ae9866000612152565b91505080611afa5750505050611bbd565b8551608081015160408201516020909201516001600160a01b037f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad169263a9059cbb9291611b489190612d25565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015611b93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bb79190612d38565b50505050505b6108b56001600055565b6101408101516001600160a01b031615611c0c5760405162461bcd60e51b81526004016104db9060208082526004908201526353534f3160e01b604082015260600190565b80610100015115611c485760405162461bcd60e51b81526004016104db9060208082526004908201526329a9a79960e11b604082015260600190565b7f00000000000000000000000000000000000000000000000000000000000003e815611f285760007f00000000000000000000000000000000000000000000000000000000000003e88260200151611ca09190612e70565b905060008111611cdb5760405162461bcd60e51b81526004016104db9060208082526004908201526353534f3360e01b604082015260600190565b6040516370a0823160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000dead1c811660048301526000917f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad909116906370a0823190602401602060405180830381865afa158015611d66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d8a9190612d5c565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad16906323b872dd90611dfd9033907f0000000000000000000000000000000000000000000000000000000000dead1c908790600401612de9565b6020604051808303816000875af1158015611e1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e409190612d38565b506040516370a0823160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000dead1c8116600483015282917f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad909116906370a0823190602401602060405180830381865afa158015611ecb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eef9190612d5c565b11611f255760405162461bcd60e51b81526004016104db9060208082526004908201526314d4d3cd60e21b604082015260600190565b50505b6040516370a0823160e01b81523060048201526000907f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad6001600160a01b0316906370a0823190602401602060405180830381865afa158015611f8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb39190612d5c565b60208301516040516323b872dd60e01b81529192506001600160a01b037f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad16916323b872dd916120099133913091600401612de9565b6020604051808303816000875af1158015612028573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061204c9190612d38565b506040516370a0823160e01b815230600482015281907f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad6001600160a01b0316906370a0823190602401602060405180830381865afa1580156120b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d79190612d5c565b6120e19190612d25565b60208301526108b5826124a6565b60008282604051602001612104929190612f68565b60405160208183030381529060405280519060200120905092915050565b6000816040516020016121359190612ff8565b604051602081830303815290604052805190602001209050919050565b81516080015160009081906001600160a01b03166121985760405162461bcd60e51b8152602060048201526003602482015262454f3160e81b60448201526064016104db565b835160a001514210156121d35760405162461bcd60e51b815260206004820152600360248201526222a79960e91b60448201526064016104db565b60006122037fbcb94af36cf248542604fdd834ea71f2887fdbb6bf99aec16cb56fa479ab2b3886600001516120ef565b905060008060007f000000000000000000000000cdcda4258412b6830cac37de84fd49412c4f64cd6001600160a01b031663df38e2c685338b6040518463ffffffff1660e01b815260040161225a9392919061303f565b6060604051808303816000875af1158015612279573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229d9190613072565b9250925092508661240257336122b3858a610b08565b6001600160a01b0316146122ef5760405162461bcd60e51b8152602060048201526003602482015262454f3360e81b60448201526064016104db565b6040516309c9289360e01b8152336004820152602481018390527f000000000000000000000000091c95772c3e61d06910d5593a59a559ca2093c46001600160a01b0316906309c9289390604401600060405180830381600087803b15801561235757600080fd5b505af115801561236b573d6000803e3d6000fd5b505060405163a9059cbb60e01b8152336004820152602481018690527f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad6001600160a01b0316925063a9059cbb91506044016020604051808303816000875af11580156123dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124009190612d38565b505b7fd115da8ce04ecb5f5673d0fa69278738b6d20e036d733108e0412a9c6d7a69a684338a8460405161243794939291906130ab565b60405180910390a1919791965090945050505050565b60026000540361249f5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016104db565b6002600055565b60808101516001600160a01b03166124e65760405162461bcd60e51b8152602060048201526003602482015262534f3160e81b60448201526064016104db565b60608101516001600160a01b031633146125285760405162461bcd60e51b815260206004820152600360248201526229a79960e91b60448201526064016104db565b8061010001516125805760408101516125429060026130e8565b8160200151101561257b5760405162461bcd60e51b8152602060048201526003602482015262534f3360e81b60448201526064016104db565b6125be565b8060400151816020015110156125be5760405162461bcd60e51b815260206004820152600360248201526214d3cd60ea1b60448201526064016104db565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000052b7d2dcc80cd2e4000000907f000000000000000000000000bbda30048189c8e505291b528ff0e9b7fddd29ad6001600160a01b0316906370a0823190602401602060405180830381865afa158015612644573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126689190612d5c565b111561269c5760405162461bcd60e51b8152602060048201526003602482015262534f3560e81b60448201526064016104db565b4260a082015260006126ce7f7132442aba1d518db9ed268db78cef775223717287fc18557b66d64ef6a206e9836120ef565b60a0830151604051636cd7285760e01b81529192506001600160a01b037f000000000000000000000000cdcda4258412b6830cac37de84fd49412c4f64cd1691636cd728579161272b918590600401918252602082015260400190565b602060405180830381865afa158015612748573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061276c9190612d38565b1561279f5760405162461bcd60e51b815260206004820152600360248201526229a79b60e91b60448201526064016104db565b60a08201516060830151602084015160405163af6f128f60e01b81526004810193909352602483018490526001600160a01b03918216604484015260648301527f000000000000000000000000cdcda4258412b6830cac37de84fd49412c4f64cd169063af6f128f90608401600060405180830381600087803b15801561282557600080fd5b505af1158015612839573d6000803e3d6000fd5b505050507f5815d7d4608a302ed19ea5444fef66f7d12df25625d7571490f234a5fc4ed91a8183604051610afc9291906130ff565b634e487b7160e01b600052604160045260246000fd5b6040516101a0810167ffffffffffffffff811182821017156128a8576128a861286e565b60405290565b80356001600160a01b03811681146128c557600080fd5b919050565b600082601f8301126128db57600080fd5b813567ffffffffffffffff808211156128f6576128f661286e565b604051601f8301601f19908116603f0116810190828211818310171561291e5761291e61286e565b8160405283815286602085880101111561293757600080fd5b836020870160208301376000602085830101528094505050505092915050565b8015158114610f2d57600080fd5b80356128c581612957565b60006101a0828403121561298357600080fd5b61298b612884565b90508135815260208201356020820152604082013560408201526129b1606083016128ae565b60608201526129c2608083016128ae565b608082015260a082013560a082015260c082013560c082015260e082013567ffffffffffffffff8111156129f557600080fd5b612a01848285016128ca565b60e083015250610100612a15818401612965565b908201526101208281013590820152610140612a328184016128ae565b90820152610160612a44838201612965565b818301525061018080830135818301525092915050565b600060a08284031215612a6d57600080fd5b60405160a0810167ffffffffffffffff8282108183111715612a9157612a9161286e565b816040528293508435915080821115612aa957600080fd5b50612ab685828601612970565b82525060208301356020820152604083013560ff81168114612ad757600080fd5b8060408301525060608301356060820152608083013560808201525092915050565b600060208284031215612b0b57600080fd5b813567ffffffffffffffff811115612b2257600080fd5b61124e84828501612a5b565b600060208284031215612b4057600080fd5b5035919050565b60008060408385031215612b5a57600080fd5b82359150602083013567ffffffffffffffff811115612b7857600080fd5b612b8485828601612a5b565b9150509250929050565b600060208284031215612ba057600080fd5b813567ffffffffffffffff811115612bb757600080fd5b61124e84828501612970565b600080600060608486031215612bd857600080fd5b612be1846128ae565b925060208401359150604084013567ffffffffffffffff811115612c0457600080fd5b612c1086828701612a5b565b9150509250925092565b600080600060608486031215612c2f57600080fd5b505081359360208301359350604090920135919050565b60008060008060808587031215612c5c57600080fd5b5050823594602084013594506040840135936060013592509050565b60008060408385031215612c8b57600080fd5b823567ffffffffffffffff80821115612ca357600080fd5b612caf86838701612a5b565b93506020850135915080821115612cc557600080fd5b50612b8485828601612a5b565b60008060408385031215612ce557600080fd5b82359150602083013567ffffffffffffffff811115612d0357600080fd5b612b8485828601612970565b634e487b7160e01b600052601160045260246000fd5b81810381811115610bed57610bed612d0f565b600060208284031215612d4a57600080fd5b8151612d5581612957565b9392505050565b600060208284031215612d6e57600080fd5b5051919050565b60005b83811015612d90578181015183820152602001612d78565b50506000910152565b60008151808452612db1816020860160208601612d75565b601f01601f19169290920160200192915050565b6001600160a01b038316815260406020820181905260009061124e90830184612d99565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60008351612e1f818460208801612d75565b9190910191825250602001919050565b80820180821115610bed57610bed612d0f565b60008060408385031215612e5557600080fd5b8251612e6081612957565b6020939093015192949293505050565b600082612e8d57634e487b7160e01b600052601260045260246000fd5b500490565b60006101a08251845260208301516020850152604083015160408501526060830151612ec960608601826001600160a01b03169052565b506080830151612ee460808601826001600160a01b03169052565b5060a083015160a085015260c083015160c085015260e08301518160e0860152612f1082860182612d99565b91505061010080840151612f278287018215159052565b50506101208381015190850152610140808401516001600160a01b031690850152610160808401511515908501526101809283015192909301919091525090565b6060815260146060820152731b185e595c98d85ad9515e1958dd5d1a5bdb925960621b608082015282602082015260a06040820152600061124e60a0830184612e92565b6000815160a08452612fc160a0850182612e92565b90506020830151602085015260ff604084015116604085015260608301516060850152608083015160808501528091505092915050565b60408152602060408201527f6c6179657263616b65496e76616c6964457865637574696f6e50726f6f6649646060820152608060208201526000612d556080830184612fac565b8381526001600160a01b038316602082015260606040820181905260009061306990830184612fac565b95945050505050565b60008060006060848603121561308757600080fd5b835192506020840151915060408401516130a081612957565b809150509250925092565b8481526001600160a01b03841660208201526080604082018190526000906130d590830185612fac565b9050821515606083015295945050505050565b8082028115828204841417610bed57610bed612d0f565b82815260406020820152600061124e6040830184612e9256fea26469706673582212204220a5600331d0793169219f050cc51edf7d3e39e743b8fd34b3fa96c753183b64736f6c63430008140033