Contract Overview
Balance:
0 Ether
Token:
More Info
My Name Tag:
Not Available
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
Contract Name:
RewardEscrowV2
Compiler Version
v0.5.16+commit.9c3226ce
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2021-01-14 */ /* ____ __ __ __ _ / __/__ __ ___ / /_ / / ___ / /_ (_)__ __ _\ \ / // // _ \/ __// _ \/ -_)/ __// / \ \ / /___/ \_, //_//_/\__//_//_/\__/ \__//_/ /_\_\ /___/ * Synthetix: RewardEscrowV2.sol * * Latest source (may be newer): https://github.com/Synthetixio/synthetix/blob/master/contracts/RewardEscrowV2.sol * Docs: https://docs.synthetix.io/contracts/RewardEscrowV2 * * Contract Dependencies: * - BaseRewardEscrowV2 * - IAddressResolver * - Owned * Libraries: * - SafeDecimalMath * - SafeMath * - VestingEntries * * MIT License * =========== * * Copyright (c) 2021 Synthetix * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ pragma solidity ^0.5.16; // https://docs.synthetix.io/contracts/source/contracts/owned contract Owned { address public owner; address public nominatedOwner; constructor(address _owner) public { require(_owner != address(0), "Owner address cannot be 0"); owner = _owner; emit OwnerChanged(address(0), _owner); } function nominateNewOwner(address _owner) external onlyOwner { nominatedOwner = _owner; emit OwnerNominated(_owner); } function acceptOwnership() external { require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership"); emit OwnerChanged(owner, nominatedOwner); owner = nominatedOwner; nominatedOwner = address(0); } modifier onlyOwner { _onlyOwner(); _; } function _onlyOwner() private view { require(msg.sender == owner, "Only the contract owner may perform this action"); } event OwnerNominated(address newOwner); event OwnerChanged(address oldOwner, address newOwner); } // https://docs.synthetix.io/contracts/source/interfaces/iaddressresolver interface IAddressResolver { function getAddress(bytes32 name) external view returns (address); function getSynth(bytes32 key) external view returns (address); function requireAndGetAddress(bytes32 name, string calldata reason) external view returns (address); } // https://docs.synthetix.io/contracts/source/interfaces/isynth interface ISynth { // Views function currencyKey() external view returns (bytes32); function transferableSynths(address account) external view returns (uint); // Mutative functions function transferAndSettle(address to, uint value) external returns (bool); function transferFromAndSettle( address from, address to, uint value ) external returns (bool); // Restricted: used internally to Synthetix function burn(address account, uint amount) external; function issue(address account, uint amount) external; } // https://docs.synthetix.io/contracts/source/interfaces/iissuer interface IIssuer { // Views function anySynthOrSNXRateIsInvalid() external view returns (bool anyRateInvalid); function availableCurrencyKeys() external view returns (bytes32[] memory); function availableSynthCount() external view returns (uint); function availableSynths(uint index) external view returns (ISynth); function canBurnSynths(address account) external view returns (bool); function collateral(address account) external view returns (uint); function collateralisationRatio(address issuer) external view returns (uint); function collateralisationRatioAndAnyRatesInvalid(address _issuer) external view returns (uint cratio, bool anyRateIsInvalid); function debtBalanceOf(address issuer, bytes32 currencyKey) external view returns (uint debtBalance); function issuanceRatio() external view returns (uint); function lastIssueEvent(address account) external view returns (uint); function maxIssuableSynths(address issuer) external view returns (uint maxIssuable); function minimumStakeTime() external view returns (uint); function remainingIssuableSynths(address issuer) external view returns ( uint maxIssuable, uint alreadyIssued, uint totalSystemDebt ); function synths(bytes32 currencyKey) external view returns (ISynth); function getSynths(bytes32[] calldata currencyKeys) external view returns (ISynth[] memory); function synthsByAddress(address synthAddress) external view returns (bytes32); function totalIssuedSynths(bytes32 currencyKey, bool excludeEtherCollateral) external view returns (uint); function transferableSynthetixAndAnyRateIsInvalid(address account, uint balance) external view returns (uint transferable, bool anyRateIsInvalid); // Restricted: used internally to Synthetix function issueSynths(address from, uint amount) external; function issueSynthsOnBehalf( address issueFor, address from, uint amount ) external; function issueMaxSynths(address from) external; function issueMaxSynthsOnBehalf(address issueFor, address from) external; function burnSynths(address from, uint amount) external; function burnSynthsOnBehalf( address burnForAddress, address from, uint amount ) external; function burnSynthsToTarget(address from) external; function burnSynthsToTargetOnBehalf(address burnForAddress, address from) external; function liquidateDelinquentAccount( address account, uint susdAmount, address liquidator ) external returns (uint totalRedeemed, uint amountToLiquidate); } // Inheritance // Internal references // https://docs.synthetix.io/contracts/source/contracts/addressresolver contract AddressResolver is Owned, IAddressResolver { mapping(bytes32 => address) public repository; constructor(address _owner) public Owned(_owner) {} /* ========== RESTRICTED FUNCTIONS ========== */ function importAddresses(bytes32[] calldata names, address[] calldata destinations) external onlyOwner { require(names.length == destinations.length, "Input lengths must match"); for (uint i = 0; i < names.length; i++) { bytes32 name = names[i]; address destination = destinations[i]; repository[name] = destination; emit AddressImported(name, destination); } } /* ========= PUBLIC FUNCTIONS ========== */ function rebuildCaches(MixinResolver[] calldata destinations) external { for (uint i = 0; i < destinations.length; i++) { destinations[i].rebuildCache(); } } /* ========== VIEWS ========== */ function areAddressesImported(bytes32[] calldata names, address[] calldata destinations) external view returns (bool) { for (uint i = 0; i < names.length; i++) { if (repository[names[i]] != destinations[i]) { return false; } } return true; } function getAddress(bytes32 name) external view returns (address) { return repository[name]; } function requireAndGetAddress(bytes32 name, string calldata reason) external view returns (address) { address _foundAddress = repository[name]; require(_foundAddress != address(0), reason); return _foundAddress; } function getSynth(bytes32 key) external view returns (address) { IIssuer issuer = IIssuer(repository["Issuer"]); require(address(issuer) != address(0), "Cannot find Issuer address"); return address(issuer.synths(key)); } /* ========== EVENTS ========== */ event AddressImported(bytes32 name, address destination); } // solhint-disable payable-fallback // https://docs.synthetix.io/contracts/source/contracts/readproxy contract ReadProxy is Owned { address public target; constructor(address _owner) public Owned(_owner) {} function setTarget(address _target) external onlyOwner { target = _target; emit TargetUpdated(target); } function() external { // The basics of a proxy read call // Note that msg.sender in the underlying will always be the address of this contract. assembly { calldatacopy(0, 0, calldatasize) // Use of staticcall - this will revert if the underlying function mutates state let result := staticcall(gas, sload(target_slot), 0, calldatasize, 0, 0) returndatacopy(0, 0, returndatasize) if iszero(result) { revert(0, returndatasize) } return(0, returndatasize) } } event TargetUpdated(address newTarget); } // Inheritance // Internal references // https://docs.synthetix.io/contracts/source/contracts/mixinresolver contract MixinResolver { AddressResolver public resolver; mapping(bytes32 => address) private addressCache; constructor(address _resolver) internal { resolver = AddressResolver(_resolver); } /* ========== INTERNAL FUNCTIONS ========== */ function combineArrays(bytes32[] memory first, bytes32[] memory second) internal pure returns (bytes32[] memory combination) { combination = new bytes32[](first.length + second.length); for (uint i = 0; i < first.length; i++) { combination[i] = first[i]; } for (uint j = 0; j < second.length; j++) { combination[first.length + j] = second[j]; } } /* ========== PUBLIC FUNCTIONS ========== */ // Note: this function is public not external in order for it to be overridden and invoked via super in subclasses function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {} function rebuildCache() public { bytes32[] memory requiredAddresses = resolverAddressesRequired(); // The resolver must call this function whenver it updates its state for (uint i = 0; i < requiredAddresses.length; i++) { bytes32 name = requiredAddresses[i]; // Note: can only be invoked once the resolver has all the targets needed added address destination = resolver.requireAndGetAddress( name, string(abi.encodePacked("Resolver missing target: ", name)) ); addressCache[name] = destination; emit CacheUpdated(name, destination); } } /* ========== VIEWS ========== */ function isResolverCached() external view returns (bool) { bytes32[] memory requiredAddresses = resolverAddressesRequired(); for (uint i = 0; i < requiredAddresses.length; i++) { bytes32 name = requiredAddresses[i]; // false if our cache is invalid or if the resolver doesn't have the required address if (resolver.getAddress(name) != addressCache[name] || addressCache[name] == address(0)) { return false; } } return true; } /* ========== INTERNAL FUNCTIONS ========== */ function requireAndGetAddress(bytes32 name) internal view returns (address) { address _foundAddress = addressCache[name]; require(_foundAddress != address(0), string(abi.encodePacked("Missing address: ", name))); return _foundAddress; } /* ========== EVENTS ========== */ event CacheUpdated(bytes32 name, address destination); } // https://docs.synthetix.io/contracts/source/contracts/limitedsetup contract LimitedSetup { uint public setupExpiryTime; /** * @dev LimitedSetup Constructor. * @param setupDuration The time the setup period will last for. */ constructor(uint setupDuration) internal { setupExpiryTime = now + setupDuration; } modifier onlyDuringSetup { require(now < setupExpiryTime, "Can only perform this action during setup"); _; } } pragma experimental ABIEncoderV2; library VestingEntries { struct VestingEntry { uint64 endTime; uint256 escrowAmount; } struct VestingEntryWithID { uint64 endTime; uint256 escrowAmount; uint256 entryID; } } interface IRewardEscrowV2 { // Views function balanceOf(address account) external view returns (uint); function numVestingEntries(address account) external view returns (uint); function totalEscrowedAccountBalance(address account) external view returns (uint); function totalVestedAccountBalance(address account) external view returns (uint); function getVestingQuantity(address account, uint256[] calldata entryIDs) external view returns (uint); function getVestingSchedules( address account, uint256 index, uint256 pageSize ) external view returns (VestingEntries.VestingEntryWithID[] memory); function getAccountVestingEntryIDs( address account, uint256 index, uint256 pageSize ) external view returns (uint256[] memory); function getVestingEntryClaimable(address account, uint256 entryID) external view returns (uint); function getVestingEntry(address account, uint256 entryID) external view returns (uint64, uint256); // Mutative functions function vest(uint256[] calldata entryIDs) external; function createEscrowEntry( address beneficiary, uint256 deposit, uint256 duration ) external; function appendVestingEntry( address account, uint256 quantity, uint256 duration ) external; function migrateVestingSchedule(address _addressToMigrate) external; function migrateAccountEscrowBalances( address[] calldata accounts, uint256[] calldata escrowBalances, uint256[] calldata vestedBalances ) external; // Account Merging function startMergingWindow() external; function mergeAccount(address accountToMerge, uint256[] calldata entryIDs) external; function nominateAccountToMerge(address account) external; function accountMergingIsOpen() external view returns (bool); // L2 Migration function importVestingEntries( address account, uint256 escrowedAmount, VestingEntries.VestingEntry[] calldata vestingEntries ) external; // Return amount of SNX transfered to SynthetixBridgeToOptimism deposit contract function burnForMigration(address account, uint256[] calldata entryIDs) external returns (uint256 escrowedAccountBalance, VestingEntries.VestingEntry[] memory vestingEntries); } /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, "SafeMath: division by zero"); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "SafeMath: modulo by zero"); return a % b; } } // Libraries // https://docs.synthetix.io/contracts/source/libraries/safedecimalmath library SafeDecimalMath { using SafeMath for uint; /* Number of decimal places in the representations. */ uint8 public constant decimals = 18; uint8 public constant highPrecisionDecimals = 27; /* The number representing 1.0. */ uint public constant UNIT = 10**uint(decimals); /* The number representing 1.0 for higher fidelity numbers. */ uint public constant PRECISE_UNIT = 10**uint(highPrecisionDecimals); uint private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = 10**uint(highPrecisionDecimals - decimals); /** * @return Provides an interface to UNIT. */ function unit() external pure returns (uint) { return UNIT; } /** * @return Provides an interface to PRECISE_UNIT. */ function preciseUnit() external pure returns (uint) { return PRECISE_UNIT; } /** * @return The result of multiplying x and y, interpreting the operands as fixed-point * decimals. * * @dev A unit factor is divided out after the product of x and y is evaluated, * so that product must be less than 2**256. As this is an integer division, * the internal division always rounds down. This helps save on gas. Rounding * is more expensive on gas. */ function multiplyDecimal(uint x, uint y) internal pure returns (uint) { /* Divide by UNIT to remove the extra factor introduced by the product. */ return x.mul(y) / UNIT; } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of the specified precision unit. * * @dev The operands should be in the form of a the specified unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function _multiplyDecimalRound( uint x, uint y, uint precisionUnit ) private pure returns (uint) { /* Divide by UNIT to remove the extra factor introduced by the product. */ uint quotientTimesTen = x.mul(y) / (precisionUnit / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of a precise unit. * * @dev The operands should be in the precise unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function multiplyDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) { return _multiplyDecimalRound(x, y, PRECISE_UNIT); } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of a standard unit. * * @dev The operands should be in the standard unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function multiplyDecimalRound(uint x, uint y) internal pure returns (uint) { return _multiplyDecimalRound(x, y, UNIT); } /** * @return The result of safely dividing x and y. The return value is a high * precision decimal. * * @dev y is divided after the product of x and the standard precision unit * is evaluated, so the product of x and UNIT must be less than 2**256. As * this is an integer division, the result is always rounded down. * This helps save on gas. Rounding is more expensive on gas. */ function divideDecimal(uint x, uint y) internal pure returns (uint) { /* Reintroduce the UNIT factor that will be divided out by y. */ return x.mul(UNIT).div(y); } /** * @return The result of safely dividing x and y. The return value is as a rounded * decimal in the precision unit specified in the parameter. * * @dev y is divided after the product of x and the specified precision unit * is evaluated, so the product of x and the specified precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function _divideDecimalRound( uint x, uint y, uint precisionUnit ) private pure returns (uint) { uint resultTimesTen = x.mul(precisionUnit * 10).div(y); if (resultTimesTen % 10 >= 5) { resultTimesTen += 10; } return resultTimesTen / 10; } /** * @return The result of safely dividing x and y. The return value is as a rounded * standard precision decimal. * * @dev y is divided after the product of x and the standard precision unit * is evaluated, so the product of x and the standard precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function divideDecimalRound(uint x, uint y) internal pure returns (uint) { return _divideDecimalRound(x, y, UNIT); } /** * @return The result of safely dividing x and y. The return value is as a rounded * high precision decimal. * * @dev y is divided after the product of x and the high precision unit * is evaluated, so the product of x and the high precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function divideDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) { return _divideDecimalRound(x, y, PRECISE_UNIT); } /** * @dev Convert a standard decimal representation to a high precision one. */ function decimalToPreciseDecimal(uint i) internal pure returns (uint) { return i.mul(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR); } /** * @dev Convert a high precision decimal to a standard decimal representation. */ function preciseDecimalToDecimal(uint i) internal pure returns (uint) { uint quotientTimesTen = i / (UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } } // https://docs.synthetix.io/contracts/source/interfaces/ierc20 interface IERC20 { // ERC20 Optional Views function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); // Views function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); // Mutative functions function transfer(address to, uint value) external returns (bool); function approve(address spender, uint value) external returns (bool); function transferFrom( address from, address to, uint value ) external returns (bool); // Events event Transfer(address indexed from, address indexed to, uint value); event Approval(address indexed owner, address indexed spender, uint value); } // https://docs.synthetix.io/contracts/source/interfaces/ifeepool interface IFeePool { // Views // solhint-disable-next-line func-name-mixedcase function FEE_ADDRESS() external view returns (address); function feesAvailable(address account) external view returns (uint, uint); function feePeriodDuration() external view returns (uint); function isFeesClaimable(address account) external view returns (bool); function targetThreshold() external view returns (uint); function totalFeesAvailable() external view returns (uint); function totalRewardsAvailable() external view returns (uint); // Mutative Functions function claimFees() external returns (bool); function claimOnBehalf(address claimingForAddress) external returns (bool); function closeCurrentFeePeriod() external; // Restricted: used internally to Synthetix function appendAccountIssuanceRecord( address account, uint lockedAmount, uint debtEntryIndex ) external; function recordFeePaid(uint sUSDAmount) external; function setRewardsToDistribute(uint amount) external; } interface IVirtualSynth { // Views function balanceOfUnderlying(address account) external view returns (uint); function rate() external view returns (uint); function readyToSettle() external view returns (bool); function secsLeftInWaitingPeriod() external view returns (uint); function settled() external view returns (bool); function synth() external view returns (ISynth); // Mutative functions function settle(address account) external; } // https://docs.synthetix.io/contracts/source/interfaces/isynthetix interface ISynthetix { // Views function anySynthOrSNXRateIsInvalid() external view returns (bool anyRateInvalid); function availableCurrencyKeys() external view returns (bytes32[] memory); function availableSynthCount() external view returns (uint); function availableSynths(uint index) external view returns (ISynth); function collateral(address account) external view returns (uint); function collateralisationRatio(address issuer) external view returns (uint); function debtBalanceOf(address issuer, bytes32 currencyKey) external view returns (uint); function isWaitingPeriod(bytes32 currencyKey) external view returns (bool); function maxIssuableSynths(address issuer) external view returns (uint maxIssuable); function remainingIssuableSynths(address issuer) external view returns ( uint maxIssuable, uint alreadyIssued, uint totalSystemDebt ); function synths(bytes32 currencyKey) external view returns (ISynth); function synthsByAddress(address synthAddress) external view returns (bytes32); function totalIssuedSynths(bytes32 currencyKey) external view returns (uint); function totalIssuedSynthsExcludeEtherCollateral(bytes32 currencyKey) external view returns (uint); function transferableSynthetix(address account) external view returns (uint transferable); // Mutative Functions function burnSynths(uint amount) external; function burnSynthsOnBehalf(address burnForAddress, uint amount) external; function burnSynthsToTarget() external; function burnSynthsToTargetOnBehalf(address burnForAddress) external; function exchange( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) external returns (uint amountReceived); function exchangeOnBehalf( address exchangeForAddress, bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) external returns (uint amountReceived); function exchangeWithTracking( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, address originator, bytes32 trackingCode ) external returns (uint amountReceived); function exchangeOnBehalfWithTracking( address exchangeForAddress, bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, address originator, bytes32 trackingCode ) external returns (uint amountReceived); function exchangeWithVirtual( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, bytes32 trackingCode ) external returns (uint amountReceived, IVirtualSynth vSynth); function issueMaxSynths() external; function issueMaxSynthsOnBehalf(address issueForAddress) external; function issueSynths(uint amount) external; function issueSynthsOnBehalf(address issueForAddress, uint amount) external; function mint() external returns (bool); function settle(bytes32 currencyKey) external returns ( uint reclaimed, uint refunded, uint numEntries ); // Liquidations function liquidateDelinquentAccount(address account, uint susdAmount) external returns (bool); // Restricted Functions function mintSecondary(address account, uint amount) external; function mintSecondaryRewards(uint amount) external; function burnSecondary(address account, uint amount) external; } // Inheritance // Libraries // Internal references // https://docs.synthetix.io/contracts/RewardEscrow contract BaseRewardEscrowV2 is Owned, IRewardEscrowV2, LimitedSetup(4 weeks), MixinResolver { using SafeMath for uint; using SafeDecimalMath for uint; mapping(address => mapping(uint256 => VestingEntries.VestingEntry)) public vestingSchedules; mapping(address => uint256[]) public accountVestingEntryIDs; /*Counter for new vesting entry ids. */ uint256 public nextEntryId; /* An account's total escrowed synthetix balance to save recomputing this for fee extraction purposes. */ mapping(address => uint256) public totalEscrowedAccountBalance; /* An account's total vested reward synthetix. */ mapping(address => uint256) public totalVestedAccountBalance; /* Mapping of nominated address to recieve account merging */ mapping(address => address) public nominatedReceiver; /* The total remaining escrowed balance, for verifying the actual synthetix balance of this contract against. */ uint256 public totalEscrowedBalance; /* Max escrow duration */ uint public max_duration = 2 * 52 weeks; // Default max 2 years duration /* Max account merging duration */ uint public maxAccountMergingDuration = 4 weeks; // Default 4 weeks is max /* ========== ACCOUNT MERGING CONFIGURATION ========== */ uint public accountMergingDuration = 1 weeks; uint public accountMergingStartTime; /* ========== ADDRESS RESOLVER CONFIGURATION ========== */ bytes32 private constant CONTRACT_SYNTHETIX = "Synthetix"; bytes32 private constant CONTRACT_ISSUER = "Issuer"; bytes32 private constant CONTRACT_FEEPOOL = "FeePool"; /* ========== CONSTRUCTOR ========== */ constructor(address _owner, address _resolver) public Owned(_owner) MixinResolver(_resolver) { nextEntryId = 1; } /* ========== VIEWS ======================= */ function feePool() internal view returns (IFeePool) { return IFeePool(requireAndGetAddress(CONTRACT_FEEPOOL)); } function synthetix() internal view returns (ISynthetix) { return ISynthetix(requireAndGetAddress(CONTRACT_SYNTHETIX)); } function issuer() internal view returns (IIssuer) { return IIssuer(requireAndGetAddress(CONTRACT_ISSUER)); } function _notImplemented() internal pure { revert("Cannot be run on this layer"); } /* ========== VIEW FUNCTIONS ========== */ // Note: use public visibility so that it can be invoked in a subclass function resolverAddressesRequired() public view returns (bytes32[] memory addresses) { addresses = new bytes32[](3); addresses[0] = CONTRACT_SYNTHETIX; addresses[1] = CONTRACT_FEEPOOL; addresses[2] = CONTRACT_ISSUER; } /** * @notice A simple alias to totalEscrowedAccountBalance: provides ERC20 balance integration. */ function balanceOf(address account) public view returns (uint) { return totalEscrowedAccountBalance[account]; } /** * @notice The number of vesting dates in an account's schedule. */ function numVestingEntries(address account) external view returns (uint) { return accountVestingEntryIDs[account].length; } /** * @notice Get a particular schedule entry for an account. * @return The vesting entry object and rate per second emission. */ function getVestingEntry(address account, uint256 entryID) external view returns (uint64 endTime, uint256 escrowAmount) { endTime = vestingSchedules[account][entryID].endTime; escrowAmount = vestingSchedules[account][entryID].escrowAmount; } function getVestingSchedules( address account, uint256 index, uint256 pageSize ) external view returns (VestingEntries.VestingEntryWithID[] memory) { uint256 endIndex = index + pageSize; // If index starts after the endIndex return no results if (endIndex <= index) { return new VestingEntries.VestingEntryWithID[](0); } // If the page extends past the end of the accountVestingEntryIDs, truncate it. if (endIndex > accountVestingEntryIDs[account].length) { endIndex = accountVestingEntryIDs[account].length; } uint256 n = endIndex - index; VestingEntries.VestingEntryWithID[] memory vestingEntries = new VestingEntries.VestingEntryWithID[](n); for (uint256 i; i < n; i++) { uint256 entryID = accountVestingEntryIDs[account][i + index]; VestingEntries.VestingEntry memory entry = vestingSchedules[account][entryID]; vestingEntries[i] = VestingEntries.VestingEntryWithID({ endTime: uint64(entry.endTime), escrowAmount: entry.escrowAmount, entryID: entryID }); } return vestingEntries; } function getAccountVestingEntryIDs( address account, uint256 index, uint256 pageSize ) external view returns (uint256[] memory) { uint256 endIndex = index + pageSize; // If the page extends past the end of the accountVestingEntryIDs, truncate it. if (endIndex > accountVestingEntryIDs[account].length) { endIndex = accountVestingEntryIDs[account].length; } if (endIndex <= index) { return new uint256[](0); } uint256 n = endIndex - index; uint256[] memory page = new uint256[](n); for (uint256 i; i < n; i++) { page[i] = accountVestingEntryIDs[account][i + index]; } return page; } function getVestingQuantity(address account, uint256[] calldata entryIDs) external view returns (uint total) { for (uint i = 0; i < entryIDs.length; i++) { VestingEntries.VestingEntry memory entry = vestingSchedules[account][entryIDs[i]]; /* Skip entry if escrowAmount == 0 */ if (entry.escrowAmount != 0) { uint256 quantity = _claimableAmount(entry); /* add quantity to total */ total = total.add(quantity); } } } function getVestingEntryClaimable(address account, uint256 entryID) external view returns (uint) { VestingEntries.VestingEntry memory entry = vestingSchedules[account][entryID]; return _claimableAmount(entry); } /* ========== MUTATIVE FUNCTIONS ========== */ /** * Vest escrowed amounts that are claimable * Allows users to vest their vesting entries based on msg.sender */ function vest(uint256[] calldata entryIDs) external { uint256 total; for (uint i = 0; i < entryIDs.length; i++) { VestingEntries.VestingEntry storage entry = vestingSchedules[msg.sender][entryIDs[i]]; /* Skip entry if escrowAmount == 0 already vested */ if (entry.escrowAmount != 0) { uint256 quantity = _claimableAmount(entry); /* update entry to remove escrowAmount */ if (quantity > 0) { entry.escrowAmount = 0; } /* add quantity to total */ total = total.add(quantity); } } /* Transfer vested tokens. Will revert if total > totalEscrowedAccountBalance */ if (total != 0) { _transferVestedTokens(msg.sender, total); } } function _claimableAmount(VestingEntries.VestingEntry memory _entry) internal view returns (uint256) { uint256 quantity; if (_entry.escrowAmount != 0) { /* Escrow amounts claimable if block.timestamp equal to or after entry endTime */ quantity = block.timestamp > _entry.endTime ? _entry.escrowAmount : 0; } return quantity; } /** * @notice Create an escrow entry to lock SNX for a given duration in seconds * @dev This call expects that the depositor (msg.sender) has already approved the Reward escrow contract to spend the the amount being escrowed. */ function createEscrowEntry( address beneficiary, uint256 deposit, uint256 duration ) external { require(beneficiary != address(0), "Cannot create escrow with address(0)"); /* Transfer SNX from msg.sender */ require(IERC20(address(synthetix())).transferFrom(msg.sender, address(this), deposit), "token transfer failed"); /* Append vesting entry for the beneficiary address */ _appendVestingEntry(beneficiary, deposit, duration); } /** * @notice Add a new vesting entry at a given time and quantity to an account's schedule. * @dev A call to this should accompany a previous successful call to synthetix.transfer(rewardEscrow, amount), * to ensure that when the funds are withdrawn, there is enough balance. * @param account The account to append a new vesting entry to. * @param quantity The quantity of SNX that will be escrowed. * @param duration The duration that SNX will be emitted. */ function appendVestingEntry( address account, uint256 quantity, uint256 duration ) external onlyFeePool { _appendVestingEntry(account, quantity, duration); } /* Transfer vested tokens and update totalEscrowedAccountBalance, totalVestedAccountBalance */ function _transferVestedTokens(address _account, uint256 _amount) internal { _reduceAccountEscrowBalances(_account, _amount); totalVestedAccountBalance[_account] = totalVestedAccountBalance[_account].add(_amount); IERC20(address(synthetix())).transfer(_account, _amount); emit Vested(_account, block.timestamp, _amount); } function _reduceAccountEscrowBalances(address _account, uint256 _amount) internal { // Reverts if amount being vested is greater than the account's existing totalEscrowedAccountBalance totalEscrowedBalance = totalEscrowedBalance.sub(_amount); totalEscrowedAccountBalance[_account] = totalEscrowedAccountBalance[_account].sub(_amount); } /* ========== ACCOUNT MERGING ========== */ function accountMergingIsOpen() public view returns (bool) { return accountMergingStartTime.add(accountMergingDuration) > block.timestamp; } function startMergingWindow() external onlyOwner { accountMergingStartTime = block.timestamp; emit AccountMergingStarted(accountMergingStartTime, accountMergingStartTime.add(accountMergingDuration)); } function setAccountMergingDuration(uint256 duration) external onlyOwner { require(duration <= maxAccountMergingDuration, "exceeds max merging duration"); accountMergingDuration = duration; emit AccountMergingDurationUpdated(duration); } function setMaxAccountMergingWindow(uint256 duration) external onlyOwner { maxAccountMergingDuration = duration; emit MaxAccountMergingDurationUpdated(duration); } function setMaxEscrowDuration(uint256 duration) external onlyOwner { max_duration = duration; emit MaxEscrowDurationUpdated(duration); } /* Nominate an account to merge escrow and vesting schedule */ function nominateAccountToMerge(address account) external { require(account != msg.sender, "Cannot nominate own account to merge"); require(accountMergingIsOpen(), "Account merging has ended"); require(issuer().debtBalanceOf(msg.sender, "sUSD") == 0, "Cannot merge accounts with debt"); nominatedReceiver[msg.sender] = account; emit NominateAccountToMerge(msg.sender, account); } function mergeAccount(address accountToMerge, uint256[] calldata entryIDs) external { require(accountMergingIsOpen(), "Account merging has ended"); require(issuer().debtBalanceOf(accountToMerge, "sUSD") == 0, "Cannot merge accounts with debt"); require(nominatedReceiver[accountToMerge] == msg.sender, "Address is not nominated to merge"); uint256 totalEscrowAmountMerged; for (uint i = 0; i < entryIDs.length; i++) { // retrieve entry VestingEntries.VestingEntry memory entry = vestingSchedules[accountToMerge][entryIDs[i]]; /* ignore vesting entries with zero escrowAmount */ if (entry.escrowAmount != 0) { /* copy entry to msg.sender (destination address) */ vestingSchedules[msg.sender][entryIDs[i]] = entry; /* Add the escrowAmount of entry to the totalEscrowAmountMerged */ totalEscrowAmountMerged = totalEscrowAmountMerged.add(entry.escrowAmount); /* append entryID to list of entries for account */ accountVestingEntryIDs[msg.sender].push(entryIDs[i]); /* Delete entry from accountToMerge */ delete vestingSchedules[accountToMerge][entryIDs[i]]; } } /* update totalEscrowedAccountBalance for merged account and accountToMerge */ totalEscrowedAccountBalance[accountToMerge] = totalEscrowedAccountBalance[accountToMerge].sub( totalEscrowAmountMerged ); totalEscrowedAccountBalance[msg.sender] = totalEscrowedAccountBalance[msg.sender].add(totalEscrowAmountMerged); emit AccountMerged(accountToMerge, msg.sender, totalEscrowAmountMerged, entryIDs, block.timestamp); } /* Internal function for importing vesting entry and creating new entry for escrow liquidations */ function _addVestingEntry(address account, VestingEntries.VestingEntry memory entry) internal returns (uint) { uint entryID = nextEntryId; vestingSchedules[account][entryID] = entry; /* append entryID to list of entries for account */ accountVestingEntryIDs[account].push(entryID); /* Increment the next entry id. */ nextEntryId = nextEntryId.add(1); return entryID; } /* ========== MIGRATION OLD ESCROW ========== */ function migrateVestingSchedule(address) external { _notImplemented(); } function migrateAccountEscrowBalances( address[] calldata, uint256[] calldata, uint256[] calldata ) external { _notImplemented(); } /* ========== L2 MIGRATION ========== */ function burnForMigration(address, uint[] calldata) external returns (uint256, VestingEntries.VestingEntry[] memory) { _notImplemented(); } function importVestingEntries( address, uint256, VestingEntries.VestingEntry[] calldata ) external { _notImplemented(); } /* ========== INTERNALS ========== */ function _appendVestingEntry( address account, uint256 quantity, uint256 duration ) internal { /* No empty or already-passed vesting entries allowed. */ require(quantity != 0, "Quantity cannot be zero"); require(duration > 0 && duration <= max_duration, "Cannot escrow with 0 duration OR above max_duration"); /* There must be enough balance in the contract to provide for the vesting entry. */ totalEscrowedBalance = totalEscrowedBalance.add(quantity); require( totalEscrowedBalance <= IERC20(address(synthetix())).balanceOf(address(this)), "Must be enough balance in the contract to provide for the vesting entry" ); /* Escrow the tokens for duration. */ uint endTime = block.timestamp + duration; /* Add quantity to account's escrowed balance */ totalEscrowedAccountBalance[account] = totalEscrowedAccountBalance[account].add(quantity); uint entryID = nextEntryId; vestingSchedules[account][entryID] = VestingEntries.VestingEntry({endTime: uint64(endTime), escrowAmount: quantity}); accountVestingEntryIDs[account].push(entryID); /* Increment the next entry id. */ nextEntryId = nextEntryId.add(1); emit VestingEntryCreated(account, block.timestamp, quantity, duration, entryID); } /* ========== MODIFIERS ========== */ modifier onlyFeePool() { require(msg.sender == address(feePool()), "Only the FeePool can perform this action"); _; } /* ========== EVENTS ========== */ event Vested(address indexed beneficiary, uint time, uint value); event VestingEntryCreated(address indexed beneficiary, uint time, uint value, uint duration, uint entryID); event MaxEscrowDurationUpdated(uint newDuration); event MaxAccountMergingDurationUpdated(uint newDuration); event AccountMergingDurationUpdated(uint newDuration); event AccountMergingStarted(uint time, uint endTime); event AccountMerged( address indexed accountToMerge, address destinationAddress, uint escrowAmountMerged, uint[] entryIDs, uint time ); event NominateAccountToMerge(address indexed account, address destination); } // https://docs.synthetix.io/contracts/source/interfaces/irewardescrow interface IRewardEscrow { // Views function balanceOf(address account) external view returns (uint); function numVestingEntries(address account) external view returns (uint); function totalEscrowedAccountBalance(address account) external view returns (uint); function totalVestedAccountBalance(address account) external view returns (uint); function getVestingScheduleEntry(address account, uint index) external view returns (uint[2] memory); function getNextVestingIndex(address account) external view returns (uint); // Mutative functions function appendVestingEntry(address account, uint quantity) external; function vest() external; } // https://docs.synthetix.io/contracts/source/interfaces/isystemstatus interface ISystemStatus { struct Status { bool canSuspend; bool canResume; } struct Suspension { bool suspended; // reason is an integer code, // 0 => no reason, 1 => upgrading, 2+ => defined by system usage uint248 reason; } // Views function accessControl(bytes32 section, address account) external view returns (bool canSuspend, bool canResume); function requireSystemActive() external view; function requireIssuanceActive() external view; function requireExchangeActive() external view; function requireSynthActive(bytes32 currencyKey) external view; function requireSynthsActive(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view; function synthSuspension(bytes32 currencyKey) external view returns (bool suspended, uint248 reason); // Restricted functions function suspendSynth(bytes32 currencyKey, uint256 reason) external; function updateAccessControl( bytes32 section, address account, bool canSuspend, bool canResume ) external; } // Inheritance // Internal references // https://docs.synthetix.io/contracts/RewardEscrow contract RewardEscrowV2 is BaseRewardEscrowV2 { mapping(address => uint256) public totalBalancePendingMigration; uint public migrateEntriesThresholdAmount = SafeDecimalMath.unit() * 1000; // Default 1000 SNX /* ========== ADDRESS RESOLVER CONFIGURATION ========== */ bytes32 private constant CONTRACT_SYNTHETIX_BRIDGE_OPTIMISM = "SynthetixBridgeToOptimism"; bytes32 private constant CONTRACT_REWARD_ESCROW = "RewardEscrow"; bytes32 private constant CONTRACT_SYSTEMSTATUS = "SystemStatus"; /* ========== CONSTRUCTOR ========== */ constructor(address _owner, address _resolver) public BaseRewardEscrowV2(_owner, _resolver) {} /* ========== VIEWS ======================= */ function resolverAddressesRequired() public view returns (bytes32[] memory addresses) { bytes32[] memory existingAddresses = BaseRewardEscrowV2.resolverAddressesRequired(); bytes32[] memory newAddresses = new bytes32[](3); newAddresses[0] = CONTRACT_SYNTHETIX_BRIDGE_OPTIMISM; newAddresses[1] = CONTRACT_REWARD_ESCROW; newAddresses[2] = CONTRACT_SYSTEMSTATUS; return combineArrays(existingAddresses, newAddresses); } function synthetixBridgeToOptimism() internal view returns (address) { return requireAndGetAddress(CONTRACT_SYNTHETIX_BRIDGE_OPTIMISM); } function oldRewardEscrow() internal view returns (IRewardEscrow) { return IRewardEscrow(requireAndGetAddress(CONTRACT_REWARD_ESCROW)); } function systemStatus() internal view returns (ISystemStatus) { return ISystemStatus(requireAndGetAddress(CONTRACT_SYSTEMSTATUS)); } /* ========== OLD ESCROW LOOKUP ========== */ uint internal constant TIME_INDEX = 0; uint internal constant QUANTITY_INDEX = 1; /* ========== MIGRATION OLD ESCROW ========== */ /* Threshold amount for migrating escrow entries from old RewardEscrow */ function setMigrateEntriesThresholdAmount(uint amount) external onlyOwner { migrateEntriesThresholdAmount = amount; emit MigrateEntriesThresholdAmountUpdated(amount); } /* Function to allow any address to migrate vesting entries from previous reward escrow */ function migrateVestingSchedule(address addressToMigrate) external systemActive { /* Ensure account escrow balance pending migration is not zero */ /* Ensure account escrowed balance is not zero - should have been migrated */ require(totalBalancePendingMigration[addressToMigrate] > 0, "No escrow migration pending"); require(totalEscrowedAccountBalance[addressToMigrate] > 0, "Address escrow balance is 0"); /* Add a vestable entry for addresses with totalBalancePendingMigration <= migrateEntriesThreshold amount of SNX */ if (totalBalancePendingMigration[addressToMigrate] <= migrateEntriesThresholdAmount) { _importVestingEntry( addressToMigrate, VestingEntries.VestingEntry({ endTime: uint64(block.timestamp), escrowAmount: totalBalancePendingMigration[addressToMigrate] }) ); /* Remove totalBalancePendingMigration[addressToMigrate] */ delete totalBalancePendingMigration[addressToMigrate]; } else { uint numEntries = oldRewardEscrow().numVestingEntries(addressToMigrate); /* iterate and migrate old escrow schedules from rewardEscrow.vestingSchedules * starting from the last entry in each staker's vestingSchedules */ for (uint i = 1; i <= numEntries; i++) { uint[2] memory vestingSchedule = oldRewardEscrow().getVestingScheduleEntry(addressToMigrate, numEntries - i); uint time = vestingSchedule[TIME_INDEX]; uint amount = vestingSchedule[QUANTITY_INDEX]; /* The list is sorted, when we reach the first entry that can be vested stop */ if (time < block.timestamp) { break; } /* import vesting entry */ _importVestingEntry( addressToMigrate, VestingEntries.VestingEntry({endTime: uint64(time), escrowAmount: amount}) ); /* subtract amount from totalBalancePendingMigration - reverts if insufficient */ totalBalancePendingMigration[addressToMigrate] = totalBalancePendingMigration[addressToMigrate].sub(amount); } } } /** * Import function for owner to import vesting schedule * All entries imported should have past their vesting timestamp and will be ready to be vested * Addresses with totalEscrowedAccountBalance == 0 will not be migrated as they have all vested */ function importVestingSchedule(address[] calldata accounts, uint256[] calldata escrowAmounts) external onlyDuringSetup onlyOwner { require(accounts.length == escrowAmounts.length, "Account and escrowAmounts Length mismatch"); for (uint i = 0; i < accounts.length; i++) { address addressToMigrate = accounts[i]; uint256 escrowAmount = escrowAmounts[i]; // ensure account have escrow migration pending require(totalEscrowedAccountBalance[addressToMigrate] > 0, "Address escrow balance is 0"); require(totalBalancePendingMigration[addressToMigrate] > 0, "No escrow migration pending"); /* Import vesting entry with endTime as block.timestamp and escrowAmount */ _importVestingEntry( addressToMigrate, VestingEntries.VestingEntry({endTime: uint64(block.timestamp), escrowAmount: escrowAmount}) ); /* update totalBalancePendingMigration - reverts if escrowAmount > remaining balance to migrate */ totalBalancePendingMigration[addressToMigrate] = totalBalancePendingMigration[addressToMigrate].sub( escrowAmount ); emit ImportedVestingSchedule(addressToMigrate, block.timestamp, escrowAmount); } } /** * Migration for owner to migrate escrowed and vested account balances * Addresses with totalEscrowedAccountBalance == 0 will not be migrated as they have all vested */ function migrateAccountEscrowBalances( address[] calldata accounts, uint256[] calldata escrowBalances, uint256[] calldata vestedBalances ) external onlyDuringSetup onlyOwner { require(accounts.length == escrowBalances.length, "Number of accounts and balances don't match"); require(accounts.length == vestedBalances.length, "Number of accounts and vestedBalances don't match"); for (uint i = 0; i < accounts.length; i++) { address account = accounts[i]; uint escrowedAmount = escrowBalances[i]; uint vestedAmount = vestedBalances[i]; // ensure account doesn't have escrow migration pending / being imported more than once require(totalBalancePendingMigration[account] == 0, "Account migration is pending already"); /* Update totalEscrowedBalance for tracking the Synthetix balance of this contract. */ totalEscrowedBalance = totalEscrowedBalance.add(escrowedAmount); /* Update totalEscrowedAccountBalance and totalVestedAccountBalance for each account */ totalEscrowedAccountBalance[account] = totalEscrowedAccountBalance[account].add(escrowedAmount); totalVestedAccountBalance[account] = totalVestedAccountBalance[account].add(vestedAmount); /* update totalBalancePendingMigration for account */ totalBalancePendingMigration[account] = escrowedAmount; emit MigratedAccountEscrow(account, escrowedAmount, vestedAmount, now); } } /* Internal function to add entry to vestingSchedules and emit event */ function _importVestingEntry(address account, VestingEntries.VestingEntry memory entry) internal { /* add vesting entry to account and assign an entryID to it */ uint entryID = BaseRewardEscrowV2._addVestingEntry(account, entry); emit ImportedVestingEntry(account, entryID, entry.escrowAmount, entry.endTime); } /* ========== L2 MIGRATION ========== */ function burnForMigration(address account, uint[] calldata entryIDs) external onlySynthetixBridge returns (uint256 escrowedAccountBalance, VestingEntries.VestingEntry[] memory vestingEntries) { require(entryIDs.length > 0, "Entry IDs required"); vestingEntries = new VestingEntries.VestingEntry[](entryIDs.length); for (uint i = 0; i < entryIDs.length; i++) { VestingEntries.VestingEntry storage entry = vestingSchedules[account][entryIDs[i]]; if (entry.escrowAmount > 0) { vestingEntries[i] = entry; /* add the escrow amount to escrowedAccountBalance */ escrowedAccountBalance = escrowedAccountBalance.add(entry.escrowAmount); /* Delete the vesting entry being migrated */ delete vestingSchedules[account][entryIDs[i]]; } } /** * update account total escrow balances for migration * transfer the escrowed SNX being migrated to the L2 deposit contract */ if (escrowedAccountBalance > 0) { _reduceAccountEscrowBalances(account, escrowedAccountBalance); IERC20(address(synthetix())).transfer(synthetixBridgeToOptimism(), escrowedAccountBalance); } emit BurnedForMigrationToL2(account, entryIDs, escrowedAccountBalance, block.timestamp); return (escrowedAccountBalance, vestingEntries); } /* ========== MODIFIERS ========== */ modifier onlySynthetixBridge() { require(msg.sender == synthetixBridgeToOptimism(), "Can only be invoked by SynthetixBridgeToOptimism contract"); _; } modifier systemActive() { systemStatus().requireSystemActive(); _; } /* ========== EVENTS ========== */ event MigratedAccountEscrow(address indexed account, uint escrowedAmount, uint vestedAmount, uint time); event ImportedVestingSchedule(address indexed account, uint time, uint escrowAmount); event BurnedForMigrationToL2(address indexed account, uint[] entryIDs, uint escrowedAmountMigrated, uint time); event ImportedVestingEntry(address indexed account, uint entryID, uint escrowAmount, uint endTime); event MigrateEntriesThresholdAmountUpdated(uint newAmount); }
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_resolver","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"accountToMerge","type":"address"},{"indexed":false,"internalType":"address","name":"destinationAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"escrowAmountMerged","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"entryIDs","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"AccountMerged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"AccountMergingDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"AccountMergingStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"entryIDs","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"escrowedAmountMigrated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"BurnedForMigrationToL2","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"name","type":"bytes32"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"CacheUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"entryID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"escrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"ImportedVestingEntry","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"escrowAmount","type":"uint256"}],"name":"ImportedVestingSchedule","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"MaxAccountMergingDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"MaxEscrowDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newAmount","type":"uint256"}],"name":"MigrateEntriesThresholdAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"escrowedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vestedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"MigratedAccountEscrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"NominateAccountToMerge","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Vested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"entryID","type":"uint256"}],"name":"VestingEntryCreated","type":"event"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"accountMergingDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"accountMergingIsOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"accountMergingStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"accountVestingEntryIDs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"appendVestingEntry","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256[]","name":"entryIDs","type":"uint256[]"}],"name":"burnForMigration","outputs":[{"internalType":"uint256","name":"escrowedAccountBalance","type":"uint256"},{"components":[{"internalType":"uint64","name":"endTime","type":"uint64"},{"internalType":"uint256","name":"escrowAmount","type":"uint256"}],"internalType":"struct VestingEntries.VestingEntry[]","name":"vestingEntries","type":"tuple[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"createEscrowEntry","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"pageSize","type":"uint256"}],"name":"getAccountVestingEntryIDs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"entryID","type":"uint256"}],"name":"getVestingEntry","outputs":[{"internalType":"uint64","name":"endTime","type":"uint64"},{"internalType":"uint256","name":"escrowAmount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"entryID","type":"uint256"}],"name":"getVestingEntryClaimable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256[]","name":"entryIDs","type":"uint256[]"}],"name":"getVestingQuantity","outputs":[{"internalType":"uint256","name":"total","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"pageSize","type":"uint256"}],"name":"getVestingSchedules","outputs":[{"components":[{"internalType":"uint64","name":"endTime","type":"uint64"},{"internalType":"uint256","name":"escrowAmount","type":"uint256"},{"internalType":"uint256","name":"entryID","type":"uint256"}],"internalType":"struct VestingEntries.VestingEntryWithID[]","name":"","type":"tuple[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"components":[{"internalType":"uint64","name":"endTime","type":"uint64"},{"internalType":"uint256","name":"escrowAmount","type":"uint256"}],"internalType":"struct VestingEntries.VestingEntry[]","name":"","type":"tuple[]"}],"name":"importVestingEntries","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"escrowAmounts","type":"uint256[]"}],"name":"importVestingSchedule","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isResolverCached","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxAccountMergingDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"max_duration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"accountToMerge","type":"address"},{"internalType":"uint256[]","name":"entryIDs","type":"uint256[]"}],"name":"mergeAccount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"escrowBalances","type":"uint256[]"},{"internalType":"uint256[]","name":"vestedBalances","type":"uint256[]"}],"name":"migrateAccountEscrowBalances","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"migrateEntriesThresholdAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"addressToMigrate","type":"address"}],"name":"migrateVestingSchedule","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nextEntryId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"nominateAccountToMerge","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nominatedReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"numVestingEntries","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"rebuildCache","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"resolver","outputs":[{"internalType":"contract AddressResolver","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"resolverAddressesRequired","outputs":[{"internalType":"bytes32[]","name":"addresses","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"setAccountMergingDuration","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"setMaxAccountMergingWindow","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"setMaxEscrowDuration","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"setMigrateEntriesThresholdAmount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"setupExpiryTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"startMergingWindow","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalBalancePendingMigration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalEscrowedAccountBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalEscrowedBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalVestedAccountBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256[]","name":"entryIDs","type":"uint256[]"}],"name":"vest","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"vestingSchedules","outputs":[{"internalType":"uint64","name":"endTime","type":"uint64"},{"internalType":"uint256","name":"escrowAmount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]
Contract Creation Code
608060408190526303bfc400600c556224ea00600d5562093a80600e55630241ebdb60e61b8152731a60e2e2a8be0bc2b6381dd31fd3fd5f9a28de4c9063907af6c09060849060209060048186803b1580156200005b57600080fd5b505af415801562000070573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620000969190810190620001f1565b6103e802601155348015620000aa57600080fd5b5060405162003ead38038062003ead833981016040819052620000cd91620001b2565b8181806224ea00836001600160a01b038116620001075760405162461bcd60e51b8152600401620000fe9062000297565b60405180910390fd5b600080546001600160a01b0319166001600160a01b0383161781556040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c916200015491849062000271565b60405180910390a1504201600255600380546001600160a01b0319166001600160a01b03929092169190911790555050600160075550620003009050565b80516200019f81620002db565b92915050565b80516200019f81620002f5565b60008060408385031215620001c657600080fd5b6000620001d4858562000192565b9250506020620001e78582860162000192565b9150509250929050565b6000602082840312156200020457600080fd5b6000620002128484620001a5565b949350505050565b6200022581620002c7565b82525050565b6200022581620002b2565b600062000245601983620002a9565b7f4f776e657220616464726573732063616e6e6f74206265203000000000000000815260200192915050565b604081016200028182856200021a565b6200029060208301846200022b565b9392505050565b602080825281016200019f8162000236565b90815260200190565b60006001600160a01b0382166200019f565b90565b60006200019f8260006200019f82620002b2565b620002e681620002b2565b8114620002f257600080fd5b50565b620002e681620002c4565b613b9d80620003106000396000f3fe608060405234801561001057600080fd5b506004361061027f5760003560e01c806370a082311161015c5780638da5cb5b116100ce578063b95375bd11610087578063b95375bd1461052e578063cd7b43dd14610541578063d621a16914610554578063e6b2cf6c14610567578063eac624891461056f578063f0b882ba1461058f5761027f565b80638da5cb5b146104dd578063910a326d146104e55780639ad6a7e5146104ed578063a0416ed3146104f5578063ae58254914610508578063b0fd59631461051b5761027f565b80637839b92f116101205780637839b92f146104665780637993e6991461047957806379ba50971461048c5780637cc1d7561461049457806380d46f58146104a7578063899ffef4146104c85761027f565b806370a082311461041057806371e780f31461042357806373307e401461042b578063741853601461043e578063773ab39f146104465761027f565b8063326a3cfb116101f557806346ba2d90116101b957806346ba2d90146103b257806353a47bb7146103ba5780635b85c200146103cf5780635eb8cf25146103e25780636154c343146103ea5780636dc05bd3146103fd5761027f565b8063326a3cfb1461035057806334c7fec91461036357806337088ffc146103765780634525aabc1461037e57806345626bd6146103915761027f565b8063178c565511610247578063178c5655146102f45780631bb47b44146102fc578063204b676a1461030f578063227d517a146103225780632af64bd31461033557806330104c5f1461033d5761027f565b8063018c6c551461028457806304f3bcec1461029957806305662986146102b75780630fcdefb7146102cc5780631627540c146102e1575b600080fd5b610297610292366004612c1e565b6105a2565b005b6102a16105ea565b6040516102ae91906137ef565b60405180910390f35b6102bf6105f9565b6040516102ae91906137a5565b6102d461061a565b6040516102ae91906137b3565b6102976102ef366004612922565b610620565b610297610673565b61029761030a366004612a54565b6106d0565b6102d461031d366004612922565b610721565b6102d4610330366004612922565b61073c565b6102bf61074e565b6102d461034b3660046129b3565b610865565b6102d461035e366004612922565b6108c4565b610297610371366004612bbf565b6108d6565b6102d461098c565b61029761038c366004612c1e565b610992565b6103a461039f3660046129b3565b6109cf565b6040516102ae929190613a44565b6102d46109ff565b6103c2610a05565b6040516102ae9190613658565b6102976103dd366004612c1e565b610a14565b6102d4610a51565b6103a46103f83660046129b3565b610a57565b6102d461040b36600461295e565b610a91565b6102d461041e366004612922565b610b3e565b6102d4610b59565b6103c2610439366004612922565b610b5f565b610297610b7a565b610459610454366004612a54565b610cd0565b6040516102ae919061374c565b610297610474366004612922565b610e70565b610297610487366004612c1e565b61116e565b6102976111cd565b6102976104a2366004612922565b611269565b6104ba6104b536600461295e565b6113b9565b6040516102ae92919061399e565b6104d0611642565b6040516102ae919061373b565b6103c261170c565b6102d461171b565b6102d4611721565b610297610503366004612a54565b611727565b6102d46105163660046129b3565b6117f2565b6102d4610529366004612922565b611820565b61029761053c366004612b03565b611832565b61029761054f3660046129ed565b611a1d565b610297610562366004612aa1565b611a2b565b6102d4611bec565b61058261057d366004612a54565b611bf2565b6040516102ae9190613794565b61029761059d36600461295e565b611cde565b6105aa61201a565b600d8190556040517fe829efae5d8a2f7163f46c23a8190bf14625c1e446561ca0f5cf279ab7c8015e906105df9083906137b3565b60405180910390a150565b6003546001600160a01b031681565b600042610613600e54600f5461204690919063ffffffff16565b1190505b90565b600f5481565b61062861201a565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22906105df908390613658565b61067b61201a565b42600f819055600e547fceade2b9bc02350b17075c94bb699508b89ed2752f501ea42024b1bb5fd3444591906106b890829063ffffffff61204616565b6040516106c69291906139be565b60405180910390a1565b6106d861206b565b6001600160a01b0316336001600160a01b0316146107115760405162461bcd60e51b81526004016107089061395e565b60405180910390fd5b61071c838383612085565b505050565b6001600160a01b031660009081526006602052604090205490565b60096020526000908152604090205481565b6000606061075a611642565b905060005b815181101561085c57600082828151811061077657fe5b60209081029190910181015160008181526004928390526040908190205460035491516321f8a72160e01b81529294506001600160a01b03908116939116916321f8a721916107c7918691016137b3565b60206040518083038186803b1580156107df57600080fd5b505afa1580156107f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108179190810190612940565b6001600160a01b031614158061084257506000818152600460205260409020546001600160a01b0316155b156108535760009350505050610617565b5060010161075f565b50600191505090565b600061086f612793565b506001600160a01b0383166000908152600560209081526040808320858452825291829020825180840190935280546001600160401b0316835260010154908201526108ba8161229d565b9150505b92915050565b60086020526000908152604090205481565b6000805b8281101561097b57336000908152600560205260408120818686858181106108fe57fe5b90506020020135815260200190815260200160002090508060010154600014610972576040805180820190915281546001600160401b031681526001820154602082015260009061094e9061229d565b9050801561095e57600060018301555b61096e848263ffffffff61204616565b9350505b506001016108da565b50801561071c5761071c33826122cd565b600d5481565b61099a61201a565b600c8190556040517f6b92bd20c4b2e6861047ba7209ddc78d538419aae187d0df46716b827b8997a4906105df9083906137b3565b6005602090815260009283526040808420909152908252902080546001909101546001600160401b039091169082565b60025481565b6001546001600160a01b031681565b610a1c61201a565b60118190556040517f7829b48ec37298e3e9b1cb2971e47abc072159681eaf558f8649a25d66ef8672906105df9083906137b3565b600c5481565b6001600160a01b039190911660009081526005602090815260408083209383529290522080546001909101546001600160401b0390911691565b6000805b82811015610b3657610aa5612793565b6001600160a01b038616600090815260056020526040812090868685818110610aca57fe5b60209081029290920135835250818101929092526040908101600020815180830190925280546001600160401b0316825260010154918101829052915015610b2d576000610b178261229d565b9050610b29848263ffffffff61204616565b9350505b50600101610a95565b509392505050565b6001600160a01b031660009081526008602052604090205490565b600b5481565b600a602052600090815260409020546001600160a01b031681565b6060610b84611642565b905060005b8151811015610ccc576000828281518110610ba057fe5b602002602001015190506000600360009054906101000a90046001600160a01b03166001600160a01b031663dacb2d018384604051602001610be2919061364d565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610c0e9291906137cf565b60206040518083038186803b158015610c2657600080fd5b505afa158015610c3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610c5e9190810190612940565b6000838152600460205260409081902080546001600160a01b0319166001600160a01b038416179055519091507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa6890610cba90849084906137c1565b60405180910390a15050600101610b89565b5050565b6060828201838111610d16576040805160008082526020820190925290610d0d565b610cfa6127aa565b815260200190600190039081610cf25790505b50915050610e69565b6001600160a01b038516600090815260066020526040902054811115610d5157506001600160a01b0384166000908152600660205260409020545b604080518583038082526020808202830101909252606090828015610d9057816020015b610d7d6127aa565b815260200190600190039081610d755790505b50905060005b82811015610e63576001600160a01b03881660009081526006602052604081208054838a01908110610dc457fe5b90600052602060002001549050610dd9612793565b506001600160a01b03891660009081526005602090815260408083208484528252918290208251808401845281546001600160401b03908116825260019092015481840190815284516060810186528251909316835251928201929092529182018390528451909190859085908110610e4e57fe5b60209081029190910101525050600101610d96565b50925050505b9392505050565b610e786123e8565b6001600160a01b031663086dabd16040518163ffffffff1660e01b815260040160006040518083038186803b158015610eb057600080fd5b505afa158015610ec4573d6000803e3d6000fd5b505050506001600160a01b038116600090815260106020526040902054610efd5760405162461bcd60e51b81526004016107089061388e565b6001600160a01b038116600090815260086020526040902054610f325760405162461bcd60e51b81526004016107089061397e565b6011546001600160a01b03821660009081526010602052604090205411610fbd57610f9f816040518060400160405280426001600160401b0316815260200160106000866001600160a01b03166001600160a01b0316815260200190815260200160002054815250612402565b6001600160a01b03811660009081526010602052604081205561116b565b6000610fc7612460565b6001600160a01b031663204b676a836040518263ffffffff1660e01b8152600401610ff29190613658565b60206040518083038186803b15801561100a57600080fd5b505afa15801561101e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110429190810190612c3c565b905060015b81811161071c576110566127d4565b61105e612460565b6001600160a01b031663da7bd3e9858486036040518363ffffffff1660e01b815260040161108d929190613720565b604080518083038186803b1580156110a457600080fd5b505afa1580156110b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110dc9190810190612ba1565b8051602082015191925090428210156110f75750505061071c565b61111e866040518060400160405280856001600160401b0316815260200184815250612402565b6001600160a01b038616600090815260106020526040902054611147908263ffffffff61247a16565b6001600160a01b038716600090815260106020526040902055505050600101611047565b50565b61117661201a565b600d548111156111985760405162461bcd60e51b81526004016107089061394e565b600e8190556040517f723c43349da7aeae47190396f2e2fbe6bedb46b9e9705bc5b908d65bc7a1e0e6906105df9083906137b3565b6001546001600160a01b031633146111f75760405162461bcd60e51b81526004016107089061380e565b6000546001546040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9261123a926001600160a01b03918216929116906136f7565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6001600160a01b0381163314156112925760405162461bcd60e51b8152600401610708906138ee565b61129a6105f9565b6112b65760405162461bcd60e51b8152600401610708906138be565b6112be6124a2565b6001600160a01b031663d37c4d8b336040518263ffffffff1660e01b81526004016112e99190613696565b60206040518083038186803b15801561130157600080fd5b505afa158015611315573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113399190810190612c3c565b156113565760405162461bcd60e51b81526004016107089061398e565b336000818152600a60205260409081902080546001600160a01b0319166001600160a01b038516179055517fcf51776bb16e5780edcca2e64a9ba8a9c7d5d00a6699cbd7606e465361ba4852906113ae908490613658565b60405180910390a250565b600060606113c56124b6565b6001600160a01b0316336001600160a01b0316146113f55760405162461bcd60e51b8152600401610708906138de565b826114125760405162461bcd60e51b8152600401610708906138fe565b60408051848152602080860282010190915283801561144b57816020015b611438612793565b8152602001906001900390816114305790505b50905060005b83811015611552576001600160a01b03861660009081526005602052604081208187878581811061147e57fe5b9050602002013581526020019081526020016000209050600081600101541115611549576040805180820190915281546001600160401b031681526001820154602082015283518490849081106114d157fe5b60200260200101819052506114f381600101548561204690919063ffffffff16565b6001600160a01b038816600090815260056020526040812091955087878581811061151a57fe5b602090810292909201358352508101919091526040016000908120805467ffffffffffffffff19168155600101555b50600101611451565b5081156115f35761156385836124dd565b61156b61253c565b6001600160a01b031663a9059cbb6115816124b6565b846040518363ffffffff1660e01b815260040161159f929190613720565b602060405180830381600087803b1580156115b957600080fd5b505af11580156115cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115f19190810190612c00565b505b846001600160a01b03167f929c8a2a06883affd05f43baf52398dbbfb6930730ce1bdb2cfe413cd44b107c85858542604051611632949392919061375d565b60405180910390a2935093915050565b60608061164d612553565b60408051600380825260808201909252919250606091906020820183803883390190505090507853796e746865746978427269646765546f4f7074696d69736d60381b8160008151811061169d57fe5b6020026020010181815250506b526577617264457363726f7760a01b816001815181106116c657fe5b6020026020010181815250506b53797374656d53746174757360a01b816002815181106116ef57fe5b60200260200101818152505061170582826125e5565b9250505090565b6000546001600160a01b031681565b600e5481565b60115481565b6001600160a01b03831661174d5760405162461bcd60e51b81526004016107089061384e565b61175561253c565b6001600160a01b03166323b872dd3330856040518463ffffffff1660e01b815260040161178493929190613666565b602060405180830381600087803b15801561179e57600080fd5b505af11580156117b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506117d69190810190612c00565b6107115760405162461bcd60e51b8152600401610708906138ce565b6006602052816000526040600020818154811061180b57fe5b90600052602060002001600091509150505481565b60106020526000908152604090205481565b60025442106118535760405162461bcd60e51b81526004016107089061393e565b61185b61201a565b84831461187a5760405162461bcd60e51b81526004016107089061396e565b8481146118995760405162461bcd60e51b81526004016107089061387e565b60005b85811015611a145760008787838181106118b257fe5b90506020020160206118c79190810190612922565b905060008686848181106118d757fe5b90506020020135905060008585858181106118ee57fe5b6001600160a01b03861660009081526010602090815260409091205491029290920135925050156119315760405162461bcd60e51b81526004016107089061381e565b600b54611944908363ffffffff61204616565b600b556001600160a01b038316600090815260086020526040902054611970908363ffffffff61204616565b6001600160a01b0384166000908152600860209081526040808320939093556009905220546119a5908263ffffffff61204616565b6001600160a01b0384166000818152600960209081526040808320949094556010905282902084905590517fa2a5ac2d2500e30aea994fc4bc99ef5535241c79d428e43c3fe204862f2874d690611a01908590859042906139cc565b60405180910390a250505060010161189c565b50505050505050565b611a256126a1565b50505050565b6002544210611a4c5760405162461bcd60e51b81526004016107089061393e565b611a5461201a565b828114611a735760405162461bcd60e51b81526004016107089061392e565b60005b83811015611be5576000858583818110611a8c57fe5b9050602002016020611aa19190810190612922565b90506000848484818110611ab157fe5b905060200201359050600060086000846001600160a01b03166001600160a01b031681526020019081526020016000205411611aff5760405162461bcd60e51b81526004016107089061397e565b6001600160a01b038216600090815260106020526040902054611b345760405162461bcd60e51b81526004016107089061388e565b611b5b826040518060400160405280426001600160401b0316815260200184815250612402565b6001600160a01b038216600090815260106020526040902054611b84908263ffffffff61247a16565b6001600160a01b038316600081815260106020526040908190209290925590517f73cefcb01ff86c575a4fbf40317a93c37b7312e0b294e588ee24b312e4f97cc490611bd390429085906139be565b60405180910390a25050600101611a76565b5050505050565b60075481565b6001600160a01b03831660009081526006602052604090205460609083830190811115611c3457506001600160a01b0384166000908152600660205260409020545b838111611c51576040805160008082526020820190925290610d0d565b604080518583038082526020808202830101909252606090828015611c80578160200160208202803883390190505b50905060005b82811015610e63576001600160a01b03881660009081526006602052604090208054828901908110611cb457fe5b9060005260206000200154828281518110611ccb57fe5b6020908102919091010152600101611c86565b611ce66105f9565b611d025760405162461bcd60e51b8152600401610708906138be565b611d0a6124a2565b6001600160a01b031663d37c4d8b846040518263ffffffff1660e01b8152600401611d359190613712565b60206040518083038186803b158015611d4d57600080fd5b505afa158015611d61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d859190810190612c3c565b15611da25760405162461bcd60e51b81526004016107089061398e565b6001600160a01b038381166000908152600a6020526040902054163314611ddb5760405162461bcd60e51b81526004016107089061391e565b6000805b82811015611f5a57611def612793565b6001600160a01b038616600090815260056020526040812090868685818110611e1457fe5b60209081029290920135835250818101929092526040908101600020815180830190925280546001600160401b0316825260010154918101829052915015611f51573360009081526005602052604081208291878786818110611e7357fe5b60209081029290920135835250818101929092526040016000208251815467ffffffffffffffff19166001600160401b0390911617815591810151600190920191909155810151611ec5908490612046565b336000908152600660205260409020909350858584818110611ee357fe5b8354600181018555600094855260208086209281029490940135910155506001600160a01b0388168252600590526040812090868685818110611f2257fe5b602090810292909201358352508101919091526040016000908120805467ffffffffffffffff19168155600101555b50600101611ddf565b506001600160a01b038416600090815260086020526040902054611f84908263ffffffff61247a16565b6001600160a01b038516600090815260086020526040808220929092553381522054611fb6908263ffffffff61204616565b33600081815260086020526040908190209290925590516001600160a01b038616917f48d567deaa7db90f8a443344e519ca8906521ffe118e1df43e89a3c257963f7c9161200c919085908890889042906136b0565b60405180910390a250505050565b6000546001600160a01b031633146120445760405162461bcd60e51b81526004016107089061390e565b565b600082820183811015610e695760405162461bcd60e51b81526004016107089061382e565b600061208066119959541bdbdb60ca1b6126b9565b905090565b816120a25760405162461bcd60e51b81526004016107089061389e565b6000811180156120b45750600c548111155b6120d05760405162461bcd60e51b81526004016107089061383e565b600b546120e3908363ffffffff61204616565b600b556120ee61253c565b6001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016121199190613658565b60206040518083038186803b15801561213157600080fd5b505afa158015612145573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506121699190810190612c3c565b600b54111561218a5760405162461bcd60e51b8152600401610708906138ae565b6001600160a01b038316600090815260086020526040902054428201906121b7908463ffffffff61204616565b6001600160a01b03851660008181526008602090815260408083209490945560078054855180870187526001600160401b0388811682528185018b81528787526005865288872084885286528887209251835467ffffffffffffffff1916921691909117825551600191820155948452600683529483208054808601825590845291909220018390555461224a91612046565b6007556040516001600160a01b038616907f2cc016694185d38abbe28d9e9baea2e9d95a321ae43475e5ea7b643756840bc09061228e9042908890889087906139e7565b60405180910390a25050505050565b60008082602001516000146108be5782516001600160401b031642116122c4576000610e69565b50506020015190565b6122d782826124dd565b6001600160a01b038216600090815260096020526040902054612300908263ffffffff61204616565b6001600160a01b03831660009081526009602052604090205561232161253c565b6001600160a01b031663a9059cbb83836040518363ffffffff1660e01b815260040161234e929190613720565b602060405180830381600087803b15801561236857600080fd5b505af115801561237c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506123a09190810190612c00565b50816001600160a01b03167ffbeff59d2bfda0d79ea8a29f8c57c66d48c7a13eabbdb90908d9115ec41c9dc642836040516123dc9291906139be565b60405180910390a25050565b60006120806b53797374656d53746174757360a01b6126b9565b600061240e8383612716565b602083015183516040519293506001600160a01b038616927fa0ba170b0a148bd927eafc64518e6c9d92eba1ea1fdf703dd8cfee6d329012bb92612453928692613a1c565b60405180910390a2505050565b60006120806b526577617264457363726f7760a01b6126b9565b60008282111561249c5760405162461bcd60e51b81526004016107089061385e565b50900390565b60006120806524b9b9bab2b960d11b6126b9565b60006120807853796e746865746978427269646765546f4f7074696d69736d60381b6126b9565b600b546124f0908263ffffffff61247a16565b600b556001600160a01b03821660009081526008602052604090205461251c908263ffffffff61247a16565b6001600160a01b0390921660009081526008602052604090209190915550565b6000612080680a6f2dce8d0cae8d2f60bb1b6126b9565b60408051600380825260808201909252606091602082018380388339019050509050680a6f2dce8d0cae8d2f60bb1b8160008151811061258f57fe5b60200260200101818152505066119959541bdbdb60ca1b816001815181106125b357fe5b6020026020010181815250506524b9b9bab2b960d11b816002815181106125d657fe5b60200260200101818152505090565b60608151835101604051908082528060200260200182016040528015612615578160200160208202803883390190505b50905060005b83518110156126575783818151811061263057fe5b602002602001015182828151811061264457fe5b602090810291909101015260010161261b565b5060005b825181101561269a5782818151811061267057fe5b602002602001015182828651018151811061268757fe5b602090810291909101015260010161265b565b5092915050565b60405162461bcd60e51b81526004016107089061386e565b60008181526004602090815260408083205490516001600160a01b0390911691821515916126e99186910161362d565b6040516020818303038152906040529061269a5760405162461bcd60e51b815260040161070891906137fd565b600780546001600160a01b038416600081815260056020908152604080832085845282528083208751815467ffffffffffffffff19166001600160401b03909116178155878301516001918201559383526006825282208054808501825590835290822001839055925461278991612046565b6007559392505050565b604080518082019091526000808252602082015290565b604051806060016040528060006001600160401b0316815260200160008152602001600081525090565b60405180604001604052806002906020820280388339509192915050565b80356108be81613b34565b80516108be81613b34565b60008083601f84011261281a57600080fd5b5081356001600160401b0381111561283157600080fd5b60208301915083602082028301111561284957600080fd5b9250929050565b60008083601f84011261286257600080fd5b5081356001600160401b0381111561287957600080fd5b60208301915083604082028301111561284957600080fd5b600082601f8301126128a257600080fd5b60026128b56128b082613a78565b613a52565b915081838560208402820111156128cb57600080fd5b60005b838110156128f757816128e18882612917565b84525060209283019291909101906001016128ce565b5050505092915050565b80516108be81613b48565b80356108be81613b51565b80516108be81613b51565b60006020828403121561293457600080fd5b60006108ba84846127f2565b60006020828403121561295257600080fd5b60006108ba84846127fd565b60008060006040848603121561297357600080fd5b600061297f86866127f2565b93505060208401356001600160401b0381111561299b57600080fd5b6129a786828701612808565b92509250509250925092565b600080604083850312156129c657600080fd5b60006129d285856127f2565b92505060206129e38582860161290c565b9150509250929050565b60008060008060608587031215612a0357600080fd5b6000612a0f87876127f2565b9450506020612a208782880161290c565b93505060408501356001600160401b03811115612a3c57600080fd5b612a4887828801612850565b95989497509550505050565b600080600060608486031215612a6957600080fd5b6000612a7586866127f2565b9350506020612a868682870161290c565b9250506040612a978682870161290c565b9150509250925092565b60008060008060408587031215612ab757600080fd5b84356001600160401b03811115612acd57600080fd5b612ad987828801612808565b945094505060208501356001600160401b03811115612af757600080fd5b612a4887828801612808565b60008060008060008060608789031215612b1c57600080fd5b86356001600160401b03811115612b3257600080fd5b612b3e89828a01612808565b965096505060208701356001600160401b03811115612b5c57600080fd5b612b6889828a01612808565b945094505060408701356001600160401b03811115612b8657600080fd5b612b9289828a01612808565b92509250509295509295509295565b600060408284031215612bb357600080fd5b60006108ba8484612891565b60008060208385031215612bd257600080fd5b82356001600160401b03811115612be857600080fd5b612bf485828601612808565b92509250509250929050565b600060208284031215612c1257600080fd5b60006108ba8484612901565b600060208284031215612c3057600080fd5b60006108ba848461290c565b600060208284031215612c4e57600080fd5b60006108ba8484612917565b6000612c668383612e33565b505060200190565b6000612c7a83836135c0565b505060600190565b6000612c8e83836135f7565b505060400190565b612c9f81613ad5565b82525050565b612c9f81613aad565b6000612cb982613a9b565b612cc38185613a9f565b9350612cce83613a95565b8060005b83811015612cfc578151612ce68882612c5a565b9750612cf183613a95565b925050600101612cd2565b509495945050505050565b6000612d1282613a9b565b612d1c8185613a9f565b9350612d2783613a95565b8060005b83811015612cfc578151612d3f8882612c6e565b9750612d4a83613a95565b925050600101612d2b565b6000612d6082613a9b565b612d6a8185613a9f565b9350612d7583613a95565b8060005b83811015612cfc578151612d8d8882612c82565b9750612d9883613a95565b925050600101612d79565b6000612daf8385613a9f565b93506001600160fb1b03831115612dc557600080fd5b602083029250612dd6838584613af2565b50500190565b6000612de782613a9b565b612df18185613a9f565b9350612dfc83613a95565b8060005b83811015612cfc578151612e148882612c5a565b9750612e1f83613a95565b925050600101612e00565b612c9f81613ab8565b612c9f81610617565b612c9f612e4882610617565b610617565b612c9f81613adc565b6000612e6182613a9b565b612e6b8185613a9f565b9350612e7b818560208601613afe565b612e8481613b2a565b9093019392505050565b6000612e9b603583613a9f565b7f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7581527402063616e20616363657074206f776e65727368697605c1b602082015260400192915050565b6000612ef2602483613a9f565b7f4163636f756e74206d6967726174696f6e2069732070656e64696e6720616c728152636561647960e01b602082015260400192915050565b6000612f38601b83613a9f565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000612f71603383613a9f565b7f43616e6e6f7420657363726f7720776974682030206475726174696f6e204f528152721030b137bb329036b0bc2fb23ab930ba34b7b760691b602082015260400192915050565b6000612fc6602483613a9f565b7f43616e6e6f742063726561746520657363726f772077697468206164647265738152637328302960e01b602082015260400192915050565b600061300c601e83613a9f565b7f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815260200192915050565b6000613045601b83613a9f565b7f43616e6e6f742062652072756e206f6e2074686973206c617965720000000000815260200192915050565b600061307e603183613a9f565b7f4e756d626572206f66206163636f756e747320616e642076657374656442616c8152700c2dcc6cae640c8dedc4ee840dac2e8c6d607b1b602082015260400192915050565b60006130d1601b83613a9f565b7f4e6f20657363726f77206d6967726174696f6e2070656e64696e670000000000815260200192915050565b600061310a601183613aa8565b70026b4b9b9b4b7339030b2323932b9b99d1607d1b815260110192915050565b6000613137601783613a9f565b7f5175616e746974792063616e6e6f74206265207a65726f000000000000000000815260200192915050565b6000613170604783613a9f565b7f4d75737420626520656e6f7567682062616c616e636520696e2074686520636f81527f6e747261637420746f2070726f7669646520666f72207468652076657374696e6020820152666720656e74727960c81b604082015260600192915050565b60006131df601983613a9f565b7f4163636f756e74206d657267696e672068617320656e64656400000000000000815260200192915050565b6000613218601583613a9f565b741d1bdad95b881d1c985b9cd9995c8819985a5b1959605a1b815260200192915050565b6000613249603983613a9f565b7f43616e206f6e6c7920626520696e766f6b65642062792053796e74686574697881527f427269646765546f4f7074696d69736d20636f6e747261637400000000000000602082015260400192915050565b60006132a8602483613a9f565b7f43616e6e6f74206e6f6d696e617465206f776e206163636f756e7420746f206d8152636572676560e01b602082015260400192915050565b60006132ee601283613a9f565b71115b9d1c9e4812511cc81c995c5d5a5c995960721b815260200192915050565b600061331c602f83613a9f565b7f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726681526e37b936903a3434b99030b1ba34b7b760891b602082015260400192915050565b631cd554d160e21b9052565b6000613379602183613a9f565b7f41646472657373206973206e6f74206e6f6d696e6174656420746f206d6572678152606560f81b602082015260400192915050565b60006133bc602983613a9f565b7f4163636f756e7420616e6420657363726f77416d6f756e7473204c656e677468815268040dad2e6dac2e8c6d60bb1b602082015260400192915050565b6000613407602983613a9f565b7f43616e206f6e6c7920706572666f726d207468697320616374696f6e206475728152680696e672073657475760bc1b602082015260400192915050565b6000613452601c83613a9f565b7f65786365656473206d6178206d657267696e67206475726174696f6e00000000815260200192915050565b600061348b601983613aa8565b7f5265736f6c766572206d697373696e67207461726765743a2000000000000000815260190192915050565b60006134c4602883613a9f565b7f4f6e6c792074686520466565506f6f6c2063616e20706572666f726d20746869815267399030b1ba34b7b760c11b602082015260400192915050565b600061350e602b83613a9f565b7f4e756d626572206f66206163636f756e747320616e642062616c616e6365732081526a0c8dedc4ee840dac2e8c6d60ab1b602082015260400192915050565b600061355b601b83613a9f565b7f4164647265737320657363726f772062616c616e636520697320300000000000815260200192915050565b6000613594601f83613a9f565b7f43616e6e6f74206d65726765206163636f756e74732077697468206465627400815260200192915050565b805160608301906135d18482613624565b5060208201516135e46020850182612e33565b506040820151611a256040850182612e33565b805160408301906136088482613624565b506020820151611a256020850182612e33565b612c9f81613ae7565b612c9f81613ac9565b6000613638826130fd565b91506136448284612e3c565b50602001919050565b60006136388261347e565b602081016108be8284612ca5565b606081016136748286612c96565b6136816020830185612ca5565b61368e6040830184612e33565b949350505050565b604081016136a48284612c96565b6108be60208301613360565b608081016136be8288612c96565b6136cb6020830187612e33565b81810360408301526136de818587612da3565b90506136ed6060830184612e33565b9695505050505050565b604081016137058285612ca5565b610e696020830184612ca5565b604081016136a48284612ca5565b6040810161372e8285612ca5565b610e696020830184612e33565b60208082528101610e698184612cae565b60208082528101610e698184612d07565b6060808252810161376f818688612da3565b905061377e6020830185612e33565b61378b6040830184612e33565b95945050505050565b60208082528101610e698184612ddc565b602081016108be8284612e2a565b602081016108be8284612e33565b604081016137058285612e33565b604081016137dd8285612e33565b818103602083015261368e8184612e56565b602081016108be8284612e4d565b60208082528101610e698184612e56565b602080825281016108be81612e8e565b602080825281016108be81612ee5565b602080825281016108be81612f2b565b602080825281016108be81612f64565b602080825281016108be81612fb9565b602080825281016108be81612fff565b602080825281016108be81613038565b602080825281016108be81613071565b602080825281016108be816130c4565b602080825281016108be8161312a565b602080825281016108be81613163565b602080825281016108be816131d2565b602080825281016108be8161320b565b602080825281016108be8161323c565b602080825281016108be8161329b565b602080825281016108be816132e1565b602080825281016108be8161330f565b602080825281016108be8161336c565b602080825281016108be816133af565b602080825281016108be816133fa565b602080825281016108be81613445565b602080825281016108be816134b7565b602080825281016108be81613501565b602080825281016108be8161354e565b602080825281016108be81613587565b604081016139ac8285612e33565b818103602083015261368e8184612d55565b6040810161372e8285612e33565b606081016139da8286612e33565b6136816020830185612e33565b608081016139f58287612e33565b613a026020830186612e33565b613a0f6040830185612e33565b61378b6060830184612e33565b60608101613a2a8286612e33565b613a376020830185612e33565b61368e604083018461361b565b6040810161372e8285613624565b6040518181016001600160401b0381118282101715613a7057600080fd5b604052919050565b60006001600160401b03821115613a8e57600080fd5b5060200290565b60200190565b5190565b90815260200190565b919050565b60006108be82613abd565b151590565b6001600160a01b031690565b6001600160401b031690565b60006108be825b60006108be82613aad565b60006108be82613ac9565b82818337506000910152565b60005b83811015613b19578181015183820152602001613b01565b83811115611a255750506000910152565b601f01601f191690565b613b3d81613aad565b811461116b57600080fd5b613b3d81613ab8565b613b3d8161061756fea365627a7a7231582039a56045b6bf760d8bf527fe78d2326d226ae63ab32f8abad0f368f4d85eb2bd6c6578706572696d656e74616cf564736f6c63430005100040000000000000000000000000b64ff7a4a33acdf48d97dab0d764afd0f6176882000000000000000000000000242a3df52c375bee81b1c668741d7c63af68fdd2
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000b64ff7a4a33acdf48d97dab0d764afd0f6176882000000000000000000000000242a3df52c375bee81b1c668741d7c63af68fdd2
-----Decoded View---------------
Arg [0] : _owner (address): 0xb64ff7a4a33acdf48d97dab0d764afd0f6176882
Arg [1] : _resolver (address): 0x242a3df52c375bee81b1c668741d7c63af68fdd2
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000b64ff7a4a33acdf48d97dab0d764afd0f6176882
Arg [1] : 000000000000000000000000242a3df52c375bee81b1c668741d7c63af68fdd2
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.