Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
xSNX
Compiler Version
v0.5.15+commit.6a57276f
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2021-05-24 */ // File: @openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol pragma solidity ^0.5.0; /** * @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) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); 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-contracts/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) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message 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. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); 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) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message 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. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File: @openzeppelin/upgrades/contracts/Initializable.sol pragma solidity >=0.4.24 <0.7.0; /** * @title Initializable * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. */ contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized"); bool isTopLevelCall = !initializing; if (isTopLevelCall) { initializing = true; initialized = true; } _; if (isTopLevelCall) { initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. address self = address(this); uint256 cs; assembly { cs := extcodesize(self) } return cs == 0; } // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; } // File: @openzeppelin/contracts-ethereum-package/contracts/GSN/Context.sol pragma solidity ^0.5.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract Context is Initializable { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. constructor () internal { } // solhint-disable-previous-line no-empty-blocks function _msgSender() internal view returns (address payable) { return msg.sender; } function _msgData() internal view returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } // File: @openzeppelin/contracts-ethereum-package/contracts/ownership/Ownable.sol pragma solidity ^0.5.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be aplied to your functions to restrict their use to * the owner. */ contract Ownable is Initializable, Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function initialize(address sender) public initializer { _owner = sender; emit OwnershipTransferred(address(0), _owner); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner(), "Ownable: caller is not the owner"); _; } /** * @dev Returns true if the caller is the current owner. */ function isOwner() public view returns (bool) { return _msgSender() == _owner; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * > Note: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } uint256[50] private ______gap; } // File: @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/IERC20.sol pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20.sol pragma solidity ^0.5.0; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20Mintable}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Initializable, Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for `sender`'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal { require(account != address(0), "ERC20: mint to the zero address"); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal { require(account != address(0), "ERC20: burn from the zero address"); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Destroys `amount` tokens from `account`.`amount` is then deducted * from the caller's allowance. * * See {_burn} and {_approve}. */ function _burnFrom(address account, uint256 amount) internal { _burn(account, amount); _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance")); } uint256[50] private ______gap; } // File: @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Detailed.sol pragma solidity ^0.5.0; /** * @dev Optional functions from the ERC20 standard. */ contract ERC20Detailed is Initializable, IERC20 { string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of * these values are immutable: they can only be set once during * construction. */ function initialize(string memory name, string memory symbol, uint8 decimals) public initializer { _name = name; _symbol = symbol; _decimals = decimals; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view returns (uint8) { return _decimals; } uint256[50] private ______gap; } // File: synthetix/contracts/interfaces/ISynth.sol pragma solidity >=0.4.24; // 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; } // File: synthetix/contracts/interfaces/IVirtualSynth.sol pragma solidity >=0.4.24; 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; } // File: synthetix/contracts/interfaces/ISynthetix.sol pragma solidity >=0.4.24; // 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; } // File: synthetix/contracts/interfaces/IRewardEscrowV2.sol pragma solidity >=0.4.24; 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); } // File: synthetix/contracts/interfaces/IExchangeRates.sol pragma solidity >=0.4.24; // https://docs.synthetix.io/contracts/source/interfaces/iexchangerates interface IExchangeRates { // Structs struct RateAndUpdatedTime { uint216 rate; uint40 time; } struct InversePricing { uint entryPoint; uint upperLimit; uint lowerLimit; bool frozenAtUpperLimit; bool frozenAtLowerLimit; } // Views function aggregators(bytes32 currencyKey) external view returns (address); function aggregatorWarningFlags() external view returns (address); function anyRateIsInvalid(bytes32[] calldata currencyKeys) external view returns (bool); function canFreezeRate(bytes32 currencyKey) external view returns (bool); function currentRoundForRate(bytes32 currencyKey) external view returns (uint); function currenciesUsingAggregator(address aggregator) external view returns (bytes32[] memory); function effectiveValue( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) external view returns (uint value); function effectiveValueAndRates( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) external view returns ( uint value, uint sourceRate, uint destinationRate ); function effectiveValueAtRound( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, uint roundIdForSrc, uint roundIdForDest ) external view returns (uint value); function getCurrentRoundId(bytes32 currencyKey) external view returns (uint); function getLastRoundIdBeforeElapsedSecs( bytes32 currencyKey, uint startingRoundId, uint startingTimestamp, uint timediff ) external view returns (uint); function inversePricing(bytes32 currencyKey) external view returns ( uint entryPoint, uint upperLimit, uint lowerLimit, bool frozenAtUpperLimit, bool frozenAtLowerLimit ); function lastRateUpdateTimes(bytes32 currencyKey) external view returns (uint256); function oracle() external view returns (address); function rateAndTimestampAtRound(bytes32 currencyKey, uint roundId) external view returns (uint rate, uint time); function rateAndUpdatedTime(bytes32 currencyKey) external view returns (uint rate, uint time); function rateAndInvalid(bytes32 currencyKey) external view returns (uint rate, bool isInvalid); function rateForCurrency(bytes32 currencyKey) external view returns (uint); function rateIsFlagged(bytes32 currencyKey) external view returns (bool); function rateIsFrozen(bytes32 currencyKey) external view returns (bool); function rateIsInvalid(bytes32 currencyKey) external view returns (bool); function rateIsStale(bytes32 currencyKey) external view returns (bool); function rateStalePeriod() external view returns (uint); function ratesAndUpdatedTimeForCurrencyLastNRounds(bytes32 currencyKey, uint numRounds) external view returns (uint[] memory rates, uint[] memory times); function ratesAndInvalidForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint[] memory rates, bool anyRateInvalid); function ratesForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint[] memory); // Mutative functions function freezeRate(bytes32 currencyKey) external; } // File: synthetix/contracts/interfaces/ISynthetixState.sol pragma solidity >=0.4.24; // https://docs.synthetix.io/contracts/source/interfaces/isynthetixstate interface ISynthetixState { // Views function debtLedger(uint index) external view returns (uint); function issuanceData(address account) external view returns (uint initialDebtOwnership, uint debtEntryIndex); function debtLedgerLength() external view returns (uint); function hasIssued(address account) external view returns (bool); function lastDebtLedgerEntry() external view returns (uint); // Mutative functions function incrementTotalIssuerCount() external; function decrementTotalIssuerCount() external; function setCurrentIssuanceData(address account, uint initialDebtOwnership) external; function appendDebtLedgerValue(uint value) external; function clearIssuanceData(address account) external; } // File: synthetix/contracts/interfaces/IAddressResolver.sol pragma solidity >=0.4.24; // 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); } // File: contracts/interface/ISystemSettings.sol pragma solidity 0.5.15; interface ISystemSettings { function issuanceRatio() external view returns(uint); } // File: contracts/interface/ICurveFi.sol pragma solidity 0.5.15; interface ICurveFi { function exchange( int128 i, int128 j, uint256 dx, uint256 min_dy ) external; function exchange_underlying( int128 i, int128 j, uint256 dx, uint256 min_dy ) external; function get_dx_underlying( int128 i, int128 j, uint256 dy ) external view returns (uint256); function get_dy_underlying( int128 i, int128 j, uint256 dx ) external view returns (uint256); function get_dx( int128 i, int128 j, uint256 dy ) external view returns (uint256); function get_dy( int128 i, int128 j, uint256 dx ) external view returns (uint256); function get_virtual_price() external view returns (uint256); } // File: contracts/interface/ISetToken.sol pragma solidity 0.5.15; interface ISetToken { function unitShares() external view returns(uint); function naturalUnit() external view returns(uint); function currentSet() external view returns(address); // function getUnits() external view returns (uint256[] memory); } // File: contracts/interface/IKyberNetworkProxy.sol pragma solidity 0.5.15; contract IKyberNetworkProxy { function getExpectedRate(ERC20 src, ERC20 dest, uint srcQty) external view returns (uint expectedRate, uint slippageRate); function swapEtherToToken(ERC20 token, uint minConversionRate) external payable returns(uint); function swapTokenToEther(ERC20 token, uint tokenQty, uint minRate) external payable returns(uint); function swapTokenToToken(ERC20 src, uint srcAmount, ERC20 dest, uint minConversionRate) public returns(uint); } // File: contracts/interface/ISetAssetBaseCollateral.sol pragma solidity 0.5.15; interface ISetAssetBaseCollateral { function getComponents() external view returns(address[] memory); function naturalUnit() external view returns(uint); function getUnits() external view returns (uint256[] memory); } // File: contracts/TradeAccounting.sol pragma solidity 0.5.15; /* xSNX Target Allocation (assuming 800% C-RATIO) ---------------------- Allocation | NAV | % NAV -------------------------------------- 800 SNX @ $1/token | $800 | 100% 100 sUSD Debt | ($100) | (12.5%) 75 USD equiv Set | $75 | 9.375% 25 USD equiv ETH | $25 | 3.125% -------------------------------------- Total $800 | 100% */ /* Conditions for `isRebalanceTowardsHedgeRequired` to return true Assuming 5% rebalance threshold Allocation | NAV | % NAV -------------------------------------- 800 SNX @ $1/token | $800 | 100.63% 105 sUSD Debt | ($105) | (13.21%) 75 USD equiv Set | $75 | 9.43% 25 USD equiv ETH | $25 | 3.14% -------------------------------------- Total $795 | 100% Debt value | $105 Hedge Assets | $100 ------------------------- Debt/hedge ratio | 105% */ /* Conditions for `isRebalanceTowardsSnxRequired` to return true Assuming 5% rebalance threshold Allocation | NAV | % NAV -------------------------------------- 800 SNX @ $1/token | $800 | 99.37% 100 sUSD Debt | ($100) | (12.42%) 75 USD equiv Set | $75 | 9.31% 30 USD equiv ETH | $30 | 3.72% -------------------------------------- Total $805 | 100% Hedge Assets | $105 Debt value | $100 ------------------------- Hedge/debt ratio | 105% */ contract TradeAccounting is Ownable { using SafeMath for uint256; uint256 private constant TEN = 10; uint256 private constant DEC_18 = 1e18; uint256 private constant PERCENT = 100; uint256 private constant ETH_TARGET = 4; // targets 1/4th of hedge portfolio uint256 private constant SLIPPAGE_RATE = 99; uint256 private constant MAX_UINT = 2**256 - 1; uint256 private constant RATE_STALE_TIME = 28800; // 8 hours uint256 private constant REBALANCE_THRESHOLD = 105; // 5% uint256 private constant INITIAL_SUPPLY_MULTIPLIER = 10; int128 usdcIndex; int128 susdIndex; ICurveFi private curveFi; ISynthetixState private synthetixState; IAddressResolver private addressResolver; IKyberNetworkProxy private kyberNetworkProxy; address private xSNXAdminInstance; address private addressValidator; address private setAddress; address private susdAddress; address private usdcAddress; address private nextCurveAddress; bytes32 constant snx = "SNX"; bytes32 constant susd = "sUSD"; bytes32 constant seth = "sETH"; bytes32[2] synthSymbols; address[2] setComponentAddresses; bytes32 constant rewardEscrowName = "RewardEscrow"; bytes32 constant exchangeRatesName = "ExchangeRates"; bytes32 constant synthetixName = "Synthetix"; bytes32 constant systemSettingsName = "SystemSettings"; bytes32 constant rewardEscrowV2Name = "RewardEscrowV2"; uint256 private constant RATE_STALE_TIME_NEW = 86400; // 24 hours function initialize( address _setAddress, address _kyberProxyAddress, address _addressResolver, address _susdAddress, address _usdcAddress, address _addressValidator, bytes32[2] memory _synthSymbols, address[2] memory _setComponentAddresses, address _ownerAddress ) public initializer { Ownable.initialize(_ownerAddress); setAddress = _setAddress; kyberNetworkProxy = IKyberNetworkProxy(_kyberProxyAddress); addressResolver = IAddressResolver(_addressResolver); susdAddress = _susdAddress; usdcAddress = _usdcAddress; addressValidator = _addressValidator; synthSymbols = _synthSymbols; setComponentAddresses = _setComponentAddresses; } modifier onlyXSNXAdmin { require( msg.sender == xSNXAdminInstance, "Only xSNXAdmin contract can call" ); _; } /* ========================================================================================= */ /* Kyber/Curve */ /* ========================================================================================= */ /* * @dev Function that processes all token to token exchanges, * sometimes via Kyber and sometimes via a combination of Kyber & Curve * @dev Only callable by xSNXAdmin contract */ function swapTokenToToken( address fromToken, uint256 amount, address toToken, uint256 minKyberRate, uint256 minCurveReturn ) public onlyXSNXAdmin { if (fromToken == susdAddress) { _exchangeUnderlying(susdIndex, usdcIndex, amount, minCurveReturn); if (toToken != usdcAddress) { uint256 usdcBal = getUsdcBalance(); _swapTokenToToken(usdcAddress, usdcBal, toToken, minKyberRate); } } else if (toToken == susdAddress) { if (fromToken != usdcAddress) { _swapTokenToToken(fromToken, amount, usdcAddress, minKyberRate); } uint256 usdcBal = getUsdcBalance(); _exchangeUnderlying(usdcIndex, susdIndex, usdcBal, minCurveReturn); } else { _swapTokenToToken(fromToken, amount, toToken, minKyberRate); } IERC20(toToken).transfer( xSNXAdminInstance, IERC20(toToken).balanceOf(address(this)) ); } function _swapTokenToToken( address _fromToken, uint256 _amount, address _toToken, uint256 _minKyberRate ) private { kyberNetworkProxy.swapTokenToToken( ERC20(_fromToken), _amount, ERC20(_toToken), _minKyberRate ); } /* * @dev Function that processes all token to ETH exchanges, * sometimes via Kyber and sometimes via a combination of Kyber & Curve * @dev Only callable by xSNXAdmin contract */ function swapTokenToEther( address fromToken, uint256 amount, uint256 minKyberRate, uint256 minCurveReturn ) public onlyXSNXAdmin { if (fromToken == susdAddress) { _exchangeUnderlying(susdIndex, usdcIndex, amount, minCurveReturn); uint256 usdcBal = getUsdcBalance(); _swapTokenToEther(usdcAddress, usdcBal, minKyberRate); } else { _swapTokenToEther(fromToken, amount, minKyberRate); } uint256 ethBal = address(this).balance; (bool success, ) = msg.sender.call.value(ethBal)(""); require(success, "Transfer failed"); } function _swapTokenToEther( address _fromToken, uint256 _amount, uint256 _minKyberRate ) private { kyberNetworkProxy.swapTokenToEther( ERC20(_fromToken), _amount, _minKyberRate ); } function _exchangeUnderlying( int128 _inputIndex, int128 _outputIndex, uint256 _amount, uint256 _minReturn ) private { curveFi.exchange_underlying( _inputIndex, _outputIndex, _amount, _minReturn ); } function getUsdcBalance() internal view returns (uint256) { return IERC20(usdcAddress).balanceOf(address(this)); } /* ========================================================================================= */ /* NAV */ /* ========================================================================================= */ function getEthBalance() public view returns (uint256) { return address(xSNXAdminInstance).balance; } /* * @dev Helper function for `xSNX.burn` that outputs NAV * redemption value in ETH terms * @param totalSupply: xSNX.totalSupply() * @param tokensToRedeem: xSNX to burn */ function calculateRedemptionValue( uint256 totalSupply, uint256 tokensToRedeem ) public view returns (uint256 valueToRedeem) { uint256 snxBalanceOwned = getSnxBalanceOwned(); uint256 contractDebtValue = getContractDebtValue(); uint256 pricePerToken = calculateRedeemTokenPrice( totalSupply, snxBalanceOwned, contractDebtValue ); valueToRedeem = pricePerToken.mul(tokensToRedeem).div(DEC_18); } /* * @dev Helper function for `xSNX.mint` that * 1) determines whether ETH contribution should be maintained in ETH or exchanged for SNX and * 2) outputs the `nonSnxAssetValue` value to be used in NAV calculation * @param totalSupply: xSNX.totalSupply() */ function getMintWithEthUtils(uint256 totalSupply) public view returns (bool allocateToEth, uint256 nonSnxAssetValue) { uint256 setHoldingsInWei = getSetHoldingsValueInWei(); // called before eth transferred from xSNX to xSNXAdmin uint256 ethBalBefore = getEthBalance(); allocateToEth = shouldAllocateEthToEthReserve( setHoldingsInWei, ethBalBefore, totalSupply ); nonSnxAssetValue = setHoldingsInWei.add(ethBalBefore); } /* * @notice xSNX system targets 25% of hedge portfolio to be maintained in ETH * @dev Function produces binary yes allocate/no allocate decision point * determining whether ETH sent on xSNX.mint() is held or exchanged * @param setHoldingsInWei: value of Set portfolio in ETH terms * @param ethBalBefore: value of ETH reserve prior to tx * @param totalSupply: xSNX.totalSupply() */ function shouldAllocateEthToEthReserve( uint256 setHoldingsInWei, uint256 ethBalBefore, uint256 totalSupply ) public pure returns (bool allocateToEth) { if (totalSupply == 0) return false; if (ethBalBefore.mul(ETH_TARGET) < ethBalBefore.add(setHoldingsInWei)) { // ETH reserve is under target return true; } return false; } /* * @dev Helper function for calculateIssueTokenPrice * @dev Called indirectly by `xSNX.mint` and `xSNX.mintWithSnx` * @dev Calculates NAV of the fund, including value of escrowed SNX, in ETH terms * @param weiPerOneSnx: SNX price in ETH terms * @param snxBalanceBefore: SNX balance pre-mint * @param nonSnxAssetValue: NAV of non-SNX slice of fund */ function calculateNetAssetValueOnMint( uint256 weiPerOneSnx, uint256 snxBalanceBefore, uint256 nonSnxAssetValue ) internal view returns (uint256) { uint256 snxTokenValueInWei = snxBalanceBefore.mul(weiPerOneSnx).div( DEC_18 ); uint256 contractDebtValue = getContractDebtValue(); uint256 contractDebtValueInWei = calculateDebtValueInWei( contractDebtValue ); return snxTokenValueInWei.add(nonSnxAssetValue).sub( contractDebtValueInWei ); } /* * @dev Helper function for calculateRedeemTokenPrice * @dev Called indirectly by `xSNX.burn` * @dev Calculates NAV of the fund, excluding value of escrowed SNX, in ETH terms * @param weiPerOneSnx: SNX price in ETH terms * @param snxBalanceOwned: non-escrowed SNX balance * @param contractDebtValueInWei: sUSD debt balance of fund in ETH terms */ function calculateNetAssetValueOnRedeem( uint256 weiPerOneSnx, uint256 snxBalanceOwned, uint256 contractDebtValueInWei ) internal view returns (uint256) { uint256 snxTokenValueInWei = snxBalanceOwned.mul(weiPerOneSnx).div( DEC_18 ); uint256 nonSnxAssetValue = calculateNonSnxAssetValue(); return snxTokenValueInWei.add(nonSnxAssetValue).sub( contractDebtValueInWei ); } /* * @dev NAV value of non-SNX assets, computed in ETH terms */ function calculateNonSnxAssetValue() internal view returns (uint256) { return getSetHoldingsValueInWei().add(getEthBalance()); } /* * @dev SNX price in ETH terms, calculated for purposes of redemption NAV * @notice Return value discounted slightly to better represent liquidation price */ function getWeiPerOneSnxOnRedeem() internal view returns (uint256 weiPerOneSnx) { uint256 snxUsdPrice = getSnxPrice(); uint256 ethUsdPrice = getSynthPrice(seth); weiPerOneSnx = snxUsdPrice .mul(DEC_18) .div(ethUsdPrice) .mul(SLIPPAGE_RATE) // used to better represent liquidation price as volume scales .div(PERCENT); } /* * @dev Returns Synthetix synth symbol for asset currently held in TokenSet (e.g., sETH for WETH) * @notice xSNX contract complex only compatible with Sets that hold a single asset at a time */ function getActiveAssetSynthSymbol() internal view returns (bytes32 synthSymbol) { synthSymbol = getAssetCurrentlyActiveInSet() == setComponentAddresses[0] ? (synthSymbols[0]) : (synthSymbols[1]); } /* * @dev Returns SNX price in ETH terms, calculated for purposes of issuance NAV (when allocateToEth) */ function getWeiPerOneSnxOnMint() internal view returns (uint256) { uint256 snxUsd = getSynthPrice(snx); uint256 ethUsd = getSynthPrice(seth); return snxUsd.mul(DEC_18).div(ethUsd); } /* * @dev Single use function to define initial xSNX issuance */ function getInitialSupply() internal view returns (uint256) { return IERC20(addressResolver.getAddress(synthetixName)) .balanceOf(xSNXAdminInstance) .mul(INITIAL_SUPPLY_MULTIPLIER); } /* * @dev Helper function for `xSNX.mint` that calculates token issuance * @param snxBalanceBefore: SNX balance pre-mint * @param ethContributed: ETH payable on mint, less fees * @param nonSnxAssetValue: NAV of non-SNX slice of fund * @param totalSupply: xSNX.totalSupply() */ function calculateTokensToMintWithEth( uint256 snxBalanceBefore, uint256 ethContributed, uint256 nonSnxAssetValue, uint256 totalSupply ) public view returns (uint256) { if (totalSupply == 0) { return getInitialSupply(); } uint256 pricePerToken = calculateIssueTokenPrice( getWeiPerOneSnxOnMint(), snxBalanceBefore, nonSnxAssetValue, totalSupply ); return ethContributed.mul(DEC_18).div(pricePerToken); } /* * @dev Helper function for `xSNX.mintWithSnx` that calculates token issuance * @param snxBalanceBefore: SNX balance pre-mint * @param snxAddedToBalance: SNX contributed by mint * @param totalSupply: xSNX.totalSupply() */ function calculateTokensToMintWithSnx( uint256 snxBalanceBefore, uint256 snxAddedToBalance, uint256 totalSupply ) public view returns (uint256) { if (totalSupply == 0) { return getInitialSupply(); } uint256 weiPerOneSnx = getWeiPerOneSnxOnMint(); // need to derive snx contribution in eth terms for NAV calc uint256 proxyEthContribution = weiPerOneSnx.mul(snxAddedToBalance).div( DEC_18 ); uint256 nonSnxAssetValue = calculateNonSnxAssetValue(); uint256 pricePerToken = calculateIssueTokenPrice( weiPerOneSnx, snxBalanceBefore, nonSnxAssetValue, totalSupply ); return proxyEthContribution.mul(DEC_18).div(pricePerToken); } /* * @dev Called indirectly by `xSNX.mint` and `xSNX.mintWithSnx` * @dev Calculates token price on issuance, including value of escrowed SNX * @param weiPerOneSnx: SNX price in ETH terms * @param snxBalanceBefore: SNX balance pre-mint * @param nonSnxAssetValue: Non-SNX slice of fund * @param totalSupply: xSNX.totalSupply() */ function calculateIssueTokenPrice( uint256 weiPerOneSnx, uint256 snxBalanceBefore, uint256 nonSnxAssetValue, uint256 totalSupply ) public view returns (uint256 pricePerToken) { pricePerToken = calculateNetAssetValueOnMint( weiPerOneSnx, snxBalanceBefore, nonSnxAssetValue ) .mul(DEC_18) .div(totalSupply); } /* * @dev Called indirectly by `xSNX.burn` * @dev Calculates token price on redemption, excluding value of escrowed SNX * @param totalSupply: xSNX.totalSupply() * @param snxBalanceOwned: non-escrowed SNX balance * @param contractDebtValue: sUSD debt in USD terms */ function calculateRedeemTokenPrice( uint256 totalSupply, uint256 snxBalanceOwned, uint256 contractDebtValue ) public view returns (uint256 pricePerToken) { // SNX won't actually be sold (burns are only distributed in available ETH) but // this is a proxy for the return value of SNX that would be sold uint256 weiPerOneSnx = getWeiPerOneSnxOnRedeem(); uint256 debtValueInWei = calculateDebtValueInWei(contractDebtValue); pricePerToken = calculateNetAssetValueOnRedeem( weiPerOneSnx, snxBalanceOwned, debtValueInWei ) .mul(DEC_18) .div(totalSupply); } /* ========================================================================================= */ /* Set */ /* ========================================================================================= */ /* * @dev Balance of underlying asset "active" in Set (e.g., WETH or USDC) */ function getActiveSetAssetBalance() public view returns (uint256) { return IERC20(getAssetCurrentlyActiveInSet()).balanceOf(xSNXAdminInstance); } /* * @dev Calculates quantity of Set Token equivalent to quantity of underlying asset token * @notice rebalancingSetQuantity return value is reduced slightly to ensure successful execution * @param componentQuantity: balance of underlying Set asset, e.g., WETH */ function calculateSetQuantity(uint256 componentQuantity) public view returns (uint256 rebalancingSetQuantity) { uint256 baseSetNaturalUnit = getBaseSetNaturalUnit(); uint256 baseSetComponentUnits = getBaseSetComponentUnits(); uint256 baseSetIssuable = componentQuantity.mul(baseSetNaturalUnit).div( baseSetComponentUnits ); uint256 rebalancingSetNaturalUnit = getSetNaturalUnit(); uint256 unitShares = getSetUnitShares(); rebalancingSetQuantity = baseSetIssuable .mul(rebalancingSetNaturalUnit) .div(unitShares) .mul(99) // ensure sufficient balance in underlying asset .div(100) .div(rebalancingSetNaturalUnit) .mul(rebalancingSetNaturalUnit); } /* * @dev Calculates mintable quantity of Set Token given asset holdings */ function calculateSetIssuanceQuantity() public view returns (uint256 rebalancingSetIssuable) { uint256 componentQuantity = getActiveSetAssetBalance(); rebalancingSetIssuable = calculateSetQuantity(componentQuantity); } /* * @dev Calculates Set token to sell given sUSD burn requirements * @param totalSusdToBurn: sUSD to burn to fix ratio or unlock staked SNX */ function calculateSetRedemptionQuantity(uint256 totalSusdToBurn) public view returns (uint256 rebalancingSetRedeemable) { address currentSetAsset = getAssetCurrentlyActiveInSet(); bytes32 activeAssetSynthSymbol = getActiveAssetSynthSymbol(); uint256 synthUsd = getSynthPrice(activeAssetSynthSymbol); // expectedSetAssetRate = amount of current set asset needed to redeem for 1 sUSD uint256 expectedSetAssetRate = DEC_18.mul(DEC_18).div(synthUsd); uint256 setAssetCollateralToSell = expectedSetAssetRate .mul(totalSusdToBurn) .div(DEC_18) .mul(103) // err on the high side .div(PERCENT); uint256 decimals = (TEN**ERC20Detailed(currentSetAsset).decimals()); setAssetCollateralToSell = setAssetCollateralToSell.mul(decimals).div( DEC_18 ); rebalancingSetRedeemable = calculateSetQuantity( setAssetCollateralToSell ); } /* * @dev Calculates value of a single 1e18 Set unit in ETH terms */ function calculateEthValueOfOneSetUnit() internal view returns (uint256 ethValue) { uint256 unitShares = getSetUnitShares(); uint256 rebalancingSetNaturalUnit = getSetNaturalUnit(); uint256 baseSetRequired = DEC_18.mul(unitShares).div( rebalancingSetNaturalUnit ); uint256 unitsOfUnderlying = getBaseSetComponentUnits(); uint256 baseSetNaturalUnit = getBaseSetNaturalUnit(); uint256 componentRequired = baseSetRequired.mul(unitsOfUnderlying).div( baseSetNaturalUnit ); address currentSetAsset = getAssetCurrentlyActiveInSet(); uint256 decimals = (TEN**ERC20Detailed(currentSetAsset).decimals()); componentRequired = componentRequired.mul(DEC_18).div(decimals); bytes32 activeAssetSynthSymbol = getActiveAssetSynthSymbol(); uint256 synthUsd = getSynthPrice(activeAssetSynthSymbol); uint256 ethUsd = getSynthPrice(seth); ethValue = componentRequired.mul(synthUsd).div(ethUsd); } /* * @dev Calculates value of Set Holdings in ETH terms */ function getSetHoldingsValueInWei() public view returns (uint256 setValInWei) { uint256 setCollateralTokens = getSetCollateralTokens(); bytes32 synthSymbol = getActiveAssetSynthSymbol(); address currentSetAsset = getAssetCurrentlyActiveInSet(); uint256 synthUsd = getSynthPrice(synthSymbol); uint256 ethUsd = getSynthPrice(seth); uint256 decimals = (TEN**ERC20Detailed(currentSetAsset).decimals()); setCollateralTokens = setCollateralTokens.mul(DEC_18).div(decimals); setValInWei = setCollateralTokens.mul(synthUsd).div(ethUsd); } function getBaseSetNaturalUnit() internal view returns (uint256) { return getCurrentCollateralSet().naturalUnit(); } /* * @dev Outputs current active Set asset * @notice xSNX contracts complex only compatible with Sets that hold a single asset at a time */ function getAssetCurrentlyActiveInSet() public view returns (address) { address[] memory currentAllocation = getCurrentCollateralSet() .getComponents(); return currentAllocation[0]; } function getCurrentCollateralSet() internal view returns (ISetAssetBaseCollateral) { return ISetAssetBaseCollateral(getCurrentSet()); } function getCurrentSet() internal view returns (address) { return ISetToken(setAddress).currentSet(); } /* * @dev Returns the number of underlying tokens in the current Set asset * e.g., the contract's Set holdings are collateralized by 10.4 WETH */ function getSetCollateralTokens() internal view returns (uint256) { return getSetBalanceCollateral().mul(getBaseSetComponentUnits()).div( getBaseSetNaturalUnit() ); } function getSetBalanceCollateral() internal view returns (uint256) { uint256 unitShares = getSetUnitShares(); uint256 naturalUnit = getSetNaturalUnit(); return getContractSetBalance().mul(unitShares).div(naturalUnit); } function getSetUnitShares() internal view returns (uint256) { return ISetToken(setAddress).unitShares(); } function getSetNaturalUnit() internal view returns (uint256) { return ISetToken(setAddress).naturalUnit(); } function getContractSetBalance() internal view returns (uint256) { return IERC20(setAddress).balanceOf(xSNXAdminInstance); } function getBaseSetComponentUnits() internal view returns (uint256) { return ISetAssetBaseCollateral(getCurrentSet()).getUnits()[0]; } /* ========================================================================================= */ /* Synthetix */ /* ========================================================================================= */ function getSusdBalance() public view returns (uint256) { return IERC20(susdAddress).balanceOf(xSNXAdminInstance); } function getSnxBalance() public view returns (uint256) { return getSnxBalanceOwned().add(getSnxBalanceEscrowed()); } function getSnxBalanceOwned() internal view returns (uint256) { return IERC20(addressResolver.getAddress(synthetixName)).balanceOf( xSNXAdminInstance ); } function getSnxBalanceEscrowed() internal view returns (uint256) { return IRewardEscrowV2(addressResolver.getAddress(rewardEscrowV2Name)) .balanceOf(xSNXAdminInstance); } function getContractEscrowedSnxValue() internal view returns (uint256) { return getSnxBalanceEscrowed().mul(getSnxPrice()).div(DEC_18); } function getContractOwnedSnxValue() internal view returns (uint256) { return getSnxBalanceOwned().mul(getSnxPrice()).div(DEC_18); } function getSnxPrice() internal view returns (uint256) { (uint256 rate, uint256 time) = IExchangeRates( addressResolver.getAddress(exchangeRatesName) ) .rateAndUpdatedTime(snx); require(time.add(RATE_STALE_TIME_NEW) > block.timestamp, "Rate stale"); return rate; } function getSynthPrice(bytes32 synth) internal view returns (uint256) { (uint256 rate, uint256 time) = IExchangeRates( addressResolver.getAddress(exchangeRatesName) ) .rateAndUpdatedTime(synth); if (synth != susd) { require(time.add(RATE_STALE_TIME_NEW) > block.timestamp, "Rate stale"); } return rate; } /* * @dev Converts sUSD debt value into ETH terms * @param debtValue: sUSD-denominated debt value */ function calculateDebtValueInWei(uint256 debtValue) internal view returns (uint256 debtBalanceInWei) { uint256 ethUsd = getSynthPrice(seth); debtBalanceInWei = debtValue.mul(DEC_18).div(ethUsd); } function getContractDebtValue() internal view returns (uint256) { return ISynthetix(addressResolver.getAddress(synthetixName)).debtBalanceOf( xSNXAdminInstance, susd ); } /* * @notice Returns inverse of target C-RATIO */ function getIssuanceRatio() internal view returns (uint256) { return ISystemSettings(addressResolver.getAddress(systemSettingsName)) .issuanceRatio(); } /* * @notice Returns NAV contribution of SNX holdings in USD terms */ function getContractSnxValue() internal view returns (uint256) { return getSnxBalance().mul(getSnxPrice()).div(DEC_18); } /* ========================================================================================= */ /* Burning sUSD */ /* ========================================================================================= */ /* * @dev Calculates sUSD to burn to restore C-RATIO * @param snxValueHeld: USD value of SNX * @param contractDebtValue: USD value of sUSD debt * @param issuanceRatio: Synthetix C-RATIO requirement */ function calculateSusdToBurnToFixRatio( uint256 snxValueHeld, uint256 contractDebtValue, uint256 issuanceRatio ) internal pure returns (uint256) { uint256 subtractor = issuanceRatio.mul(snxValueHeld).div(DEC_18); if (subtractor > contractDebtValue) return 0; return contractDebtValue.sub(subtractor); } /* * @dev Calculates sUSD to burn to restore C-RATIO */ function calculateSusdToBurnToFixRatioExternal() public view returns (uint256) { uint256 snxValueHeld = getContractSnxValue(); uint256 debtValue = getContractDebtValue(); uint256 issuanceRatio = getIssuanceRatio(); return calculateSusdToBurnToFixRatio( snxValueHeld, debtValue, issuanceRatio ); } /* * @dev Calculates sUSD to burn to eclipse value of escrowed SNX * @notice Synthetix system requires escrowed SNX to be "unlocked" first * @param issuanceRatio: Synthetix C-RATIO requirement */ function calculateSusdToBurnToEclipseEscrowed(uint256 issuanceRatio) public view returns (uint256) { uint256 escrowedSnxValue = getContractEscrowedSnxValue(); if (escrowedSnxValue == 0) return 0; return escrowedSnxValue.mul(issuanceRatio).div(DEC_18); } /* * @dev Helper function to calculate sUSD burn required for a potential redemption * @param tokensToRedeem: potential tokens to burn * @param totalSupply: xSNX.totalSupply() * @param contractDebtValue: sUSD debt value * @param issuanceRatio: Synthetix C-RATIO requirement */ function calculateSusdToBurnForRedemption( uint256 tokensToRedeem, uint256 totalSupply, uint256 contractDebtValue, uint256 issuanceRatio ) public view returns (uint256 susdToBurn) { uint256 nonEscrowedSnxValue = getContractOwnedSnxValue(); uint256 lockedSnxValue = contractDebtValue.mul(DEC_18).div( issuanceRatio ); uint256 valueOfSnxToSell = nonEscrowedSnxValue.mul(tokensToRedeem).div( totalSupply ); susdToBurn = ( lockedSnxValue.add(valueOfSnxToSell).sub(nonEscrowedSnxValue) ) .mul(issuanceRatio) .div(DEC_18); } /* ========================================================================================= */ /* Rebalances */ /* ========================================================================================= */ /* * @dev Helper function to facilitate xSNXAdmin.rebalanceTowardsHedge() */ function calculateAssetChangesForRebalanceToHedge() internal view returns (uint256 totalSusdToBurn, uint256 snxToSell) { uint256 snxValueHeld = getContractSnxValue(); uint256 debtValueInUsd = getContractDebtValue(); uint256 issuanceRatio = getIssuanceRatio(); uint256 susdToBurnToFixRatio = calculateSusdToBurnToFixRatio( snxValueHeld, debtValueInUsd, issuanceRatio ); uint256 susdToBurnToEclipseEscrowed = calculateSusdToBurnToEclipseEscrowed(issuanceRatio); uint256 hedgeAssetsValueInUsd = calculateHedgeAssetsValueInUsd(); uint256 valueToUnlockInUsd = debtValueInUsd.sub(hedgeAssetsValueInUsd); uint256 susdToBurnToUnlockTransfer = valueToUnlockInUsd .mul(issuanceRatio) .div(DEC_18); totalSusdToBurn = ( susdToBurnToFixRatio.add(susdToBurnToEclipseEscrowed).add( susdToBurnToUnlockTransfer ) ); snxToSell = valueToUnlockInUsd.mul(DEC_18).div(getSnxPrice()); } /* * @dev Helper function to facilitate xSNXAdmin.rebalanceTowardsSnx() */ function calculateAssetChangesForRebalanceToSnx() public view returns (uint256 setToSell) { ( uint256 debtValueInWei, uint256 hedgeAssetsBalance ) = getRebalanceUtils(); uint256 setValueToSell = hedgeAssetsBalance.sub(debtValueInWei); uint256 ethValueOfOneSet = calculateEthValueOfOneSetUnit(); setToSell = setValueToSell.mul(DEC_18).div(ethValueOfOneSet); // Set quantity must be multiple of natural unit uint256 naturalUnit = getSetNaturalUnit(); setToSell = setToSell.div(naturalUnit).mul(naturalUnit); } /* * @dev Helper function to facilitate xSNXAdmin.rebalanceTowardsSnx() */ function getRebalanceTowardsSnxUtils() public view returns (uint256 setToSell, address activeAsset) { setToSell = calculateAssetChangesForRebalanceToSnx(); activeAsset = getAssetCurrentlyActiveInSet(); } /* * @dev Helper function to facilitate xSNXAdmin.rebalanceTowardsSnx(), xSNXAdmin.rebalanceTowardsHedge() * @dev Denominated in ETH terms */ function getRebalanceUtils() public view returns (uint256 debtValueInWei, uint256 hedgeAssetsBalance) { uint256 setHoldingsInWei = getSetHoldingsValueInWei(); uint256 ethBalance = getEthBalance(); uint256 debtValue = getContractDebtValue(); debtValueInWei = calculateDebtValueInWei(debtValue); hedgeAssetsBalance = setHoldingsInWei.add(ethBalance); } /* * @dev Helper function to facilitate xSNXAdmin.rebalanceTowardsHedge() * @dev Denominated in USD terms */ function calculateHedgeAssetsValueInUsd() internal view returns (uint256 hedgeAssetsValueInUsd) { address currentSetAsset = getAssetCurrentlyActiveInSet(); uint256 decimals = (TEN**ERC20Detailed(currentSetAsset).decimals()); uint256 setCollateralTokens = getSetCollateralTokens(); setCollateralTokens = setCollateralTokens.mul(DEC_18).div(decimals); bytes32 activeAssetSynthSymbol = getActiveAssetSynthSymbol(); uint256 synthUsd = getSynthPrice(activeAssetSynthSymbol); uint256 setValueUsd = setCollateralTokens.mul(synthUsd).div(DEC_18); uint256 ethBalance = getEthBalance(); uint256 ethUsd = getSynthPrice(seth); uint256 ethValueUsd = ethBalance.mul(ethUsd).div(DEC_18); hedgeAssetsValueInUsd = setValueUsd.add(ethValueUsd); } /* * @dev Helper function to determine whether xSNXAdmin.rebalanceTowardsSnx() is required */ function isRebalanceTowardsSnxRequired() public view returns (bool) { ( uint256 debtValueInWei, uint256 hedgeAssetsBalance ) = getRebalanceUtils(); if ( debtValueInWei.mul(REBALANCE_THRESHOLD).div(PERCENT) < hedgeAssetsBalance ) { return true; } return false; } /* * @dev Helper function to determine whether xSNXAdmin.rebalanceTowardsHedge() is required */ function isRebalanceTowardsHedgeRequired() public view returns (bool) { ( uint256 debtValueInWei, uint256 hedgeAssetsBalance ) = getRebalanceUtils(); if ( hedgeAssetsBalance.mul(REBALANCE_THRESHOLD).div(PERCENT) < debtValueInWei ) { return true; } return false; } /* * @dev Helper function to facilitate xSNXAdmin.rebalanceTowardsHedge() * @notice Will fail if !isRebalanceTowardsHedgeRequired() */ function getRebalanceTowardsHedgeUtils() public view returns ( uint256, uint256, address ) { ( uint256 totalSusdToBurn, uint256 snxToSell ) = calculateAssetChangesForRebalanceToHedge(); address activeAsset = getAssetCurrentlyActiveInSet(); return (totalSusdToBurn, snxToSell, activeAsset); } /* * @dev Helper for `hedge` function * @dev Determines share of sUSD to allocate to ETH * @dev Implicitly determines Set allocation as well * @param susdBal: sUSD balance post minting */ function getEthAllocationOnHedge(uint256 susdBal) public view returns (uint256 ethAllocation) { uint256 ethUsd = getSynthPrice(seth); uint256 setHoldingsInUsd = getSetHoldingsValueInWei().mul(ethUsd).div( DEC_18 ); uint256 ethBalInUsd = getEthBalance().mul(ethUsd).div(DEC_18); uint256 hedgeAssets = setHoldingsInUsd.add(ethBalInUsd); if (ethBalInUsd.mul(ETH_TARGET) >= hedgeAssets.add(susdBal)) { // full bal directed toward Set // eth allocation is 0 } else if ((ethBalInUsd.add(susdBal)).mul(ETH_TARGET) < hedgeAssets) { // full bal directed toward Eth ethAllocation = susdBal; } else { // fractionate allocation ethAllocation = ((hedgeAssets.add(susdBal)).div(ETH_TARGET)).sub( ethBalInUsd ); } } /* * @dev Helper function to facilitate xSNXAdmin.rebalanceSetToEth() */ function calculateSetToSellForRebalanceSetToEth() public view returns (uint256 setQuantityToSell) { uint256 setHoldingsInWei = getSetHoldingsValueInWei(); uint256 ethBal = getEthBalance(); uint256 hedgeAssets = setHoldingsInWei.add(ethBal); require( ethBal.mul(ETH_TARGET) < hedgeAssets, "Rebalance not necessary" ); uint256 ethToAdd = ((hedgeAssets.div(ETH_TARGET)).sub(ethBal)); setQuantityToSell = getContractSetBalance().mul(ethToAdd).div( setHoldingsInWei ); uint256 naturalUnit = getSetNaturalUnit(); setQuantityToSell = setQuantityToSell.div(naturalUnit).mul(naturalUnit); } /* ========================================================================================= */ /* Address Setters */ /* ========================================================================================= */ function setAdminInstanceAddress(address _xSNXAdminInstance) public onlyOwner { if (xSNXAdminInstance == address(0)) { xSNXAdminInstance = _xSNXAdminInstance; } } function setCurve( address curvePoolAddress, int128 _usdcIndex, int128 _susdIndex ) public onlyOwner { if (address(curveFi) == address(0)) { // if initial set on deployment, immediately activate Curve address curveFi = ICurveFi(curvePoolAddress); nextCurveAddress = curvePoolAddress; } else { // if updating Curve address (i.e., not initial setting of address on deployment), // store nextCurveAddress but don't activate until addressValidator has confirmed nextCurveAddress = curvePoolAddress; } usdcIndex = _usdcIndex; susdIndex = _susdIndex; } /* ========================================================================================= */ /* Utils */ /* ========================================================================================= */ // admin on deployment approve [snx, susd, setComponentA, setComponentB] function approveKyber(address tokenAddress) public onlyOwner { IERC20(tokenAddress).approve(address(kyberNetworkProxy), MAX_UINT); } // admin on deployment approve [susd, usdc] function approveCurve(address tokenAddress) public onlyOwner { IERC20(tokenAddress).approve(address(curveFi), MAX_UINT); } function confirmCurveAddress(address _nextCurveAddress) public { require(msg.sender == addressValidator, "Incorrect caller"); require(nextCurveAddress == _nextCurveAddress, "Addresses don't match"); curveFi = ICurveFi(nextCurveAddress); } function() external payable {} } // File: contracts/helpers/Pausable.sol pragma solidity ^0.5.15; /* Adapted from OpenZeppelin */ contract Pausable is Initializable { /** * @dev Emitted when the pause is triggered by a pauser. */ event Paused(); /** * @dev Emitted when the pause is lifted by a pauser. */ event Unpaused(); bool private _paused; address public pauser; /** * @dev Initializes the contract in unpaused state. Assigns the Pauser role * to the deployer. */ constructor () internal { _paused = false; pauser = msg.sender; } /** * @dev Initializes the contract in unpaused state. Assigns the Pauser role * to the deployer. This function is called when the contract is used in a upgradeable context. */ function initialize(address sender) public initializer { _paused = false; pauser = sender; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPaused() { require(!_paused, "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. */ modifier whenPaused() { require(_paused, "Pausable: not paused"); _; } /** * @dev Called by a pauser to pause, triggers stopped state. */ function pause() public onlyPauser whenNotPaused { _paused = true; emit Paused(); } /** * @dev Called by a pauser to unpause, returns to normal state. */ function unpause() public onlyPauser whenPaused { _paused = false; emit Unpaused(); } modifier onlyPauser { require(msg.sender == pauser, "Don't have rights"); _; } } // File: contracts/interface/IxSNXAdmin.sol pragma solidity 0.5.15; contract IxSNXAdmin { function sendEthOnRedemption(uint valueToRedeem) external; } // File: contracts/xSNX.sol pragma solidity 0.5.15; contract xSNX is ERC20, ERC20Detailed, Pausable, Ownable { TradeAccounting private tradeAccounting; IKyberNetworkProxy private kyberNetworkProxy; address xsnxAdmin; address snxAddress; address susdAddress; uint256 public withdrawableEthFees; function initialize( address payable _tradeAccountingAddress, address _kyberProxyAddress, address _snxAddress, address _susdAddress, address _xsnxAdmin, address _ownerAddress, uint256 _mintFeeDivisor, uint256 _burnFeeDivisor, uint256 _claimFeeDivisor, uint256 _initialMint ) public initializer { Ownable.initialize(_ownerAddress); ERC20Detailed.initialize("xSNX", "xSNXa", 18); Pausable.initialize(_ownerAddress); tradeAccounting = TradeAccounting(_tradeAccountingAddress); kyberNetworkProxy = IKyberNetworkProxy(_kyberProxyAddress); snxAddress = _snxAddress; susdAddress = _susdAddress; xsnxAdmin = _xsnxAdmin; _setFeeDivisors(_mintFeeDivisor, _burnFeeDivisor, _claimFeeDivisor); _mint(msg.sender, _initialMint); } event Mint( address indexed user, uint256 timestamp, uint256 valueSent, uint256 mintAmount, bool mintWithEth ); event Burn( address indexed user, uint256 timestamp, uint256 burnAmount, uint256 valueToSend ); event WithdrawFees( uint256 ethAmount, uint256 susdAmount, uint256 snxAmount ); struct FeeDivisors { uint256 mintFee; uint256 burnFee; uint256 claimFee; } FeeDivisors public feeDivisors; // addresses are locked from transfer after minting or burning uint256 private constant BLOCK_LOCK_COUNT = 6; // last block for which this address is timelocked mapping(address => uint256) public lastLockedBlock; /* * @notice Mint new xSNX tokens from the contract by sending ETH * @dev Exchanges ETH for SNX * @dev Min rate ETH/SNX sourced from Kyber in JS * @dev: Calculates overall fund NAV in ETH terms, using ETH/SNX implicit conversion rate * or ETH/SNX price (via SNX oracle) in case of allocateToEth * @dev: Mints/distributes new xSNX tokens based on contribution to NAV * @param: minRate: kyberProxy.getExpectedRate eth=>snx */ function mint(uint256 minRate) external payable whenNotPaused notLocked(msg.sender) { require(msg.value > 0, "Must send ETH"); lock(msg.sender); uint256 fee = calculateFee(msg.value, feeDivisors.mintFee); uint256 ethContribution = msg.value.sub(fee); uint256 snxBalanceBefore = tradeAccounting.getSnxBalance(); uint256 totalSupply = totalSupply(); (bool allocateToEth, uint256 nonSnxAssetValue) = tradeAccounting .getMintWithEthUtils(totalSupply); if (!allocateToEth) { uint256 snxAcquired = kyberNetworkProxy.swapEtherToToken.value( ethContribution )(ERC20(snxAddress), minRate); require( IERC20(snxAddress).transfer(xsnxAdmin, snxAcquired), "Transfer failed" ); } else { (bool success, ) = xsnxAdmin.call.value(ethContribution)(""); require(success, "Transfer failed"); } uint256 mintAmount = tradeAccounting.calculateTokensToMintWithEth( snxBalanceBefore, ethContribution, nonSnxAssetValue, totalSupply ); emit Mint(msg.sender, block.timestamp, msg.value, mintAmount, true); return super._mint(msg.sender, mintAmount); } /* * @notice Mint new xSNX tokens from the contract by sending SNX * @notice Won't run without ERC20 approval * @dev: Calculates overall fund NAV in ETH terms, using ETH/SNX price (via SNX oracle) * @dev: Mints/distributes new xSNX tokens based on contribution to NAV * @param: snxAmount: SNX to contribute */ function mintWithSnx(uint256 snxAmount) external whenNotPaused notLocked(msg.sender) { require(snxAmount > 0, "Must send SNX"); lock(msg.sender); uint256 snxBalanceBefore = tradeAccounting.getSnxBalance(); uint256 fee = calculateFee(snxAmount, feeDivisors.mintFee); uint256 snxContribution = snxAmount.sub(fee); require( IERC20(snxAddress).transferFrom(msg.sender, address(this), fee), "Transfer failed" ); require( IERC20(snxAddress).transferFrom( msg.sender, xsnxAdmin, snxContribution ), "Transfer failed" ); uint256 mintAmount = tradeAccounting.calculateTokensToMintWithSnx( snxBalanceBefore, snxContribution, totalSupply() ); emit Mint( msg.sender, block.timestamp, snxContribution, mintAmount, false ); return super._mint(msg.sender, mintAmount); } /* * @notice Redeems and burns xSNX tokens and sends ETH to user * @dev Checks if ETH reserve is sufficient to settle redeem obligation * @dev Will only redeem if ETH reserve is sufficient * @param tokensToRedeem */ function burn(uint256 tokensToRedeem) external notLocked(msg.sender) { require(tokensToRedeem > 0, "Must burn tokens"); lock(msg.sender); uint256 valueToRedeem = tradeAccounting.calculateRedemptionValue( totalSupply(), tokensToRedeem ); require( tradeAccounting.getEthBalance() >= valueToRedeem, "Redeem amount exceeds available liquidity" ); IxSNXAdmin(xsnxAdmin).sendEthOnRedemption(valueToRedeem); uint256 valueToSend = valueToRedeem.sub( calculateFee(valueToRedeem, feeDivisors.burnFee) ); super._burn(msg.sender, tokensToRedeem); emit Burn(msg.sender, block.timestamp, tokensToRedeem, valueToSend); (bool success, ) = msg.sender.call.value(valueToSend)(""); require(success, "Burn transfer failed"); } function transfer(address recipient, uint256 amount) public notLocked(msg.sender) returns (bool) { return super.transfer(recipient, amount); } function transferFrom( address sender, address recipient, uint256 amount ) public notLocked(sender) returns (bool) { return super.transferFrom(sender, recipient, amount); } function calculateFee(uint256 _value, uint256 _feeDivisor) internal pure returns (uint256 fee) { if (_feeDivisor > 0) { fee = _value.div(_feeDivisor); } } /* * @notice Inverse of fee i.e., a fee divisor of 100 == 1% * @notice Three fee types * @dev Mint fee 0 or <= 2% * @dev Burn fee 0 or <= 1% * @dev Claim fee 0 <= 4% */ function setFeeDivisors( uint256 mintFeeDivisor, uint256 burnFeeDivisor, uint256 claimFeeDivisor ) public onlyOwner { _setFeeDivisors(mintFeeDivisor, burnFeeDivisor, claimFeeDivisor); } function _setFeeDivisors( uint256 _mintFeeDivisor, uint256 _burnFeeDivisor, uint256 _claimFeeDivisor ) private { require(_mintFeeDivisor == 0 || _mintFeeDivisor >= 50, "Invalid fee"); require(_burnFeeDivisor == 0 || _burnFeeDivisor >= 100, "Invalid fee"); require(_claimFeeDivisor >= 25, "Invalid fee"); feeDivisors.mintFee = _mintFeeDivisor; feeDivisors.burnFee = _burnFeeDivisor; feeDivisors.claimFee = _claimFeeDivisor; } /* * @notice Withdraws ETH, sUSD and SNX fees to owner address */ function withdrawFees() public onlyOwner { uint256 ethFeesToWithdraw = address(this).balance; uint256 susdFeesToWithdraw = IERC20(susdAddress).balanceOf( address(this) ); uint256 snxFeesToWithdraw = IERC20(snxAddress).balanceOf(address(this)); (bool success, ) = msg.sender.call.value(ethFeesToWithdraw)(""); require(success, "Transfer failed"); IERC20(susdAddress).transfer(msg.sender, susdFeesToWithdraw); IERC20(snxAddress).transfer(msg.sender, snxFeesToWithdraw); emit WithdrawFees( ethFeesToWithdraw, susdFeesToWithdraw, snxFeesToWithdraw ); } /* * @notice Emergency function in case of errant transfer of * xSNX token directly to contract */ function withdrawNativeToken() public onlyOwner { uint256 tokenBal = balanceOf(address(this)); if (tokenBal > 0) { IERC20(address(this)).transfer(msg.sender, tokenBal); } } /* * @dev Helper function for xSNXAdmin to calculate and * transfer claim fees */ function getClaimFeeDivisor() public view returns (uint256) { return feeDivisors.claimFee; } /** * BlockLock logic: Implements locking of mint, burn, transfer and transferFrom * functions via a notLocked modifier. * Functions are locked per address. */ modifier notLocked(address lockedAddress) { require( lastLockedBlock[lockedAddress] <= block.number, "Function is temporarily locked for this address" ); _; } /** * @dev Lock mint, burn, transfer and transferFrom functions * for _address for BLOCK_LOCK_COUNT blocks */ function lock(address _address) private { lastLockedBlock[_address] = block.number + BLOCK_LOCK_COUNT; } function() external payable { require(msg.sender == xsnxAdmin, "Invalid send"); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"burnAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"valueToSend","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"valueSent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"mintWithEth","type":"bool"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"ethAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"susdAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"snxAmount","type":"uint256"}],"name":"WithdrawFees","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"uint256","name":"tokensToRedeem","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"feeDivisors","outputs":[{"internalType":"uint256","name":"mintFee","type":"uint256"},{"internalType":"uint256","name":"burnFee","type":"uint256"},{"internalType":"uint256","name":"claimFee","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getClaimFeeDivisor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"_tradeAccountingAddress","type":"address"},{"internalType":"address","name":"_kyberProxyAddress","type":"address"},{"internalType":"address","name":"_snxAddress","type":"address"},{"internalType":"address","name":"_susdAddress","type":"address"},{"internalType":"address","name":"_xsnxAdmin","type":"address"},{"internalType":"address","name":"_ownerAddress","type":"address"},{"internalType":"uint256","name":"_mintFeeDivisor","type":"uint256"},{"internalType":"uint256","name":"_burnFeeDivisor","type":"uint256"},{"internalType":"uint256","name":"_claimFeeDivisor","type":"uint256"},{"internalType":"uint256","name":"_initialMint","type":"uint256"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastLockedBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"minRate","type":"uint256"}],"name":"mint","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"snxAmount","type":"uint256"}],"name":"mintWithSnx","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pauser","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"mintFeeDivisor","type":"uint256"},{"internalType":"uint256","name":"burnFeeDivisor","type":"uint256"},{"internalType":"uint256","name":"claimFeeDivisor","type":"uint256"}],"name":"setFeeDivisors","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"withdrawFees","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"withdrawNativeToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"withdrawableEthFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]
Contract Creation Code
6080604052609d80546001600160a81b03191661010033021790556130f4806100296000396000f3fe6080604052600436106101e35760003560e01c8063715018a611610102578063a457c2d711610095578063e7654b3c11610064578063e7654b3c1461053f578063f00703331461055f578063f09ddae71461057f578063f2fde38b14610594576101e3565b8063a457c2d7146104bf578063a9059cbb146104df578063c4d66de8146104ff578063dd62ed3e1461051f576101e3565b806395d89b41116100d157806395d89b41146104625780639f3e8b34146104775780639fd0506d14610497578063a0712d68146104ac576101e3565b8063715018a6146104015780638456cb59146104165780638da5cb5b1461042b5780638f32d59b1461044d576101e3565b80633986de6a1161017a5780635a18664c116101495780635a18664c146103935780635c975abb146103a8578063629c577e146103bd57806370a08231146103e1576101e3565b80633986de6a146103295780633f4ba83a1461034957806342966c681461035e578063476343ee1461037e576101e3565b80631838d85c116101b65780631838d85c146102b257806323b872dd146102c7578063313ce567146102e75780633950935114610309576101e3565b806306fdde0314610218578063095ea7b3146102435780631624f6c61461027057806318160ddd14610290575b60d3546001600160a01b031633146102165760405162461bcd60e51b815260040161020d90612d27565b60405180910390fd5b005b34801561022457600080fd5b5061022d6105b4565b60405161023a9190612cf6565b60405180910390f35b34801561024f57600080fd5b5061026361025e36600461257f565b61064b565b60405161023a9190612cda565b34801561027c57600080fd5b5061021661028b3660046125fd565b610669565b34801561029c57600080fd5b506102a5610726565b60405161023a9190612e67565b3480156102be57600080fd5b506102a561072c565b3480156102d357600080fd5b506102636102e2366004612532565b610732565b3480156102f357600080fd5b506102fc610780565b60405161023a9190612f08565b34801561031557600080fd5b5061026361032436600461257f565b610789565b34801561033557600080fd5b5061021661034436600461241f565b6107e2565b34801561035557600080fd5b50610216610931565b34801561036a57600080fd5b5061021661037936600461266f565b6109b7565b34801561038a57600080fd5b50610216610c97565b34801561039f57600080fd5b50610216610f8f565b3480156103b457600080fd5b50610263611042565b3480156103c957600080fd5b506103d261104b565b60405161023a93929190612e83565b3480156103ed57600080fd5b506102a56103fc366004612401565b611057565b34801561040d57600080fd5b50610216611072565b34801561042257600080fd5b506102166110e0565b34801561043757600080fd5b5061044061116a565b60405161023a9190612c52565b34801561045957600080fd5b50610263611179565b34801561046e57600080fd5b5061022d61119f565b34801561048357600080fd5b506102a5610492366004612401565b611200565b3480156104a357600080fd5b50610440611212565b6102166104ba36600461266f565b611226565b3480156104cb57600080fd5b506102636104da36600461257f565b61168b565b3480156104eb57600080fd5b506102636104fa36600461257f565b6116f9565b34801561050b57600080fd5b5061021661051a366004612401565b61173d565b34801561052b57600080fd5b506102a561053a3660046124f8565b61180f565b34801561054b57600080fd5b5061021661055a3660046126ab565b61183a565b34801561056b57600080fd5b5061021661057a36600461266f565b61186e565b34801561058b57600080fd5b506102a5611bbf565b3480156105a057600080fd5b506102166105af366004612401565b611bc5565b60688054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156106405780601f1061061557610100808354040283529160200191610640565b820191906000526020600020905b81548152906001019060200180831161062357829003601f168201915b505050505090505b90565b600061065f610658611bf2565b8484611bf6565b5060015b92915050565b600054610100900460ff16806106825750610682611caa565b80610690575060005460ff16155b6106ac5760405162461bcd60e51b815260040161020d90612dd7565b600054610100900460ff161580156106d7576000805460ff1961ff0019909116610100171660011790555b83516106ea9060689060208701906122de565b5082516106fe9060699060208601906122de565b50606a805460ff191660ff84161790558015610720576000805461ff00191690555b50505050565b60355490565b60d65481565b6001600160a01b038316600090815260da6020526040812054849043101561076c5760405162461bcd60e51b815260040161020d90612da7565b610777858585611cb0565b95945050505050565b606a5460ff1690565b600061065f610796611bf2565b846107dd85603460006107a7611bf2565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff611d3916565b611bf6565b600054610100900460ff16806107fb57506107fb611caa565b80610809575060005460ff16155b6108255760405162461bcd60e51b815260040161020d90612dd7565b600054610100900460ff16158015610850576000805460ff1961ff0019909116610100171660011790555b6108598661173d565b61089e604051806040016040528060048152602001630f0a69cb60e31b8152506040518060400160405280600581526020016478534e586160d81b8152506012610669565b6108a786611d5e565b60d180546001600160a01b03199081166001600160a01b038e81169190911790925560d2805482168d841617905560d4805482168c841617905560d5805482168b841617905560d38054909116918916919091179055610908858585611e00565b6109123383611e83565b8015610924576000805461ff00191690555b5050505050505050505050565b609d5461010090046001600160a01b031633146109605760405162461bcd60e51b815260040161020d90612d77565b609d5460ff166109825760405162461bcd60e51b815260040161020d90612d17565b609d805460ff191690556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d1693390600090a1565b33600081815260da60205260409020544310156109e65760405162461bcd60e51b815260040161020d90612da7565b60008211610a065760405162461bcd60e51b815260040161020d90612e27565b610a0f33611f43565b60d1546000906001600160a01b03166318d814ba610a2b610726565b856040518363ffffffff1660e01b8152600401610a49929190612e75565b60206040518083038186803b158015610a6157600080fd5b505afa158015610a75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a99919081019061268d565b90508060d160009054906101000a90046001600160a01b03166001600160a01b03166370ed0ada6040518163ffffffff1660e01b815260040160206040518083038186803b158015610aea57600080fd5b505afa158015610afe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b22919081019061268d565b1015610b405760405162461bcd60e51b815260040161020d90612e47565b60d35460405163a965072760e01b81526001600160a01b039091169063a965072790610b70908490600401612e67565b600060405180830381600087803b158015610b8a57600080fd5b505af1158015610b9e573d6000803e3d6000fd5b505050506000610bc3610bb68360d760010154611f62565b839063ffffffff611f7a16565b9050610bcf3385611fbc565b336001600160a01b03167f743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644428684604051610c0c93929190612e83565b60405180910390a26000336001600160a01b031682604051610c2d90612c47565b60006040518083038185875af1925050503d8060008114610c6a576040519150601f19603f3d011682016040523d82523d6000602084013e610c6f565b606091505b5050905080610c905760405162461bcd60e51b815260040161020d90612d87565b5050505050565b610c9f611179565b610cbb5760405162461bcd60e51b815260040161020d90612dc7565b60d5546040516370a0823160e01b815247916000916001600160a01b03909116906370a0823190610cf0903090600401612c60565b60206040518083038186803b158015610d0857600080fd5b505afa158015610d1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d40919081019061268d565b60d4546040516370a0823160e01b81529192506000916001600160a01b03909116906370a0823190610d76903090600401612c60565b60206040518083038186803b158015610d8e57600080fd5b505afa158015610da2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610dc6919081019061268d565b90506000336001600160a01b031684604051610de190612c47565b60006040518083038185875af1925050503d8060008114610e1e576040519150601f19603f3d011682016040523d82523d6000602084013e610e23565b606091505b5050905080610e445760405162461bcd60e51b815260040161020d90612d57565b60d55460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90610e769033908790600401612cb1565b602060405180830381600087803b158015610e9057600080fd5b505af1158015610ea4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ec891908101906125af565b5060d45460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90610efb9033908690600401612cb1565b602060405180830381600087803b158015610f1557600080fd5b505af1158015610f29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610f4d91908101906125af565b507fa80975b2ffacb3d3f1fcfd13863288991d27ae8e617c147e7c83d240b82bd1f6848484604051610f8193929190612e83565b60405180910390a150505050565b610f97611179565b610fb35760405162461bcd60e51b815260040161020d90612dc7565b6000610fbe30611057565b9050801561103f5760405163a9059cbb60e01b8152309063a9059cbb90610feb9033908590600401612cb1565b602060405180830381600087803b15801561100557600080fd5b505af1158015611019573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061103d91908101906125af565b505b50565b609d5460ff1690565b60d75460d85460d95483565b6001600160a01b031660009081526033602052604090205490565b61107a611179565b6110965760405162461bcd60e51b815260040161020d90612dc7565b609e546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3609e80546001600160a01b0319169055565b609d5461010090046001600160a01b0316331461110f5760405162461bcd60e51b815260040161020d90612d77565b609d5460ff16156111325760405162461bcd60e51b815260040161020d90612d97565b609d805460ff191660011790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e75290600090a1565b609e546001600160a01b031690565b609e546000906001600160a01b0316611190611bf2565b6001600160a01b031614905090565b60698054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156106405780601f1061061557610100808354040283529160200191610640565b60da6020526000908152604090205481565b609d5461010090046001600160a01b031681565b609d5460ff16156112495760405162461bcd60e51b815260040161020d90612d97565b33600081815260da60205260409020544310156112785760405162461bcd60e51b815260040161020d90612da7565b600034116112985760405162461bcd60e51b815260040161020d90612e37565b6112a133611f43565b60006112b23460d760000154611f62565b905060006112c6348363ffffffff611f7a16565b9050600060d160009054906101000a90046001600160a01b03166001600160a01b03166389afb5b76040518163ffffffff1660e01b815260040160206040518083038186803b15801561131857600080fd5b505afa15801561132c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611350919081019061268d565b9050600061135c610726565b60d154604051634ebb2f5360e11b815291925060009182916001600160a01b031690639d765ea690611392908690600401612e67565b604080518083038186803b1580156113a957600080fd5b505afa1580156113bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113e191908101906125cd565b91509150816115225760d25460d454604051633d15022b60e11b81526000926001600160a01b0390811692637a2a0456928a926114249216908e90600401612ce8565b6020604051808303818588803b15801561143d57600080fd5b505af1158015611451573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250611476919081019061268d565b60d45460d35460405163a9059cbb60e01b81529293506001600160a01b039182169263a9059cbb926114ae9216908590600401612ccc565b602060405180830381600087803b1580156114c857600080fd5b505af11580156114dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061150091908101906125af565b61151c5760405162461bcd60e51b815260040161020d90612d57565b506115a5565b60d3546040516000916001600160a01b031690879061154090612c47565b60006040518083038185875af1925050503d806000811461157d576040519150601f19603f3d011682016040523d82523d6000602084013e611582565b606091505b50509050806115a35760405162461bcd60e51b815260040161020d90612d57565b505b60d154604051630748416d60e41b81526000916001600160a01b03169063748416d0906115dc9088908a9087908a90600401612ed3565b60206040518083038186803b1580156115f457600080fd5b505afa158015611608573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061162c919081019061268d565b9050336001600160a01b03167f5b5de75983fe8891c65234472ee1805018163815d4c146f10bf176b736093c09423484600160405161166e9493929190612e9e565b60405180910390a26116803382611e83565b505050505050505050565b600061065f611698611bf2565b846107dd8560405180606001604052806025815260200161308d60259139603460006116c2611bf2565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff61209216565b33600081815260da602052604081205490919043101561172b5760405162461bcd60e51b815260040161020d90612da7565b61173584846120be565b949350505050565b600054610100900460ff16806117565750611756611caa565b80611764575060005460ff16155b6117805760405162461bcd60e51b815260040161020d90612dd7565b600054610100900460ff161580156117ab576000805460ff1961ff0019909116610100171660011790555b609e80546001600160a01b0319166001600160a01b0384811691909117918290556040519116906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3801561103d576000805461ff00191690555050565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b611842611179565b61185e5760405162461bcd60e51b815260040161020d90612dc7565b611869838383611e00565b505050565b609d5460ff16156118915760405162461bcd60e51b815260040161020d90612d97565b33600081815260da60205260409020544310156118c05760405162461bcd60e51b815260040161020d90612da7565b600082116118e05760405162461bcd60e51b815260040161020d90612e07565b6118e933611f43565b60d154604080516389afb5b760e01b815290516000926001600160a01b0316916389afb5b7916004808301926020929190829003018186803b15801561192e57600080fd5b505afa158015611942573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611966919081019061268d565b905060006119798460d760000154611f62565b9050600061198d858363ffffffff611f7a16565b60d4546040516323b872dd60e01b81529192506001600160a01b0316906323b872dd906119c290339030908790600401612c6e565b602060405180830381600087803b1580156119dc57600080fd5b505af11580156119f0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a1491908101906125af565b611a305760405162461bcd60e51b815260040161020d90612d57565b60d45460d3546040516323b872dd60e01b81526001600160a01b03928316926323b872dd92611a69923392909116908690600401612c96565b602060405180830381600087803b158015611a8357600080fd5b505af1158015611a97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611abb91908101906125af565b611ad75760405162461bcd60e51b815260040161020d90612d57565b60d1546000906001600160a01b0316632bdbe2198584611af5610726565b6040518463ffffffff1660e01b8152600401611b1393929190612e83565b60206040518083038186803b158015611b2b57600080fd5b505afa158015611b3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b63919081019061268d565b9050336001600160a01b03167f5b5de75983fe8891c65234472ee1805018163815d4c146f10bf176b736093c094284846000604051611ba59493929190612e9e565b60405180910390a2611bb73382611e83565b505050505050565b60d95490565b611bcd611179565b611be95760405162461bcd60e51b815260040161020d90612dc7565b61103f816120d2565b3390565b6001600160a01b038316611c1c5760405162461bcd60e51b815260040161020d90612e17565b6001600160a01b038216611c425760405162461bcd60e51b815260040161020d90612d47565b6001600160a01b0380841660008181526034602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590611c9d908590612e67565b60405180910390a3505050565b303b1590565b6000611cbd848484612154565b611d2e84611cc9611bf2565b6107dd85604051806060016040528060288152602001613065602891396001600160a01b038a16600090815260346020526040812090611d07611bf2565b6001600160a01b03168152602081019190915260400160002054919063ffffffff61209216565b5060015b9392505050565b600082820183811015611d325760405162461bcd60e51b815260040161020d90612d67565b600054610100900460ff1680611d775750611d77611caa565b80611d85575060005460ff16155b611da15760405162461bcd60e51b815260040161020d90612dd7565b600054610100900460ff16158015611dcc576000805460ff1961ff0019909116610100171660011790555b609d80546001600160a81b0319166101006001600160a01b03851602179055801561103d576000805461ff00191690555050565b821580611e0e575060328310155b611e2a5760405162461bcd60e51b815260040161020d90612db7565b811580611e38575060648210155b611e545760405162461bcd60e51b815260040161020d90612db7565b6019811015611e755760405162461bcd60e51b815260040161020d90612db7565b60d79290925560d85560d955565b6001600160a01b038216611ea95760405162461bcd60e51b815260040161020d90612e57565b603554611ebc908263ffffffff611d3916565b6035556001600160a01b038216600090815260336020526040902054611ee8908263ffffffff611d3916565b6001600160a01b0383166000818152603360205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611f37908590612e67565b60405180910390a35050565b6001600160a01b0316600090815260da60205260409020436006019055565b6000811561066357611d32838363ffffffff61226a16565b6000611d3283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612092565b6001600160a01b038216611fe25760405162461bcd60e51b815260040161020d90612de7565b6120258160405180606001604052806022815260200161301d602291396001600160a01b038516600090815260336020526040902054919063ffffffff61209216565b6001600160a01b038316600090815260336020526040902055603554612051908263ffffffff611f7a16565b6035556040516000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611f37908590612e67565b600081848411156120b65760405162461bcd60e51b815260040161020d9190612cf6565b505050900390565b600061065f6120cb611bf2565b8484612154565b6001600160a01b0381166120f85760405162461bcd60e51b815260040161020d90612d37565b609e546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3609e80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03831661217a5760405162461bcd60e51b815260040161020d90612df7565b6001600160a01b0382166121a05760405162461bcd60e51b815260040161020d90612d07565b6121e38160405180606001604052806026815260200161303f602691396001600160a01b038616600090815260336020526040902054919063ffffffff61209216565b6001600160a01b038085166000908152603360205260408082209390935590841681522054612218908263ffffffff611d3916565b6001600160a01b0380841660008181526033602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611c9d908590612e67565b6000611d3283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250600081836122c85760405162461bcd60e51b815260040161020d9190612cf6565b5060008385816122d457fe5b0495945050505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061231f57805160ff191683800117855561234c565b8280016001018555821561234c579182015b8281111561234c578251825591602001919060010190612331565b5061235892915061235c565b5090565b61064891905b808211156123585760008155600101612362565b803561066381612fed565b805161066381613001565b600082601f83011261239d57600080fd5b81356123b06123ab82612f3d565b612f16565b915080825260208301602083018583830111156123cc57600080fd5b6123d7838284612fab565b50505092915050565b80356106638161300a565b80516106638161300a565b803561066381613013565b60006020828403121561241357600080fd5b60006117358484612376565b6000806000806000806000806000806101408b8d03121561243f57600080fd5b600061244b8d8d612376565b9a5050602061245c8d828e01612376565b995050604061246d8d828e01612376565b985050606061247e8d828e01612376565b975050608061248f8d828e01612376565b96505060a06124a08d828e01612376565b95505060c06124b18d828e016123e0565b94505060e06124c28d828e016123e0565b9350506101006124d48d828e016123e0565b9250506101206124e68d828e016123e0565b9150509295989b9194979a5092959850565b6000806040838503121561250b57600080fd5b60006125178585612376565b925050602061252885828601612376565b9150509250929050565b60008060006060848603121561254757600080fd5b60006125538686612376565b935050602061256486828701612376565b9250506040612575868287016123e0565b9150509250925092565b6000806040838503121561259257600080fd5b600061259e8585612376565b9250506020612528858286016123e0565b6000602082840312156125c157600080fd5b60006117358484612381565b600080604083850312156125e057600080fd5b60006125ec8585612381565b9250506020612528858286016123eb565b60008060006060848603121561261257600080fd5b833567ffffffffffffffff81111561262957600080fd5b6126358682870161238c565b935050602084013567ffffffffffffffff81111561265257600080fd5b61265e8682870161238c565b9250506040612575868287016123f6565b60006020828403121561268157600080fd5b600061173584846123e0565b60006020828403121561269f57600080fd5b600061173584846123eb565b6000806000606084860312156126c057600080fd5b60006126cc86866123e0565b9350506020612564868287016123e0565b6126e681612f99565b82525050565b6126e681612f77565b6126e681612f82565b6126e681612fa0565b600061271282612f65565b61271c8185612f6e565b935061272c818560208601612fb7565b61273581612fe3565b9093019392505050565b600061274c602383612f6e565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647281526265737360e81b602082015260400192915050565b6000612791601483612f6e565b7314185d5cd8589b194e881b9bdd081c185d5cd95960621b815260200192915050565b60006127c1600c83612f6e565b6b125b9d985b1a59081cd95b9960a21b815260200192915050565b60006127e9602683612f6e565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000612831602283612f6e565b7f45524332303a20617070726f766520746f20746865207a65726f206164647265815261737360f01b602082015260400192915050565b6000612875600f83612f6e565b6e151c985b9cd9995c8819985a5b1959608a1b815260200192915050565b60006128a0601b83612f6e565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b60006128d9601183612f6e565b70446f6e277420686176652072696768747360781b815260200192915050565b6000612906601483612f6e565b73109d5c9b881d1c985b9cd9995c8819985a5b195960621b815260200192915050565b6000612936601083612f6e565b6f14185d5cd8589b194e881c185d5cd95960821b815260200192915050565b6000612962602f83612f6e565b7f46756e6374696f6e2069732074656d706f726172696c79206c6f636b6564206681526e6f722074686973206164647265737360881b602082015260400192915050565b60006129b3600b83612f6e565b6a496e76616c69642066656560a81b815260200192915050565b60006129da602083612f6e565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572815260200192915050565b6000612a13602e83612f6e565b7f436f6e747261637420696e7374616e63652068617320616c726561647920626581526d195b881a5b9a5d1a585b1a5e995960921b602082015260400192915050565b6000612a63602183612f6e565b7f45524332303a206275726e2066726f6d20746865207a65726f206164647265738152607360f81b602082015260400192915050565b6000612aa6602583612f6e565b7f45524332303a207472616e736665722066726f6d20746865207a65726f206164815264647265737360d81b602082015260400192915050565b6000612aed600d83612f6e565b6c09aeae6e840e6cadcc840a69cb609b1b815260200192915050565b6000610663600083612f69565b6000612b23602483612f6e565b7f45524332303a20617070726f76652066726f6d20746865207a65726f206164648152637265737360e01b602082015260400192915050565b6000612b69601083612f6e565b6f4d757374206275726e20746f6b656e7360801b815260200192915050565b6000612b95600d83612f6e565b6c09aeae6e840e6cadcc8408aa89609b1b815260200192915050565b6000612bbe602983612f6e565b7f52656465656d20616d6f756e74206578636565647320617661696c61626c65208152686c697175696469747960b81b602082015260400192915050565b6000612c09601f83612f6e565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300815260200192915050565b6126e681610648565b6126e681612f93565b600061066382612b09565b6020810161066382846126ec565b6020810161066382846126dd565b60608101612c7c82866126dd565b612c8960208301856126dd565b6117356040830184612c35565b60608101612ca482866126dd565b612c8960208301856126ec565b60408101612cbf82856126dd565b611d326020830184612c35565b60408101612cbf82856126ec565b6020810161066382846126f5565b60408101612cbf82856126fe565b60208082528101611d328184612707565b602080825281016106638161273f565b6020808252810161066381612784565b60208082528101610663816127b4565b60208082528101610663816127dc565b6020808252810161066381612824565b6020808252810161066381612868565b6020808252810161066381612893565b60208082528101610663816128cc565b60208082528101610663816128f9565b6020808252810161066381612929565b6020808252810161066381612955565b60208082528101610663816129a6565b60208082528101610663816129cd565b6020808252810161066381612a06565b6020808252810161066381612a56565b6020808252810161066381612a99565b6020808252810161066381612ae0565b6020808252810161066381612b16565b6020808252810161066381612b5c565b6020808252810161066381612b88565b6020808252810161066381612bb1565b6020808252810161066381612bfc565b602081016106638284612c35565b60408101612cbf8285612c35565b60608101612e918286612c35565b612c896020830185612c35565b60808101612eac8287612c35565b612eb96020830186612c35565b612ec66040830185612c35565b61077760608301846126f5565b60808101612ee18287612c35565b612eee6020830186612c35565b612efb6040830185612c35565b6107776060830184612c35565b602081016106638284612c3e565b60405181810167ffffffffffffffff81118282101715612f3557600080fd5b604052919050565b600067ffffffffffffffff821115612f5457600080fd5b506020601f91909101601f19160190565b5190565b919050565b90815260200190565b600061066382612f87565b151590565b6001600160a01b031690565b60ff1690565b6000610663825b600061066382612f77565b82818337506000910152565b60005b83811015612fd2578181015183820152602001612fba565b838111156107205750506000910152565b601f01601f191690565b612ff681612f77565b811461103f57600080fd5b612ff681612f82565b612ff681610648565b612ff681612f9356fe45524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa365627a7a723158201b55f4e85d25ec19534b6dce9285d84f0ee17accbec39864cf4ae689a3c46ae86c6578706572696d656e74616cf564736f6c634300050f0040
Deployed Bytecode
0x6080604052600436106101e35760003560e01c8063715018a611610102578063a457c2d711610095578063e7654b3c11610064578063e7654b3c1461053f578063f00703331461055f578063f09ddae71461057f578063f2fde38b14610594576101e3565b8063a457c2d7146104bf578063a9059cbb146104df578063c4d66de8146104ff578063dd62ed3e1461051f576101e3565b806395d89b41116100d157806395d89b41146104625780639f3e8b34146104775780639fd0506d14610497578063a0712d68146104ac576101e3565b8063715018a6146104015780638456cb59146104165780638da5cb5b1461042b5780638f32d59b1461044d576101e3565b80633986de6a1161017a5780635a18664c116101495780635a18664c146103935780635c975abb146103a8578063629c577e146103bd57806370a08231146103e1576101e3565b80633986de6a146103295780633f4ba83a1461034957806342966c681461035e578063476343ee1461037e576101e3565b80631838d85c116101b65780631838d85c146102b257806323b872dd146102c7578063313ce567146102e75780633950935114610309576101e3565b806306fdde0314610218578063095ea7b3146102435780631624f6c61461027057806318160ddd14610290575b60d3546001600160a01b031633146102165760405162461bcd60e51b815260040161020d90612d27565b60405180910390fd5b005b34801561022457600080fd5b5061022d6105b4565b60405161023a9190612cf6565b60405180910390f35b34801561024f57600080fd5b5061026361025e36600461257f565b61064b565b60405161023a9190612cda565b34801561027c57600080fd5b5061021661028b3660046125fd565b610669565b34801561029c57600080fd5b506102a5610726565b60405161023a9190612e67565b3480156102be57600080fd5b506102a561072c565b3480156102d357600080fd5b506102636102e2366004612532565b610732565b3480156102f357600080fd5b506102fc610780565b60405161023a9190612f08565b34801561031557600080fd5b5061026361032436600461257f565b610789565b34801561033557600080fd5b5061021661034436600461241f565b6107e2565b34801561035557600080fd5b50610216610931565b34801561036a57600080fd5b5061021661037936600461266f565b6109b7565b34801561038a57600080fd5b50610216610c97565b34801561039f57600080fd5b50610216610f8f565b3480156103b457600080fd5b50610263611042565b3480156103c957600080fd5b506103d261104b565b60405161023a93929190612e83565b3480156103ed57600080fd5b506102a56103fc366004612401565b611057565b34801561040d57600080fd5b50610216611072565b34801561042257600080fd5b506102166110e0565b34801561043757600080fd5b5061044061116a565b60405161023a9190612c52565b34801561045957600080fd5b50610263611179565b34801561046e57600080fd5b5061022d61119f565b34801561048357600080fd5b506102a5610492366004612401565b611200565b3480156104a357600080fd5b50610440611212565b6102166104ba36600461266f565b611226565b3480156104cb57600080fd5b506102636104da36600461257f565b61168b565b3480156104eb57600080fd5b506102636104fa36600461257f565b6116f9565b34801561050b57600080fd5b5061021661051a366004612401565b61173d565b34801561052b57600080fd5b506102a561053a3660046124f8565b61180f565b34801561054b57600080fd5b5061021661055a3660046126ab565b61183a565b34801561056b57600080fd5b5061021661057a36600461266f565b61186e565b34801561058b57600080fd5b506102a5611bbf565b3480156105a057600080fd5b506102166105af366004612401565b611bc5565b60688054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156106405780601f1061061557610100808354040283529160200191610640565b820191906000526020600020905b81548152906001019060200180831161062357829003601f168201915b505050505090505b90565b600061065f610658611bf2565b8484611bf6565b5060015b92915050565b600054610100900460ff16806106825750610682611caa565b80610690575060005460ff16155b6106ac5760405162461bcd60e51b815260040161020d90612dd7565b600054610100900460ff161580156106d7576000805460ff1961ff0019909116610100171660011790555b83516106ea9060689060208701906122de565b5082516106fe9060699060208601906122de565b50606a805460ff191660ff84161790558015610720576000805461ff00191690555b50505050565b60355490565b60d65481565b6001600160a01b038316600090815260da6020526040812054849043101561076c5760405162461bcd60e51b815260040161020d90612da7565b610777858585611cb0565b95945050505050565b606a5460ff1690565b600061065f610796611bf2565b846107dd85603460006107a7611bf2565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff611d3916565b611bf6565b600054610100900460ff16806107fb57506107fb611caa565b80610809575060005460ff16155b6108255760405162461bcd60e51b815260040161020d90612dd7565b600054610100900460ff16158015610850576000805460ff1961ff0019909116610100171660011790555b6108598661173d565b61089e604051806040016040528060048152602001630f0a69cb60e31b8152506040518060400160405280600581526020016478534e586160d81b8152506012610669565b6108a786611d5e565b60d180546001600160a01b03199081166001600160a01b038e81169190911790925560d2805482168d841617905560d4805482168c841617905560d5805482168b841617905560d38054909116918916919091179055610908858585611e00565b6109123383611e83565b8015610924576000805461ff00191690555b5050505050505050505050565b609d5461010090046001600160a01b031633146109605760405162461bcd60e51b815260040161020d90612d77565b609d5460ff166109825760405162461bcd60e51b815260040161020d90612d17565b609d805460ff191690556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d1693390600090a1565b33600081815260da60205260409020544310156109e65760405162461bcd60e51b815260040161020d90612da7565b60008211610a065760405162461bcd60e51b815260040161020d90612e27565b610a0f33611f43565b60d1546000906001600160a01b03166318d814ba610a2b610726565b856040518363ffffffff1660e01b8152600401610a49929190612e75565b60206040518083038186803b158015610a6157600080fd5b505afa158015610a75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a99919081019061268d565b90508060d160009054906101000a90046001600160a01b03166001600160a01b03166370ed0ada6040518163ffffffff1660e01b815260040160206040518083038186803b158015610aea57600080fd5b505afa158015610afe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b22919081019061268d565b1015610b405760405162461bcd60e51b815260040161020d90612e47565b60d35460405163a965072760e01b81526001600160a01b039091169063a965072790610b70908490600401612e67565b600060405180830381600087803b158015610b8a57600080fd5b505af1158015610b9e573d6000803e3d6000fd5b505050506000610bc3610bb68360d760010154611f62565b839063ffffffff611f7a16565b9050610bcf3385611fbc565b336001600160a01b03167f743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644428684604051610c0c93929190612e83565b60405180910390a26000336001600160a01b031682604051610c2d90612c47565b60006040518083038185875af1925050503d8060008114610c6a576040519150601f19603f3d011682016040523d82523d6000602084013e610c6f565b606091505b5050905080610c905760405162461bcd60e51b815260040161020d90612d87565b5050505050565b610c9f611179565b610cbb5760405162461bcd60e51b815260040161020d90612dc7565b60d5546040516370a0823160e01b815247916000916001600160a01b03909116906370a0823190610cf0903090600401612c60565b60206040518083038186803b158015610d0857600080fd5b505afa158015610d1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d40919081019061268d565b60d4546040516370a0823160e01b81529192506000916001600160a01b03909116906370a0823190610d76903090600401612c60565b60206040518083038186803b158015610d8e57600080fd5b505afa158015610da2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610dc6919081019061268d565b90506000336001600160a01b031684604051610de190612c47565b60006040518083038185875af1925050503d8060008114610e1e576040519150601f19603f3d011682016040523d82523d6000602084013e610e23565b606091505b5050905080610e445760405162461bcd60e51b815260040161020d90612d57565b60d55460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90610e769033908790600401612cb1565b602060405180830381600087803b158015610e9057600080fd5b505af1158015610ea4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ec891908101906125af565b5060d45460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90610efb9033908690600401612cb1565b602060405180830381600087803b158015610f1557600080fd5b505af1158015610f29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610f4d91908101906125af565b507fa80975b2ffacb3d3f1fcfd13863288991d27ae8e617c147e7c83d240b82bd1f6848484604051610f8193929190612e83565b60405180910390a150505050565b610f97611179565b610fb35760405162461bcd60e51b815260040161020d90612dc7565b6000610fbe30611057565b9050801561103f5760405163a9059cbb60e01b8152309063a9059cbb90610feb9033908590600401612cb1565b602060405180830381600087803b15801561100557600080fd5b505af1158015611019573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061103d91908101906125af565b505b50565b609d5460ff1690565b60d75460d85460d95483565b6001600160a01b031660009081526033602052604090205490565b61107a611179565b6110965760405162461bcd60e51b815260040161020d90612dc7565b609e546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3609e80546001600160a01b0319169055565b609d5461010090046001600160a01b0316331461110f5760405162461bcd60e51b815260040161020d90612d77565b609d5460ff16156111325760405162461bcd60e51b815260040161020d90612d97565b609d805460ff191660011790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e75290600090a1565b609e546001600160a01b031690565b609e546000906001600160a01b0316611190611bf2565b6001600160a01b031614905090565b60698054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156106405780601f1061061557610100808354040283529160200191610640565b60da6020526000908152604090205481565b609d5461010090046001600160a01b031681565b609d5460ff16156112495760405162461bcd60e51b815260040161020d90612d97565b33600081815260da60205260409020544310156112785760405162461bcd60e51b815260040161020d90612da7565b600034116112985760405162461bcd60e51b815260040161020d90612e37565b6112a133611f43565b60006112b23460d760000154611f62565b905060006112c6348363ffffffff611f7a16565b9050600060d160009054906101000a90046001600160a01b03166001600160a01b03166389afb5b76040518163ffffffff1660e01b815260040160206040518083038186803b15801561131857600080fd5b505afa15801561132c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611350919081019061268d565b9050600061135c610726565b60d154604051634ebb2f5360e11b815291925060009182916001600160a01b031690639d765ea690611392908690600401612e67565b604080518083038186803b1580156113a957600080fd5b505afa1580156113bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113e191908101906125cd565b91509150816115225760d25460d454604051633d15022b60e11b81526000926001600160a01b0390811692637a2a0456928a926114249216908e90600401612ce8565b6020604051808303818588803b15801561143d57600080fd5b505af1158015611451573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250611476919081019061268d565b60d45460d35460405163a9059cbb60e01b81529293506001600160a01b039182169263a9059cbb926114ae9216908590600401612ccc565b602060405180830381600087803b1580156114c857600080fd5b505af11580156114dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061150091908101906125af565b61151c5760405162461bcd60e51b815260040161020d90612d57565b506115a5565b60d3546040516000916001600160a01b031690879061154090612c47565b60006040518083038185875af1925050503d806000811461157d576040519150601f19603f3d011682016040523d82523d6000602084013e611582565b606091505b50509050806115a35760405162461bcd60e51b815260040161020d90612d57565b505b60d154604051630748416d60e41b81526000916001600160a01b03169063748416d0906115dc9088908a9087908a90600401612ed3565b60206040518083038186803b1580156115f457600080fd5b505afa158015611608573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061162c919081019061268d565b9050336001600160a01b03167f5b5de75983fe8891c65234472ee1805018163815d4c146f10bf176b736093c09423484600160405161166e9493929190612e9e565b60405180910390a26116803382611e83565b505050505050505050565b600061065f611698611bf2565b846107dd8560405180606001604052806025815260200161308d60259139603460006116c2611bf2565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff61209216565b33600081815260da602052604081205490919043101561172b5760405162461bcd60e51b815260040161020d90612da7565b61173584846120be565b949350505050565b600054610100900460ff16806117565750611756611caa565b80611764575060005460ff16155b6117805760405162461bcd60e51b815260040161020d90612dd7565b600054610100900460ff161580156117ab576000805460ff1961ff0019909116610100171660011790555b609e80546001600160a01b0319166001600160a01b0384811691909117918290556040519116906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3801561103d576000805461ff00191690555050565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b611842611179565b61185e5760405162461bcd60e51b815260040161020d90612dc7565b611869838383611e00565b505050565b609d5460ff16156118915760405162461bcd60e51b815260040161020d90612d97565b33600081815260da60205260409020544310156118c05760405162461bcd60e51b815260040161020d90612da7565b600082116118e05760405162461bcd60e51b815260040161020d90612e07565b6118e933611f43565b60d154604080516389afb5b760e01b815290516000926001600160a01b0316916389afb5b7916004808301926020929190829003018186803b15801561192e57600080fd5b505afa158015611942573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611966919081019061268d565b905060006119798460d760000154611f62565b9050600061198d858363ffffffff611f7a16565b60d4546040516323b872dd60e01b81529192506001600160a01b0316906323b872dd906119c290339030908790600401612c6e565b602060405180830381600087803b1580156119dc57600080fd5b505af11580156119f0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a1491908101906125af565b611a305760405162461bcd60e51b815260040161020d90612d57565b60d45460d3546040516323b872dd60e01b81526001600160a01b03928316926323b872dd92611a69923392909116908690600401612c96565b602060405180830381600087803b158015611a8357600080fd5b505af1158015611a97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611abb91908101906125af565b611ad75760405162461bcd60e51b815260040161020d90612d57565b60d1546000906001600160a01b0316632bdbe2198584611af5610726565b6040518463ffffffff1660e01b8152600401611b1393929190612e83565b60206040518083038186803b158015611b2b57600080fd5b505afa158015611b3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b63919081019061268d565b9050336001600160a01b03167f5b5de75983fe8891c65234472ee1805018163815d4c146f10bf176b736093c094284846000604051611ba59493929190612e9e565b60405180910390a2611bb73382611e83565b505050505050565b60d95490565b611bcd611179565b611be95760405162461bcd60e51b815260040161020d90612dc7565b61103f816120d2565b3390565b6001600160a01b038316611c1c5760405162461bcd60e51b815260040161020d90612e17565b6001600160a01b038216611c425760405162461bcd60e51b815260040161020d90612d47565b6001600160a01b0380841660008181526034602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590611c9d908590612e67565b60405180910390a3505050565b303b1590565b6000611cbd848484612154565b611d2e84611cc9611bf2565b6107dd85604051806060016040528060288152602001613065602891396001600160a01b038a16600090815260346020526040812090611d07611bf2565b6001600160a01b03168152602081019190915260400160002054919063ffffffff61209216565b5060015b9392505050565b600082820183811015611d325760405162461bcd60e51b815260040161020d90612d67565b600054610100900460ff1680611d775750611d77611caa565b80611d85575060005460ff16155b611da15760405162461bcd60e51b815260040161020d90612dd7565b600054610100900460ff16158015611dcc576000805460ff1961ff0019909116610100171660011790555b609d80546001600160a81b0319166101006001600160a01b03851602179055801561103d576000805461ff00191690555050565b821580611e0e575060328310155b611e2a5760405162461bcd60e51b815260040161020d90612db7565b811580611e38575060648210155b611e545760405162461bcd60e51b815260040161020d90612db7565b6019811015611e755760405162461bcd60e51b815260040161020d90612db7565b60d79290925560d85560d955565b6001600160a01b038216611ea95760405162461bcd60e51b815260040161020d90612e57565b603554611ebc908263ffffffff611d3916565b6035556001600160a01b038216600090815260336020526040902054611ee8908263ffffffff611d3916565b6001600160a01b0383166000818152603360205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611f37908590612e67565b60405180910390a35050565b6001600160a01b0316600090815260da60205260409020436006019055565b6000811561066357611d32838363ffffffff61226a16565b6000611d3283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612092565b6001600160a01b038216611fe25760405162461bcd60e51b815260040161020d90612de7565b6120258160405180606001604052806022815260200161301d602291396001600160a01b038516600090815260336020526040902054919063ffffffff61209216565b6001600160a01b038316600090815260336020526040902055603554612051908263ffffffff611f7a16565b6035556040516000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611f37908590612e67565b600081848411156120b65760405162461bcd60e51b815260040161020d9190612cf6565b505050900390565b600061065f6120cb611bf2565b8484612154565b6001600160a01b0381166120f85760405162461bcd60e51b815260040161020d90612d37565b609e546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3609e80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03831661217a5760405162461bcd60e51b815260040161020d90612df7565b6001600160a01b0382166121a05760405162461bcd60e51b815260040161020d90612d07565b6121e38160405180606001604052806026815260200161303f602691396001600160a01b038616600090815260336020526040902054919063ffffffff61209216565b6001600160a01b038085166000908152603360205260408082209390935590841681522054612218908263ffffffff611d3916565b6001600160a01b0380841660008181526033602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611c9d908590612e67565b6000611d3283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250600081836122c85760405162461bcd60e51b815260040161020d9190612cf6565b5060008385816122d457fe5b0495945050505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061231f57805160ff191683800117855561234c565b8280016001018555821561234c579182015b8281111561234c578251825591602001919060010190612331565b5061235892915061235c565b5090565b61064891905b808211156123585760008155600101612362565b803561066381612fed565b805161066381613001565b600082601f83011261239d57600080fd5b81356123b06123ab82612f3d565b612f16565b915080825260208301602083018583830111156123cc57600080fd5b6123d7838284612fab565b50505092915050565b80356106638161300a565b80516106638161300a565b803561066381613013565b60006020828403121561241357600080fd5b60006117358484612376565b6000806000806000806000806000806101408b8d03121561243f57600080fd5b600061244b8d8d612376565b9a5050602061245c8d828e01612376565b995050604061246d8d828e01612376565b985050606061247e8d828e01612376565b975050608061248f8d828e01612376565b96505060a06124a08d828e01612376565b95505060c06124b18d828e016123e0565b94505060e06124c28d828e016123e0565b9350506101006124d48d828e016123e0565b9250506101206124e68d828e016123e0565b9150509295989b9194979a5092959850565b6000806040838503121561250b57600080fd5b60006125178585612376565b925050602061252885828601612376565b9150509250929050565b60008060006060848603121561254757600080fd5b60006125538686612376565b935050602061256486828701612376565b9250506040612575868287016123e0565b9150509250925092565b6000806040838503121561259257600080fd5b600061259e8585612376565b9250506020612528858286016123e0565b6000602082840312156125c157600080fd5b60006117358484612381565b600080604083850312156125e057600080fd5b60006125ec8585612381565b9250506020612528858286016123eb565b60008060006060848603121561261257600080fd5b833567ffffffffffffffff81111561262957600080fd5b6126358682870161238c565b935050602084013567ffffffffffffffff81111561265257600080fd5b61265e8682870161238c565b9250506040612575868287016123f6565b60006020828403121561268157600080fd5b600061173584846123e0565b60006020828403121561269f57600080fd5b600061173584846123eb565b6000806000606084860312156126c057600080fd5b60006126cc86866123e0565b9350506020612564868287016123e0565b6126e681612f99565b82525050565b6126e681612f77565b6126e681612f82565b6126e681612fa0565b600061271282612f65565b61271c8185612f6e565b935061272c818560208601612fb7565b61273581612fe3565b9093019392505050565b600061274c602383612f6e565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647281526265737360e81b602082015260400192915050565b6000612791601483612f6e565b7314185d5cd8589b194e881b9bdd081c185d5cd95960621b815260200192915050565b60006127c1600c83612f6e565b6b125b9d985b1a59081cd95b9960a21b815260200192915050565b60006127e9602683612f6e565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000612831602283612f6e565b7f45524332303a20617070726f766520746f20746865207a65726f206164647265815261737360f01b602082015260400192915050565b6000612875600f83612f6e565b6e151c985b9cd9995c8819985a5b1959608a1b815260200192915050565b60006128a0601b83612f6e565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b60006128d9601183612f6e565b70446f6e277420686176652072696768747360781b815260200192915050565b6000612906601483612f6e565b73109d5c9b881d1c985b9cd9995c8819985a5b195960621b815260200192915050565b6000612936601083612f6e565b6f14185d5cd8589b194e881c185d5cd95960821b815260200192915050565b6000612962602f83612f6e565b7f46756e6374696f6e2069732074656d706f726172696c79206c6f636b6564206681526e6f722074686973206164647265737360881b602082015260400192915050565b60006129b3600b83612f6e565b6a496e76616c69642066656560a81b815260200192915050565b60006129da602083612f6e565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572815260200192915050565b6000612a13602e83612f6e565b7f436f6e747261637420696e7374616e63652068617320616c726561647920626581526d195b881a5b9a5d1a585b1a5e995960921b602082015260400192915050565b6000612a63602183612f6e565b7f45524332303a206275726e2066726f6d20746865207a65726f206164647265738152607360f81b602082015260400192915050565b6000612aa6602583612f6e565b7f45524332303a207472616e736665722066726f6d20746865207a65726f206164815264647265737360d81b602082015260400192915050565b6000612aed600d83612f6e565b6c09aeae6e840e6cadcc840a69cb609b1b815260200192915050565b6000610663600083612f69565b6000612b23602483612f6e565b7f45524332303a20617070726f76652066726f6d20746865207a65726f206164648152637265737360e01b602082015260400192915050565b6000612b69601083612f6e565b6f4d757374206275726e20746f6b656e7360801b815260200192915050565b6000612b95600d83612f6e565b6c09aeae6e840e6cadcc8408aa89609b1b815260200192915050565b6000612bbe602983612f6e565b7f52656465656d20616d6f756e74206578636565647320617661696c61626c65208152686c697175696469747960b81b602082015260400192915050565b6000612c09601f83612f6e565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300815260200192915050565b6126e681610648565b6126e681612f93565b600061066382612b09565b6020810161066382846126ec565b6020810161066382846126dd565b60608101612c7c82866126dd565b612c8960208301856126dd565b6117356040830184612c35565b60608101612ca482866126dd565b612c8960208301856126ec565b60408101612cbf82856126dd565b611d326020830184612c35565b60408101612cbf82856126ec565b6020810161066382846126f5565b60408101612cbf82856126fe565b60208082528101611d328184612707565b602080825281016106638161273f565b6020808252810161066381612784565b60208082528101610663816127b4565b60208082528101610663816127dc565b6020808252810161066381612824565b6020808252810161066381612868565b6020808252810161066381612893565b60208082528101610663816128cc565b60208082528101610663816128f9565b6020808252810161066381612929565b6020808252810161066381612955565b60208082528101610663816129a6565b60208082528101610663816129cd565b6020808252810161066381612a06565b6020808252810161066381612a56565b6020808252810161066381612a99565b6020808252810161066381612ae0565b6020808252810161066381612b16565b6020808252810161066381612b5c565b6020808252810161066381612b88565b6020808252810161066381612bb1565b6020808252810161066381612bfc565b602081016106638284612c35565b60408101612cbf8285612c35565b60608101612e918286612c35565b612c896020830185612c35565b60808101612eac8287612c35565b612eb96020830186612c35565b612ec66040830185612c35565b61077760608301846126f5565b60808101612ee18287612c35565b612eee6020830186612c35565b612efb6040830185612c35565b6107776060830184612c35565b602081016106638284612c3e565b60405181810167ffffffffffffffff81118282101715612f3557600080fd5b604052919050565b600067ffffffffffffffff821115612f5457600080fd5b506020601f91909101601f19160190565b5190565b919050565b90815260200190565b600061066382612f87565b151590565b6001600160a01b031690565b60ff1690565b6000610663825b600061066382612f77565b82818337506000910152565b60005b83811015612fd2578181015183820152602001612fba565b838111156107205750506000910152565b601f01601f191690565b612ff681612f77565b811461103f57600080fd5b612ff681612f82565b612ff681610648565b612ff681612f9356fe45524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa365627a7a723158201b55f4e85d25ec19534b6dce9285d84f0ee17accbec39864cf4ae689a3c46ae86c6578706572696d656e74616cf564736f6c634300050f0040
Deployed Bytecode Sourcemap
84398:10251:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;94612:9;;-1:-1:-1;;;;;94612:9:0;94598:10;:23;94590:48;;;;-1:-1:-1;;;94590:48:0;;;;;;;;;;;;;;;;;84398:10251;23559:83;;8:9:-1;5:2;;;30:1;27;20:12;5:2;23559:83:0;;;:::i;:::-;;;;;;;;;;;;;;;;17002:152;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;17002:152:0;;;;;;;;:::i;:::-;;;;;;;;23303:186;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;23303:186:0;;;;;;;;:::i;16023:91::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;16023:91:0;;;:::i;:::-;;;;;;;;84638:34;;8:9:-1;5:2;;;30:1;27;20:12;5:2;84638:34:0;;;:::i;91085:218::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;91085:218:0;;;;;;;;:::i;24411:83::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;24411:83:0;;;:::i;:::-;;;;;;;;18339:210;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;18339:210:0;;;;;;;;:::i;84681:909::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;84681:909:0;;;;;;;;:::i;83932:108::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;83932:108:0;;;:::i;89980:901::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;89980:901:0;;;;;;;;:::i;92596:701::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;92596:701:0;;;:::i;93427:217::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;93427:217:0;;;:::i;83151:78::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;83151:78:0;;;:::i;86140:30::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;86140:30:0;;;:::i;:::-;;;;;;;;;;16177:110;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;16177:110:0;;;;;;;;:::i;10717:140::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;10717:140:0;;;:::i;83731:106::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;83731:106:0;;;:::i;9904:79::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9904:79:0;;;:::i;:::-;;;;;;;;10270:94;;8:9:-1;5:2;;;30:1;27;20:12;5:2;10270:94:0;;;:::i;23761:87::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;23761:87:0;;;:::i;86355:50::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;86355:50:0;;;;;;;;:::i;82486:21::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;82486:21:0;;;:::i;86891:1358::-;;;;;;;;;:::i;19052:261::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;19052:261:0;;;;;;;;:::i;90889:188::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;90889:188:0;;;;;;;;:::i;9678:145::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;9678:145:0;;;;;;;;:::i;16721:134::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;16721:134:0;;;;;;;;:::i;91751:231::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;91751:231:0;;;;;;;;:::i;88608:1113::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;88608:1113:0;;;;;;;;:::i;93757:106::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;93757:106:0;;;:::i;11012:109::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;11012:109:0;;;;;;;;:::i;23559:83::-;23629:5;23622:12;;;;;;;;-1:-1:-1;;23622:12:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23596:13;;23622:12;;23629:5;;23622:12;;23629:5;23622:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23559:83;;:::o;17002:152::-;17068:4;17085:39;17094:12;:10;:12::i;:::-;17108:7;17117:6;17085:8;:39::i;:::-;-1:-1:-1;17142:4:0;17002:152;;;;;:::o;23303:186::-;6655:12;;;;;;;;:31;;;6671:15;:13;:15::i;:::-;6655:47;;;-1:-1:-1;6691:11:0;;;;6690:12;6655:47;6647:106;;;;-1:-1:-1;;;6647:106:0;;;;;;;;;6762:19;6785:12;;;;;;6784:13;6804:83;;;;6833:12;:19;;-1:-1:-1;;;;6833:19:0;;;;;6861:18;6848:4;6861:18;;;6804:83;23411:12;;;;:5;;:12;;;;;:::i;:::-;-1:-1:-1;23434:16:0;;;;:7;;:16;;;;;:::i;:::-;-1:-1:-1;23461:9:0;:20;;-1:-1:-1;;23461:20:0;;;;;;;6905:57;;;;6949:5;6934:20;;-1:-1:-1;;6934:20:0;;;6905:57;23303:186;;;;:::o;16023:91::-;16094:12;;16023:91;:::o;84638:34::-;;;;:::o;91085:218::-;-1:-1:-1;;;;;94138:30:0;;91226:4;94138:30;;;:15;:30;;;;;;91209:6;;94172:12;-1:-1:-1;94138:46:0;94116:143;;;;-1:-1:-1;;;94116:143:0;;;;;;;;;91250:45;91269:6;91277:9;91288:6;91250:18;:45::i;:::-;91243:52;91085:218;-1:-1:-1;;;;;91085:218:0:o;24411:83::-;24477:9;;;;24411:83;:::o;18339:210::-;18419:4;18436:83;18445:12;:10;:12::i;:::-;18459:7;18468:50;18507:10;18468:11;:25;18480:12;:10;:12::i;:::-;-1:-1:-1;;;;;18468:25:0;;;;;;;;;;;;;;;;;-1:-1:-1;18468:25:0;;;:34;;;;;;;;;;;:50;:38;:50;:::i;:::-;18436:8;:83::i;84681:909::-;6655:12;;;;;;;;:31;;;6671:15;:13;:15::i;:::-;6655:47;;;-1:-1:-1;6691:11:0;;;;6690:12;6655:47;6647:106;;;;-1:-1:-1;;;6647:106:0;;;;;;;;;6762:19;6785:12;;;;;;6784:13;6804:83;;;;6833:12;:19;;-1:-1:-1;;;;6833:19:0;;;;;6861:18;6848:4;6861:18;;;6804:83;85081:33;85100:13;85081:18;:33::i;:::-;85125:45;;;;;;;;;;;;;;-1:-1:-1;;;85125:45:0;;;;;;;;;;;;;;;;-1:-1:-1;;;85125:45:0;;;85167:2;85125:24;:45::i;:::-;85181:34;85201:13;85181:19;:34::i;:::-;85228:15;:58;;-1:-1:-1;;;;;;85228:58:0;;;-1:-1:-1;;;;;85228:58:0;;;;;;;;;;85297:17;:58;;;;;;;;;;85366:10;:24;;;;;;;;;;85401:11;:26;;;;;;;;;;85438:9;:22;;;;;;;;;;;;;;85473:67;85489:15;85506;85523:16;85473:15;:67::i;:::-;85551:31;85557:10;85569:12;85551:5;:31::i;:::-;6909:14;6905:57;;;6949:5;6934:20;;-1:-1:-1;;6934:20:0;;;6905:57;84681:909;;;;;;;;;;;:::o;83932:108::-;84101:6;;;;;-1:-1:-1;;;;;84101:6:0;84087:10;:20;84079:50;;;;-1:-1:-1;;;84079:50:0;;;;;;;;;83587:7;;;;83579:40;;;;-1:-1:-1;;;83579:40:0;;;;;;;;;83991:7;:15;;-1:-1:-1;;83991:15:0;;;84022:10;;;;84001:5;;84022:10;83932:108::o;89980:901::-;90037:10;94138:30;;;;:15;:30;;;;;;94172:12;-1:-1:-1;94138:46:0;94116:143;;;;-1:-1:-1;;;94116:143:0;;;;;;;;;90085:1;90068:14;:18;90060:47;;;;-1:-1:-1;;;90060:47:0;;;;;;;;;90118:16;90123:10;90118:4;:16::i;:::-;90171:15;;90147:21;;-1:-1:-1;;;;;90171:15:0;:40;90226:13;:11;:13::i;:::-;90254:14;90171:108;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;90171:108:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;90171:108:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;90171:108:0;;;;;;;;;90147:132;;90349:13;90314:15;;;;;;;;;-1:-1:-1;;;;;90314:15:0;-1:-1:-1;;;;;90314:29:0;;:31;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;90314:31:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;90314:31:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;90314:31:0;;;;;;;;;:48;;90292:139;;;;-1:-1:-1;;;90292:139:0;;;;;;;;;90455:9;;90444:56;;-1:-1:-1;;;90444:56:0;;-1:-1:-1;;;;;90455:9:0;;;;90444:41;;:56;;90486:13;;90444:56;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;90444:56:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;90444:56:0;;;;90511:19;90533:91;90565:48;90578:13;90593:11;:19;;;90565:12;:48::i;:::-;90533:13;;:91;:17;:91;:::i;:::-;90511:113;;90635:39;90647:10;90659:14;90635:11;:39::i;:::-;90695:10;-1:-1:-1;;;;;90690:62:0;;90707:15;90724:14;90740:11;90690:62;;;;;;;;;;;;;;;;;90766:12;90784:10;-1:-1:-1;;;;;90784:15:0;90806:11;90784:38;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;90765:57:0;;;90841:7;90833:40;;;;-1:-1:-1;;;90833:40:0;;;;;;;;;94270:1;;;89980:901;;:::o;92596:701::-;10116:9;:7;:9::i;:::-;10108:54;;;;-1:-1:-1;;;10108:54:0;;;;;;;;;92744:11;;92737:68;;-1:-1:-1;;;92737:68:0;;92676:21;;92648:25;;-1:-1:-1;;;;;92744:11:0;;;;92737:29;;:68;;92789:4;;92737:68;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;92737:68:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;92737:68:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;92737:68:0;;;;;;;;;92851:10;;92844:43;;-1:-1:-1;;;92844:43:0;;92708:97;;-1:-1:-1;92816:25:0;;-1:-1:-1;;;;;92851:10:0;;;;92844:28;;:43;;92881:4;;92844:43;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;92844:43:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;92844:43:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;92844:43:0;;;;;;;;;92816:71;;92901:12;92919:10;-1:-1:-1;;;;;92919:15:0;92941:17;92919:44;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;92900:63:0;;;92982:7;92974:35;;;;-1:-1:-1;;;92974:35:0;;;;;;;;;93029:11;;93022:60;;-1:-1:-1;;;93022:60:0;;-1:-1:-1;;;;;93029:11:0;;;;93022:28;;:60;;93051:10;;93063:18;;93022:60;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;93022:60:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;93022:60:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;93022:60:0;;;;;;;;;-1:-1:-1;93100:10:0;;93093:58;;-1:-1:-1;;;93093:58:0;;-1:-1:-1;;;;;93100:10:0;;;;93093:27;;:58;;93121:10;;93133:17;;93093:58;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;93093:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;93093:58:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;93093:58:0;;;;;;;;;;93169:120;93196:17;93228:18;93261:17;93169:120;;;;;;;;;;;;;;;;;10173:1;;;;92596:701::o;93427:217::-;10116:9;:7;:9::i;:::-;10108:54;;;;-1:-1:-1;;;10108:54:0;;;;;;;;;93486:16;93505:24;93523:4;93505:9;:24::i;:::-;93486:43;-1:-1:-1;93544:12:0;;93540:97;;93573:52;;-1:-1:-1;;;93573:52:0;;93588:4;;93573:30;;:52;;93604:10;;93616:8;;93573:52;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;93573:52:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;93573:52:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;93573:52:0;;;;;;;;;;93540:97;10173:1;93427:217::o;83151:78::-;83214:7;;;;83151:78;:::o;86140:30::-;;;;;;;;:::o;16177:110::-;-1:-1:-1;;;;;16261:18:0;16234:7;16261:18;;;:9;:18;;;;;;;16177:110::o;10717:140::-;10116:9;:7;:9::i;:::-;10108:54;;;;-1:-1:-1;;;10108:54:0;;;;;;;;;10800:6;;10779:40;;10816:1;;-1:-1:-1;;;;;10800:6:0;;10779:40;;10816:1;;10779:40;10830:6;:19;;-1:-1:-1;;;;;;10830:19:0;;;10717:140::o;83731:106::-;84101:6;;;;;-1:-1:-1;;;;;84101:6:0;84087:10;:20;84079:50;;;;-1:-1:-1;;;84079:50:0;;;;;;;;;83388:7;;;;83387:8;83379:37;;;;-1:-1:-1;;;83379:37:0;;;;;;;;;83791:7;:14;;-1:-1:-1;;83791:14:0;83801:4;83791:14;;;83821:8;;;;83791:7;;83821:8;83731:106::o;9904:79::-;9969:6;;-1:-1:-1;;;;;9969:6:0;9904:79;:::o;10270:94::-;10350:6;;10310:4;;-1:-1:-1;;;;;10350:6:0;10334:12;:10;:12::i;:::-;-1:-1:-1;;;;;10334:22:0;;10327:29;;10270:94;:::o;23761:87::-;23833:7;23826:14;;;;;;;;-1:-1:-1;;23826:14:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23800:13;;23826:14;;23833:7;;23826:14;;23833:7;23826:14;;;;;;;;;;;;;;;;;;;;;;;;86355:50;;;;;;;;;;;;;:::o;82486:21::-;;;;;;-1:-1:-1;;;;;82486:21:0;;:::o;86891:1358::-;83388:7;;;;83387:8;83379:37;;;;-1:-1:-1;;;83379:37:0;;;;;;;;;86963:10;94138:30;;;;:15;:30;;;;;;94172:12;-1:-1:-1;94138:46:0;94116:143;;;;-1:-1:-1;;;94116:143:0;;;;;;;;;87006:1;86994:9;:13;86986:39;;;;-1:-1:-1;;;86986:39:0;;;;;;;;;87036:16;87041:10;87036:4;:16::i;:::-;87065:11;87079:44;87092:9;87103:11;:19;;;87079:12;:44::i;:::-;87065:58;-1:-1:-1;87134:23:0;87160:18;:9;87065:58;87160:18;:13;:18;:::i;:::-;87134:44;;87189:24;87216:15;;;;;;;;;-1:-1:-1;;;;;87216:15:0;-1:-1:-1;;;;;87216:29:0;;:31;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;87216:31:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;87216:31:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;87216:31:0;;;;;;;;;87189:58;;87260:19;87282:13;:11;:13::i;:::-;87355:15;;:62;;-1:-1:-1;;;87355:62:0;;87260:35;;-1:-1:-1;87307:18:0;;;;-1:-1:-1;;;;;87355:15:0;;:49;;:62;;87260:35;;87355:62;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;87355:62:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;87355:62:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;87355:62:0;;;;;;;;;87306:111;;;;87435:13;87430:472;;87487:17;;87583:10;;87487:117;;-1:-1:-1;;;87487:117:0;;87465:19;;-1:-1:-1;;;;;87487:17:0;;;;:34;;87546:15;;87487:117;;87583:10;;87596:7;;87487:117;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;87487:117:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;87487:117:0;;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;87487:117:0;;;;;;;;;87652:10;;87673:9;;87645:51;;-1:-1:-1;;;87645:51:0;;87465:139;;-1:-1:-1;;;;;;87652:10:0;;;;87645:27;;:51;;87673:9;;87465:139;;87645:51;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;87645:51:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;87645:51:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;87645:51:0;;;;;;;;;87619:128;;;;-1:-1:-1;;;87619:128:0;;;;;;;;;87430:472;;;;87799:9;;:41;;87781:12;;-1:-1:-1;;;;;87799:9:0;;87820:15;;87799:41;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;87780:60:0;;;87863:7;87855:35;;;;-1:-1:-1;;;87855:35:0;;;;;;;;;87430:472;;87935:15;;:173;;-1:-1:-1;;;87935:173:0;;87914:18;;-1:-1:-1;;;;;87935:15:0;;:44;;:173;;87994:16;;88025:15;;88055:16;;88086:11;;87935:173;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;87935:173:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;87935:173:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;87935:173:0;;;;;;;;;87914:194;;88131:10;-1:-1:-1;;;;;88126:62:0;;88143:15;88160:9;88171:10;88183:4;88126:62;;;;;;;;;;;;;;;;;;88206:35;88218:10;88230;88206:11;:35::i;:::-;88199:42;;;;;;;83427:1;86891:1358;:::o;19052:261::-;19137:4;19154:129;19163:12;:10;:12::i;:::-;19177:7;19186:96;19225:15;19186:96;;;;;;;;;;;;;;;;;:11;:25;19198:12;:10;:12::i;:::-;-1:-1:-1;;;;;19186:25:0;;;;;;;;;;;;;;;;;-1:-1:-1;19186:25:0;;;:34;;;;;;;;;;;:96;;:38;:96;:::i;90889:188::-;90977:10;91007:4;94138:30;;;:15;:30;;;;;;91007:4;;90977:10;94172:12;-1:-1:-1;94138:46:0;94116:143;;;;-1:-1:-1;;;94116:143:0;;;;;;;;;91036:33;91051:9;91062:6;91036:14;:33::i;:::-;91029:40;90889:188;-1:-1:-1;;;;90889:188:0:o;9678:145::-;6655:12;;;;;;;;:31;;;6671:15;:13;:15::i;:::-;6655:47;;;-1:-1:-1;6691:11:0;;;;6690:12;6655:47;6647:106;;;;-1:-1:-1;;;6647:106:0;;;;;;;;;6762:19;6785:12;;;;;;6784:13;6804:83;;;;6833:12;:19;;-1:-1:-1;;;;6833:19:0;;;;;6861:18;6848:4;6861:18;;;6804:83;9744:6;:15;;-1:-1:-1;;;;;;9744:15:0;-1:-1:-1;;;;;9744:15:0;;;;;;;;;;;9775:40;;9808:6;;;-1:-1:-1;;9775:40:0;;-1:-1:-1;;9775:40:0;6909:14;6905:57;;;6949:5;6934:20;;-1:-1:-1;;6934:20:0;;;9678:145;;:::o;16721:134::-;-1:-1:-1;;;;;16820:18:0;;;16793:7;16820:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;16721:134::o;91751:231::-;10116:9;:7;:9::i;:::-;10108:54;;;;-1:-1:-1;;;10108:54:0;;;;;;;;;91910:64;91926:14;91942;91958:15;91910;:64::i;:::-;91751:231;;;:::o;88608:1113::-;83388:7;;;;83387:8;83379:37;;;;-1:-1:-1;;;83379:37:0;;;;;;;;;88681:10;94138:30;;;;:15;:30;;;;;;94172:12;-1:-1:-1;94138:46:0;94116:143;;;;-1:-1:-1;;;94116:143:0;;;;;;;;;88724:1;88712:9;:13;88704:39;;;;-1:-1:-1;;;88704:39:0;;;;;;;;;88754:16;88759:10;88754:4;:16::i;:::-;88808:15;;:31;;;-1:-1:-1;;;88808:31:0;;;;88781:24;;-1:-1:-1;;;;;88808:15:0;;:29;;:31;;;;;;;;;;;;;;:15;:31;;;5:2:-1;;;;30:1;27;20:12;5:2;88808:31:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;88808:31:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;88808:31:0;;;;;;;;;88781:58;;88852:11;88866:44;88879:9;88890:11;:19;;;88866:12;:44::i;:::-;88852:58;-1:-1:-1;88921:23:0;88947:18;:9;88852:58;88947:18;:13;:18;:::i;:::-;89007:10;;89000:63;;-1:-1:-1;;;89000:63:0;;88921:44;;-1:-1:-1;;;;;;89007:10:0;;89000:31;;:63;;89032:10;;89052:4;;89059:3;;89000:63;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;89000:63:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;89000:63:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;89000:63:0;;;;;;;;;88978:128;;;;-1:-1:-1;;;88978:128:0;;;;;;;;;89146:10;;89218:9;;89139:137;;-1:-1:-1;;;89139:137:0;;-1:-1:-1;;;;;89146:10:0;;;;89139:31;;:137;;89189:10;;89218:9;;;;89246:15;;89139:137;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;89139:137:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;89139:137:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;89139:137:0;;;;;;;;;89117:202;;;;-1:-1:-1;;;89117:202:0;;;;;;;;;89353:15;;89332:18;;-1:-1:-1;;;;;89353:15:0;:44;89412:16;89443:15;89473:13;:11;:13::i;:::-;89353:144;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;89353:144:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;89353:144:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;89353:144:0;;;;;;;;;89332:165;;89534:10;-1:-1:-1;;;;;89515:145:0;;89559:15;89589;89619:10;89644:5;89515:145;;;;;;;;;;;;;;;;;;89678:35;89690:10;89702;89678:11;:35::i;:::-;89671:42;;;;83427:1;88608:1113;:::o;93757:106::-;93835:20;;93757:106;:::o;11012:109::-;10116:9;:7;:9::i;:::-;10108:54;;;;-1:-1:-1;;;10108:54:0;;;;;;;;;11085:28;11104:8;11085:18;:28::i;8583:98::-;8663:10;8583:98;:::o;21983:338::-;-1:-1:-1;;;;;22077:19:0;;22069:68;;;;-1:-1:-1;;;22069:68:0;;;;;;;;;-1:-1:-1;;;;;22156:21:0;;22148:68;;;;-1:-1:-1;;;22148:68:0;;;;;;;;;-1:-1:-1;;;;;22229:18:0;;;;;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;;:36;;;22281:32;;;;;22259:6;;22281:32;;;;;;;;;;21983:338;;;:::o;7056:508::-;7473:4;7519:17;7551:7;7056:508;:::o;17626:304::-;17715:4;17732:36;17742:6;17750:9;17761:6;17732:9;:36::i;:::-;17779:121;17788:6;17796:12;:10;:12::i;:::-;17810:89;17848:6;17810:89;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;17810:19:0;;;;;;:11;:19;;;;;;17830:12;:10;:12::i;:::-;-1:-1:-1;;;;;17810:33:0;;;;;;;;;;;;-1:-1:-1;17810:33:0;;;:89;;:37;:89;:::i;17779:121::-;-1:-1:-1;17918:4:0;17626:304;;;;;;:::o;940:181::-;998:7;1030:5;;;1054:6;;;;1046:46;;;;-1:-1:-1;;;1046:46:0;;;;;;;;82936:115;6655:12;;;;;;;;:31;;;6671:15;:13;:15::i;:::-;6655:47;;;-1:-1:-1;6691:11:0;;;;6690:12;6655:47;6647:106;;;;-1:-1:-1;;;6647:106:0;;;;;;;;;6762:19;6785:12;;;;;;6784:13;6804:83;;;;6833:12;:19;;-1:-1:-1;;;;6833:19:0;;;;;6861:18;6848:4;6861:18;;;6804:83;83002:7;:15;;-1:-1:-1;;;;;;83028:15:0;83002;-1:-1:-1;;;;;83028:15:0;;;;;;6905:57;;;;6949:5;6934:20;;-1:-1:-1;;6934:20:0;;;82936:115;;:::o;91990:515::-;92152:20;;;:45;;;92195:2;92176:15;:21;;92152:45;92144:69;;;;-1:-1:-1;;;92144:69:0;;;;;;;;;92232:20;;;:46;;;92275:3;92256:15;:22;;92232:46;92224:70;;;;-1:-1:-1;;;92224:70:0;;;;;;;;;92333:2;92313:16;:22;;92305:46;;;;-1:-1:-1;;;92305:46:0;;;;;;;;;92362:11;:37;;;;92410:19;:37;92458:20;:39;91990:515::o;20555:308::-;-1:-1:-1;;;;;20631:21:0;;20623:65;;;;-1:-1:-1;;;20623:65:0;;;;;;;;;20716:12;;:24;;20733:6;20716:24;:16;:24;:::i;:::-;20701:12;:39;-1:-1:-1;;;;;20772:18:0;;;;;;:9;:18;;;;;;:30;;20795:6;20772:30;:22;:30;:::i;:::-;-1:-1:-1;;;;;20751:18:0;;;;;;:9;:18;;;;;;:51;;;;20818:37;;20751:18;;;20818:37;;;;20848:6;;20818:37;;;;;;;;;;20555:308;;:::o;94425:118::-;-1:-1:-1;;;;;94476:25:0;;;;;:15;:25;;;;;94504:12;86291:1;94504:31;94476:59;;94425:118::o;91311:222::-;91420:11;91453:15;;91449:77;;91491:23;:6;91502:11;91491:23;:10;:23;:::i;1396:136::-;1454:7;1481:43;1485:1;1488;1481:43;;;;;;;;;;;;;;;;;:3;:43::i;21195:348::-;-1:-1:-1;;;;;21271:21:0;;21263:67;;;;-1:-1:-1;;;21263:67:0;;;;;;;;;21364:68;21387:6;21364:68;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;21364:18:0;;;;;;:9;:18;;;;;;;:68;;:22;:68;:::i;:::-;-1:-1:-1;;;;;21343:18:0;;;;;;:9;:18;;;;;:89;21458:12;;:24;;21475:6;21458:24;:16;:24;:::i;:::-;21443:12;:39;21498:37;;21524:1;;-1:-1:-1;;;;;21498:37:0;;;;;;;21528:6;;21498:37;;1869:192;1955:7;1991:12;1983:6;;;;1975:29;;;;-1:-1:-1;;;1975:29:0;;;;;;;;;;-1:-1:-1;;;2027:5:0;;;1869:192::o;16500:158::-;16569:4;16586:42;16596:12;:10;:12::i;:::-;16610:9;16621:6;16586:9;:42::i;11227:229::-;-1:-1:-1;;;;;11301:22:0;;11293:73;;;;-1:-1:-1;;;11293:73:0;;;;;;;;;11403:6;;11382:38;;-1:-1:-1;;;;;11382:38:0;;;;11403:6;;11382:38;;11403:6;;11382:38;11431:6;:17;;-1:-1:-1;;;;;;11431:17:0;-1:-1:-1;;;;;11431:17:0;;;;;;;;;;11227:229::o;19803:471::-;-1:-1:-1;;;;;19901:20:0;;19893:70;;;;-1:-1:-1;;;19893:70:0;;;;;;;;;-1:-1:-1;;;;;19982:23:0;;19974:71;;;;-1:-1:-1;;;19974:71:0;;;;;;;;;20078;20100:6;20078:71;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;20078:17:0;;;;;;:9;:17;;;;;;;:71;;:21;:71;:::i;:::-;-1:-1:-1;;;;;20058:17:0;;;;;;;:9;:17;;;;;;:91;;;;20183:20;;;;;;;:32;;20208:6;20183:32;:24;:32;:::i;:::-;-1:-1:-1;;;;;20160:20:0;;;;;;;:9;:20;;;;;;;:55;;;;20231:35;;;;;;;;;;20259:6;;20231:35;;3251:132;3309:7;3336:39;3340:1;3343;3336:39;;;;;;;;;;;;;;;;;3999:7;4101:12;4094:5;4086:28;;;;-1:-1:-1;;;4086:28:0;;;;;;;;;;;4125:9;4141:1;4137;:5;;;;;;;3913:345;-1:-1:-1;;;;;3913:345:0:o;84398:10251::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;84398:10251:0;;;-1:-1:-1;84398:10251:0;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;5:130:-1;72:20;;97:33;72:20;97:33;;295:128;370:13;;388:30;370:13;388:30;;431:442;;533:3;526:4;518:6;514:17;510:27;500:2;;551:1;548;541:12;500:2;588:6;575:20;610:65;625:49;667:6;625:49;;;610:65;;;601:74;;695:6;688:5;681:21;731:4;723:6;719:17;764:4;757:5;753:16;799:3;790:6;785:3;781:16;778:25;775:2;;;816:1;813;806:12;775:2;826:41;860:6;855:3;850;826:41;;;493:380;;;;;;;;881:130;948:20;;973:33;948:20;973:33;;1018:134;1096:13;;1114:33;1096:13;1114:33;;1159:126;1224:20;;1249:31;1224:20;1249:31;;1292:241;;1396:2;1384:9;1375:7;1371:23;1367:32;1364:2;;;1412:1;1409;1402:12;1364:2;1447:1;1464:53;1509:7;1489:9;1464:53;;1540:1389;;;;;;;;;;;1805:3;1793:9;1784:7;1780:23;1776:33;1773:2;;;1822:1;1819;1812:12;1773:2;1857:1;1874:61;1927:7;1907:9;1874:61;;;1864:71;;1836:105;1972:2;1990:53;2035:7;2026:6;2015:9;2011:22;1990:53;;;1980:63;;1951:98;2080:2;2098:53;2143:7;2134:6;2123:9;2119:22;2098:53;;;2088:63;;2059:98;2188:2;2206:53;2251:7;2242:6;2231:9;2227:22;2206:53;;;2196:63;;2167:98;2296:3;2315:53;2360:7;2351:6;2340:9;2336:22;2315:53;;;2305:63;;2275:99;2405:3;2424:53;2469:7;2460:6;2449:9;2445:22;2424:53;;;2414:63;;2384:99;2514:3;2533:53;2578:7;2569:6;2558:9;2554:22;2533:53;;;2523:63;;2493:99;2623:3;2642:53;2687:7;2678:6;2667:9;2663:22;2642:53;;;2632:63;;2602:99;2732:3;2751:53;2796:7;2787:6;2776:9;2772:22;2751:53;;;2741:63;;2711:99;2841:3;2860:53;2905:7;2896:6;2885:9;2881:22;2860:53;;;2850:63;;2820:99;1767:1162;;;;;;;;;;;;;;2936:366;;;3057:2;3045:9;3036:7;3032:23;3028:32;3025:2;;;3073:1;3070;3063:12;3025:2;3108:1;3125:53;3170:7;3150:9;3125:53;;;3115:63;;3087:97;3215:2;3233:53;3278:7;3269:6;3258:9;3254:22;3233:53;;;3223:63;;3194:98;3019:283;;;;;;3309:491;;;;3447:2;3435:9;3426:7;3422:23;3418:32;3415:2;;;3463:1;3460;3453:12;3415:2;3498:1;3515:53;3560:7;3540:9;3515:53;;;3505:63;;3477:97;3605:2;3623:53;3668:7;3659:6;3648:9;3644:22;3623:53;;;3613:63;;3584:98;3713:2;3731:53;3776:7;3767:6;3756:9;3752:22;3731:53;;;3721:63;;3692:98;3409:391;;;;;;3807:366;;;3928:2;3916:9;3907:7;3903:23;3899:32;3896:2;;;3944:1;3941;3934:12;3896:2;3979:1;3996:53;4041:7;4021:9;3996:53;;;3986:63;;3958:97;4086:2;4104:53;4149:7;4140:6;4129:9;4125:22;4104:53;;4180:257;;4292:2;4280:9;4271:7;4267:23;4263:32;4260:2;;;4308:1;4305;4298:12;4260:2;4343:1;4360:61;4413:7;4393:9;4360:61;;4444:393;;;4573:2;4561:9;4552:7;4548:23;4544:32;4541:2;;;4589:1;4586;4579:12;4541:2;4624:1;4641:61;4694:7;4674:9;4641:61;;;4631:71;;4603:105;4739:2;4757:64;4813:7;4804:6;4793:9;4789:22;4757:64;;4844:699;;;;5000:2;4988:9;4979:7;4975:23;4971:32;4968:2;;;5016:1;5013;5006:12;4968:2;5051:31;;5102:18;5091:30;;5088:2;;;5134:1;5131;5124:12;5088:2;5154:63;5209:7;5200:6;5189:9;5185:22;5154:63;;;5144:73;;5030:193;5282:2;5271:9;5267:18;5254:32;5306:18;5298:6;5295:30;5292:2;;;5338:1;5335;5328:12;5292:2;5358:63;5413:7;5404:6;5393:9;5389:22;5358:63;;;5348:73;;5233:194;5458:2;5476:51;5519:7;5510:6;5499:9;5495:22;5476:51;;5550:241;;5654:2;5642:9;5633:7;5629:23;5625:32;5622:2;;;5670:1;5667;5660:12;5622:2;5705:1;5722:53;5767:7;5747:9;5722:53;;5798:263;;5913:2;5901:9;5892:7;5888:23;5884:32;5881:2;;;5929:1;5926;5919:12;5881:2;5964:1;5981:64;6037:7;6017:9;5981:64;;6068:491;;;;6206:2;6194:9;6185:7;6181:23;6177:32;6174:2;;;6222:1;6219;6212:12;6174:2;6257:1;6274:53;6319:7;6299:9;6274:53;;;6264:63;;6236:97;6364:2;6382:53;6427:7;6418:6;6407:9;6403:22;6382:53;;6566:142;6657:45;6696:5;6657:45;;;6652:3;6645:58;6639:69;;;6715:113;6798:24;6816:5;6798:24;;6835:104;6912:21;6927:5;6912:21;;6946:152;7042:50;7086:5;7042:50;;7105:347;;7217:39;7250:5;7217:39;;;7268:71;7332:6;7327:3;7268:71;;;7261:78;;7344:52;7389:6;7384:3;7377:4;7370:5;7366:16;7344:52;;;7417:29;7439:6;7417:29;;;7408:39;;;;7197:255;-1:-1;;;7197:255;7460:372;;7620:67;7684:2;7679:3;7620:67;;;7720:34;7700:55;;-1:-1;;;7784:2;7775:12;;7768:27;7823:2;7814:12;;7606:226;-1:-1;;7606:226;7841:320;;8001:67;8065:2;8060:3;8001:67;;;-1:-1;;;8081:43;;8152:2;8143:12;;7987:174;-1:-1;;7987:174;8170:312;;8330:67;8394:2;8389:3;8330:67;;;-1:-1;;;8410:35;;8473:2;8464:12;;8316:166;-1:-1;;8316:166;8491:375;;8651:67;8715:2;8710:3;8651:67;;;8751:34;8731:55;;-1:-1;;;8815:2;8806:12;;8799:30;8857:2;8848:12;;8637:229;-1:-1;;8637:229;8875:371;;9035:67;9099:2;9094:3;9035:67;;;9135:34;9115:55;;-1:-1;;;9199:2;9190:12;;9183:26;9237:2;9228:12;;9021:225;-1:-1;;9021:225;9255:315;;9415:67;9479:2;9474:3;9415:67;;;-1:-1;;;9495:38;;9561:2;9552:12;;9401:169;-1:-1;;9401:169;9579:327;;9739:67;9803:2;9798:3;9739:67;;;9839:29;9819:50;;9897:2;9888:12;;9725:181;-1:-1;;9725:181;9915:317;;10075:67;10139:2;10134:3;10075:67;;;-1:-1;;;10155:40;;10223:2;10214:12;;10061:171;-1:-1;;10061:171;10241:320;;10401:67;10465:2;10460:3;10401:67;;;-1:-1;;;10481:43;;10552:2;10543:12;;10387:174;-1:-1;;10387:174;10570:316;;10730:67;10794:2;10789:3;10730:67;;;-1:-1;;;10810:39;;10877:2;10868:12;;10716:170;-1:-1;;10716:170;10895:384;;11055:67;11119:2;11114:3;11055:67;;;11155:34;11135:55;;-1:-1;;;11219:2;11210:12;;11203:39;11270:2;11261:12;;11041:238;-1:-1;;11041:238;11288:311;;11448:67;11512:2;11507:3;11448:67;;;-1:-1;;;11528:34;;11590:2;11581:12;;11434:165;-1:-1;;11434:165;11608:332;;11768:67;11832:2;11827:3;11768:67;;;11868:34;11848:55;;11931:2;11922:12;;11754:186;-1:-1;;11754:186;11949:383;;12109:67;12173:2;12168:3;12109:67;;;12209:34;12189:55;;-1:-1;;;12273:2;12264:12;;12257:38;12323:2;12314:12;;12095:237;-1:-1;;12095:237;12341:370;;12501:67;12565:2;12560:3;12501:67;;;12601:34;12581:55;;-1:-1;;;12665:2;12656:12;;12649:25;12702:2;12693:12;;12487:224;-1:-1;;12487:224;12720:374;;12880:67;12944:2;12939:3;12880:67;;;12980:34;12960:55;;-1:-1;;;13044:2;13035:12;;13028:29;13085:2;13076:12;;12866:228;-1:-1;;12866:228;13103:313;;13263:67;13327:2;13322:3;13263:67;;;-1:-1;;;13343:36;;13407:2;13398:12;;13249:167;-1:-1;;13249:167;13425:296;;13602:83;13683:1;13678:3;13602:83;;13730:373;;13890:67;13954:2;13949:3;13890:67;;;13990:34;13970:55;;-1:-1;;;14054:2;14045:12;;14038:28;14094:2;14085:12;;13876:227;-1:-1;;13876:227;14112:316;;14272:67;14336:2;14331:3;14272:67;;;-1:-1;;;14352:39;;14419:2;14410:12;;14258:170;-1:-1;;14258:170;14437:313;;14597:67;14661:2;14656:3;14597:67;;;-1:-1;;;14677:36;;14741:2;14732:12;;14583:167;-1:-1;;14583:167;14759:378;;14919:67;14983:2;14978:3;14919:67;;;15019:34;14999:55;;-1:-1;;;15083:2;15074:12;;15067:33;15128:2;15119:12;;14905:232;-1:-1;;14905:232;15146:331;;15306:67;15370:2;15365:3;15306:67;;;15406:33;15386:54;;15468:2;15459:12;;15292:185;-1:-1;;15292:185;15485:113;15568:24;15586:5;15568:24;;15605:107;15684:22;15700:5;15684:22;;15719:370;;15917:147;16060:3;15917:147;;16096:213;16214:2;16199:18;;16228:71;16203:9;16272:6;16228:71;;16316:229;16442:2;16427:18;;16456:79;16431:9;16508:6;16456:79;;16552:467;16742:2;16727:18;;16756:79;16731:9;16808:6;16756:79;;;16846:80;16922:2;16911:9;16907:18;16898:6;16846:80;;;16937:72;17005:2;16994:9;16990:18;16981:6;16937:72;;17026:451;17208:2;17193:18;;17222:79;17197:9;17274:6;17222:79;;;17312:72;17380:2;17369:9;17365:18;17356:6;17312:72;;17484:340;17638:2;17623:18;;17652:79;17627:9;17704:6;17652:79;;;17742:72;17810:2;17799:9;17795:18;17786:6;17742:72;;17831:324;17977:2;17962:18;;17991:71;17966:9;18035:6;17991:71;;18162:201;18274:2;18259:18;;18288:65;18263:9;18326:6;18288:65;;18370:350;18529:2;18514:18;;18543:84;18518:9;18600:6;18543:84;;18727:301;18865:2;18879:47;;;18850:18;;18940:78;18850:18;19004:6;18940:78;;19035:407;19226:2;19240:47;;;19211:18;;19301:131;19211:18;19301:131;;19449:407;19640:2;19654:47;;;19625:18;;19715:131;19625:18;19715:131;;19863:407;20054:2;20068:47;;;20039:18;;20129:131;20039:18;20129:131;;20277:407;20468:2;20482:47;;;20453:18;;20543:131;20453:18;20543:131;;20691:407;20882:2;20896:47;;;20867:18;;20957:131;20867:18;20957:131;;21105:407;21296:2;21310:47;;;21281:18;;21371:131;21281:18;21371:131;;21519:407;21710:2;21724:47;;;21695:18;;21785:131;21695:18;21785:131;;21933:407;22124:2;22138:47;;;22109:18;;22199:131;22109:18;22199:131;;22347:407;22538:2;22552:47;;;22523:18;;22613:131;22523:18;22613:131;;22761:407;22952:2;22966:47;;;22937:18;;23027:131;22937:18;23027:131;;23175:407;23366:2;23380:47;;;23351:18;;23441:131;23351:18;23441:131;;23589:407;23780:2;23794:47;;;23765:18;;23855:131;23765:18;23855:131;;24003:407;24194:2;24208:47;;;24179:18;;24269:131;24179:18;24269:131;;24417:407;24608:2;24622:47;;;24593:18;;24683:131;24593:18;24683:131;;24831:407;25022:2;25036:47;;;25007:18;;25097:131;25007:18;25097:131;;25245:407;25436:2;25450:47;;;25421:18;;25511:131;25421:18;25511:131;;25659:407;25850:2;25864:47;;;25835:18;;25925:131;25835:18;25925:131;;26073:407;26264:2;26278:47;;;26249:18;;26339:131;26249:18;26339:131;;26487:407;26678:2;26692:47;;;26663:18;;26753:131;26663:18;26753:131;;26901:407;27092:2;27106:47;;;27077:18;;27167:131;27077:18;27167:131;;27315:407;27506:2;27520:47;;;27491:18;;27581:131;27491:18;27581:131;;27729:407;27920:2;27934:47;;;27905:18;;27995:131;27905:18;27995:131;;28143:213;28261:2;28246:18;;28275:71;28250:9;28319:6;28275:71;;28363:324;28509:2;28494:18;;28523:71;28498:9;28567:6;28523:71;;28694:435;28868:2;28853:18;;28882:71;28857:9;28926:6;28882:71;;;28964:72;29032:2;29021:9;29017:18;29008:6;28964:72;;29136:535;29332:3;29317:19;;29347:71;29321:9;29391:6;29347:71;;;29429:72;29497:2;29486:9;29482:18;29473:6;29429:72;;;29512;29580:2;29569:9;29565:18;29556:6;29512:72;;;29595:66;29657:2;29646:9;29642:18;29633:6;29595:66;;29678:547;29880:3;29865:19;;29895:71;29869:9;29939:6;29895:71;;;29977:72;30045:2;30034:9;30030:18;30021:6;29977:72;;;30060;30128:2;30117:9;30113:18;30104:6;30060:72;;;30143;30211:2;30200:9;30196:18;30187:6;30143:72;;30232:205;30346:2;30331:18;;30360:67;30335:9;30400:6;30360:67;;30444:256;30506:2;30500:9;30532:17;;;30607:18;30592:34;;30628:22;;;30589:62;30586:2;;;30664:1;30661;30654:12;30586:2;30680;30673:22;30484:216;;-1:-1;30484:216;30707:322;;30851:18;30843:6;30840:30;30837:2;;;30883:1;30880;30873:12;30837:2;-1:-1;31014:4;30950;30927:17;;;;-1:-1;;30923:33;31004:15;;30774:255;31036:122;31124:12;;31095:63;31166:144;31301:3;31279:31;-1:-1;31279:31;31319:163;31422:19;;;31471:4;31462:14;;31415:67;31490:91;;31552:24;31570:5;31552:24;;31694:85;31760:13;31753:21;;31736:43;31786:121;-1:-1;;;;;31848:54;;31831:76;31993:81;32064:4;32053:16;;32036:38;32081:129;;32168:37;32199:5;32217:147;;32309:50;32353:5;32309:50;;32743:145;32824:6;32819:3;32814;32801:30;-1:-1;32880:1;32862:16;;32855:27;32794:94;32897:268;32962:1;32969:101;32983:6;32980:1;32977:13;32969:101;;;33050:11;;;33044:18;33031:11;;;33024:39;33005:2;32998:10;32969:101;;;33085:6;33082:1;33079:13;33076:2;;;-1:-1;;33150:1;33132:16;;33125:27;32946:219;33173:97;33261:2;33241:14;-1:-1;;33237:28;;33221:49;33278:117;33347:24;33365:5;33347:24;;;33340:5;33337:35;33327:2;;33386:1;33383;33376:12;33542:111;33608:21;33623:5;33608:21;;33660:117;33729:24;33747:5;33729:24;;33784:113;33851:22;33867:5;33851:22;
Swarm Source
bzzr://1b55f4e85d25ec19534b6dce9285d84f0ee17accbec39864cf4ae689a3c46ae8
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.