Overview
MOVR Balance
MOVR Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 6,683 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Swap To Base | 1210830 | 1207 days ago | IN | 0 MOVR | 0.00026443 | ||||
Swap From Base | 1210824 | 1207 days ago | IN | 0 MOVR | 0.00031697 | ||||
Swap From Base | 1204877 | 1208 days ago | IN | 0 MOVR | 0.00153847 | ||||
Swap To Base | 1204875 | 1208 days ago | IN | 0 MOVR | 0.00120244 | ||||
Swap From Base | 1204333 | 1208 days ago | IN | 0 MOVR | 0.00165803 | ||||
Swap To Base | 1204333 | 1208 days ago | IN | 0 MOVR | 0.00133898 | ||||
Swap From Base | 1195674 | 1209 days ago | IN | 0 MOVR | 0.00163241 | ||||
Swap To Base | 1195673 | 1209 days ago | IN | 0 MOVR | 0.00131542 | ||||
Swap From Base | 1194596 | 1209 days ago | IN | 0 MOVR | 0.00172841 | ||||
Swap To Base | 1194596 | 1209 days ago | IN | 0 MOVR | 0.00141834 | ||||
Swap From Base | 1194014 | 1210 days ago | IN | 0 MOVR | 0.00021766 | ||||
Swap To Base | 1194014 | 1210 days ago | IN | 0 MOVR | 0.00019922 | ||||
Swap From Base | 1185444 | 1211 days ago | IN | 0 MOVR | 0.00157672 | ||||
Swap To Base | 1185443 | 1211 days ago | IN | 0 MOVR | 0.00122268 | ||||
Swap From Base | 1185014 | 1211 days ago | IN | 0 MOVR | 0.00175568 | ||||
Swap To Base | 1185014 | 1211 days ago | IN | 0 MOVR | 0.00142223 | ||||
Swap From Base | 1180455 | 1212 days ago | IN | 0 MOVR | 0.0015491 | ||||
Swap To Base | 1180453 | 1212 days ago | IN | 0 MOVR | 0.00121377 | ||||
Swap From Base | 1177861 | 1212 days ago | IN | 0 MOVR | 0.00167751 | ||||
Swap To Base | 1177861 | 1212 days ago | IN | 0 MOVR | 0.00133131 | ||||
Swap From Base | 1177857 | 1212 days ago | IN | 0 MOVR | 0.00167751 | ||||
Swap To Base | 1177857 | 1212 days ago | IN | 0 MOVR | 0.00133131 | ||||
Swap From Base | 1176959 | 1212 days ago | IN | 0 MOVR | 0.00163921 | ||||
Swap To Base | 1176959 | 1212 days ago | IN | 0 MOVR | 0.00131845 | ||||
Swap From Base | 1176954 | 1212 days ago | IN | 0 MOVR | 0.0017352 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
StableSwapRouter
Compiler Version
v0.8.4+commit.c7e474f2
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "../interfaces/IStableSwap.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; contract StableSwapRouter { using SafeERC20 for IERC20; function convert( IStableSwap fromPool, IStableSwap toPool, uint256 amount, uint256 minToMint, uint256 deadline ) external returns (uint256) { uint256 fromPoolLength = fromPool.getNumberOfTokens(); uint256 toPoolLength = toPool.getNumberOfTokens(); require(address(fromPool) != address(toPool), "fromPool = toPool"); require(fromPoolLength == toPoolLength, "poolTokensLengthMissmatch"); IERC20 fromToken = fromPool.getLpToken(); IERC20 toToken = toPool.getLpToken(); uint256[] memory min_amounts = new uint256[](fromPoolLength); // validate token for (uint8 i = 0; i < fromPoolLength; i++) { IERC20 coin = fromPool.getToken(i); toPool.getTokenIndex(address(coin)); } fromToken.transferFrom(msg.sender, address(this), amount); fromToken.safeIncreaseAllowance(address(fromPool), amount); fromPool.removeLiquidity(amount, min_amounts, deadline); uint256[] memory meta_amounts = new uint256[](toPoolLength); for (uint8 i = 0; i < toPoolLength; i++) { IERC20 coin = toPool.getToken(i); uint256 addBalance = coin.balanceOf(address(this)); coin.safeIncreaseAllowance(address(toPool), addBalance); meta_amounts[i] = addBalance; } toPool.addLiquidity(meta_amounts, minToMint, deadline); uint256 lpAmount = toToken.balanceOf(address(this)); toToken.transfer(msg.sender, lpAmount); return lpAmount; } function addLiquidity( IStableSwap pool, IStableSwap basePool, uint256[] memory meta_amounts, uint256[] memory base_amounts, uint256 minToMint, uint256 deadline ) external returns (uint256) { IERC20 token = IERC20(pool.getLpToken()); require(base_amounts.length == basePool.getNumberOfTokens(), "invalidBaseAmountsLength"); require(meta_amounts.length == pool.getNumberOfTokens(), "invalidMetaAmountsLength"); bool deposit_base = false; for (uint8 i = 0; i < base_amounts.length; i++) { uint256 amount = base_amounts[i]; if (amount > 0) { deposit_base = true; IERC20 coin = basePool.getToken(i); coin.safeTransferFrom(msg.sender, address(this), amount); uint256 transferred = coin.balanceOf(address(this)); coin.safeIncreaseAllowance(address(basePool), transferred); base_amounts[i] = transferred; } } if (deposit_base) { basePool.addLiquidity(base_amounts, 0, deadline); } for (uint8 i = 0; i < meta_amounts.length; i++) { IERC20 coin = pool.getToken(i); if (meta_amounts[i] > 0) { coin.safeTransferFrom(msg.sender, address(this), meta_amounts[i]); } uint256 transferred = coin.balanceOf(address(this)); coin.safeIncreaseAllowance(address(pool), transferred); meta_amounts[i] = transferred; } pool.addLiquidity(meta_amounts, minToMint, deadline); uint256 lpAmount = token.balanceOf(address(this)); token.transfer(msg.sender, lpAmount); return lpAmount; } function removeLiquidity( IStableSwap pool, IStableSwap basePool, uint256 _amount, uint256[] calldata min_amounts_meta, uint256[] calldata min_amounts_base, uint256 deadline ) external returns (uint256[] memory amounts, uint256[] memory base_amounts) { IERC20 token = pool.getLpToken(); IERC20 baseToken = basePool.getLpToken(); token.transferFrom(msg.sender, address(this), _amount); token.safeIncreaseAllowance(address(pool), _amount); pool.removeLiquidity(_amount, min_amounts_meta, deadline); uint256 _base_amount = baseToken.balanceOf(address(this)); baseToken.safeIncreaseAllowance(address(basePool), _base_amount); basePool.removeLiquidity(_base_amount, min_amounts_base, deadline); // Transfer all coins out amounts = new uint256[](pool.getNumberOfTokens()); for (uint8 i = 0; i < pool.getNumberOfTokens(); i++) { IERC20 coin = pool.getToken(i); amounts[i] = coin.balanceOf(address(this)); if (amounts[i] > 0) { coin.safeTransfer(msg.sender, amounts[i]); } } base_amounts = new uint256[](basePool.getNumberOfTokens()); for (uint8 i = 0; i < basePool.getNumberOfTokens(); i++) { IERC20 coin = basePool.getToken(i); base_amounts[i] = coin.balanceOf(address(this)); if (base_amounts[i] > 0) { coin.safeTransfer(msg.sender, base_amounts[i]); } } } function removeBaseLiquidityOneToken( IStableSwap pool, IStableSwap basePool, uint256 _token_amount, uint8 i, uint256 _min_amount, uint256 deadline ) external returns (uint256) { IERC20 token = pool.getLpToken(); IERC20 baseToken = basePool.getLpToken(); uint8 baseTokenIndex = pool.getTokenIndex(address(baseToken)); token.transferFrom(msg.sender, address(this), _token_amount); token.approve(address(pool), _token_amount); pool.removeLiquidityOneToken(_token_amount, baseTokenIndex, 0, deadline); uint256 _base_amount = baseToken.balanceOf(address(this)); baseToken.approve(address(basePool), _base_amount); basePool.removeLiquidityOneToken(_base_amount, i, _min_amount, deadline); IERC20 coin = basePool.getToken(i); uint256 coin_amount = coin.balanceOf(address(this)); coin.safeTransfer(msg.sender, coin_amount); return coin_amount; } function swapFromBase( IStableSwap pool, IStableSwap basePool, uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx, uint256 minDy, uint256 deadline ) external returns (uint256) { IERC20 baseToken = basePool.getLpToken(); uint8 baseTokenIndex = pool.getTokenIndex(address(baseToken)); uint256[] memory base_amounts = new uint256[](basePool.getNumberOfTokens()); base_amounts[tokenIndexFrom] = dx; IERC20 coin = basePool.getToken(tokenIndexFrom); coin.safeTransferFrom(msg.sender, address(this), dx); coin.safeIncreaseAllowance(address(basePool), dx); uint256 baseLpAmount = basePool.addLiquidity(base_amounts, 0, deadline); if (baseTokenIndex != tokenIndexTo) { baseToken.safeIncreaseAllowance(address(pool), baseLpAmount); pool.swap(baseTokenIndex, tokenIndexTo, baseLpAmount, minDy, deadline); } IERC20 coinTo = pool.getToken(tokenIndexTo); uint256 amountOut = coinTo.balanceOf(address(this)); coinTo.safeTransfer(msg.sender, amountOut); return amountOut; } function swapToBase( IStableSwap pool, IStableSwap basePool, uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx, uint256 minDy, uint256 deadline ) external returns (uint256) { IERC20 baseToken = basePool.getLpToken(); uint8 baseTokenIndex = pool.getTokenIndex(address(baseToken)); IERC20 coin = pool.getToken(tokenIndexFrom); coin.safeTransferFrom(msg.sender, address(this), dx); uint256 tokenLPAmount = dx; if (baseTokenIndex != tokenIndexFrom) { coin.safeIncreaseAllowance(address(pool), dx); tokenLPAmount = pool.swap(tokenIndexFrom, baseTokenIndex, dx, 0, deadline); } baseToken.safeIncreaseAllowance(address(basePool), tokenLPAmount); basePool.removeLiquidityOneToken(tokenLPAmount, tokenIndexTo, minDy, deadline); IERC20 coinTo = basePool.getToken(tokenIndexTo); uint256 amountOut = coinTo.balanceOf(address(this)); coinTo.safeTransfer(msg.sender, amountOut); return amountOut; } // =========== VIEW =========== function calculateConvert( IStableSwap fromPool, IStableSwap toPool, uint256 amount ) external view returns (uint256) { uint256 fromPoolLength = fromPool.getNumberOfTokens(); uint256[] memory amounts = fromPool.calculateRemoveLiquidity(amount); uint256[] memory meta_amounts = new uint256[](fromPoolLength); for (uint8 i = 0; i < fromPoolLength; i++) { IERC20 fromCoin = fromPool.getToken(i); uint256 toCoinIndex = toPool.getTokenIndex(address(fromCoin)); meta_amounts[toCoinIndex] = amounts[i]; } return toPool.calculateTokenAmount(meta_amounts, true); } function calculateTokenAmount( IStableSwap pool, IStableSwap basePool, uint256[] memory meta_amounts, uint256[] memory base_amounts, bool is_deposit ) external view returns (uint256) { IERC20 baseToken = basePool.getLpToken(); uint8 baseTokenIndex = pool.getTokenIndex(address(baseToken)); uint256 _base_tokens = basePool.calculateTokenAmount(base_amounts, is_deposit); meta_amounts[baseTokenIndex] = meta_amounts[baseTokenIndex] + _base_tokens; return pool.calculateTokenAmount(meta_amounts, is_deposit); } function calculateRemoveLiquidity( IStableSwap pool, IStableSwap basePool, uint256 amount ) external view returns (uint256[] memory meta_amounts, uint256[] memory base_amounts) { IERC20 baseToken = basePool.getLpToken(); uint8 baseTokenIndex = pool.getTokenIndex(address(baseToken)); meta_amounts = pool.calculateRemoveLiquidity(amount); uint256 lpAmount = meta_amounts[baseTokenIndex]; meta_amounts[baseTokenIndex] = 0; base_amounts = basePool.calculateRemoveLiquidity(lpAmount); } function calculateRemoveBaseLiquidityOneToken( IStableSwap pool, IStableSwap basePool, uint256 _token_amount, uint8 iBase ) external view returns (uint256 availableTokenAmount) { IERC20 baseToken = basePool.getLpToken(); uint8 baseTokenIndex = pool.getTokenIndex(address(baseToken)); uint256 _base_tokens = pool.calculateRemoveLiquidityOneToken(_token_amount, baseTokenIndex); availableTokenAmount = basePool.calculateRemoveLiquidityOneToken(_base_tokens, iBase); } function calculateSwapFromBase( IStableSwap pool, IStableSwap basePool, uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx ) external view returns (uint256) { IERC20 baseToken = basePool.getLpToken(); uint8 baseTokenIndex = pool.getTokenIndex(address(baseToken)); uint256[] memory base_amounts = new uint256[](basePool.getNumberOfTokens()); base_amounts[tokenIndexFrom] = dx; uint256 baseLpAmount = basePool.calculateTokenAmount(base_amounts, true); if (baseTokenIndex == tokenIndexTo) { return baseLpAmount; } return pool.calculateSwap(baseTokenIndex, tokenIndexTo, baseLpAmount); } function calculateSwapToBase( IStableSwap pool, IStableSwap basePool, uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx ) external view returns (uint256) { IERC20 baseToken = basePool.getLpToken(); uint8 baseTokenIndex = pool.getTokenIndex(address(baseToken)); uint256 tokenLPAmount = dx; if (baseTokenIndex != tokenIndexFrom) { tokenLPAmount = pool.calculateSwap(tokenIndexFrom, baseTokenIndex, dx); } return basePool.calculateRemoveLiquidityOneToken(tokenLPAmount, tokenIndexTo); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.4; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "../interfaces/IRewarder.sol"; /* OneSwapChef is a fork from Sushi's MiniChef v2 */ contract OneSwapChef is Ownable { using SafeERC20 for IERC20; struct UserInfo { uint256 amount; int256 rewardDebt; } struct PoolInfo { uint256 accRewardPerShare; uint256 lastRewardTime; uint256 allocPoint; } IERC20 public reward; /// @notice Info of each MCV2 pool. PoolInfo[] public poolInfo; /// @notice Address of the LP token for each MCV2 pool. IERC20[] public lpToken; /// @notice Address of each `IRewarder` contract in MCV2. IRewarder[] public rewarder; /// @notice Info of each user that stakes LP tokens. mapping(uint256 => mapping(address => UserInfo)) public userInfo; /// @dev Total allocation points. Must be the sum of all allocation points in all pools. uint256 public totalAllocPoint = 0; uint256 public rewardPerSecond; uint256 private constant ACC_REWARD_PRECISION = 1e12; constructor(IERC20 _reward) { reward = _reward; } /* ========== PUBLIC FUNCTIONS ========== */ /// @notice Returns the number of MCV2 pools. function poolLength() public view returns (uint256 pools) { pools = poolInfo.length; } /// @notice View function to see pending reward on frontend. /// @param _pid The index of the pool. See `poolInfo`. /// @param _user Address of user. /// @return pending reward for a given user. function pendingReward(uint256 _pid, address _user) external view returns (uint256 pending) { PoolInfo memory pool = poolInfo[_pid]; UserInfo storage user = userInfo[_pid][_user]; uint256 accRewardPerShare = pool.accRewardPerShare; uint256 lpSupply = lpToken[_pid].balanceOf(address(this)); if (block.timestamp > pool.lastRewardTime && lpSupply != 0) { uint256 time = block.timestamp - pool.lastRewardTime; uint256 rewardAmount = (time * rewardPerSecond * pool.allocPoint) / totalAllocPoint; accRewardPerShare += (rewardAmount * ACC_REWARD_PRECISION) / lpSupply; } pending = uint256(int256((user.amount * accRewardPerShare) / ACC_REWARD_PRECISION) - user.rewardDebt); } /// @notice Update reward variables of the given pool. /// @param pid The index of the pool. See `poolInfo`. /// @return pool Returns the pool that was updated. function updatePool(uint256 pid) public returns (PoolInfo memory pool) { pool = poolInfo[pid]; if (block.timestamp > pool.lastRewardTime) { uint256 lpSupply = lpToken[pid].balanceOf(address(this)); if (lpSupply > 0) { uint256 time = block.timestamp - pool.lastRewardTime; uint256 rewardAmount = (time * rewardPerSecond * pool.allocPoint) / totalAllocPoint; pool.accRewardPerShare += (rewardAmount * ACC_REWARD_PRECISION) / lpSupply; } pool.lastRewardTime = block.timestamp; poolInfo[pid] = pool; emit LogUpdatePool(pid, pool.lastRewardTime, lpSupply, pool.accRewardPerShare); } } /// @notice Update reward variables for all pools. Be careful of gas spending! /// @param pids Pool IDs of all to be updated. Make sure to update all active pools. function massUpdatePools(uint256[] calldata pids) external { uint256 len = pids.length; for (uint256 i = 0; i < len; ++i) { updatePool(pids[i]); } } /// @notice Deposit LP tokens to MCV2 for reward allocation. /// @param pid The index of the pool. See `poolInfo`. /// @param amount LP token amount to deposit. /// @param to The receiver of `amount` deposit benefit. function deposit( uint256 pid, uint256 amount, address to ) public { PoolInfo memory pool = updatePool(pid); UserInfo storage user = userInfo[pid][to]; // Effects user.amount += amount; user.rewardDebt += int256((amount * pool.accRewardPerShare) / ACC_REWARD_PRECISION); // Interactions IRewarder _rewarder = rewarder[pid]; if (address(_rewarder) != address(0)) { _rewarder.onReward(pid, to, to, 0, user.amount); } lpToken[pid].safeTransferFrom(msg.sender, address(this), amount); emit Deposit(msg.sender, pid, amount, to); } /// @notice Withdraw LP tokens from MCV2. /// @param pid The index of the pool. See `poolInfo`. /// @param amount LP token amount to withdraw. /// @param to Receiver of the LP tokens. function withdraw( uint256 pid, uint256 amount, address to ) public { PoolInfo memory pool = updatePool(pid); UserInfo storage user = userInfo[pid][msg.sender]; // Effects user.rewardDebt -= int256((amount * pool.accRewardPerShare) / ACC_REWARD_PRECISION); user.amount -= amount; // Interactions IRewarder _rewarder = rewarder[pid]; if (address(_rewarder) != address(0)) { _rewarder.onReward(pid, msg.sender, to, 0, user.amount); } lpToken[pid].safeTransfer(to, amount); emit Withdraw(msg.sender, pid, amount, to); } /// @notice Harvest proceeds for transaction sender to `to`. /// @param pid The index of the pool. See `poolInfo`. /// @param to Receiver of rewards. function harvest(uint256 pid, address to) public { PoolInfo memory pool = updatePool(pid); UserInfo storage user = userInfo[pid][msg.sender]; int256 accumulatedReward = int256((user.amount * pool.accRewardPerShare) / ACC_REWARD_PRECISION); uint256 _pendingReward = uint256(accumulatedReward - user.rewardDebt); // Effects user.rewardDebt = accumulatedReward; // Interactions if (_pendingReward != 0) { reward.safeTransfer(to, _pendingReward); } IRewarder _rewarder = rewarder[pid]; if (address(_rewarder) != address(0)) { _rewarder.onReward(pid, msg.sender, to, _pendingReward, user.amount); } emit Harvest(msg.sender, pid, _pendingReward); } /// @notice Withdraw LP tokens from MCV2 and harvest proceeds for transaction sender to `to`. /// @param pid The index of the pool. See `poolInfo`. /// @param amount LP token amount to withdraw. /// @param to Receiver of the LP tokens and rewards. function withdrawAndHarvest( uint256 pid, uint256 amount, address to ) public { PoolInfo memory pool = updatePool(pid); UserInfo storage user = userInfo[pid][msg.sender]; int256 accumulatedReward = int256((user.amount * pool.accRewardPerShare) / ACC_REWARD_PRECISION); uint256 _pendingReward = uint256(accumulatedReward - user.rewardDebt); // Effects user.rewardDebt = accumulatedReward - int256((amount * pool.accRewardPerShare) / ACC_REWARD_PRECISION); user.amount -= amount; // Interactions if (_pendingReward != 0) { reward.safeTransfer(to, _pendingReward); } IRewarder _rewarder = rewarder[pid]; if (address(_rewarder) != address(0)) { _rewarder.onReward(pid, msg.sender, to, _pendingReward, user.amount); } lpToken[pid].safeTransfer(to, amount); emit Withdraw(msg.sender, pid, amount, to); emit Harvest(msg.sender, pid, _pendingReward); } /// @notice Withdraw without caring about rewards. EMERGENCY ONLY. /// @param pid The index of the pool. See `poolInfo`. /// @param to Receiver of the LP tokens. function emergencyWithdraw(uint256 pid, address to) public { UserInfo storage user = userInfo[pid][msg.sender]; uint256 amount = user.amount; user.amount = 0; user.rewardDebt = 0; IRewarder _rewarder = rewarder[pid]; if (address(_rewarder) != address(0)) { _rewarder.onReward(pid, msg.sender, to, 0, 0); } // Note: transfer can fail or succeed if `amount` is zero. lpToken[pid].safeTransfer(to, amount); emit EmergencyWithdraw(msg.sender, pid, amount, to); } function harvestAllRewards(address to) external { uint256 length = poolInfo.length; for (uint256 pid = 0; pid < length; ++pid) { if (userInfo[pid][msg.sender].amount > 0) { harvest(pid, to); } } } /* ========== INTERNAL FUNCTIONS ========== */ function checkPoolDuplicate(IERC20 _lpToken) internal view { uint256 length = poolInfo.length; for (uint256 pid = 0; pid < length; ++pid) { require(lpToken[pid] != _lpToken, "add: existing pool?"); } } /* ========== RESTRICTED FUNCTIONS ========== */ /// @notice Add a new LP to the pool. Can only be called by the owner. /// DO NOT add the same LP token more than once. Rewards will be messed up if you do. /// @param allocPoint AP of the new pool. /// @param _lpToken Address of the LP ERC-20 token. /// @param _rewarder Address of the rewarder delegate. function add( uint256 allocPoint, IERC20 _lpToken, IRewarder _rewarder ) public onlyOwner { checkPoolDuplicate(_lpToken); totalAllocPoint += allocPoint; lpToken.push(_lpToken); rewarder.push(_rewarder); poolInfo.push(PoolInfo({allocPoint: allocPoint, lastRewardTime: block.timestamp, accRewardPerShare: 0})); emit LogPoolAddition(lpToken.length - 1, allocPoint, _lpToken, _rewarder); } /// @notice Update the given pool's reward allocation point and `IRewarder` contract. Can only be called by the owner. /// @param _pid The index of the pool. See `poolInfo`. /// @param _allocPoint New AP of the pool. /// @param _rewarder Address of the rewarder delegate. /// @param overwrite True if _rewarder should be `set`. Otherwise `_rewarder` is ignored. function set( uint256 _pid, uint256 _allocPoint, IRewarder _rewarder, bool overwrite ) public onlyOwner { totalAllocPoint = totalAllocPoint - poolInfo[_pid].allocPoint + _allocPoint; poolInfo[_pid].allocPoint = _allocPoint; if (overwrite) { rewarder[_pid] = _rewarder; } emit LogSetPool(_pid, _allocPoint, overwrite ? _rewarder : rewarder[_pid], overwrite); } /// @notice Sets the reward per second to be distributed. Can only be called by the owner. /// @param _rewardPerSecond The amount of reward to be distributed per second. function setRewardPerSecond(uint256 _rewardPerSecond) public onlyOwner { rewardPerSecond = _rewardPerSecond; emit LogRewardPerSecond(_rewardPerSecond); } /* =============== EVENTS ==================== */ event Deposit(address indexed user, uint256 indexed pid, uint256 amount, address indexed to); event Withdraw(address indexed user, uint256 indexed pid, uint256 amount, address indexed to); event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount, address indexed to); event Harvest(address indexed user, uint256 indexed pid, uint256 amount); event LogPoolAddition(uint256 indexed pid, uint256 allocPoint, IERC20 indexed lpToken, IRewarder indexed rewarder); event LogSetPool(uint256 indexed pid, uint256 allocPoint, IRewarder indexed rewarder, bool overwrite); event LogUpdatePool(uint256 indexed pid, uint256 lastRewardTime, uint256 lpSupply, uint256 accRewardPerShare); event LogRewardPerSecond(uint256 rewardPerSecond); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @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. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _setOwner(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the 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 virtual onlyOwner { _setOwner(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 virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _setOwner(newOwner); } function _setOwner(address newOwner) private { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ 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); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IRewarder { function onReward( uint256 pid, address user, address recipient, uint256 rewardAmount, uint256 newLpAmount ) external; function pendingTokens( uint256 pid, address user, uint256 rewardAmount ) external view returns (IERC20[] memory, uint256[] memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.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 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. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IStableSwap { /// EVENTS event AddLiquidity( address indexed provider, uint256[] tokenAmounts, uint256[] fees, uint256 invariant, uint256 tokenSupply ); event TokenExchange( address indexed buyer, uint256 soldId, uint256 tokensSold, uint256 boughtId, uint256 tokensBought ); event RemoveLiquidity(address indexed provider, uint256[] tokenAmounts, uint256[] fees, uint256 tokenSupply); event RemoveLiquidityOne(address indexed provider, uint256 tokenIndex, uint256 tokenAmount, uint256 coinAmount); event RemoveLiquidityImbalance( address indexed provider, uint256[] tokenAmounts, uint256[] fees, uint256 invariant, uint256 tokenSupply ); event RampA(uint256 oldA, uint256 newA, uint256 initialTime, uint256 futureTime); event StopRampA(uint256 A, uint256 timestamp); event NewFee(uint256 fee, uint256 adminFee); event CollectProtocolFee(address token, uint256 amount); event FeeControllerChanged(address newController); event FeeDistributorChanged(address newController); // pool data view functions function getLpToken() external view returns (IERC20 lpToken); function getA() external view returns (uint256); function getAPrecise() external view returns (uint256); function getToken(uint8 index) external view returns (IERC20); function getTokens() external view returns (IERC20[] memory); function getTokenIndex(address tokenAddress) external view returns (uint8); function getTokenBalance(uint8 index) external view returns (uint256); function getTokenBalances() external view returns (uint256[] memory); function getNumberOfTokens() external view returns (uint256); function getVirtualPrice() external view returns (uint256); function calculateTokenAmount(uint256[] calldata amounts, bool deposit) external view returns (uint256); function calculateSwap( uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx ) external view returns (uint256); function calculateRemoveLiquidity(uint256 amount) external view returns (uint256[] memory); function calculateRemoveLiquidityOneToken(uint256 tokenAmount, uint8 tokenIndex) external view returns (uint256 availableTokenAmount); function getAdminBalances() external view returns (uint256[] memory adminBalances); function getAdminBalance(uint8 index) external view returns (uint256); // state modifying functions function swap( uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx, uint256 minDy, uint256 deadline ) external returns (uint256); function addLiquidity( uint256[] calldata amounts, uint256 minToMint, uint256 deadline ) external returns (uint256); function removeLiquidity( uint256 amount, uint256[] calldata minAmounts, uint256 deadline ) external returns (uint256[] memory); function removeLiquidityOneToken( uint256 tokenAmount, uint8 tokenIndex, uint256 minAmount, uint256 deadline ) external returns (uint256); function removeLiquidityImbalance( uint256[] calldata amounts, uint256 maxBurnAmount, uint256 deadline ) external returns (uint256); function withdrawAdminFee() external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./LPToken.sol"; /** * StableSwap main algorithm */ library StableSwapStorage { using SafeERC20 for IERC20; event AddLiquidity( address indexed provider, uint256[] token_amounts, uint256[] fees, uint256 invariant, uint256 token_supply ); event TokenExchange( address indexed buyer, uint256 sold_id, uint256 tokens_sold, uint256 bought_id, uint256 tokens_bought ); event RemoveLiquidity(address indexed provider, uint256[] token_amounts, uint256[] fees, uint256 token_supply); event RemoveLiquidityOne(address indexed provider, uint256 index, uint256 token_amount, uint256 coin_amount); event RemoveLiquidityImbalance( address indexed provider, uint256[] token_amounts, uint256[] fees, uint256 invariant, uint256 token_supply ); uint256 public constant FEE_DENOMINATOR = 1e10; // uint256 public constant PRECISION = 1e18; /// @dev protect from division loss when run approximation loop. We cannot divide at the end because of overflow, /// so we add some (small) PRECISION when divide in each iteration uint256 public constant A_PRECISION = 100; /// @dev max iteration of converge calccuate uint256 internal constant MAX_ITERATION = 256; uint256 public constant POOL_TOKEN_COMMON_DECIMALS = 18; struct SwapStorage { IERC20[] pooledTokens; LPToken lpToken; /// @dev token i multiplier to reach POOL_TOKEN_COMMON_DECIMALS uint256[] tokenMultipliers; /// @dev effective balance which might different from token balance of the contract 'cause it hold admin fee as well uint256[] balances; /// @dev swap fee ratio. Charge on any action which move balance state far from the ideal state uint256 fee; /// @dev admin fee in ratio of swap fee. uint256 adminFee; /// @dev observation of A, multiplied with A_PRECISION uint256 initialA; uint256 futureA; uint256 initialATime; uint256 futureATime; } /** * @notice Deposit coins into the pool * @param amounts List of amounts of coins to deposit * @param minMintAmount Minimum amount of LP tokens to mint from the deposit * @return mintAmount Amount of LP tokens received by depositing */ function addLiquidity( SwapStorage storage self, uint256[] memory amounts, uint256 minMintAmount ) external returns (uint256 mintAmount) { uint256 nCoins = self.pooledTokens.length; require(amounts.length == nCoins, "invalidAmountsLength"); uint256[] memory fees = new uint256[](nCoins); uint256 _fee = _feePerToken(self); uint256 tokenSupply = self.lpToken.totalSupply(); uint256 amp = _getAPrecise(self); uint256 D0 = 0; if (tokenSupply > 0) { D0 = _getD(_xp(self.balances, self.tokenMultipliers), amp); } uint256[] memory newBalances = self.balances; for (uint256 i = 0; i < nCoins; i++) { if (tokenSupply == 0) { require(amounts[i] > 0, "initialDepositRequireAllTokens"); } // get real transfer in amount newBalances[i] += _doTransferIn(self.pooledTokens[i], amounts[i]); } uint256 D1 = _getD(_xp(newBalances, self.tokenMultipliers), amp); assert(D1 > D0); // double check if (tokenSupply == 0) { self.balances = newBalances; mintAmount = D1; } else { uint256 diff = 0; for (uint256 i = 0; i < nCoins; i++) { diff = _distance((D1 * self.balances[i]) / D0, newBalances[i]); fees[i] = (_fee * diff) / FEE_DENOMINATOR; self.balances[i] = newBalances[i] - ((fees[i] * self.adminFee) / FEE_DENOMINATOR); newBalances[i] -= fees[i]; } D1 = _getD(_xp(newBalances, self.tokenMultipliers), amp); mintAmount = (tokenSupply * (D1 - D0)) / D0; } require(mintAmount >= minMintAmount, "> slippage"); self.lpToken.mint(msg.sender, mintAmount); emit AddLiquidity(msg.sender, amounts, fees, D1, mintAmount); } function swap( SwapStorage storage self, uint256 i, uint256 j, uint256 inAmount, uint256 minOutAmount ) external returns (uint256) { IERC20 inCoin = self.pooledTokens[i]; uint256[] memory normalizedBalances = _xp(self); inAmount = _doTransferIn(inCoin, inAmount); uint256 x = normalizedBalances[i] + (inAmount * self.tokenMultipliers[i]); uint256 y = _getY(self, i, j, x, normalizedBalances); uint256 dy = normalizedBalances[j] - y - 1; // iliminate rouding errors uint256 dy_fee = (dy * self.fee) / FEE_DENOMINATOR; dy = (dy - dy_fee) / self.tokenMultipliers[j]; // denormalize require(dy >= minOutAmount, "> slippage"); uint256 _adminFee = (dy_fee * self.adminFee) / FEE_DENOMINATOR / self.tokenMultipliers[j]; // update balances self.balances[i] += inAmount; self.balances[j] -= dy + _adminFee; self.pooledTokens[j].safeTransfer(msg.sender, dy); emit TokenExchange(msg.sender, i, inAmount, j, dy); return dy; } function removeLiquidity( SwapStorage storage self, uint256 lpAmount, uint256[] memory minAmounts ) external returns (uint256[] memory amounts) { uint256 totalSupply = self.lpToken.totalSupply(); require(lpAmount <= totalSupply); uint256 nCoins = self.pooledTokens.length; uint256[] memory fees = new uint256[](nCoins); amounts = _calculateRemoveLiquidity(self, lpAmount); for (uint256 i = 0; i < amounts.length; i++) { require(amounts[i] >= minAmounts[i], "> slippage"); self.balances[i] = self.balances[i] - amounts[i]; self.pooledTokens[i].safeTransfer(msg.sender, amounts[i]); } self.lpToken.burnFrom(msg.sender, lpAmount); emit RemoveLiquidity(msg.sender, amounts, fees, totalSupply - lpAmount); } function removeLiquidityOneToken( SwapStorage storage self, uint256 lpAmount, uint256 index, uint256 minAmount ) external returns (uint256) { uint256 totalSupply = self.lpToken.totalSupply(); require(totalSupply > 0, "totalSupply = 0"); uint256 numTokens = self.pooledTokens.length; require(lpAmount <= self.lpToken.balanceOf(msg.sender), "> balance"); require(lpAmount <= totalSupply, "> totalSupply"); require(index < numTokens, "tokenNotFound"); uint256 dyFee; uint256 dy; (dy, dyFee) = _calculateRemoveLiquidityOneToken(self, lpAmount, index); require(dy >= minAmount, "> slippage"); self.balances[index] -= (dy + (dyFee * self.adminFee) / FEE_DENOMINATOR); self.lpToken.burnFrom(msg.sender, lpAmount); self.pooledTokens[index].safeTransfer(msg.sender, dy); emit RemoveLiquidityOne(msg.sender, index, lpAmount, dy); return dy; } function removeLiquidityImbalance( SwapStorage storage self, uint256[] memory amounts, uint256 maxBurnAmount ) external returns (uint256 burnAmount) { uint256 nCoins = self.pooledTokens.length; require(amounts.length == nCoins, "invalidAmountsLength"); uint256 totalSupply = self.lpToken.totalSupply(); require(totalSupply != 0, "totalSupply = 0"); uint256 _fee = _feePerToken(self); uint256 amp = _getAPrecise(self); uint256[] memory newBalances = self.balances; uint256 D0 = _getD(_xp(self), amp); for (uint256 i = 0; i < nCoins; i++) { newBalances[i] -= amounts[i]; } uint256 D1 = _getD(_xp(newBalances, self.tokenMultipliers), amp); uint256[] memory fees = new uint256[](nCoins); for (uint256 i = 0; i < nCoins; i++) { uint256 idealBalance = (D1 * self.balances[i]) / D0; uint256 diff = _distance(newBalances[i], idealBalance); fees[i] = (_fee * diff) / FEE_DENOMINATOR; self.balances[i] = newBalances[i] - ((fees[i] * self.adminFee) / FEE_DENOMINATOR); newBalances[i] -= fees[i]; } // recalculate invariant with fee charged balances D1 = _getD(_xp(newBalances, self.tokenMultipliers), amp); burnAmount = ((D0 - D1) * totalSupply) / D0; assert(burnAmount > 0); require(burnAmount <= maxBurnAmount, "> slippage"); self.lpToken.burnFrom(msg.sender, burnAmount); for (uint256 i = 0; i < nCoins; i++) { if (amounts[i] != 0) { self.pooledTokens[i].safeTransfer(msg.sender, amounts[i]); } } emit RemoveLiquidityImbalance(msg.sender, amounts, fees, D1, totalSupply - burnAmount); } /// VIEW FUNCTIONS function getAPrecise(SwapStorage storage self) external view returns (uint256) { return _getAPrecise(self); } /** * Returns portfolio virtual price (for calculating profit) * scaled up by 1e18 */ function getVirtualPrice(SwapStorage storage self) external view returns (uint256) { uint256 D = _getD(_xp(self), _getAPrecise(self)); uint256 tokenSupply = self.lpToken.totalSupply(); return (D * 10**POOL_TOKEN_COMMON_DECIMALS) / tokenSupply; } function getAdminBalance(SwapStorage storage self, uint256 index) external view returns (uint256) { require(index < self.pooledTokens.length, "indexOutOfRange"); return self.pooledTokens[index].balanceOf(address(this)) - (self.balances[index]); } /** * Estimate amount of LP token minted or burned at deposit or withdrawal * without taking fees into account */ function calculateTokenAmount( SwapStorage storage self, uint256[] memory amounts, bool deposit ) external view returns (uint256) { uint256 nCoins = self.pooledTokens.length; require(amounts.length == nCoins, "invalidAmountsLength"); uint256 amp = _getAPrecise(self); uint256 D0 = _getD(_xp(self), amp); uint256[] memory newBalances = self.balances; for (uint256 i = 0; i < nCoins; i++) { if (deposit) { newBalances[i] += amounts[i]; } else { newBalances[i] -= amounts[i]; } } uint256 D1 = _getD(_xp(newBalances, self.tokenMultipliers), amp); uint256 totalSupply = self.lpToken.totalSupply(); if (totalSupply == 0) { return D1; // first depositor take it all } uint256 diff = deposit ? D1 - D0 : D0 - D1; return (diff * self.lpToken.totalSupply()) / D0; } function getA(SwapStorage storage self) external view returns (uint256) { return _getAPrecise(self) / A_PRECISION; } function calculateSwap( SwapStorage storage self, uint256 inIndex, uint256 outIndex, uint256 inAmount ) external view returns (uint256) { uint256[] memory normalizedBalances = _xp(self); uint256 newInBalance = normalizedBalances[inIndex] + (inAmount * self.tokenMultipliers[inIndex]); uint256 outBalance = _getY(self, inIndex, outIndex, newInBalance, normalizedBalances); uint256 outAmount = (normalizedBalances[outIndex] - outBalance - 1) / self.tokenMultipliers[outIndex]; uint256 _fee = (self.fee * outAmount) / FEE_DENOMINATOR; return outAmount - _fee; } function calculateRemoveLiquidity(SwapStorage storage self, uint256 amount) external view returns (uint256[] memory) { return _calculateRemoveLiquidity(self, amount); } function calculateRemoveLiquidityOneToken( SwapStorage storage self, uint256 lpAmount, uint256 tokenIndex ) external view returns (uint256 amount) { (amount, ) = _calculateRemoveLiquidityOneToken(self, lpAmount, tokenIndex); } /// INTERNAL FUNCTIONS /** * Ramping A up or down, return A with precision of A_PRECISION */ function _getAPrecise(SwapStorage storage self) internal view returns (uint256) { if (block.timestamp >= self.futureATime) { return self.futureA; } if (self.futureA > self.initialA) { return self.initialA + ((self.futureA - self.initialA) * (block.timestamp - self.initialATime)) / (self.futureATime - self.initialATime); } return self.initialA - ((self.initialA - self.futureA) * (block.timestamp - self.initialATime)) / (self.futureATime - self.initialATime); } /** * normalized balances of each tokens. */ function _xp(uint256[] memory balances, uint256[] memory rates) internal pure returns (uint256[] memory) { for (uint256 i = 0; i < balances.length; i++) { rates[i] = (rates[i] * balances[i]); } return rates; } function _xp(SwapStorage storage self) internal view returns (uint256[] memory) { return _xp(self.balances, self.tokenMultipliers); } /** * Calculate D for *NORMALIZED* balances of each tokens * @param xp normalized balances of token */ function _getD(uint256[] memory xp, uint256 amp) internal pure returns (uint256) { uint256 nCoins = xp.length; uint256 sum = _sumOf(xp); if (sum == 0) { return 0; } uint256 Dprev = 0; uint256 D = sum; uint256 Ann = amp * nCoins; for (uint256 i = 0; i < MAX_ITERATION; i++) { uint256 D_P = D; for (uint256 j = 0; j < xp.length; j++) { D_P = (D_P * D) / (xp[j] * nCoins); } Dprev = D; D = (((Ann * sum) / A_PRECISION + D_P * nCoins) * D) / (((Ann - A_PRECISION) * D) / A_PRECISION + (nCoins + 1) * D_P); if (_distance(D, Dprev) <= 1) { return D; } } // Convergence should occur in 4 loops or less. If this is reached, there may be something wrong // with the pool. If this were to occur repeatedly, LPs should withdraw via `removeLiquidity()` // function which does not rely on D. revert("invariantCalculationFailed"); } /** * calculate new balance of when swap * Done by solving quadratic equation iteratively. * x_1**2 + x_1 * (sum' - (A*n**n - 1) * D / (A * n**n)) = D ** (n + 1) / (n ** (2 * n) * prod' * A) * x_1**2 + b*x_1 = c * x_1 = (x_1**2 + c) / (2*x_1 + b) * @param inIndex index of token to swap in * @param outIndex index of token to swap out * @param inBalance new balance (normalized) of input token if the swap success * @return NORMALIZED balance of output token if the swap success */ function _getY( SwapStorage storage self, uint256 inIndex, uint256 outIndex, uint256 inBalance, uint256[] memory normalizedBalances ) internal view returns (uint256) { require(inIndex != outIndex, "sameToken"); uint256 nCoins = self.pooledTokens.length; require(inIndex < nCoins && outIndex < nCoins, "indexOutOfRange"); uint256 amp = _getAPrecise(self); uint256 Ann = amp * nCoins; uint256 D = _getD(normalizedBalances, amp); uint256 sum = 0; // sum of new balances except output token uint256 c = D; for (uint256 i = 0; i < nCoins; i++) { if (i == outIndex) { continue; } uint256 x = i == inIndex ? inBalance : normalizedBalances[i]; sum += x; c = (c * D) / (x * nCoins); } c = (c * D * A_PRECISION) / (Ann * nCoins); uint256 b = sum + (D * A_PRECISION) / Ann; uint256 lastY = 0; uint256 y = D; for (uint256 index = 0; index < MAX_ITERATION; index++) { lastY = y; y = (y * y + c) / (2 * y + b - D); if (_distance(lastY, y) <= 1) { return y; } } revert("yCalculationFailed"); } function _calculateRemoveLiquidity(SwapStorage storage self, uint256 amount) internal view returns (uint256[] memory) { uint256 totalSupply = self.lpToken.totalSupply(); require(amount <= totalSupply, "Cannot exceed total supply"); uint256[] memory amounts = new uint256[](self.pooledTokens.length); for (uint256 i = 0; i < self.pooledTokens.length; i++) { amounts[i] = (self.balances[i] * (amount)) / (totalSupply); } return amounts; } function _calculateRemoveLiquidityOneToken( SwapStorage storage self, uint256 tokenAmount, uint256 index ) internal view returns (uint256 dy, uint256 fee) { require(index < self.pooledTokens.length, "indexOutOfRange"); uint256 amp = _getAPrecise(self); uint256[] memory xp = _xp(self); uint256 D0 = _getD(xp, amp); uint256 D1 = D0 - (tokenAmount * D0) / self.lpToken.totalSupply(); uint256 newY = _getYD(self, amp, index, xp, D1); uint256[] memory reducedXP = xp; uint256 _fee = _feePerToken(self); for (uint256 i = 0; i < self.pooledTokens.length; i++) { uint256 expectedDx = 0; if (i == index) { expectedDx = (xp[i] * D1) / D0 - newY; } else { expectedDx = xp[i] - (xp[i] * D1) / D0; } reducedXP[i] -= (_fee * expectedDx) / FEE_DENOMINATOR; } dy = reducedXP[index] - _getYD(self, amp, index, reducedXP, D1); dy = (dy - 1) / self.tokenMultipliers[index]; fee = ((xp[index] - newY) / self.tokenMultipliers[index]) - dy; } function _feePerToken(SwapStorage storage self) internal view returns (uint256) { uint256 nCoins = self.pooledTokens.length; return (self.fee * nCoins) / (4 * (nCoins - 1)); } function _getYD( SwapStorage storage self, uint256 A, uint256 index, uint256[] memory xp, uint256 D ) internal view returns (uint256) { uint256 nCoins = self.pooledTokens.length; assert(index < nCoins); uint256 Ann = A * nCoins; uint256 c = D; uint256 s = 0; uint256 _x = 0; uint256 yPrev = 0; for (uint256 i = 0; i < nCoins; i++) { if (i == index) { continue; } _x = xp[i]; s += _x; c = (c * D) / (_x * nCoins); } c = (c * D * A_PRECISION) / (Ann * nCoins); uint256 b = s + (D * A_PRECISION) / Ann; uint256 y = D; for (uint256 i = 0; i < MAX_ITERATION; i++) { yPrev = y; y = (y * y + c) / (2 * y + b - D); if (_distance(yPrev, y) <= 1) { return y; } } revert("invariantCalculationFailed"); } function _doTransferIn(IERC20 token, uint256 amount) internal returns (uint256) { uint256 priorBalance = token.balanceOf(address(this)); token.safeTransferFrom(msg.sender, address(this), amount); return token.balanceOf(address(this)) - priorBalance; } function _sumOf(uint256[] memory x) internal pure returns (uint256 sum) { sum = 0; for (uint256 i = 0; i < x.length; i++) { sum += x[i]; } } function _distance(uint256 x, uint256 y) internal pure returns (uint256) { return x > y ? x - y : y - x; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "../interfaces/IStableSwap.sol"; contract LPToken is Ownable, ERC20Burnable { IStableSwap public swap; constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) { swap = IStableSwap(msg.sender); } function mint(address _to, uint256 _amount) external onlyOwner { require(_amount > 0, "zeroMintAmount"); _mint(_to, _amount); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../ERC20.sol"; import "../../../utils/Context.sol"; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ abstract contract ERC20Burnable is Context, ERC20 { /** * @dev Destroys `amount` tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 amount) public virtual { _burn(_msgSender(), amount); } /** * @dev Destroys `amount` tokens from `account`, deducting from the caller's * allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `amount`. */ function burnFrom(address account, uint256 amount) public virtual { uint256 currentAllowance = allowance(account, _msgSender()); require(currentAllowance >= amount, "ERC20: burn amount exceeds allowance"); unchecked { _approve(account, _msgSender(), currentAllowance - amount); } _burn(account, amount); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @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 {ERC20PresetMinterPauser}. * * 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 Contracts guidelines: functions revert * instead 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 Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override 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. This is the value {ERC20} uses, unless this function is * overridden; * * 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 virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override 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 virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override 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 virtual override returns (bool) { _transfer(sender, recipient, amount); uint256 currentAllowance = _allowances[sender][_msgSender()]; require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); unchecked { _approve(sender, _msgSender(), currentAllowance - amount); } 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 virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + 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 virtual returns (bool) { uint256 currentAllowance = _allowances[_msgSender()][spender]; require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(_msgSender(), spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `sender` to `recipient`. * * This 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 virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); uint256 senderBalance = _balances[sender]; require(senderBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[sender] = senderBalance - amount; } _balances[recipient] += amount; emit Transfer(sender, recipient, amount); _afterTokenTransfer(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: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); _afterTokenTransfer(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 virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; } _totalSupply -= amount; emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This 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 virtual { 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 Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./OwnerPausable.sol"; import "./StableSwapStorage.sol"; import "../interfaces/IStableSwap.sol"; contract StableSwap is OwnerPausable, ReentrancyGuard, Initializable, IStableSwap { using StableSwapStorage for StableSwapStorage.SwapStorage; using SafeERC20 for IERC20; /// constants uint256 public constant MIN_RAMP_TIME = 1 days; uint256 public constant MAX_A = 1e6; // max_a with precision uint256 public constant MAX_A_CHANGE = 10; uint256 public constant MAX_ADMIN_FEE = 1e10; // 100% uint256 public constant MAX_SWAP_FEE = 1e8; // 1% /// STATE VARS StableSwapStorage.SwapStorage public swapStorage; address public feeDistributor; address public feeController; mapping(address => uint8) public tokenIndexes; modifier deadlineCheck(uint256 _deadline) { require(block.timestamp <= _deadline, "timeout"); _; } modifier onlyFeeControllerOrOwner() { require(msg.sender == feeController || msg.sender == owner(), "!feeControllerOrOwner"); _; } function initialize( address[] memory _coins, uint8[] memory _decimals, string memory lpTokenName, string memory lpTokenSymbol, uint256 _A, uint256 _fee, uint256 _adminFee, address _feeDistributor ) external onlyOwner initializer { require(_coins.length == _decimals.length, "coinsLength != decimalsLength"); require(_feeDistributor != address(0), "feeDistributor = empty"); uint256 numberOfCoins = _coins.length; uint256[] memory rates = new uint256[](numberOfCoins); IERC20[] memory coins = new IERC20[](numberOfCoins); for (uint256 i = 0; i < numberOfCoins; i++) { require(_coins[i] != address(0), "invalidTokenAddress"); require(_decimals[i] <= StableSwapStorage.POOL_TOKEN_COMMON_DECIMALS, "invalidDecimals"); rates[i] = 10**(StableSwapStorage.POOL_TOKEN_COMMON_DECIMALS - _decimals[i]); coins[i] = IERC20(_coins[i]); tokenIndexes[address(coins[i])] = uint8(i); } require(_A < MAX_A, "> maxA"); require(_fee <= MAX_SWAP_FEE, "> maxSwapFee"); require(_adminFee <= MAX_ADMIN_FEE, "> maxAdminFee"); swapStorage.lpToken = new LPToken(lpTokenName, lpTokenSymbol); swapStorage.balances = new uint256[](numberOfCoins); swapStorage.tokenMultipliers = rates; swapStorage.pooledTokens = coins; swapStorage.initialA = _A * StableSwapStorage.A_PRECISION; swapStorage.futureA = _A * StableSwapStorage.A_PRECISION; swapStorage.fee = _fee; swapStorage.adminFee = _adminFee; feeDistributor = _feeDistributor; } /// PUBLIC FUNCTIONS function addLiquidity( uint256[] memory amounts, uint256 minMintAmount, uint256 deadline ) external override whenNotPaused nonReentrant deadlineCheck(deadline) returns (uint256) { return swapStorage.addLiquidity(amounts, minMintAmount); } function swap( uint8 fromIndex, uint8 toIndex, uint256 inAmount, uint256 minOutAmount, uint256 deadline ) external override whenNotPaused nonReentrant deadlineCheck(deadline) returns (uint256) { return swapStorage.swap(fromIndex, toIndex, inAmount, minOutAmount); } function removeLiquidity( uint256 lpAmount, uint256[] memory minAmounts, uint256 deadline ) external override nonReentrant deadlineCheck(deadline) returns (uint256[] memory) { return swapStorage.removeLiquidity(lpAmount, minAmounts); } function removeLiquidityOneToken( uint256 lpAmount, uint8 index, uint256 minAmount, uint256 deadline ) external override nonReentrant whenNotPaused deadlineCheck(deadline) returns (uint256) { return swapStorage.removeLiquidityOneToken(lpAmount, index, minAmount); } function removeLiquidityImbalance( uint256[] memory amounts, uint256 maxBurnAmount, uint256 deadline ) external override nonReentrant whenNotPaused deadlineCheck(deadline) returns (uint256) { return swapStorage.removeLiquidityImbalance(amounts, maxBurnAmount); } /// VIEW FUNCTIONS function getVirtualPrice() external view override returns (uint256) { return swapStorage.getVirtualPrice(); } function getA() external view override returns (uint256) { return swapStorage.getA(); } function getAPrecise() external view override returns (uint256) { return swapStorage.getAPrecise(); } function getTokens() external view override returns (IERC20[] memory) { return swapStorage.pooledTokens; } function getToken(uint8 index) external view override returns (IERC20) { return swapStorage.pooledTokens[index]; } function getLpToken() external view override returns (IERC20) { return swapStorage.lpToken; } function getTokenIndex(address token) external view override returns (uint8 index) { index = tokenIndexes[token]; require(address(swapStorage.pooledTokens[index]) == token, "tokenNotFound"); } function getTokenPrecisionMultipliers() external view returns (uint256[] memory) { return swapStorage.tokenMultipliers; } function getTokenBalances() external view override returns (uint256[] memory) { return swapStorage.balances; } function getTokenBalance(uint8 index) external view override returns (uint256) { return swapStorage.balances[index]; } function getNumberOfTokens() external view override returns (uint256) { return swapStorage.pooledTokens.length; } function getAdminBalances() external view override returns (uint256[] memory adminBalances) { uint256 length = swapStorage.pooledTokens.length; adminBalances = new uint256[](length); for (uint256 i = 0; i < length; i++) { adminBalances[i] = swapStorage.getAdminBalance(i); } } function getAdminBalance(uint8 index) external view override returns (uint256) { return swapStorage.getAdminBalance((index)); } function calculateTokenAmount(uint256[] calldata amounts, bool deposit) external view override returns (uint256) { return swapStorage.calculateTokenAmount(amounts, deposit); } function calculateSwap( uint8 inIndex, uint8 outIndex, uint256 inAmount ) external view override returns (uint256) { return swapStorage.calculateSwap(inIndex, outIndex, inAmount); } function calculateRemoveLiquidity(uint256 amount) external view override returns (uint256[] memory) { return swapStorage.calculateRemoveLiquidity(amount); } function calculateRemoveLiquidityOneToken(uint256 amount, uint8 index) external view override returns (uint256) { return swapStorage.calculateRemoveLiquidityOneToken(amount, index); } /// RESTRICTED FUNCTION /** * @notice Sets the admin fee * @dev adminFee cannot be higher than 100% of the swap fee * swap fee cannot be higher than 1% of each swap * @param newSwapFee new swap fee to be applied on future transactions * @param newAdminFee new admin fee to be applied on future transactions */ function setFee(uint256 newSwapFee, uint256 newAdminFee) external onlyOwner { require(newSwapFee <= MAX_SWAP_FEE, "> maxSwapFee"); require(newAdminFee <= MAX_ADMIN_FEE, "> maxAdminFee"); swapStorage.adminFee = newAdminFee; swapStorage.fee = newSwapFee; emit NewFee(newSwapFee, newAdminFee); } /** * @notice Start ramping up or down A parameter towards given futureA_ and futureTime_ * Checks if the change is too rapid, and commits the new A value only when it falls under * the limit range. * @param futureA the new A to ramp towards * @param futureATime timestamp when the new A should be reached */ function rampA(uint256 futureA, uint256 futureATime) external onlyOwner { require(block.timestamp >= swapStorage.initialATime + (1 days), "< rampDelay"); // please wait 1 days before start a new ramping require(futureATime >= block.timestamp + (MIN_RAMP_TIME), "< minRampTime"); require(0 < futureA && futureA < MAX_A, "outOfRange"); uint256 initialAPrecise = swapStorage.getAPrecise(); uint256 futureAPrecise = futureA * StableSwapStorage.A_PRECISION; if (futureAPrecise < initialAPrecise) { require(futureAPrecise * (MAX_A_CHANGE) >= initialAPrecise, "> maxChange"); } else { require(futureAPrecise <= initialAPrecise * (MAX_A_CHANGE), "> maxChange"); } swapStorage.initialA = initialAPrecise; swapStorage.futureA = futureAPrecise; swapStorage.initialATime = block.timestamp; swapStorage.futureATime = futureATime; emit RampA(initialAPrecise, futureAPrecise, block.timestamp, futureATime); } function stopRampA() external onlyOwner { require(swapStorage.futureATime > block.timestamp, "alreadyStopped"); uint256 currentA = swapStorage.getAPrecise(); swapStorage.initialA = currentA; swapStorage.futureA = currentA; swapStorage.initialATime = block.timestamp; swapStorage.futureATime = block.timestamp; emit StopRampA(currentA, block.timestamp); } function setFeeController(address _feeController) external onlyOwner { require(_feeController != address(0), "zeroAddress"); feeController = _feeController; emit FeeControllerChanged(_feeController); } function setFeeDistributor(address _feeDistributor) external onlyOwner { require(_feeDistributor != address(0), "zeroAddress"); feeDistributor = _feeDistributor; emit FeeDistributorChanged(_feeDistributor); } function withdrawAdminFee() external override onlyFeeControllerOrOwner { for (uint256 i = 0; i < swapStorage.pooledTokens.length; i++) { IERC20 token = swapStorage.pooledTokens[i]; uint256 balance = token.balanceOf(address(this)) - (swapStorage.balances[i]); if (balance != 0) { token.safeTransfer(feeDistributor, balance); emit CollectProtocolFee(address(token), balance); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract 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 protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/security/Pausable.sol"; abstract contract OwnerPausable is Ownable, Pausable { function pause() external onlyOwner { _pause(); } function unpause() external onlyOwner { _unpause(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "../interfaces/IUniswapV2Pair.sol"; contract PriceLens { uint256 public constant PRECISION = 1e18; function consultUniswapV2LPToken( IUniswapV2Pair lpToken, address token0Route, address token1Route, address chainlinkAddress0, address chainlinkAddress1 ) external view returns (uint256) { address token0 = lpToken.token0(); address token1 = lpToken.token1(); uint256 token0Part = calculatePartOfLP(lpToken, token0, token0Route); uint256 token1Part = calculatePartOfLP(lpToken, token1, token1Route); token0Part = getChainlinkPrice(chainlinkAddress0, token0Part); token1Part = getChainlinkPrice(chainlinkAddress1, token1Part); uint256 totalSupply = lpToken.totalSupply(); uint256 decimals = lpToken.decimals(); uint256 totalAmount = token0Part + token1Part; return (totalAmount * 10**decimals) / totalSupply; } /** * calculate token price from series of Uniswap pair and chainlink price feed. * Once swap route is empty * @param token address of token to consult * @param pair swap route to get price * @param chainlinkAddress chainlink price feed */ function consultToken( address token, address pair, address chainlinkAddress ) public view returns (uint256) { require(pair != address(0) || chainlinkAddress != address(0), "route empty"); uint256 amountOut = consultTokenToToken(token, pair); if (chainlinkAddress == address(0)) { return amountOut; } return getChainlinkPrice(chainlinkAddress, amountOut); } // internal function function consultTokenToToken(address tokenIn, address pairAddress) internal view returns (uint256) { address tokenOut = address(0); if (pairAddress == address(0)) { return PRECISION; } uint256 amountIn = 10**ERC20(tokenIn).decimals(); IUniswapV2Pair pair = IUniswapV2Pair(pairAddress); (uint112 reserve0, uint112 reserve1, ) = pair.getReserves(); uint256 amountOut; if (tokenIn == pair.token0()) { tokenOut = pair.token1(); amountOut = getAmountOut(amountIn, reserve0, reserve1); } else { assert(tokenIn == pair.token1()); tokenOut = pair.token0(); amountOut = getAmountOut(amountIn, reserve1, reserve0); } uint8 tokenOutDecimals = ERC20(tokenOut).decimals(); return (amountOut * PRECISION) / 10**tokenOutDecimals; } // UniswapV2Libarary.getAmountOut function getAmountOut( uint256 amountIn, uint256 reserveIn, uint256 reserveOut ) internal pure returns (uint256 amountOut) { require(amountIn > 0, "UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT"); require(reserveIn > 0 && reserveOut > 0, "UniswapV2Library: INSUFFICIENT_LIQUIDITY"); uint256 numerator = amountIn * reserveOut; uint256 denominator = reserveIn + amountIn; amountOut = numerator / denominator; } function getChainlinkPrice(address _priceFeedAddress, uint256 _amountIn) internal view returns (uint256) { assert(_priceFeedAddress != address(0)); AggregatorV3Interface _priceFeed = AggregatorV3Interface(_priceFeedAddress); (, int256 _price, , , ) = _priceFeed.latestRoundData(); uint8 _decimals = _priceFeed.decimals(); return (uint256(_price) * _amountIn) / (10**_decimals); } function calculatePartOfLP( IUniswapV2Pair lpToken, address underlyingAddress, address token0Route ) internal view returns (uint256) { ERC20 underlying = ERC20(underlyingAddress); uint256 decimals = underlying.decimals(); uint256 balance = underlying.balanceOf(address(lpToken)); uint256 price = consultTokenToToken(address(underlying), token0Route); return (balance * price) / 10**decimals; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface AggregatorV3Interface { function decimals() external view returns ( uint8 ); function description() external view returns ( string memory ); function version() external view returns ( uint256 ); // getRoundData and latestRoundData should both raise "No data present" // if they do not have data to report, instead of returning unset values // which could be misinterpreted as actual reported values. function getRoundData( uint80 _roundId ) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0; interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint256 value); event Transfer(address indexed from, address indexed to, uint256 value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint256); function balanceOf(address owner) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 value) external returns (bool); function transfer(address to, uint256 value) external returns (bool); function transferFrom( address from, address to, uint256 value ) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint256); function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; event Mint(address indexed sender, uint256 amount0, uint256 amount1); event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to); event Swap( address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint256); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns ( uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast ); function price0CumulativeLast() external view returns (uint256); function price1CumulativeLast() external view returns (uint256); function kLast() external view returns (uint256); function mint(address to) external returns (uint256 liquidity); function burn(address to) external returns (uint256 amount0, uint256 amount1); function swap( uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data ) external; function skim(address to) external; function sync() external; function initialize(address, address) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract MockERC20 is ERC20 { uint8 internal decimals_; constructor( string memory _name, string memory _symbol, uint8 _decimals ) ERC20(_name, _symbol) { decimals_ = _decimals; } function mint(uint256 _amount) public { _mint(msg.sender, _amount); } function decimals() public view virtual override returns (uint8) { return decimals_; } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "metadata": { "useLiteralContent": true } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IStableSwap","name":"pool","type":"address"},{"internalType":"contract IStableSwap","name":"basePool","type":"address"},{"internalType":"uint256[]","name":"meta_amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"base_amounts","type":"uint256[]"},{"internalType":"uint256","name":"minToMint","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IStableSwap","name":"fromPool","type":"address"},{"internalType":"contract IStableSwap","name":"toPool","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"calculateConvert","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IStableSwap","name":"pool","type":"address"},{"internalType":"contract IStableSwap","name":"basePool","type":"address"},{"internalType":"uint256","name":"_token_amount","type":"uint256"},{"internalType":"uint8","name":"iBase","type":"uint8"}],"name":"calculateRemoveBaseLiquidityOneToken","outputs":[{"internalType":"uint256","name":"availableTokenAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IStableSwap","name":"pool","type":"address"},{"internalType":"contract IStableSwap","name":"basePool","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"calculateRemoveLiquidity","outputs":[{"internalType":"uint256[]","name":"meta_amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"base_amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IStableSwap","name":"pool","type":"address"},{"internalType":"contract IStableSwap","name":"basePool","type":"address"},{"internalType":"uint8","name":"tokenIndexFrom","type":"uint8"},{"internalType":"uint8","name":"tokenIndexTo","type":"uint8"},{"internalType":"uint256","name":"dx","type":"uint256"}],"name":"calculateSwapFromBase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IStableSwap","name":"pool","type":"address"},{"internalType":"contract IStableSwap","name":"basePool","type":"address"},{"internalType":"uint8","name":"tokenIndexFrom","type":"uint8"},{"internalType":"uint8","name":"tokenIndexTo","type":"uint8"},{"internalType":"uint256","name":"dx","type":"uint256"}],"name":"calculateSwapToBase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IStableSwap","name":"pool","type":"address"},{"internalType":"contract IStableSwap","name":"basePool","type":"address"},{"internalType":"uint256[]","name":"meta_amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"base_amounts","type":"uint256[]"},{"internalType":"bool","name":"is_deposit","type":"bool"}],"name":"calculateTokenAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IStableSwap","name":"fromPool","type":"address"},{"internalType":"contract IStableSwap","name":"toPool","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minToMint","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"convert","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IStableSwap","name":"pool","type":"address"},{"internalType":"contract IStableSwap","name":"basePool","type":"address"},{"internalType":"uint256","name":"_token_amount","type":"uint256"},{"internalType":"uint8","name":"i","type":"uint8"},{"internalType":"uint256","name":"_min_amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeBaseLiquidityOneToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IStableSwap","name":"pool","type":"address"},{"internalType":"contract IStableSwap","name":"basePool","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256[]","name":"min_amounts_meta","type":"uint256[]"},{"internalType":"uint256[]","name":"min_amounts_base","type":"uint256[]"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"base_amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IStableSwap","name":"pool","type":"address"},{"internalType":"contract IStableSwap","name":"basePool","type":"address"},{"internalType":"uint8","name":"tokenIndexFrom","type":"uint8"},{"internalType":"uint8","name":"tokenIndexTo","type":"uint8"},{"internalType":"uint256","name":"dx","type":"uint256"},{"internalType":"uint256","name":"minDy","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapFromBase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IStableSwap","name":"pool","type":"address"},{"internalType":"contract IStableSwap","name":"basePool","type":"address"},{"internalType":"uint8","name":"tokenIndexFrom","type":"uint8"},{"internalType":"uint8","name":"tokenIndexTo","type":"uint8"},{"internalType":"uint256","name":"dx","type":"uint256"},{"internalType":"uint256","name":"minDy","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapToBase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5061449c806100206000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c8063643abb8611610071578063643abb861461015057806377269e291461016357806379701821146101765780638a311c5714610189578063998cae471461019c578063ff969322146101af57600080fd5b80630c8b2216146100b95780630d6307eb146100e357806324a5bf21146101045780633214b8c91461011757806338c789731461012a57806354681c411461013d575b600080fd5b6100cc6100c7366004613ecc565b6101c2565b6040516100da92919061423b565b60405180910390f35b6100f66100f1366004613e35565b610420565b6040519081526020016100da565b6100cc610112366004613f0c565b610bca565b6100f66101253660046140b4565b6114d3565b6100f6610138366004614117565b6116f3565b6100f661014b366004613ffe565b611be6565b6100f661015e366004613ecc565b611df0565b6100f6610171366004613d9b565b612143565b6100f6610184366004613fae565b61234c565b6100f66101973660046140b4565b612b9d565b6100f66101aa366004614050565b612eb9565b6100f66101bd366004614117565b61346e565b6060806000846001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b15801561020057600080fd5b505afa158015610214573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102389190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918816906366c0bd249060240160206040518083038186803b15801561027f57600080fd5b505afa158015610293573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b791906141a5565b60405163797d695b60e11b8152600481018790529091506001600160a01b0388169063f2fad2b69060240160006040518083038186803b1580156102fa57600080fd5b505afa15801561030e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526103369190810190613cd1565b93506000848260ff168151811061035d57634e487b7160e01b600052603260045260246000fd5b602002602001015190506000858360ff168151811061038c57634e487b7160e01b600052603260045260246000fd5b602090810291909101015260405163797d695b60e11b8152600481018290526001600160a01b0388169063f2fad2b69060240160006040518083038186803b1580156103d757600080fd5b505afa1580156103eb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104139190810190613cd1565b9350505050935093915050565b600080876001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b15801561045c57600080fd5b505afa158015610470573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104949190613d7f565b9050866001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b1580156104cf57600080fd5b505afa1580156104e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610507919061418d565b85511461055b5760405162461bcd60e51b815260206004820152601860248201527f696e76616c696442617365416d6f756e74734c656e677468000000000000000060448201526064015b60405180910390fd5b876001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b15801561059457600080fd5b505afa1580156105a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105cc919061418d565b86511461061b5760405162461bcd60e51b815260206004820152601860248201527f696e76616c69644d657461416d6f756e74734c656e67746800000000000000006044820152606401610552565b6000805b86518160ff1610156107d0576000878260ff168151811061065057634e487b7160e01b600052603260045260246000fd5b6020026020010151905060008111156107bd5760405162415c3360e91b815260ff83166004820152600193506000906001600160a01b038c16906382b866009060240160206040518083038186803b1580156106ab57600080fd5b505afa1580156106bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e39190613d7f565b90506106fa6001600160a01b03821633308561387b565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b15801561073c57600080fd5b505afa158015610750573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610774919061418d565b905061078a6001600160a01b0383168d836138d9565b808a8560ff16815181106107ae57634e487b7160e01b600052603260045260246000fd5b60200260200101818152505050505b50806107c8816143e5565b91505061061f565b50801561085c57604051634d49e87d60e01b81526001600160a01b03891690634d49e87d906108089089906000908990600401614284565b602060405180830381600087803b15801561082257600080fd5b505af1158015610836573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085a919061418d565b505b60005b87518160ff161015610a3b5760405162415c3360e91b815260ff821660048201526000906001600160a01b038c16906382b866009060240160206040518083038186803b1580156108af57600080fd5b505afa1580156108c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e79190613d7f565b90506000898360ff168151811061090e57634e487b7160e01b600052603260045260246000fd5b602002602001015111156109665761096633308b8560ff168151811061094457634e487b7160e01b600052603260045260246000fd5b6020026020010151846001600160a01b031661387b909392919063ffffffff16565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b1580156109a857600080fd5b505afa1580156109bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e0919061418d565b90506109f66001600160a01b0383168d836138d9565b808a8460ff1681518110610a1a57634e487b7160e01b600052603260045260246000fd5b60200260200101818152505050508080610a33906143e5565b91505061085f565b50604051634d49e87d60e01b81526001600160a01b038a1690634d49e87d90610a6c908a9089908990600401614284565b602060405180830381600087803b158015610a8657600080fd5b505af1158015610a9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610abe919061418d565b506040516370a0823160e01b81523060048201526000906001600160a01b038416906370a082319060240160206040518083038186803b158015610b0157600080fd5b505afa158015610b15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b39919061418d565b60405163a9059cbb60e01b8152336004820152602481018290529091506001600160a01b0384169063a9059cbb90604401602060405180830381600087803b158015610b8457600080fd5b505af1158015610b98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bbc9190613d63565b509998505050505050505050565b60608060008a6001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b158015610c0857600080fd5b505afa158015610c1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c409190613d7f565b905060008a6001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b158015610c7d57600080fd5b505afa158015610c91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb59190613d7f565b6040516323b872dd60e01b81529091506001600160a01b038316906323b872dd90610ce890339030908f90600401614217565b602060405180830381600087803b158015610d0257600080fd5b505af1158015610d16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3a9190613d63565b50610d4f6001600160a01b0383168d8c6138d9565b60405163031cd52b60e41b81526001600160a01b038d16906331cd52b090610d81908d908d908d908b906004016142dc565b600060405180830381600087803b158015610d9b57600080fd5b505af1158015610daf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610dd79190810190613cd1565b506040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b158015610e1a57600080fd5b505afa158015610e2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e52919061418d565b9050610e686001600160a01b0383168d836138d9565b60405163031cd52b60e41b81526001600160a01b038d16906331cd52b090610e9a9084908c908c908c906004016142dc565b600060405180830381600087803b158015610eb457600080fd5b505af1158015610ec8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ef09190810190613cd1565b508c6001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b158015610f2a57600080fd5b505afa158015610f3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f62919061418d565b6001600160401b03811115610f8757634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015610fb0578160200160208202803683370190505b50945060005b8d6001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b158015610fef57600080fd5b505afa158015611003573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611027919061418d565b8160ff1610156111ef5760008e6001600160a01b03166382b86600836040518263ffffffff1660e01b8152600401611068919060ff91909116815260200190565b60206040518083038186803b15801561108057600080fd5b505afa158015611094573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b89190613d7f565b6040516370a0823160e01b81523060048201529091506001600160a01b038216906370a082319060240160206040518083038186803b1580156110fa57600080fd5b505afa15801561110e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611132919061418d565b878360ff168151811061115557634e487b7160e01b600052603260045260246000fd5b6020026020010181815250506000878360ff168151811061118657634e487b7160e01b600052603260045260246000fd5b602002602001015111156111dc576111dc33888460ff16815181106111bb57634e487b7160e01b600052603260045260246000fd5b6020026020010151836001600160a01b031661399a9092919063ffffffff16565b50806111e7816143e5565b915050610fb6565b508b6001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b15801561122957600080fd5b505afa15801561123d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611261919061418d565b6001600160401b0381111561128657634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156112af578160200160208202803683370190505b50935060005b8c6001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b1580156112ee57600080fd5b505afa158015611302573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611326919061418d565b8160ff1610156114c25760405162415c3360e91b815260ff821660048201526000906001600160a01b038f16906382b866009060240160206040518083038186803b15801561137457600080fd5b505afa158015611388573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ac9190613d7f565b6040516370a0823160e01b81523060048201529091506001600160a01b038216906370a082319060240160206040518083038186803b1580156113ee57600080fd5b505afa158015611402573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611426919061418d565b868360ff168151811061144957634e487b7160e01b600052603260045260246000fd5b6020026020010181815250506000868360ff168151811061147a57634e487b7160e01b600052603260045260246000fd5b602002602001015111156114af576114af33878460ff16815181106111bb57634e487b7160e01b600052603260045260246000fd5b50806114ba816143e5565b9150506112b5565b505050509850989650505050505050565b600080856001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b15801561150f57600080fd5b505afa158015611523573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115479190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918916906366c0bd249060240160206040518083038186803b15801561158e57600080fd5b505afa1580156115a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c691906141a5565b90508360ff808316908816146116625760405163a95b089f60e01b815260ff808916600483015283166024820152604481018690526001600160a01b038a169063a95b089f9060640160206040518083038186803b15801561162757600080fd5b505afa15801561163b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165f919061418d565b90505b60405163342a87a160e01b81526004810182905260ff871660248201526001600160a01b0389169063342a87a1906044015b60206040518083038186803b1580156116ac57600080fd5b505afa1580156116c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e4919061418d565b93505050505b95945050505050565b600080876001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b15801561172f57600080fd5b505afa158015611743573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117679190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918b16906366c0bd249060240160206040518083038186803b1580156117ae57600080fd5b505afa1580156117c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e691906141a5565b90506000896001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b15801561182357600080fd5b505afa158015611837573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185b919061418d565b6001600160401b0381111561188057634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156118a9578160200160208202803683370190505b50905086818a60ff16815181106118d057634e487b7160e01b600052603260045260246000fd5b602090810291909101015260405162415c3360e91b815260ff8a1660048201526000906001600160a01b038c16906382b866009060240160206040518083038186803b15801561191f57600080fd5b505afa158015611933573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119579190613d7f565b905061196e6001600160a01b03821633308b61387b565b6119826001600160a01b0382168c8a6138d9565b604051634d49e87d60e01b81526000906001600160a01b038d1690634d49e87d906119b590869085908c90600401614284565b602060405180830381600087803b1580156119cf57600080fd5b505af11580156119e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a07919061418d565b90508960ff168460ff1614611ac557611a2a6001600160a01b0386168e836138d9565b6040516348b4aac360e11b815260ff80861660048301528b1660248201526044810182905260648101899052608481018890526001600160a01b038e169063916955869060a401602060405180830381600087803b158015611a8b57600080fd5b505af1158015611a9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac3919061418d565b505b60405162415c3360e91b815260ff8b1660048201526000906001600160a01b038f16906382b866009060240160206040518083038186803b158015611b0957600080fd5b505afa158015611b1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b419190613d7f565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a082319060240160206040518083038186803b158015611b8657600080fd5b505afa158015611b9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bbe919061418d565b9050611bd46001600160a01b038316338361399a565b9e9d5050505050505050505050505050565b600080846001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b158015611c2257600080fd5b505afa158015611c36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c5a9190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918816906366c0bd249060240160206040518083038186803b158015611ca157600080fd5b505afa158015611cb5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cd991906141a5565b60405163342a87a160e01b81526004810187905260ff821660248201529091506000906001600160a01b0389169063342a87a19060440160206040518083038186803b158015611d2857600080fd5b505afa158015611d3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d60919061418d565b60405163342a87a160e01b81526004810182905260ff871660248201529091506001600160a01b0388169063342a87a19060440160206040518083038186803b158015611dac57600080fd5b505afa158015611dc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de4919061418d565b98975050505050505050565b600080846001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b158015611e2c57600080fd5b505afa158015611e40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e64919061418d565b60405163797d695b60e11b8152600481018590529091506000906001600160a01b0387169063f2fad2b69060240160006040518083038186803b158015611eaa57600080fd5b505afa158015611ebe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ee69190810190613cd1565b90506000826001600160401b03811115611f1057634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611f39578160200160208202803683370190505b50905060005b838160ff1610156120b65760405162415c3360e91b815260ff821660048201526000906001600160a01b038a16906382b866009060240160206040518083038186803b158015611f8e57600080fd5b505afa158015611fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc69190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918a16906366c0bd249060240160206040518083038186803b15801561200d57600080fd5b505afa158015612021573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061204591906141a5565b60ff169050848360ff168151811061206d57634e487b7160e01b600052603260045260246000fd5b602002602001015184828151811061209557634e487b7160e01b600052603260045260246000fd5b602002602001018181525050505080806120ae906143e5565b915050611f3f565b50604051637355940360e11b81526001600160a01b0387169063e6ab2806906120e6908490600190600401614260565b60206040518083038186803b1580156120fe57600080fd5b505afa158015612112573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612136919061418d565b93505050505b9392505050565b600080856001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b15801561217f57600080fd5b505afa158015612193573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b79190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918916906366c0bd249060240160206040518083038186803b1580156121fe57600080fd5b505afa158015612212573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061223691906141a5565b90506000876001600160a01b031663e6ab280687876040518363ffffffff1660e01b8152600401612268929190614260565b60206040518083038186803b15801561228057600080fd5b505afa158015612294573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122b8919061418d565b905080878360ff16815181106122de57634e487b7160e01b600052603260045260246000fd5b60200260200101516122f091906143a1565b878360ff168151811061231357634e487b7160e01b600052603260045260246000fd5b6020908102919091010152604051637355940360e11b81526001600160a01b038a169063e6ab280690611694908a908990600401614260565b600080866001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b15801561238857600080fd5b505afa15801561239c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c0919061418d565b90506000866001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b1580156123fd57600080fd5b505afa158015612411573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612435919061418d565b9050866001600160a01b0316886001600160a01b0316141561248d5760405162461bcd60e51b8152602060048201526011602482015270199c9bdb541bdbdb080f481d1bd41bdbdb607a1b6044820152606401610552565b8082146124dc5760405162461bcd60e51b815260206004820152601960248201527f706f6f6c546f6b656e734c656e6774684d6973736d61746368000000000000006044820152606401610552565b6000886001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b15801561251757600080fd5b505afa15801561252b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061254f9190613d7f565b90506000886001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b15801561258c57600080fd5b505afa1580156125a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c49190613d7f565b90506000846001600160401b038111156125ee57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612617578160200160208202803683370190505b50905060005b858160ff1610156127365760405162415c3360e91b815260ff821660048201526000906001600160a01b038e16906382b866009060240160206040518083038186803b15801561266c57600080fd5b505afa158015612680573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126a49190613d7f565b6040516319b02f4960e21b81526001600160a01b038083166004830152919250908d16906366c0bd249060240160206040518083038186803b1580156126e957600080fd5b505afa1580156126fd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061272191906141a5565b5050808061272e906143e5565b91505061261d565b506040516323b872dd60e01b81526001600160a01b038416906323b872dd9061276790339030908e90600401614217565b602060405180830381600087803b15801561278157600080fd5b505af1158015612795573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127b99190613d63565b506127ce6001600160a01b0384168c8b6138d9565b60405163031cd52b60e41b81526001600160a01b038c16906331cd52b0906127fe908c9085908c90600401614325565b600060405180830381600087803b15801561281857600080fd5b505af115801561282c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128549190810190613cd1565b506000846001600160401b0381111561287d57634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156128a6578160200160208202803683370190505b50905060005b858160ff161015612a0b5760405162415c3360e91b815260ff821660048201526000906001600160a01b038e16906382b866009060240160206040518083038186803b1580156128fb57600080fd5b505afa15801561290f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129339190613d7f565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a082319060240160206040518083038186803b15801561297857600080fd5b505afa15801561298c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129b0919061418d565b90506129c66001600160a01b0383168f836138d9565b80848460ff16815181106129ea57634e487b7160e01b600052603260045260246000fd5b60200260200101818152505050508080612a03906143e5565b9150506128ac565b50604051634d49e87d60e01b81526001600160a01b038c1690634d49e87d90612a3c9084908d908d90600401614284565b602060405180830381600087803b158015612a5657600080fd5b505af1158015612a6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8e919061418d565b506040516370a0823160e01b81523060048201526000906001600160a01b038516906370a082319060240160206040518083038186803b158015612ad157600080fd5b505afa158015612ae5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b09919061418d565b60405163a9059cbb60e01b8152336004820152602481018290529091506001600160a01b0385169063a9059cbb90604401602060405180830381600087803b158015612b5457600080fd5b505af1158015612b68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b8c9190613d63565b509c9b505050505050505050505050565b600080856001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b158015612bd957600080fd5b505afa158015612bed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c119190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918916906366c0bd249060240160206040518083038186803b158015612c5857600080fd5b505afa158015612c6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9091906141a5565b90506000876001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b158015612ccd57600080fd5b505afa158015612ce1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d05919061418d565b6001600160401b03811115612d2a57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612d53578160200160208202803683370190505b50905084818860ff1681518110612d7a57634e487b7160e01b600052603260045260246000fd5b6020908102919091010152604051637355940360e11b81526000906001600160a01b038a169063e6ab280690612db7908590600190600401614260565b60206040518083038186803b158015612dcf57600080fd5b505afa158015612de3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e07919061418d565b90508660ff168360ff161415612e225793506116ea92505050565b60405163a95b089f60e01b815260ff808516600483015288166024820152604481018290526001600160a01b038b169063a95b089f9060640160206040518083038186803b158015612e7357600080fd5b505afa158015612e87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eab919061418d565b9a9950505050505050505050565b600080876001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b158015612ef557600080fd5b505afa158015612f09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f2d9190613d7f565b90506000876001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b158015612f6a57600080fd5b505afa158015612f7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fa29190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918b16906366c0bd249060240160206040518083038186803b158015612fe957600080fd5b505afa158015612ffd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061302191906141a5565b6040516323b872dd60e01b81529091506001600160a01b038416906323b872dd9061305490339030908d90600401614217565b602060405180830381600087803b15801561306e57600080fd5b505af1158015613082573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130a69190613d63565b5060405163095ea7b360e01b81526001600160a01b038b81166004830152602482018a905284169063095ea7b390604401602060405180830381600087803b1580156130f157600080fd5b505af1158015613105573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131299190613d63565b506040516301f1d0ab60e51b81526004810189905260ff8216602482015260006044820152606481018690526001600160a01b038b1690633e3a156090608401602060405180830381600087803b15801561318357600080fd5b505af1158015613197573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131bb919061418d565b506040516370a0823160e01b81523060048201526000906001600160a01b038416906370a082319060240160206040518083038186803b1580156131fe57600080fd5b505afa158015613212573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613236919061418d565b60405163095ea7b360e01b81526001600160a01b038c81166004830152602482018390529192509084169063095ea7b390604401602060405180830381600087803b15801561328457600080fd5b505af1158015613298573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132bc9190613d63565b506040516301f1d0ab60e51b81526004810182905260ff8916602482015260448101889052606481018790526001600160a01b038b1690633e3a156090608401602060405180830381600087803b15801561331657600080fd5b505af115801561332a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061334e919061418d565b5060405162415c3360e91b815260ff891660048201526000906001600160a01b038c16906382b866009060240160206040518083038186803b15801561339357600080fd5b505afa1580156133a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133cb9190613d7f565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a082319060240160206040518083038186803b15801561341057600080fd5b505afa158015613424573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613448919061418d565b905061345e6001600160a01b038316338361399a565b9c9b505050505050505050505050565b600080876001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b1580156134aa57600080fd5b505afa1580156134be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134e29190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918b16906366c0bd249060240160206040518083038186803b15801561352957600080fd5b505afa15801561353d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061356191906141a5565b60405162415c3360e91b815260ff8a1660048201529091506000906001600160a01b038c16906382b866009060240160206040518083038186803b1580156135a857600080fd5b505afa1580156135bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135e09190613d7f565b90506135f76001600160a01b03821633308a61387b565b8660ff838116908b16146136b5576136196001600160a01b0383168d8a6138d9565b6040516348b4aac360e11b815260ff808c166004830152841660248201526044810189905260006064820152608481018790526001600160a01b038d169063916955869060a401602060405180830381600087803b15801561367a57600080fd5b505af115801561368e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136b2919061418d565b90505b6136c96001600160a01b0385168c836138d9565b6040516301f1d0ab60e51b81526004810182905260ff8a16602482015260448101889052606481018790526001600160a01b038c1690633e3a156090608401602060405180830381600087803b15801561372257600080fd5b505af1158015613736573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061375a919061418d565b5060405162415c3360e91b815260ff8a1660048201526000906001600160a01b038d16906382b866009060240160206040518083038186803b15801561379f57600080fd5b505afa1580156137b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d79190613d7f565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a082319060240160206040518083038186803b15801561381c57600080fd5b505afa158015613830573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613854919061418d565b905061386a6001600160a01b038316338361399a565b9d9c50505050505050505050505050565b6138d3846323b872dd60e01b85858560405160240161389c93929190614217565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526139cf565b50505050565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e9060440160206040518083038186803b15801561392557600080fd5b505afa158015613939573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061395d919061418d565b61396791906143a1565b6040516001600160a01b0385166024820152604481018290529091506138d390859063095ea7b360e01b9060640161389c565b6040516001600160a01b0383166024820152604481018290526139ca90849063a9059cbb60e01b9060640161389c565b505050565b6000613a24826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613aa19092919063ffffffff16565b8051909150156139ca5780806020019051810190613a429190613d63565b6139ca5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610552565b6060613ab08484600085613ab8565b949350505050565b606082471015613b195760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610552565b843b613b675760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610552565b600080866001600160a01b03168587604051613b8391906141fb565b60006040518083038185875af1925050503d8060008114613bc0576040519150601f19603f3d011682016040523d82523d6000602084013e613bc5565b606091505b5091509150613bd5828286613be0565b979650505050505050565b60608315613bef57508161213c565b825115613bff5782518084602001fd5b8160405162461bcd60e51b815260040161055291906142a9565b60008083601f840112613c2a578182fd5b5081356001600160401b03811115613c40578182fd5b6020830191508360208260051b8501011115613c5b57600080fd5b9250929050565b600082601f830112613c72578081fd5b81356020613c87613c828361437e565b61434e565b80838252828201915082860187848660051b8901011115613ca6578586fd5b855b85811015613cc457813584529284019290840190600101613ca8565b5090979650505050505050565b60006020808385031215613ce3578182fd5b82516001600160401b03811115613cf8578283fd5b8301601f81018513613d08578283fd5b8051613d16613c828261437e565b80828252848201915084840188868560051b8701011115613d35578687fd5b8694505b83851015613d57578051835260019490940193918501918501613d39565b50979650505050505050565b600060208284031215613d74578081fd5b815161213c81614431565b600060208284031215613d90578081fd5b815161213c81614442565b600080600080600060a08688031215613db2578081fd5b8535613dbd81614442565b94506020860135613dcd81614442565b935060408601356001600160401b0380821115613de8578283fd5b613df489838a01613c62565b94506060880135915080821115613e09578283fd5b50613e1688828901613c62565b9250506080860135613e2781614431565b809150509295509295909350565b60008060008060008060c08789031215613e4d578081fd5b8635613e5881614442565b95506020870135613e6881614442565b945060408701356001600160401b0380821115613e83578283fd5b613e8f8a838b01613c62565b95506060890135915080821115613ea4578283fd5b50613eb189828a01613c62565b9350506080870135915060a087013590509295509295509295565b600080600060608486031215613ee0578283fd5b8335613eeb81614442565b92506020840135613efb81614442565b929592945050506040919091013590565b60008060008060008060008060c0898b031215613f27578182fd5b8835613f3281614442565b97506020890135613f4281614442565b96506040890135955060608901356001600160401b0380821115613f64578384fd5b613f708c838d01613c19565b909750955060808b0135915080821115613f88578384fd5b50613f958b828c01613c19565b999c989b50969995989497949560a00135949350505050565b600080600080600060a08688031215613fc5578081fd5b8535613fd081614442565b94506020860135613fe081614442565b94979496505050506040830135926060810135926080909101359150565b60008060008060808587031215614013578182fd5b843561401e81614442565b9350602085013561402e81614442565b925060408501359150606085013561404581614457565b939692955090935050565b60008060008060008060c08789031215614068578384fd5b863561407381614442565b9550602087013561408381614442565b945060408701359350606087013561409a81614457565b9598949750929560808101359460a0909101359350915050565b600080600080600060a086880312156140cb578283fd5b85356140d681614442565b945060208601356140e681614442565b935060408601356140f681614457565b9250606086013561410681614457565b949793965091946080013592915050565b600080600080600080600060e0888a031215614131578081fd5b873561413c81614442565b9650602088013561414c81614442565b9550604088013561415c81614457565b9450606088013561416c81614457565b9699959850939660808101359560a0820135955060c0909101359350915050565b60006020828403121561419e578081fd5b5051919050565b6000602082840312156141b6578081fd5b815161213c81614457565b6000815180845260208085019450808401835b838110156141f0578151875295820195908201906001016141d4565b509495945050505050565b6000825161420d8184602087016143b9565b9190910192915050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60408152600061424e60408301856141c1565b82810360208401526116ea81856141c1565b60408152600061427360408301856141c1565b905082151560208301529392505050565b60608152600061429760608301866141c1565b60208301949094525060400152919050565b60208152600082518060208401526142c88160408501602087016143b9565b601f01601f19169190910160400192915050565b848152606060208201819052810183905260006001600160fb1b03841115614302578081fd5b8360051b8086608085013782016080019081526040909101919091529392505050565b83815260606020820152600061433e60608301856141c1565b9050826040830152949350505050565b604051601f8201601f191681016001600160401b03811182821017156143765761437661441b565b604052919050565b60006001600160401b038211156143975761439761441b565b5060051b60200190565b600082198211156143b4576143b4614405565b500190565b60005b838110156143d45781810151838201526020016143bc565b838111156138d35750506000910152565b600060ff821660ff8114156143fc576143fc614405565b60010192915050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b801515811461443f57600080fd5b50565b6001600160a01b038116811461443f57600080fd5b60ff8116811461443f57600080fdfea2646970667358221220343d6ecd35e1011becba92cf5dffcce4f5c47674024af1782dd1cbb4727d35a764736f6c63430008040033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100b45760003560e01c8063643abb8611610071578063643abb861461015057806377269e291461016357806379701821146101765780638a311c5714610189578063998cae471461019c578063ff969322146101af57600080fd5b80630c8b2216146100b95780630d6307eb146100e357806324a5bf21146101045780633214b8c91461011757806338c789731461012a57806354681c411461013d575b600080fd5b6100cc6100c7366004613ecc565b6101c2565b6040516100da92919061423b565b60405180910390f35b6100f66100f1366004613e35565b610420565b6040519081526020016100da565b6100cc610112366004613f0c565b610bca565b6100f66101253660046140b4565b6114d3565b6100f6610138366004614117565b6116f3565b6100f661014b366004613ffe565b611be6565b6100f661015e366004613ecc565b611df0565b6100f6610171366004613d9b565b612143565b6100f6610184366004613fae565b61234c565b6100f66101973660046140b4565b612b9d565b6100f66101aa366004614050565b612eb9565b6100f66101bd366004614117565b61346e565b6060806000846001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b15801561020057600080fd5b505afa158015610214573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102389190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918816906366c0bd249060240160206040518083038186803b15801561027f57600080fd5b505afa158015610293573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b791906141a5565b60405163797d695b60e11b8152600481018790529091506001600160a01b0388169063f2fad2b69060240160006040518083038186803b1580156102fa57600080fd5b505afa15801561030e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526103369190810190613cd1565b93506000848260ff168151811061035d57634e487b7160e01b600052603260045260246000fd5b602002602001015190506000858360ff168151811061038c57634e487b7160e01b600052603260045260246000fd5b602090810291909101015260405163797d695b60e11b8152600481018290526001600160a01b0388169063f2fad2b69060240160006040518083038186803b1580156103d757600080fd5b505afa1580156103eb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104139190810190613cd1565b9350505050935093915050565b600080876001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b15801561045c57600080fd5b505afa158015610470573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104949190613d7f565b9050866001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b1580156104cf57600080fd5b505afa1580156104e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610507919061418d565b85511461055b5760405162461bcd60e51b815260206004820152601860248201527f696e76616c696442617365416d6f756e74734c656e677468000000000000000060448201526064015b60405180910390fd5b876001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b15801561059457600080fd5b505afa1580156105a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105cc919061418d565b86511461061b5760405162461bcd60e51b815260206004820152601860248201527f696e76616c69644d657461416d6f756e74734c656e67746800000000000000006044820152606401610552565b6000805b86518160ff1610156107d0576000878260ff168151811061065057634e487b7160e01b600052603260045260246000fd5b6020026020010151905060008111156107bd5760405162415c3360e91b815260ff83166004820152600193506000906001600160a01b038c16906382b866009060240160206040518083038186803b1580156106ab57600080fd5b505afa1580156106bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e39190613d7f565b90506106fa6001600160a01b03821633308561387b565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b15801561073c57600080fd5b505afa158015610750573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610774919061418d565b905061078a6001600160a01b0383168d836138d9565b808a8560ff16815181106107ae57634e487b7160e01b600052603260045260246000fd5b60200260200101818152505050505b50806107c8816143e5565b91505061061f565b50801561085c57604051634d49e87d60e01b81526001600160a01b03891690634d49e87d906108089089906000908990600401614284565b602060405180830381600087803b15801561082257600080fd5b505af1158015610836573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085a919061418d565b505b60005b87518160ff161015610a3b5760405162415c3360e91b815260ff821660048201526000906001600160a01b038c16906382b866009060240160206040518083038186803b1580156108af57600080fd5b505afa1580156108c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e79190613d7f565b90506000898360ff168151811061090e57634e487b7160e01b600052603260045260246000fd5b602002602001015111156109665761096633308b8560ff168151811061094457634e487b7160e01b600052603260045260246000fd5b6020026020010151846001600160a01b031661387b909392919063ffffffff16565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b1580156109a857600080fd5b505afa1580156109bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e0919061418d565b90506109f66001600160a01b0383168d836138d9565b808a8460ff1681518110610a1a57634e487b7160e01b600052603260045260246000fd5b60200260200101818152505050508080610a33906143e5565b91505061085f565b50604051634d49e87d60e01b81526001600160a01b038a1690634d49e87d90610a6c908a9089908990600401614284565b602060405180830381600087803b158015610a8657600080fd5b505af1158015610a9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610abe919061418d565b506040516370a0823160e01b81523060048201526000906001600160a01b038416906370a082319060240160206040518083038186803b158015610b0157600080fd5b505afa158015610b15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b39919061418d565b60405163a9059cbb60e01b8152336004820152602481018290529091506001600160a01b0384169063a9059cbb90604401602060405180830381600087803b158015610b8457600080fd5b505af1158015610b98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bbc9190613d63565b509998505050505050505050565b60608060008a6001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b158015610c0857600080fd5b505afa158015610c1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c409190613d7f565b905060008a6001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b158015610c7d57600080fd5b505afa158015610c91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb59190613d7f565b6040516323b872dd60e01b81529091506001600160a01b038316906323b872dd90610ce890339030908f90600401614217565b602060405180830381600087803b158015610d0257600080fd5b505af1158015610d16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3a9190613d63565b50610d4f6001600160a01b0383168d8c6138d9565b60405163031cd52b60e41b81526001600160a01b038d16906331cd52b090610d81908d908d908d908b906004016142dc565b600060405180830381600087803b158015610d9b57600080fd5b505af1158015610daf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610dd79190810190613cd1565b506040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b158015610e1a57600080fd5b505afa158015610e2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e52919061418d565b9050610e686001600160a01b0383168d836138d9565b60405163031cd52b60e41b81526001600160a01b038d16906331cd52b090610e9a9084908c908c908c906004016142dc565b600060405180830381600087803b158015610eb457600080fd5b505af1158015610ec8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ef09190810190613cd1565b508c6001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b158015610f2a57600080fd5b505afa158015610f3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f62919061418d565b6001600160401b03811115610f8757634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015610fb0578160200160208202803683370190505b50945060005b8d6001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b158015610fef57600080fd5b505afa158015611003573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611027919061418d565b8160ff1610156111ef5760008e6001600160a01b03166382b86600836040518263ffffffff1660e01b8152600401611068919060ff91909116815260200190565b60206040518083038186803b15801561108057600080fd5b505afa158015611094573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b89190613d7f565b6040516370a0823160e01b81523060048201529091506001600160a01b038216906370a082319060240160206040518083038186803b1580156110fa57600080fd5b505afa15801561110e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611132919061418d565b878360ff168151811061115557634e487b7160e01b600052603260045260246000fd5b6020026020010181815250506000878360ff168151811061118657634e487b7160e01b600052603260045260246000fd5b602002602001015111156111dc576111dc33888460ff16815181106111bb57634e487b7160e01b600052603260045260246000fd5b6020026020010151836001600160a01b031661399a9092919063ffffffff16565b50806111e7816143e5565b915050610fb6565b508b6001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b15801561122957600080fd5b505afa15801561123d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611261919061418d565b6001600160401b0381111561128657634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156112af578160200160208202803683370190505b50935060005b8c6001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b1580156112ee57600080fd5b505afa158015611302573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611326919061418d565b8160ff1610156114c25760405162415c3360e91b815260ff821660048201526000906001600160a01b038f16906382b866009060240160206040518083038186803b15801561137457600080fd5b505afa158015611388573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ac9190613d7f565b6040516370a0823160e01b81523060048201529091506001600160a01b038216906370a082319060240160206040518083038186803b1580156113ee57600080fd5b505afa158015611402573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611426919061418d565b868360ff168151811061144957634e487b7160e01b600052603260045260246000fd5b6020026020010181815250506000868360ff168151811061147a57634e487b7160e01b600052603260045260246000fd5b602002602001015111156114af576114af33878460ff16815181106111bb57634e487b7160e01b600052603260045260246000fd5b50806114ba816143e5565b9150506112b5565b505050509850989650505050505050565b600080856001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b15801561150f57600080fd5b505afa158015611523573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115479190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918916906366c0bd249060240160206040518083038186803b15801561158e57600080fd5b505afa1580156115a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c691906141a5565b90508360ff808316908816146116625760405163a95b089f60e01b815260ff808916600483015283166024820152604481018690526001600160a01b038a169063a95b089f9060640160206040518083038186803b15801561162757600080fd5b505afa15801561163b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165f919061418d565b90505b60405163342a87a160e01b81526004810182905260ff871660248201526001600160a01b0389169063342a87a1906044015b60206040518083038186803b1580156116ac57600080fd5b505afa1580156116c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e4919061418d565b93505050505b95945050505050565b600080876001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b15801561172f57600080fd5b505afa158015611743573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117679190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918b16906366c0bd249060240160206040518083038186803b1580156117ae57600080fd5b505afa1580156117c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e691906141a5565b90506000896001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b15801561182357600080fd5b505afa158015611837573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185b919061418d565b6001600160401b0381111561188057634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156118a9578160200160208202803683370190505b50905086818a60ff16815181106118d057634e487b7160e01b600052603260045260246000fd5b602090810291909101015260405162415c3360e91b815260ff8a1660048201526000906001600160a01b038c16906382b866009060240160206040518083038186803b15801561191f57600080fd5b505afa158015611933573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119579190613d7f565b905061196e6001600160a01b03821633308b61387b565b6119826001600160a01b0382168c8a6138d9565b604051634d49e87d60e01b81526000906001600160a01b038d1690634d49e87d906119b590869085908c90600401614284565b602060405180830381600087803b1580156119cf57600080fd5b505af11580156119e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a07919061418d565b90508960ff168460ff1614611ac557611a2a6001600160a01b0386168e836138d9565b6040516348b4aac360e11b815260ff80861660048301528b1660248201526044810182905260648101899052608481018890526001600160a01b038e169063916955869060a401602060405180830381600087803b158015611a8b57600080fd5b505af1158015611a9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac3919061418d565b505b60405162415c3360e91b815260ff8b1660048201526000906001600160a01b038f16906382b866009060240160206040518083038186803b158015611b0957600080fd5b505afa158015611b1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b419190613d7f565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a082319060240160206040518083038186803b158015611b8657600080fd5b505afa158015611b9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bbe919061418d565b9050611bd46001600160a01b038316338361399a565b9e9d5050505050505050505050505050565b600080846001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b158015611c2257600080fd5b505afa158015611c36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c5a9190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918816906366c0bd249060240160206040518083038186803b158015611ca157600080fd5b505afa158015611cb5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cd991906141a5565b60405163342a87a160e01b81526004810187905260ff821660248201529091506000906001600160a01b0389169063342a87a19060440160206040518083038186803b158015611d2857600080fd5b505afa158015611d3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d60919061418d565b60405163342a87a160e01b81526004810182905260ff871660248201529091506001600160a01b0388169063342a87a19060440160206040518083038186803b158015611dac57600080fd5b505afa158015611dc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de4919061418d565b98975050505050505050565b600080846001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b158015611e2c57600080fd5b505afa158015611e40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e64919061418d565b60405163797d695b60e11b8152600481018590529091506000906001600160a01b0387169063f2fad2b69060240160006040518083038186803b158015611eaa57600080fd5b505afa158015611ebe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ee69190810190613cd1565b90506000826001600160401b03811115611f1057634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611f39578160200160208202803683370190505b50905060005b838160ff1610156120b65760405162415c3360e91b815260ff821660048201526000906001600160a01b038a16906382b866009060240160206040518083038186803b158015611f8e57600080fd5b505afa158015611fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc69190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918a16906366c0bd249060240160206040518083038186803b15801561200d57600080fd5b505afa158015612021573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061204591906141a5565b60ff169050848360ff168151811061206d57634e487b7160e01b600052603260045260246000fd5b602002602001015184828151811061209557634e487b7160e01b600052603260045260246000fd5b602002602001018181525050505080806120ae906143e5565b915050611f3f565b50604051637355940360e11b81526001600160a01b0387169063e6ab2806906120e6908490600190600401614260565b60206040518083038186803b1580156120fe57600080fd5b505afa158015612112573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612136919061418d565b93505050505b9392505050565b600080856001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b15801561217f57600080fd5b505afa158015612193573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b79190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918916906366c0bd249060240160206040518083038186803b1580156121fe57600080fd5b505afa158015612212573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061223691906141a5565b90506000876001600160a01b031663e6ab280687876040518363ffffffff1660e01b8152600401612268929190614260565b60206040518083038186803b15801561228057600080fd5b505afa158015612294573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122b8919061418d565b905080878360ff16815181106122de57634e487b7160e01b600052603260045260246000fd5b60200260200101516122f091906143a1565b878360ff168151811061231357634e487b7160e01b600052603260045260246000fd5b6020908102919091010152604051637355940360e11b81526001600160a01b038a169063e6ab280690611694908a908990600401614260565b600080866001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b15801561238857600080fd5b505afa15801561239c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c0919061418d565b90506000866001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b1580156123fd57600080fd5b505afa158015612411573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612435919061418d565b9050866001600160a01b0316886001600160a01b0316141561248d5760405162461bcd60e51b8152602060048201526011602482015270199c9bdb541bdbdb080f481d1bd41bdbdb607a1b6044820152606401610552565b8082146124dc5760405162461bcd60e51b815260206004820152601960248201527f706f6f6c546f6b656e734c656e6774684d6973736d61746368000000000000006044820152606401610552565b6000886001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b15801561251757600080fd5b505afa15801561252b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061254f9190613d7f565b90506000886001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b15801561258c57600080fd5b505afa1580156125a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c49190613d7f565b90506000846001600160401b038111156125ee57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612617578160200160208202803683370190505b50905060005b858160ff1610156127365760405162415c3360e91b815260ff821660048201526000906001600160a01b038e16906382b866009060240160206040518083038186803b15801561266c57600080fd5b505afa158015612680573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126a49190613d7f565b6040516319b02f4960e21b81526001600160a01b038083166004830152919250908d16906366c0bd249060240160206040518083038186803b1580156126e957600080fd5b505afa1580156126fd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061272191906141a5565b5050808061272e906143e5565b91505061261d565b506040516323b872dd60e01b81526001600160a01b038416906323b872dd9061276790339030908e90600401614217565b602060405180830381600087803b15801561278157600080fd5b505af1158015612795573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127b99190613d63565b506127ce6001600160a01b0384168c8b6138d9565b60405163031cd52b60e41b81526001600160a01b038c16906331cd52b0906127fe908c9085908c90600401614325565b600060405180830381600087803b15801561281857600080fd5b505af115801561282c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128549190810190613cd1565b506000846001600160401b0381111561287d57634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156128a6578160200160208202803683370190505b50905060005b858160ff161015612a0b5760405162415c3360e91b815260ff821660048201526000906001600160a01b038e16906382b866009060240160206040518083038186803b1580156128fb57600080fd5b505afa15801561290f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129339190613d7f565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a082319060240160206040518083038186803b15801561297857600080fd5b505afa15801561298c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129b0919061418d565b90506129c66001600160a01b0383168f836138d9565b80848460ff16815181106129ea57634e487b7160e01b600052603260045260246000fd5b60200260200101818152505050508080612a03906143e5565b9150506128ac565b50604051634d49e87d60e01b81526001600160a01b038c1690634d49e87d90612a3c9084908d908d90600401614284565b602060405180830381600087803b158015612a5657600080fd5b505af1158015612a6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8e919061418d565b506040516370a0823160e01b81523060048201526000906001600160a01b038516906370a082319060240160206040518083038186803b158015612ad157600080fd5b505afa158015612ae5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b09919061418d565b60405163a9059cbb60e01b8152336004820152602481018290529091506001600160a01b0385169063a9059cbb90604401602060405180830381600087803b158015612b5457600080fd5b505af1158015612b68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b8c9190613d63565b509c9b505050505050505050505050565b600080856001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b158015612bd957600080fd5b505afa158015612bed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c119190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918916906366c0bd249060240160206040518083038186803b158015612c5857600080fd5b505afa158015612c6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9091906141a5565b90506000876001600160a01b031663efeecb516040518163ffffffff1660e01b815260040160206040518083038186803b158015612ccd57600080fd5b505afa158015612ce1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d05919061418d565b6001600160401b03811115612d2a57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612d53578160200160208202803683370190505b50905084818860ff1681518110612d7a57634e487b7160e01b600052603260045260246000fd5b6020908102919091010152604051637355940360e11b81526000906001600160a01b038a169063e6ab280690612db7908590600190600401614260565b60206040518083038186803b158015612dcf57600080fd5b505afa158015612de3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e07919061418d565b90508660ff168360ff161415612e225793506116ea92505050565b60405163a95b089f60e01b815260ff808516600483015288166024820152604481018290526001600160a01b038b169063a95b089f9060640160206040518083038186803b158015612e7357600080fd5b505afa158015612e87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eab919061418d565b9a9950505050505050505050565b600080876001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b158015612ef557600080fd5b505afa158015612f09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f2d9190613d7f565b90506000876001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b158015612f6a57600080fd5b505afa158015612f7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fa29190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918b16906366c0bd249060240160206040518083038186803b158015612fe957600080fd5b505afa158015612ffd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061302191906141a5565b6040516323b872dd60e01b81529091506001600160a01b038416906323b872dd9061305490339030908d90600401614217565b602060405180830381600087803b15801561306e57600080fd5b505af1158015613082573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130a69190613d63565b5060405163095ea7b360e01b81526001600160a01b038b81166004830152602482018a905284169063095ea7b390604401602060405180830381600087803b1580156130f157600080fd5b505af1158015613105573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131299190613d63565b506040516301f1d0ab60e51b81526004810189905260ff8216602482015260006044820152606481018690526001600160a01b038b1690633e3a156090608401602060405180830381600087803b15801561318357600080fd5b505af1158015613197573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131bb919061418d565b506040516370a0823160e01b81523060048201526000906001600160a01b038416906370a082319060240160206040518083038186803b1580156131fe57600080fd5b505afa158015613212573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613236919061418d565b60405163095ea7b360e01b81526001600160a01b038c81166004830152602482018390529192509084169063095ea7b390604401602060405180830381600087803b15801561328457600080fd5b505af1158015613298573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132bc9190613d63565b506040516301f1d0ab60e51b81526004810182905260ff8916602482015260448101889052606481018790526001600160a01b038b1690633e3a156090608401602060405180830381600087803b15801561331657600080fd5b505af115801561332a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061334e919061418d565b5060405162415c3360e91b815260ff891660048201526000906001600160a01b038c16906382b866009060240160206040518083038186803b15801561339357600080fd5b505afa1580156133a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133cb9190613d7f565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a082319060240160206040518083038186803b15801561341057600080fd5b505afa158015613424573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613448919061418d565b905061345e6001600160a01b038316338361399a565b9c9b505050505050505050505050565b600080876001600160a01b0316638214f5a46040518163ffffffff1660e01b815260040160206040518083038186803b1580156134aa57600080fd5b505afa1580156134be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134e29190613d7f565b6040516319b02f4960e21b81526001600160a01b0380831660048301529192506000918b16906366c0bd249060240160206040518083038186803b15801561352957600080fd5b505afa15801561353d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061356191906141a5565b60405162415c3360e91b815260ff8a1660048201529091506000906001600160a01b038c16906382b866009060240160206040518083038186803b1580156135a857600080fd5b505afa1580156135bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135e09190613d7f565b90506135f76001600160a01b03821633308a61387b565b8660ff838116908b16146136b5576136196001600160a01b0383168d8a6138d9565b6040516348b4aac360e11b815260ff808c166004830152841660248201526044810189905260006064820152608481018790526001600160a01b038d169063916955869060a401602060405180830381600087803b15801561367a57600080fd5b505af115801561368e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136b2919061418d565b90505b6136c96001600160a01b0385168c836138d9565b6040516301f1d0ab60e51b81526004810182905260ff8a16602482015260448101889052606481018790526001600160a01b038c1690633e3a156090608401602060405180830381600087803b15801561372257600080fd5b505af1158015613736573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061375a919061418d565b5060405162415c3360e91b815260ff8a1660048201526000906001600160a01b038d16906382b866009060240160206040518083038186803b15801561379f57600080fd5b505afa1580156137b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d79190613d7f565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a082319060240160206040518083038186803b15801561381c57600080fd5b505afa158015613830573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613854919061418d565b905061386a6001600160a01b038316338361399a565b9d9c50505050505050505050505050565b6138d3846323b872dd60e01b85858560405160240161389c93929190614217565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526139cf565b50505050565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e9060440160206040518083038186803b15801561392557600080fd5b505afa158015613939573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061395d919061418d565b61396791906143a1565b6040516001600160a01b0385166024820152604481018290529091506138d390859063095ea7b360e01b9060640161389c565b6040516001600160a01b0383166024820152604481018290526139ca90849063a9059cbb60e01b9060640161389c565b505050565b6000613a24826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613aa19092919063ffffffff16565b8051909150156139ca5780806020019051810190613a429190613d63565b6139ca5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610552565b6060613ab08484600085613ab8565b949350505050565b606082471015613b195760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610552565b843b613b675760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610552565b600080866001600160a01b03168587604051613b8391906141fb565b60006040518083038185875af1925050503d8060008114613bc0576040519150601f19603f3d011682016040523d82523d6000602084013e613bc5565b606091505b5091509150613bd5828286613be0565b979650505050505050565b60608315613bef57508161213c565b825115613bff5782518084602001fd5b8160405162461bcd60e51b815260040161055291906142a9565b60008083601f840112613c2a578182fd5b5081356001600160401b03811115613c40578182fd5b6020830191508360208260051b8501011115613c5b57600080fd5b9250929050565b600082601f830112613c72578081fd5b81356020613c87613c828361437e565b61434e565b80838252828201915082860187848660051b8901011115613ca6578586fd5b855b85811015613cc457813584529284019290840190600101613ca8565b5090979650505050505050565b60006020808385031215613ce3578182fd5b82516001600160401b03811115613cf8578283fd5b8301601f81018513613d08578283fd5b8051613d16613c828261437e565b80828252848201915084840188868560051b8701011115613d35578687fd5b8694505b83851015613d57578051835260019490940193918501918501613d39565b50979650505050505050565b600060208284031215613d74578081fd5b815161213c81614431565b600060208284031215613d90578081fd5b815161213c81614442565b600080600080600060a08688031215613db2578081fd5b8535613dbd81614442565b94506020860135613dcd81614442565b935060408601356001600160401b0380821115613de8578283fd5b613df489838a01613c62565b94506060880135915080821115613e09578283fd5b50613e1688828901613c62565b9250506080860135613e2781614431565b809150509295509295909350565b60008060008060008060c08789031215613e4d578081fd5b8635613e5881614442565b95506020870135613e6881614442565b945060408701356001600160401b0380821115613e83578283fd5b613e8f8a838b01613c62565b95506060890135915080821115613ea4578283fd5b50613eb189828a01613c62565b9350506080870135915060a087013590509295509295509295565b600080600060608486031215613ee0578283fd5b8335613eeb81614442565b92506020840135613efb81614442565b929592945050506040919091013590565b60008060008060008060008060c0898b031215613f27578182fd5b8835613f3281614442565b97506020890135613f4281614442565b96506040890135955060608901356001600160401b0380821115613f64578384fd5b613f708c838d01613c19565b909750955060808b0135915080821115613f88578384fd5b50613f958b828c01613c19565b999c989b50969995989497949560a00135949350505050565b600080600080600060a08688031215613fc5578081fd5b8535613fd081614442565b94506020860135613fe081614442565b94979496505050506040830135926060810135926080909101359150565b60008060008060808587031215614013578182fd5b843561401e81614442565b9350602085013561402e81614442565b925060408501359150606085013561404581614457565b939692955090935050565b60008060008060008060c08789031215614068578384fd5b863561407381614442565b9550602087013561408381614442565b945060408701359350606087013561409a81614457565b9598949750929560808101359460a0909101359350915050565b600080600080600060a086880312156140cb578283fd5b85356140d681614442565b945060208601356140e681614442565b935060408601356140f681614457565b9250606086013561410681614457565b949793965091946080013592915050565b600080600080600080600060e0888a031215614131578081fd5b873561413c81614442565b9650602088013561414c81614442565b9550604088013561415c81614457565b9450606088013561416c81614457565b9699959850939660808101359560a0820135955060c0909101359350915050565b60006020828403121561419e578081fd5b5051919050565b6000602082840312156141b6578081fd5b815161213c81614457565b6000815180845260208085019450808401835b838110156141f0578151875295820195908201906001016141d4565b509495945050505050565b6000825161420d8184602087016143b9565b9190910192915050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60408152600061424e60408301856141c1565b82810360208401526116ea81856141c1565b60408152600061427360408301856141c1565b905082151560208301529392505050565b60608152600061429760608301866141c1565b60208301949094525060400152919050565b60208152600082518060208401526142c88160408501602087016143b9565b601f01601f19169190910160400192915050565b848152606060208201819052810183905260006001600160fb1b03841115614302578081fd5b8360051b8086608085013782016080019081526040909101919091529392505050565b83815260606020820152600061433e60608301856141c1565b9050826040830152949350505050565b604051601f8201601f191681016001600160401b03811182821017156143765761437661441b565b604052919050565b60006001600160401b038211156143975761439761441b565b5060051b60200190565b600082198211156143b4576143b4614405565b500190565b60005b838110156143d45781810151838201526020016143bc565b838111156138d35750506000910152565b600060ff821660ff8114156143fc576143fc614405565b60010192915050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b801515811461443f57600080fd5b50565b6001600160a01b038116811461443f57600080fd5b60ff8116811461443f57600080fdfea2646970667358221220343d6ecd35e1011becba92cf5dffcce4f5c47674024af1782dd1cbb4727d35a764736f6c63430008040033
Deployed Bytecode Sourcemap
221:11959:19:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9758:562;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;1864:1756;;;;;;:::i;:::-;;:::i;:::-;;;17600:25:23;;;17588:2;17573:18;1864:1756:19;17555:76:23;3626:1557:19;;;;;;:::i;:::-;;:::i;11584:594::-;;;;;;:::i;:::-;;:::i;6193:1159::-;;;;;;:::i;:::-;;:::i;10326:537::-;;;;;;:::i;:::-;;:::i;8480:671::-;;;;;;:::i;:::-;;:::i;9157:595::-;;;;;;:::i;:::-;;:::i;286:1572::-;;;;;;:::i;:::-;;:::i;10869:709::-;;;;;;:::i;:::-;;:::i;5189:998::-;;;;;;:::i;:::-;;:::i;7358:1079::-;;;;;;:::i;:::-;;:::i;9758:562::-;9901:29;9932;9973:16;9992:8;-1:-1:-1;;;;;9992:19:19;;:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10046:38;;-1:-1:-1;;;10046:38:19;;-1:-1:-1;;;;;11831:32:23;;;10046:38:19;;;11813:51:23;9973:40:19;;-1:-1:-1;10023:20:19;;10046:18;;;;;11786::23;;10046:38:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10109:37;;-1:-1:-1;;;10109:37:19;;;;;17600:25:23;;;10023:61:19;;-1:-1:-1;;;;;;10109:29:19;;;;;17573:18:23;;10109:37:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;10109:37:19;;;;;;;;;;;;:::i;:::-;10094:52;;10156:16;10175:12;10188:14;10175:28;;;;;;;;-1:-1:-1;;;10175:28:19;;;;;;;;;;;;;;;10156:47;;10244:1;10213:12;10226:14;10213:28;;;;;;;;-1:-1:-1;;;10213:28:19;;;;;;;;;;;;;;;;;;:32;10270:43;;-1:-1:-1;;;10270:43:19;;;;;17600:25:23;;;-1:-1:-1;;;;;10270:33:19;;;;;17573:18:23;;10270:43:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;10270:43:19;;;;;;;;;;;;:::i;:::-;10255:58;;9758:562;;;;;;;;;:::o;1864:1756::-;2097:7;2116:12;2138:4;-1:-1:-1;;;;;2138:15:19;;:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2116:40;;2197:8;-1:-1:-1;;;;;2197:26:19;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2174:12;:19;:51;2166:88;;;;-1:-1:-1;;;2166:88:19;;16534:2:23;2166:88:19;;;16516:21:23;16573:2;16553:18;;;16546:30;16612:26;16592:18;;;16585:54;16656:18;;2166:88:19;;;;;;;;;2295:4;-1:-1:-1;;;;;2295:22:19;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2272:12;:19;:47;2264:84;;;;-1:-1:-1;;;2264:84:19;;16181:2:23;2264:84:19;;;16163:21:23;16220:2;16200:18;;;16193:30;16259:26;16239:18;;;16232:54;16303:18;;2264:84:19;16153:174:23;2264:84:19;2358:17;2398:7;2393:504;2415:12;:19;2411:1;:23;;;2393:504;;;2455:14;2472:12;2485:1;2472:15;;;;;;;;-1:-1:-1;;;2472:15:19;;;;;;;;;;;;;;;2455:32;;2514:1;2505:6;:10;2501:386;;;2586:20;;-1:-1:-1;;;2586:20:19;;19934:4:23;19922:17;;2586:20:19;;;19904:36:23;2550:4:19;;-1:-1:-1;2572:11:19;;-1:-1:-1;;;;;2586:17:19;;;;;19877:18:23;;2586:20:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2572:34;-1:-1:-1;2624:56:19;-1:-1:-1;;;;;2624:21:19;;2646:10;2666:4;2673:6;2624:21;:56::i;:::-;2720:29;;-1:-1:-1;;;2720:29:19;;2743:4;2720:29;;;11813:51:23;2698:19:19;;-1:-1:-1;;;;;2720:14:19;;;;;11786:18:23;;2720:29:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2698:51;-1:-1:-1;2767:58:19;-1:-1:-1;;;;;2767:26:19;;2802:8;2698:51;2767:26;:58::i;:::-;2861:11;2843:12;2856:1;2843:15;;;;;;;;-1:-1:-1;;;2843:15:19;;;;;;;;;;;;;;:29;;;;;2501:386;;;-1:-1:-1;2436:3:19;;;;:::i;:::-;;;;2393:504;;;;2910:12;2906:91;;;2938:48;;-1:-1:-1;;;2938:48:19;;-1:-1:-1;;;;;2938:21:19;;;;;:48;;2960:12;;2974:1;;2977:8;;2938:48;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;2906:91;3012:7;3007:415;3029:12;:19;3025:1;:23;;;3007:415;;;3083:16;;-1:-1:-1;;;3083:16:19;;19934:4:23;19922:17;;3083:16:19;;;19904:36:23;3069:11:19;;-1:-1:-1;;;;;3083:13:19;;;;;19877:18:23;;3083:16:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3069:30;;3135:1;3117:12;3130:1;3117:15;;;;;;;;-1:-1:-1;;;3117:15:19;;;;;;;;;;;;;;;:19;3113:123;;;3156:65;3178:10;3198:4;3205:12;3218:1;3205:15;;;;;;;;-1:-1:-1;;;3205:15:19;;;;;;;;;;;;;;;3156:4;-1:-1:-1;;;;;3156:21:19;;;:65;;;;;;:::i;:::-;3271:29;;-1:-1:-1;;;3271:29:19;;3294:4;3271:29;;;11813:51:23;3249:19:19;;-1:-1:-1;;;;;3271:14:19;;;;;11786:18:23;;3271:29:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3249:51;-1:-1:-1;3314:54:19;-1:-1:-1;;;;;3314:26:19;;3349:4;3249:51;3314:26;:54::i;:::-;3400:11;3382:12;3395:1;3382:15;;;;;;;;-1:-1:-1;;;3382:15:19;;;;;;;;;;;;;;:29;;;;;3007:415;;3050:3;;;;;:::i;:::-;;;;3007:415;;;-1:-1:-1;3431:52:19;;-1:-1:-1;;;3431:52:19;;-1:-1:-1;;;;;3431:17:19;;;;;:52;;3449:12;;3463:9;;3474:8;;3431:52;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;3512:30:19;;-1:-1:-1;;;3512:30:19;;3536:4;3512:30;;;11813:51:23;3493:16:19;;-1:-1:-1;;;;;3512:15:19;;;;;11786:18:23;;3512:30:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3552:36;;-1:-1:-1;;;3552:36:19;;3567:10;3552:36;;;12738:51:23;12805:18;;;12798:34;;;3493:49:19;;-1:-1:-1;;;;;;3552:14:19;;;;;12711:18:23;;3552:36:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;3605:8:19;1864:1756;-1:-1:-1;;;;;;;;;1864:1756:19:o;3626:1557::-;3872:24;3898:29;3939:12;3954:4;-1:-1:-1;;;;;3954:15:19;;:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3939:32;;3981:16;4000:8;-1:-1:-1;;;;;4000:19:19;;:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4031:54;;-1:-1:-1;;;4031:54:19;;3981:40;;-1:-1:-1;;;;;;4031:18:19;;;;;:54;;4050:10;;4070:4;;4077:7;;4031:54;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;4095:51:19;-1:-1:-1;;;;;4095:27:19;;4131:4;4138:7;4095:27;:51::i;:::-;4156:57;;-1:-1:-1;;;4156:57:19;;-1:-1:-1;;;;;4156:20:19;;;;;:57;;4177:7;;4186:16;;;;4204:8;;4156:57;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4156:57:19;;;;;;;;;;;;:::i;:::-;-1:-1:-1;4246:34:19;;-1:-1:-1;;;4246:34:19;;4274:4;4246:34;;;11813:51:23;4223:20:19;;-1:-1:-1;;;;;4246:19:19;;;;;11786:18:23;;4246:34:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4223:57;-1:-1:-1;4290:64:19;-1:-1:-1;;;;;4290:31:19;;4330:8;4223:57;4290:31;:64::i;:::-;4365:66;;-1:-1:-1;;;4365:66:19;;-1:-1:-1;;;;;4365:24:19;;;;;:66;;4390:12;;4404:16;;;;4422:8;;4365:66;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4365:66:19;;;;;;;;;;;;:::i;:::-;;4499:4;-1:-1:-1;;;;;4499:22:19;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;4485:39:19;;;;;-1:-1:-1;;;4485:39:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4485:39:19;;4475:49;;4539:7;4534:271;4556:4;-1:-1:-1;;;;;4556:22:19;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4552:1;:28;;;4534:271;;;4601:11;4615:4;-1:-1:-1;;;;;4615:13:19;;4629:1;4615:16;;;;;;;;;;;;;;19934:4:23;19922:17;;;;19904:36;;19892:2;19877:18;;19859:87;4615:16:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4658:29;;-1:-1:-1;;;4658:29:19;;4681:4;4658:29;;;11813:51:23;4601:30:19;;-1:-1:-1;;;;;;4658:14:19;;;;;11786:18:23;;4658:29:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4645:7;4653:1;4645:10;;;;;;;;-1:-1:-1;;;4645:10:19;;;;;;;;;;;;;;:42;;;;;4718:1;4705:7;4713:1;4705:10;;;;;;;;-1:-1:-1;;;4705:10:19;;;;;;;;;;;;;;;:14;4701:94;;;4739:41;4757:10;4769:7;4777:1;4769:10;;;;;;;;-1:-1:-1;;;4769:10:19;;;;;;;;;;;;;;;4739:4;-1:-1:-1;;;;;4739:17:19;;;:41;;;;;:::i;:::-;-1:-1:-1;4582:3:19;;;;:::i;:::-;;;;4534:271;;;;4844:8;-1:-1:-1;;;;;4844:26:19;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;4830:43:19;;;;;-1:-1:-1;;;4830:43:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4830:43:19;;4815:58;;4888:7;4883:294;4905:8;-1:-1:-1;;;;;4905:26:19;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4901:1;:32;;;4883:294;;;4968:20;;-1:-1:-1;;;4968:20:19;;19934:4:23;19922:17;;4968:20:19;;;19904:36:23;4954:11:19;;-1:-1:-1;;;;;4968:17:19;;;;;19877:18:23;;4968:20:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5020:29;;-1:-1:-1;;;5020:29:19;;5043:4;5020:29;;;11813:51:23;4954:34:19;;-1:-1:-1;;;;;;5020:14:19;;;;;11786:18:23;;5020:29:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5002:12;5015:1;5002:15;;;;;;;;-1:-1:-1;;;5002:15:19;;;;;;;;;;;;;;:47;;;;;5085:1;5067:12;5080:1;5067:15;;;;;;;;-1:-1:-1;;;5067:15:19;;;;;;;;;;;;;;;:19;5063:104;;;5106:46;5124:10;5136:12;5149:1;5136:15;;;;;;;;-1:-1:-1;;;5136:15:19;;;;;;;;5106:46;-1:-1:-1;4935:3:19;;;;:::i;:::-;;;;4883:294;;;;3626:1557;;;;;;;;;;;;;;:::o;11584:594::-;11776:7;11795:16;11814:8;-1:-1:-1;;;;;11814:19:19;;:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11868:38;;-1:-1:-1;;;11868:38:19;;-1:-1:-1;;;;;11831:32:23;;;11868:38:19;;;11813:51:23;11795:40:19;;-1:-1:-1;11845:20:19;;11868:18;;;;;11786::23;;11868:38:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11845:61;-1:-1:-1;11940:2:19;11956:32;;;;;;;;11952:133;;12020:54;;-1:-1:-1;;;12020:54:19;;20175:4:23;20163:17;;;12020:54:19;;;20145:36:23;20217:17;;20197:18;;;20190:45;20251:18;;;20244:34;;;-1:-1:-1;;;;;12020:18:19;;;;;20118::23;;12020:54:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;12004:70;;11952:133;12101:70;;-1:-1:-1;;;12101:70:19;;;;;18858:25:23;;;18931:4;18919:17;;18899:18;;;18892:45;-1:-1:-1;;;;;12101:41:19;;;;;18831:18:23;;12101:70:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;12094:77;;;;;11584:594;;;;;;;;:::o;6193:1159::-;6422:7;6441:16;6460:8;-1:-1:-1;;;;;6460:19:19;;:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6514:38;;-1:-1:-1;;;6514:38:19;;-1:-1:-1;;;;;11831:32:23;;;6514:38:19;;;11813:51:23;6441:40:19;;-1:-1:-1;6491:20:19;;6514:18;;;;;11786::23;;6514:38:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6491:61;;6562:29;6608:8;-1:-1:-1;;;;;6608:26:19;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;6594:43:19;;;;;-1:-1:-1;;;6594:43:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6594:43:19;;6562:75;;6678:2;6647:12;6660:14;6647:28;;;;;;;;-1:-1:-1;;;6647:28:19;;;;;;;;;;;;;;;;;;:33;6704;;-1:-1:-1;;;6704:33:19;;19934:4:23;19922:17;;6704:33:19;;;19904:36:23;6690:11:19;;-1:-1:-1;;;;;6704:17:19;;;;;19877:18:23;;6704:33:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6690:47;-1:-1:-1;6747:52:19;-1:-1:-1;;;;;6747:21:19;;6769:10;6789:4;6796:2;6747:21;:52::i;:::-;6809:49;-1:-1:-1;;;;;6809:26:19;;6844:8;6855:2;6809:26;:49::i;:::-;6891:48;;-1:-1:-1;;;6891:48:19;;6868:20;;-1:-1:-1;;;;;6891:21:19;;;;;:48;;6913:12;;6868:20;;6930:8;;6891:48;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6868:71;;6971:12;6953:30;;:14;:30;;;6949:205;;6999:60;-1:-1:-1;;;;;6999:31:19;;7039:4;7046:12;6999:31;:60::i;:::-;7073:70;;-1:-1:-1;;;7073:70:19;;20578:4:23;20566:17;;;7073:70:19;;;20548:36:23;20620:17;;20600:18;;;20593:45;20654:18;;;20647:34;;;20697:18;;;20690:34;;;20740:19;;;20733:35;;;-1:-1:-1;;;;;7073:9:19;;;;;20520:19:23;;7073:70:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;6949:205;7179:27;;-1:-1:-1;;;7179:27:19;;19934:4:23;19922:17;;7179:27:19;;;19904:36:23;7163:13:19;;-1:-1:-1;;;;;7179:13:19;;;;;19877:18:23;;7179:27:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7236:31;;-1:-1:-1;;;7236:31:19;;7261:4;7236:31;;;11813:51:23;7163:43:19;;-1:-1:-1;7216:17:19;;-1:-1:-1;;;;;7236:16:19;;;;;11786:18:23;;7236:31:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7216:51;-1:-1:-1;7277:42:19;-1:-1:-1;;;;;7277:19:19;;7297:10;7216:51;7277:19;:42::i;:::-;7336:9;6193:1159;-1:-1:-1;;;;;;;;;;;;;;6193:1159:19:o;10326:537::-;10509:28;10549:16;10568:8;-1:-1:-1;;;;;10568:19:19;;:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10622:38;;-1:-1:-1;;;10622:38:19;;-1:-1:-1;;;;;11831:32:23;;;10622:38:19;;;11813:51:23;10549:40:19;;-1:-1:-1;10599:20:19;;10622:18;;;;;11786::23;;10622:38:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10693:68;;-1:-1:-1;;;10693:68:19;;;;;18858:25:23;;;18931:4;18919:17;;18899:18;;;18892:45;10599:61:19;;-1:-1:-1;10670:20:19;;-1:-1:-1;;;;;10693:37:19;;;;;18831:18:23;;10693:68:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10794:62;;-1:-1:-1;;;10794:62:19;;;;;18858:25:23;;;18931:4;18919:17;;18899:18;;;18892:45;10670:91:19;;-1:-1:-1;;;;;;10794:41:19;;;;;18831:18:23;;10794:62:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10771:85;10326:537;-1:-1:-1;;;;;;;;10326:537:19:o;8480:671::-;8617:7;8636:22;8661:8;-1:-1:-1;;;;;8661:26:19;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8726:41;;-1:-1:-1;;;8726:41:19;;;;;17600:25:23;;;8636:53:19;;-1:-1:-1;8699:24:19;;-1:-1:-1;;;;;8726:33:19;;;;;17573:18:23;;8726:41:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;8726:41:19;;;;;;;;;;;;:::i;:::-;8699:68;;8777:29;8823:14;-1:-1:-1;;;;;8809:29:19;;;;;-1:-1:-1;;;8809:29:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;8809:29:19;;8777:61;;8853:7;8848:233;8870:14;8866:1;:18;;;8848:233;;;8923:20;;-1:-1:-1;;;8923:20:19;;19934:4:23;19922:17;;8923:20:19;;;19904:36:23;8905:15:19;;-1:-1:-1;;;;;8923:17:19;;;;;19877:18:23;;8923:20:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8979:39;;-1:-1:-1;;;8979:39:19;;-1:-1:-1;;;;;11831:32:23;;;8979:39:19;;;11813:51:23;8905:38:19;;-1:-1:-1;8957:19:19;;8979:20;;;;;11786:18:23;;8979:39:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8957:61;;;;9060:7;9068:1;9060:10;;;;;;;;-1:-1:-1;;;9060:10:19;;;;;;;;;;;;;;;9032:12;9045:11;9032:25;;;;;;-1:-1:-1;;;9032:25:19;;;;;;;;;;;;;;:38;;;;;8848:233;;8886:3;;;;;:::i;:::-;;;;8848:233;;;-1:-1:-1;9097:47:19;;-1:-1:-1;;;9097:47:19;;-1:-1:-1;;;;;9097:27:19;;;;;:47;;9125:12;;9139:4;;9097:47;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9090:54;;;;;8480:671;;;;;;:::o;9157:595::-;9375:7;9394:16;9413:8;-1:-1:-1;;;;;9413:19:19;;:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9467:38;;-1:-1:-1;;;9467:38:19;;-1:-1:-1;;;;;11831:32:23;;;9467:38:19;;;11813:51:23;9394:40:19;;-1:-1:-1;9444:20:19;;9467:18;;;;;11786::23;;9467:38:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9444:61;;9515:20;9538:8;-1:-1:-1;;;;;9538:29:19;;9568:12;9582:10;9538:55;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9515:78;;9665:12;9634;9647:14;9634:28;;;;;;;;-1:-1:-1;;;9634:28:19;;;;;;;;;;;;;;;:43;;;;:::i;:::-;9603:12;9616:14;9603:28;;;;;;;;-1:-1:-1;;;9603:28:19;;;;;;;;;;;;;;;;;;:74;9694:51;;-1:-1:-1;;;9694:51:19;;-1:-1:-1;;;;;9694:25:19;;;;;:51;;9720:12;;9734:10;;9694:51;;;:::i;286:1572::-;462:7;481:22;506:8;-1:-1:-1;;;;;506:26:19;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;481:53;;544:20;567:6;-1:-1:-1;;;;;567:24:19;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;544:49;;640:6;-1:-1:-1;;;;;611:36:19;619:8;-1:-1:-1;;;;;611:36:19;;;603:66;;;;-1:-1:-1;;;603:66:19;;15835:2:23;603:66:19;;;15817:21:23;15874:2;15854:18;;;15847:30;-1:-1:-1;;;15893:18:23;;;15886:47;15950:18;;603:66:19;15807:167:23;603:66:19;705:12;687:14;:30;679:68;;;;-1:-1:-1;;;679:68:19;;15481:2:23;679:68:19;;;15463:21:23;15520:2;15500:18;;;15493:30;15559:27;15539:18;;;15532:55;15604:18;;679:68:19;15453:175:23;679:68:19;757:16;776:8;-1:-1:-1;;;;;776:19:19;;:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;757:40;;807:14;824:6;-1:-1:-1;;;;;824:17:19;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;807:36;;853:28;898:14;-1:-1:-1;;;;;884:29:19;;;;;-1:-1:-1;;;884:29:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;884:29:19;;853:60;;954:7;949:151;971:14;967:1;:18;;;949:151;;;1020:20;;-1:-1:-1;;;1020:20:19;;19934:4:23;19922:17;;1020:20:19;;;19904:36:23;1006:11:19;;-1:-1:-1;;;;;1020:17:19;;;;;19877:18:23;;1020:20:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1054:35;;-1:-1:-1;;;1054:35:19;;-1:-1:-1;;;;;11831:32:23;;;1054:35:19;;;11813:51:23;1006:34:19;;-1:-1:-1;1054:20:19;;;;;;11786:18:23;;1054:35:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;949:151;987:3;;;;;:::i;:::-;;;;949:151;;;-1:-1:-1;1109:57:19;;-1:-1:-1;;;1109:57:19;;-1:-1:-1;;;;;1109:22:19;;;;;:57;;1132:10;;1152:4;;1159:6;;1109:57;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;1176:58:19;-1:-1:-1;;;;;1176:31:19;;1216:8;1227:6;1176:31;:58::i;:::-;1244:55;;-1:-1:-1;;;1244:55:19;;-1:-1:-1;;;;;1244:24:19;;;;;:55;;1269:6;;1277:11;;1290:8;;1244:55;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1244:55:19;;;;;;;;;;;;:::i;:::-;;1310:29;1356:12;-1:-1:-1;;;;;1342:27:19;;;;;-1:-1:-1;;;1342:27:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1342:27:19;;1310:59;;1385:7;1380:273;1402:12;1398:1;:16;;;1380:273;;;1449:18;;-1:-1:-1;;;1449:18:19;;19934:4:23;19922:17;;1449:18:19;;;19904:36:23;1435:11:19;;-1:-1:-1;;;;;1449:15:19;;;;;19877:18:23;;1449::19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1502:29;;-1:-1:-1;;;1502:29:19;;1525:4;1502:29;;;11813:51:23;1435:32:19;;-1:-1:-1;1481:18:19;;-1:-1:-1;;;;;1502:14:19;;;;;11786:18:23;;1502:29:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1481:50;-1:-1:-1;1545:55:19;-1:-1:-1;;;;;1545:26:19;;1580:6;1481:50;1545:26;:55::i;:::-;1632:10;1614:12;1627:1;1614:15;;;;;;;;-1:-1:-1;;;1614:15:19;;;;;;;;;;;;;;:28;;;;;1380:273;;1416:3;;;;;:::i;:::-;;;;1380:273;;;-1:-1:-1;1662:54:19;;-1:-1:-1;;;1662:54:19;;-1:-1:-1;;;;;1662:19:19;;;;;:54;;1682:12;;1696:9;;1707:8;;1662:54;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;1746:32:19;;-1:-1:-1;;;1746:32:19;;1772:4;1746:32;;;11813:51:23;1727:16:19;;-1:-1:-1;;;;;1746:17:19;;;;;11786:18:23;;1746:32:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1788:38;;-1:-1:-1;;;1788:38:19;;1805:10;1788:38;;;12738:51:23;12805:18;;;12798:34;;;1727:51:19;;-1:-1:-1;;;;;;1788:16:19;;;;;12711:18:23;;1788:38:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;1843:8:19;286:1572;-1:-1:-1;;;;;;;;;;;;286:1572:19:o;10869:709::-;11063:7;11082:16;11101:8;-1:-1:-1;;;;;11101:19:19;;:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11155:38;;-1:-1:-1;;;11155:38:19;;-1:-1:-1;;;;;11831:32:23;;;11155:38:19;;;11813:51:23;11082:40:19;;-1:-1:-1;11132:20:19;;11155:18;;;;;11786::23;;11155:38:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11132:61;;11203:29;11249:8;-1:-1:-1;;;;;11249:26:19;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;11235:43:19;;;;;-1:-1:-1;;;11235:43:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;11235:43:19;;11203:75;;11319:2;11288:12;11301:14;11288:28;;;;;;;;-1:-1:-1;;;11288:28:19;;;;;;;;;;;;;;;;;;:33;11354:49;;-1:-1:-1;;;11354:49:19;;11331:20;;-1:-1:-1;;;;;11354:29:19;;;;;:49;;11384:12;;11398:4;;11354:49;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11331:72;;11435:12;11417:30;;:14;:30;;;11413:80;;;11470:12;-1:-1:-1;11463:19:19;;-1:-1:-1;;;11463:19:19;11413:80;11509:62;;-1:-1:-1;;;11509:62:19;;20175:4:23;20163:17;;;11509:62:19;;;20145:36:23;20217:17;;20197:18;;;20190:45;20251:18;;;20244:34;;;-1:-1:-1;;;;;11509:18:19;;;;;20118::23;;11509:62:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11502:69;10869:709;-1:-1:-1;;;;;;;;;;10869:709:19:o;5189:998::-;5409:7;5428:12;5443:4;-1:-1:-1;;;;;5443:15:19;;:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5428:32;;5470:16;5489:8;-1:-1:-1;;;;;5489:19:19;;:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5543:38;;-1:-1:-1;;;5543:38:19;;-1:-1:-1;;;;;11831:32:23;;;5543:38:19;;;11813:51:23;5470:40:19;;-1:-1:-1;5520:20:19;;5543:18;;;;;11786::23;;5543:38:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5591:60;;-1:-1:-1;;;5591:60:19;;5520:61;;-1:-1:-1;;;;;;5591:18:19;;;;;:60;;5610:10;;5630:4;;5637:13;;5591:60;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;5661:43:19;;-1:-1:-1;;;5661:43:19;;-1:-1:-1;;;;;12756:32:23;;;5661:43:19;;;12738:51:23;12805:18;;;12798:34;;;5661:13:19;;;;;12711:18:23;;5661:43:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;5714:72:19;;-1:-1:-1;;;5714:72:19;;;;;19183:25:23;;;19256:4;19244:17;;19224:18;;;19217:45;5774:1:19;19278:18:23;;;19271:34;19321:18;;;19314:34;;;-1:-1:-1;;;;;5714:28:19;;;;;19155:19:23;;5714:72:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;5819:34:19;;-1:-1:-1;;;5819:34:19;;5847:4;5819:34;;;11813:51:23;5796:20:19;;-1:-1:-1;;;;;5819:19:19;;;;;11786:18:23;;5819:34:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5863:50;;-1:-1:-1;;;5863:50:19;;-1:-1:-1;;;;;12756:32:23;;;5863:50:19;;;12738:51:23;12805:18;;;12798:34;;;5796:57:19;;-1:-1:-1;5863:17:19;;;;;;12711:18:23;;5863:50:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;5923:72:19;;-1:-1:-1;;;5923:72:19;;;;;19183:25:23;;;19256:4;19244:17;;19224:18;;;19217:45;19278:18;;;19271:34;;;19321:18;;;19314:34;;;-1:-1:-1;;;;;5923:32:19;;;;;19155:19:23;;5923:72:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;6019:20:19;;-1:-1:-1;;;6019:20:19;;19934:4:23;19922:17;;6019:20:19;;;19904:36:23;6005:11:19;;-1:-1:-1;;;;;6019:17:19;;;;;19877:18:23;;6019:20:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6071:29;;-1:-1:-1;;;6071:29:19;;6094:4;6071:29;;;11813:51:23;6005:34:19;;-1:-1:-1;6049:19:19;;-1:-1:-1;;;;;6071:14:19;;;;;11786:18:23;;6071:29:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6049:51;-1:-1:-1;6110:42:19;-1:-1:-1;;;;;6110:17:19;;6128:10;6049:51;6110:17;:42::i;:::-;6169:11;5189:998;-1:-1:-1;;;;;;;;;;;;5189:998:19:o;7358:1079::-;7585:7;7604:16;7623:8;-1:-1:-1;;;;;7623:19:19;;:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7677:38;;-1:-1:-1;;;7677:38:19;;-1:-1:-1;;;;;11831:32:23;;;7677:38:19;;;11813:51:23;7604:40:19;;-1:-1:-1;7654:20:19;;7677:18;;;;;11786::23;;7677:38:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7739:29;;-1:-1:-1;;;7739:29:19;;19934:4:23;19922:17;;7739:29:19;;;19904:36:23;7654:61:19;;-1:-1:-1;7725:11:19;;-1:-1:-1;;;;;7739:13:19;;;;;19877:18:23;;7739:29:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7725:43;-1:-1:-1;7778:52:19;-1:-1:-1;;;;;7778:21:19;;7800:10;7820:4;7827:2;7778:21;:52::i;:::-;7864:2;7880:32;;;;;;;;7876:196;;7928:45;-1:-1:-1;;;;;7928:26:19;;7963:4;7970:2;7928:26;:45::i;:::-;8003:58;;-1:-1:-1;;;8003:58:19;;20578:4:23;20566:17;;;8003:58:19;;;20548:36:23;20620:17;;20600:18;;;20593:45;20654:18;;;20647:34;;;8049:1:19;20697:18:23;;;20690:34;20740:19;;;20733:35;;;-1:-1:-1;;;;;8003:9:19;;;;;20520:19:23;;8003:58:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7987:74;;7876:196;8081:65;-1:-1:-1;;;;;8081:31:19;;8121:8;8132:13;8081:31;:65::i;:::-;8156:78;;-1:-1:-1;;;8156:78:19;;;;;19183:25:23;;;19256:4;19244:17;;19224:18;;;19217:45;19278:18;;;19271:34;;;19321:18;;;19314:34;;;-1:-1:-1;;;;;8156:32:19;;;;;19155:19:23;;8156:78:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;8260:31:19;;-1:-1:-1;;;8260:31:19;;19934:4:23;19922:17;;8260:31:19;;;19904:36:23;8244:13:19;;-1:-1:-1;;;;;8260:17:19;;;;;19877:18:23;;8260:31:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8321;;-1:-1:-1;;;8321:31:19;;8346:4;8321:31;;;11813:51:23;8244:47:19;;-1:-1:-1;8301:17:19;;-1:-1:-1;;;;;8321:16:19;;;;;11786:18:23;;8321:31:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8301:51;-1:-1:-1;8362:42:19;-1:-1:-1;;;;;8362:19:19;;8382:10;8301:51;8362:19;:42::i;:::-;8421:9;7358:1079;-1:-1:-1;;;;;;;;;;;;;7358:1079:19:o;845:241:9:-;983:96;1003:5;1033:27;;;1062:4;1068:2;1072:5;1010:68;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;1010:68:9;;;;;;;;;;;;;;-1:-1:-1;;;;;1010:68:9;-1:-1:-1;;;;;;1010:68:9;;;;;;;;;;983:19;:96::i;:::-;845:241;;;;:::o;1955:310::-;2104:39;;-1:-1:-1;;;2104:39:9;;2128:4;2104:39;;;12087:34:23;-1:-1:-1;;;;;12157:15:23;;;12137:18;;;12130:43;2081:20:9;;2146:5;;2104:15;;;;;12022:18:23;;2104:39:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:47;;;;:::i;:::-;2188:69;;-1:-1:-1;;;;;12756:32:23;;2188:69:9;;;12738:51:23;12805:18;;;12798:34;;;2081:70:9;;-1:-1:-1;2161:97:9;;2181:5;;-1:-1:-1;;;2211:22:9;12711:18:23;;2188:69:9;12693:145:23;634:205:9;773:58;;-1:-1:-1;;;;;12756:32:23;;773:58:9;;;12738:51:23;12805:18;;;12798:34;;;746:86:9;;766:5;;-1:-1:-1;;;796:23:9;12711:18:23;;773:58:9;12693:145:23;746:86:9;634:205;;;:::o;3140:706::-;3559:23;3585:69;3613:4;3585:69;;;;;;;;;;;;;;;;;3593:5;-1:-1:-1;;;;;3585:27:9;;;:69;;;;;:::i;:::-;3668:17;;3559:95;;-1:-1:-1;3668:21:9;3664:176;;3763:10;3752:30;;;;;;;;;;;;:::i;:::-;3744:85;;;;-1:-1:-1;;;3744:85:9;;17245:2:23;3744:85:9;;;17227:21:23;17284:2;17264:18;;;17257:30;17323:34;17303:18;;;17296:62;-1:-1:-1;;;17374:18:23;;;17367:40;17424:19;;3744:85:9;17217:232:23;3461:223:10;3594:12;3625:52;3647:6;3655:4;3661:1;3664:12;3625:21;:52::i;:::-;3618:59;3461:223;-1:-1:-1;;;;3461:223:10:o;4548:499::-;4713:12;4770:5;4745:21;:30;;4737:81;;;;-1:-1:-1;;;4737:81:10;;15074:2:23;4737:81:10;;;15056:21:23;15113:2;15093:18;;;15086:30;15152:34;15132:18;;;15125:62;-1:-1:-1;;;15203:18:23;;;15196:36;15249:19;;4737:81:10;15046:228:23;4737:81:10;1034:20;;4828:60;;;;-1:-1:-1;;;4828:60:10;;16887:2:23;4828:60:10;;;16869:21:23;16926:2;16906:18;;;16899:30;16965:31;16945:18;;;16938:59;17014:18;;4828:60:10;16859:179:23;4828:60:10;4900:12;4914:23;4941:6;-1:-1:-1;;;;;4941:11:10;4960:5;4967:4;4941:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4899:73;;;;4989:51;5006:7;5015:10;5027:12;4989:16;:51::i;:::-;4982:58;4548:499;-1:-1:-1;;;;;;;4548:499:10:o;7161:692::-;7307:12;7335:7;7331:516;;;-1:-1:-1;7365:10:10;7358:17;;7331:516;7476:17;;:21;7472:365;;7670:10;7664:17;7730:15;7717:10;7713:2;7709:19;7702:44;7619:145;7809:12;7802:20;;-1:-1:-1;;;7802:20:10;;;;;;;;:::i;14:395:23:-;77:8;87:6;141:3;134:4;126:6;122:17;118:27;108:2;;166:8;156;149:26;108:2;-1:-1:-1;196:20:23;;-1:-1:-1;;;;;228:30:23;;225:2;;;278:8;268;261:26;225:2;322:4;314:6;310:17;298:29;;382:3;375:4;365:6;362:1;358:14;350:6;346:27;342:38;339:47;336:2;;;399:1;396;389:12;336:2;98:311;;;;;:::o;414:693::-;468:5;521:3;514:4;506:6;502:17;498:27;488:2;;543:5;536;529:20;488:2;583:6;570:20;609:4;633:60;649:43;689:2;649:43;:::i;:::-;633:60;:::i;:::-;715:3;739:2;734:3;727:15;767:2;762:3;758:12;751:19;;802:2;794:6;790:15;854:3;849:2;843;840:1;836:10;828:6;824:23;820:32;817:41;814:2;;;875:5;868;861:20;814:2;901:5;915:163;929:2;926:1;923:9;915:163;;;986:17;;974:30;;1024:12;;;;1056;;;;947:1;940:9;915:163;;;-1:-1:-1;1096:5:23;;478:629;-1:-1:-1;;;;;;;478:629:23:o;1112:937::-;1207:6;1238:2;1281;1269:9;1260:7;1256:23;1252:32;1249:2;;;1302:6;1294;1287:22;1249:2;1340:9;1334:16;-1:-1:-1;;;;;1365:6:23;1362:30;1359:2;;;1410:6;1402;1395:22;1359:2;1438:22;;1491:4;1483:13;;1479:27;-1:-1:-1;1469:2:23;;1525:6;1517;1510:22;1469:2;1559;1553:9;1582:60;1598:43;1638:2;1598:43;:::i;1582:60::-;1664:3;1688:2;1683:3;1676:15;1716:2;1711:3;1707:12;1700:19;;1747:2;1743;1739:11;1795:7;1790:2;1784;1781:1;1777:10;1773:2;1769:19;1765:28;1762:41;1759:2;;;1821:6;1813;1806:22;1759:2;1848:6;1839:15;;1863:156;1877:2;1874:1;1871:9;1863:156;;;1934:10;;1922:23;;1895:1;1888:9;;;;;1965:12;;;;1997;;1863:156;;;-1:-1:-1;2038:5:23;1218:831;-1:-1:-1;;;;;;;1218:831:23:o;2054:255::-;2121:6;2174:2;2162:9;2153:7;2149:23;2145:32;2142:2;;;2195:6;2187;2180:22;2142:2;2232:9;2226:16;2251:28;2273:5;2251:28;:::i;2314:283::-;2398:6;2451:2;2439:9;2430:7;2426:23;2422:32;2419:2;;;2472:6;2464;2457:22;2419:2;2509:9;2503:16;2528:39;2561:5;2528:39;:::i;2602:1094::-;2784:6;2792;2800;2808;2816;2869:3;2857:9;2848:7;2844:23;2840:33;2837:2;;;2891:6;2883;2876:22;2837:2;2935:9;2922:23;2954:39;2987:5;2954:39;:::i;:::-;3012:5;-1:-1:-1;3069:2:23;3054:18;;3041:32;3082:41;3041:32;3082:41;:::i;:::-;3142:7;-1:-1:-1;3200:2:23;3185:18;;3172:32;-1:-1:-1;;;;;3253:14:23;;;3250:2;;;3285:6;3277;3270:22;3250:2;3313:61;3366:7;3357:6;3346:9;3342:22;3313:61;:::i;:::-;3303:71;;3427:2;3416:9;3412:18;3399:32;3383:48;;3456:2;3446:8;3443:16;3440:2;;;3477:6;3469;3462:22;3440:2;;3505:63;3560:7;3549:8;3538:9;3534:24;3505:63;:::i;:::-;3495:73;;;3620:3;3609:9;3605:19;3592:33;3634:30;3656:7;3634:30;:::i;:::-;3683:7;3673:17;;;2827:869;;;;;;;;:::o;3701:1096::-;3895:6;3903;3911;3919;3927;3935;3988:3;3976:9;3967:7;3963:23;3959:33;3956:2;;;4010:6;4002;3995:22;3956:2;4054:9;4041:23;4073:39;4106:5;4073:39;:::i;:::-;4131:5;-1:-1:-1;4188:2:23;4173:18;;4160:32;4201:41;4160:32;4201:41;:::i;:::-;4261:7;-1:-1:-1;4319:2:23;4304:18;;4291:32;-1:-1:-1;;;;;4372:14:23;;;4369:2;;;4404:6;4396;4389:22;4369:2;4432:61;4485:7;4476:6;4465:9;4461:22;4432:61;:::i;:::-;4422:71;;4546:2;4535:9;4531:18;4518:32;4502:48;;4575:2;4565:8;4562:16;4559:2;;;4596:6;4588;4581:22;4559:2;;4624:63;4679:7;4668:8;4657:9;4653:24;4624:63;:::i;:::-;4614:73;;;4734:3;4723:9;4719:19;4706:33;4696:43;;4786:3;4775:9;4771:19;4758:33;4748:43;;3946:851;;;;;;;;:::o;4802:522::-;4919:6;4927;4935;4988:2;4976:9;4967:7;4963:23;4959:32;4956:2;;;5009:6;5001;4994:22;4956:2;5053:9;5040:23;5072:39;5105:5;5072:39;:::i;:::-;5130:5;-1:-1:-1;5187:2:23;5172:18;;5159:32;5200:41;5159:32;5200:41;:::i;:::-;4946:378;;5260:7;;-1:-1:-1;;;5314:2:23;5299:18;;;;5286:32;;4946:378::o;5329:1274::-;5527:6;5535;5543;5551;5559;5567;5575;5583;5636:3;5624:9;5615:7;5611:23;5607:33;5604:2;;;5658:6;5650;5643:22;5604:2;5702:9;5689:23;5721:39;5754:5;5721:39;:::i;:::-;5779:5;-1:-1:-1;5836:2:23;5821:18;;5808:32;5849:41;5808:32;5849:41;:::i;:::-;5909:7;-1:-1:-1;5963:2:23;5948:18;;5935:32;;-1:-1:-1;6018:2:23;6003:18;;5990:32;-1:-1:-1;;;;;6071:14:23;;;6068:2;;;6103:6;6095;6088:22;6068:2;6147:70;6209:7;6200:6;6189:9;6185:22;6147:70;:::i;:::-;6236:8;;-1:-1:-1;6121:96:23;-1:-1:-1;6324:3:23;6309:19;;6296:33;;-1:-1:-1;6341:16:23;;;6338:2;;;6375:6;6367;6360:22;6338:2;;6419:72;6483:7;6472:8;6461:9;6457:24;6419:72;:::i;:::-;5594:1009;;;;-1:-1:-1;5594:1009:23;;;;;;6393:98;;6592:3;6577:19;6564:33;;5594:1009;-1:-1:-1;;;;5594:1009:23:o;6608:660::-;6743:6;6751;6759;6767;6775;6828:3;6816:9;6807:7;6803:23;6799:33;6796:2;;;6850:6;6842;6835:22;6796:2;6894:9;6881:23;6913:39;6946:5;6913:39;:::i;:::-;6971:5;-1:-1:-1;7028:2:23;7013:18;;7000:32;7041:41;7000:32;7041:41;:::i;:::-;6786:482;;7101:7;;-1:-1:-1;;;;7155:2:23;7140:18;;7127:32;;7206:2;7191:18;;7178:32;;7257:3;7242:19;;;7229:33;;-1:-1:-1;6786:482:23:o;7273:660::-;7397:6;7405;7413;7421;7474:3;7462:9;7453:7;7449:23;7445:33;7442:2;;;7496:6;7488;7481:22;7442:2;7540:9;7527:23;7559:39;7592:5;7559:39;:::i;:::-;7617:5;-1:-1:-1;7674:2:23;7659:18;;7646:32;7687:41;7646:32;7687:41;:::i;:::-;7747:7;-1:-1:-1;7801:2:23;7786:18;;7773:32;;-1:-1:-1;7857:2:23;7842:18;;7829:32;7870:31;7829:32;7870:31;:::i;:::-;7432:501;;;;-1:-1:-1;7432:501:23;;-1:-1:-1;;7432:501:23:o;7938:798::-;8080:6;8088;8096;8104;8112;8120;8173:3;8161:9;8152:7;8148:23;8144:33;8141:2;;;8195:6;8187;8180:22;8141:2;8239:9;8226:23;8258:39;8291:5;8258:39;:::i;:::-;8316:5;-1:-1:-1;8373:2:23;8358:18;;8345:32;8386:41;8345:32;8386:41;:::i;:::-;8446:7;-1:-1:-1;8500:2:23;8485:18;;8472:32;;-1:-1:-1;8556:2:23;8541:18;;8528:32;8569:31;8528:32;8569:31;:::i;:::-;8131:605;;;;-1:-1:-1;8131:605:23;;8673:3;8658:19;;8645:33;;8725:3;8710:19;;;8697:33;;-1:-1:-1;8131:605:23;-1:-1:-1;;8131:605:23:o;8741:798::-;8872:6;8880;8888;8896;8904;8957:3;8945:9;8936:7;8932:23;8928:33;8925:2;;;8979:6;8971;8964:22;8925:2;9023:9;9010:23;9042:39;9075:5;9042:39;:::i;:::-;9100:5;-1:-1:-1;9157:2:23;9142:18;;9129:32;9170:41;9129:32;9170:41;:::i;:::-;9230:7;-1:-1:-1;9289:2:23;9274:18;;9261:32;9302:31;9261:32;9302:31;:::i;:::-;9352:7;-1:-1:-1;9411:2:23;9396:18;;9383:32;9424:31;9383:32;9424:31;:::i;:::-;8915:624;;;;-1:-1:-1;8915:624:23;;9528:3;9513:19;9500:33;;8915:624;-1:-1:-1;;8915:624:23:o;9544:936::-;9693:6;9701;9709;9717;9725;9733;9741;9794:3;9782:9;9773:7;9769:23;9765:33;9762:2;;;9816:6;9808;9801:22;9762:2;9860:9;9847:23;9879:39;9912:5;9879:39;:::i;:::-;9937:5;-1:-1:-1;9994:2:23;9979:18;;9966:32;10007:41;9966:32;10007:41;:::i;:::-;10067:7;-1:-1:-1;10126:2:23;10111:18;;10098:32;10139:31;10098:32;10139:31;:::i;:::-;10189:7;-1:-1:-1;10248:2:23;10233:18;;10220:32;10261:31;10220:32;10261:31;:::i;:::-;9752:728;;;;-1:-1:-1;9752:728:23;;10365:3;10350:19;;10337:33;;10417:3;10402:19;;10389:33;;-1:-1:-1;10469:3:23;10454:19;;;10441:33;;-1:-1:-1;9752:728:23;-1:-1:-1;;9752:728:23:o;10485:194::-;10555:6;10608:2;10596:9;10587:7;10583:23;10579:32;10576:2;;;10629:6;10621;10614:22;10576:2;-1:-1:-1;10657:16:23;;10566:113;-1:-1:-1;10566:113:23:o;10684:257::-;10752:6;10805:2;10793:9;10784:7;10780:23;10776:32;10773:2;;;10826:6;10818;10811:22;10773:2;10863:9;10857:16;10882:29;10905:5;10882:29;:::i;10946:437::-;10999:3;11037:5;11031:12;11064:6;11059:3;11052:19;11090:4;11119:2;11114:3;11110:12;11103:19;;11156:2;11149:5;11145:14;11177:3;11189:169;11203:6;11200:1;11197:13;11189:169;;;11264:13;;11252:26;;11298:12;;;;11333:15;;;;11225:1;11218:9;11189:169;;;-1:-1:-1;11374:3:23;;11007:376;-1:-1:-1;;;;;11007:376:23:o;11388:274::-;11517:3;11555:6;11549:13;11571:53;11617:6;11612:3;11605:4;11597:6;11593:17;11571:53;:::i;:::-;11640:16;;;;;11525:137;-1:-1:-1;;11525:137:23:o;12184:375::-;-1:-1:-1;;;;;12442:15:23;;;12424:34;;12494:15;;;;12489:2;12474:18;;12467:43;12541:2;12526:18;;12519:34;;;;12374:2;12359:18;;12341:218::o;12843:465::-;13100:2;13089:9;13082:21;13063:4;13126:56;13178:2;13167:9;13163:18;13155:6;13126:56;:::i;:::-;13230:9;13222:6;13218:22;13213:2;13202:9;13198:18;13191:50;13258:44;13295:6;13287;13258:44;:::i;13313:342::-;13514:2;13503:9;13496:21;13477:4;13534:56;13586:2;13575:9;13571:18;13563:6;13534:56;:::i;:::-;13526:64;;13640:6;13633:14;13626:22;13621:2;13610:9;13606:18;13599:50;13486:169;;;;;:::o;13660:411::-;13903:2;13892:9;13885:21;13866:4;13923:56;13975:2;13964:9;13960:18;13952:6;13923:56;:::i;:::-;14010:2;13995:18;;13988:34;;;;-1:-1:-1;14053:2:23;14038:18;14031:34;13915:64;13875:196;-1:-1:-1;13875:196:23:o;14484:383::-;14633:2;14622:9;14615:21;14596:4;14665:6;14659:13;14708:6;14703:2;14692:9;14688:18;14681:34;14724:66;14783:6;14778:2;14767:9;14763:18;14758:2;14750:6;14746:15;14724:66;:::i;:::-;14851:2;14830:15;-1:-1:-1;;14826:29:23;14811:45;;;;14858:2;14807:54;;14605:262;-1:-1:-1;;14605:262:23:o;17636:639::-;17863:25;;;17924:2;17919;17904:18;;17897:30;;;17943:18;;17936:34;;;-1:-1:-1;;;;;;17982:31:23;;17979:2;;;18029:4;18023;18016:18;17979:2;18066:6;18063:1;18059:14;18124:6;18116;18110:3;18099:9;18095:19;18082:49;18154:22;;18178:3;18150:32;18191:16;;;18257:2;18242:18;;;18235:34;;;;18150:32;17853:422;-1:-1:-1;;;17853:422:23:o;18280:403::-;18515:6;18504:9;18497:25;18558:2;18553;18542:9;18538:18;18531:30;18478:4;18578:56;18630:2;18619:9;18615:18;18607:6;18578:56;:::i;:::-;18570:64;;18670:6;18665:2;18654:9;18650:18;18643:34;18487:196;;;;;;:::o;21261:275::-;21332:2;21326:9;21397:2;21378:13;;-1:-1:-1;;21374:27:23;21362:40;;-1:-1:-1;;;;;21417:34:23;;21453:22;;;21414:62;21411:2;;;21479:18;;:::i;:::-;21515:2;21508:22;21306:230;;-1:-1:-1;21306:230:23:o;21541:183::-;21601:4;-1:-1:-1;;;;;21626:6:23;21623:30;21620:2;;;21656:18;;:::i;:::-;-1:-1:-1;21701:1:23;21697:14;21713:4;21693:25;;21610:114::o;21729:128::-;21769:3;21800:1;21796:6;21793:1;21790:13;21787:2;;;21806:18;;:::i;:::-;-1:-1:-1;21842:9:23;;21777:80::o;21862:258::-;21934:1;21944:113;21958:6;21955:1;21952:13;21944:113;;;22034:11;;;22028:18;22015:11;;;22008:39;21980:2;21973:10;21944:113;;;22075:6;22072:1;22069:13;22066:2;;;-1:-1:-1;;22110:1:23;22092:16;;22085:27;21915:205::o;22125:175::-;22162:3;22206:4;22199:5;22195:16;22235:4;22226:7;22223:17;22220:2;;;22243:18;;:::i;:::-;22292:1;22279:15;;22170:130;-1:-1:-1;;22170:130:23:o;22305:127::-;22366:10;22361:3;22357:20;22354:1;22347:31;22397:4;22394:1;22387:15;22421:4;22418:1;22411:15;22437:127;22498:10;22493:3;22489:20;22486:1;22479:31;22529:4;22526:1;22519:15;22553:4;22550:1;22543:15;22569:118;22655:5;22648:13;22641:21;22634:5;22631:32;22621:2;;22677:1;22674;22667:12;22621:2;22611:76;:::o;22692:139::-;-1:-1:-1;;;;;22775:31:23;;22765:42;;22755:2;;22821:1;22818;22811:12;22836:114;22920:4;22913:5;22909:16;22902:5;22899:27;22889:2;;22940:1;22937;22930:12
Swarm Source
ipfs://343d6ecd35e1011becba92cf5dffcce4f5c47674024af1782dd1cbb4727d35a7
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
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.