Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- PulseXStableSwapThreePoolDeployer
- Optimization enabled
- true
- Compiler version
- v0.8.10+commit.fc410830
- Optimization runs
- 100
- EVM Version
- default
- Verified at
- 2024-09-04T14:01:23.860999Z
contracts/PulseXStableSwapThreePoolDeployer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import "@openzeppelin-4.5.0/contracts/access/Ownable.sol";
import "./PulseXStableSwapThreePool.sol";
import { CreateThreePoolArgs } from "./interfaces/IPulseXStableSwapDeployer.sol";
error FailedDeployment();
contract PulseXStableSwapThreePoolDeployer is Ownable {
uint256 public constant N_COINS = 3;
/**
* @notice constructor
*/
constructor() {}
/**
* @notice createPool
* @param args: CreateThreePoolArgs struct.
*/
function createPool(CreateThreePoolArgs calldata args) external virtual onlyOwner returns (address) {
require(args.tokenA != address(0) && args.tokenB != address(0) && args.tokenC != address(0), "Illegal token");
address t0 = args.tokenA;
address t1 = args.tokenB;
address t2 = args.tokenC;
address[N_COINS] memory coins = [t0, t1, t2];
// create swap contract
bytes memory bytecode = abi.encodePacked(
type(PulseXStableSwapThreePool).creationCode,
abi.encode(args.STABLESWAP_FACTORY),
abi.encode(args.WPLS)
);
bytes32 salt = keccak256(abi.encodePacked(t0, t1, t2, msg.sender, block.timestamp, block.chainid));
address swapContract;
assembly {
swapContract := create2(0, add(bytecode, 32), mload(bytecode), salt)
}
if (swapContract == address(0)) {
revert FailedDeployment();
}
PulseXStableSwapThreePool(swapContract).initialize(coins, args.A, args.fee, args.admin_fee, args.admin, args.LP);
return swapContract;
}
}
contracts/interfaces/IWPLS.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
interface IWPLS {
function deposit() external payable;
function transfer(address to, uint256 value) external returns (bool);
function withdraw(uint256) external;
function balanceOf(address account) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
}
@openzeppelin-4.5.0/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
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;
}
}
contracts/PulseXStableSwapThreePool.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import "@openzeppelin-4.5.0/contracts/access/Ownable.sol";
import "@openzeppelin-4.5.0/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin-4.5.0/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin-4.5.0/contracts/security/ReentrancyGuard.sol";
import "./interfaces/IPulseXStableSwapFactory.sol";
import "./interfaces/IPulseXStableSwapLP.sol";
import "./interfaces/IWPLS.sol";
contract PulseXStableSwapThreePool is Ownable, ReentrancyGuard {
using SafeERC20 for IERC20;
uint256 public constant N_COINS = 3;
uint256 public constant MAX_DECIMAL = 18;
uint256 public constant FEE_DENOMINATOR = 1e10;
uint256 public constant PRECISION = 1e18;
uint256[N_COINS] public PRECISION_MUL;
uint256[N_COINS] public RATES;
uint256 public constant MAX_ADMIN_FEE = 1e10;
uint256 public constant MAX_FEE = 5e9;
uint256 public constant MAX_A = 1e6;
uint256 public constant MAX_A_CHANGE = 10;
uint256 public constant MIN_PLS_GAS = 2300;
uint256 public constant MAX_PLS_GAS = 23000;
uint256 public constant ADMIN_ACTIONS_DELAY = 3 days;
uint256 public constant MIN_RAMP_TIME = 1 days;
address[N_COINS] public coins;
uint256[N_COINS] public balances;
uint256 public fee; // fee * 1e10.
uint256 public admin_fee; // admin_fee * 1e10.
uint256 public pls_gas = 4029; // transfer pls gas.
IPulseXStableSwapLP public token;
address constant PLS_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
bool public support_PLS;
uint256 public initial_A;
uint256 public future_A;
uint256 public initial_A_time;
uint256 public future_A_time;
uint256 public admin_actions_deadline;
uint256 public future_fee;
uint256 public future_admin_fee;
uint256 public kill_deadline;
uint256 public constant KILL_DEADLINE_DT = 2 * 30 days;
bool public is_killed;
address public immutable STABLESWAP_FACTORY;
address public immutable POOL_DEPLOYER;
address public immutable WPLS;
bool public isInitialized;
event TokenExchange(
address indexed buyer,
uint256 sold_id,
uint256 tokens_sold,
uint256 bought_id,
uint256 tokens_bought
);
event AddLiquidity(
address indexed provider,
uint256[N_COINS] token_amounts,
uint256[N_COINS] fees,
uint256 invariant,
uint256 token_supply
);
event RemoveLiquidity(
address indexed provider,
uint256[N_COINS] token_amounts,
uint256[N_COINS] fees,
uint256 token_supply
);
event RemoveLiquidityOne(address indexed provider, uint256 index, uint256 token_amount, uint256 coin_amount);
event RemoveLiquidityImbalance(
address indexed provider,
uint256[N_COINS] token_amounts,
uint256[N_COINS] fees,
uint256 invariant,
uint256 token_supply
);
event CommitNewFee(uint256 indexed deadline, uint256 fee, uint256 admin_fee);
event NewFee(uint256 fee, uint256 admin_fee);
event RampA(uint256 old_A, uint256 new_A, uint256 initial_time, uint256 future_time);
event StopRampA(uint256 A, uint256 t);
event SetPLSGas(uint256 pls_gas);
event RevertParameters();
event DonateAdminFees();
event Kill();
event Unkill();
/**
* @notice constructor
*/
constructor(address _STABLESWAP_FACTORY, address _WPLS) {
POOL_DEPLOYER = msg.sender;
STABLESWAP_FACTORY = _STABLESWAP_FACTORY;
WPLS = _WPLS;
}
/**
* @notice initialize
* @param _coins: Addresses of ERC20 conracts of coins (c-tokens) involved
* @param _A: Amplification coefficient multiplied by n * (n - 1)
* @param _fee: Fee to charge for exchanges
* @param _admin_fee: Admin fee
* @param _owner: Owner
* @param _LP: LP address
*/
function initialize(
address[N_COINS] memory _coins,
uint256 _A,
uint256 _fee,
uint256 _admin_fee,
address _owner,
address _LP
) external {
require(!isInitialized, "Operations: Already initialized");
require(msg.sender == POOL_DEPLOYER, "Operations: Not deployer");
require(_A <= MAX_A, "_A exceeds maximum");
require(_fee <= MAX_FEE, "_fee exceeds maximum");
require(_admin_fee <= MAX_ADMIN_FEE, "_admin_fee exceeds maximum");
isInitialized = true;
for (uint256 i = 0; i < N_COINS; i++) {
require(_coins[i] != address(0), "ZERO Address");
uint256 coinDecimal;
if (_coins[i] == PLS_ADDRESS) {
coinDecimal = 18;
support_PLS = true;
} else {
coinDecimal = IERC20Metadata(_coins[i]).decimals();
}
require(coinDecimal <= MAX_DECIMAL, "The maximum decimal cannot exceed 18");
//set PRECISION_MUL and RATES
PRECISION_MUL[i] = 10**(MAX_DECIMAL - coinDecimal);
RATES[i] = PRECISION * PRECISION_MUL[i];
}
coins = _coins;
initial_A = _A;
future_A = _A;
fee = _fee;
admin_fee = _admin_fee;
kill_deadline = block.timestamp + KILL_DEADLINE_DT;
token = IPulseXStableSwapLP(_LP);
transferOwnership(_owner);
}
function get_A() internal view returns (uint256) {
//Handle ramping A up or down
uint256 t1 = future_A_time;
uint256 A1 = future_A;
if (block.timestamp < t1) {
uint256 A0 = initial_A;
uint256 t0 = initial_A_time;
// Expressions in uint256 cannot have negative numbers, thus "if"
if (A1 > A0) {
return A0 + ((A1 - A0) * (block.timestamp - t0)) / (t1 - t0);
} else {
return A0 - ((A0 - A1) * (block.timestamp - t0)) / (t1 - t0);
}
} else {
// when t1 == 0 or block.timestamp >= t1
return A1;
}
}
function A() external view returns (uint256) {
return get_A();
}
function _xp() internal view returns (uint256[N_COINS] memory result) {
result = RATES;
for (uint256 i = 0; i < N_COINS; i++) {
result[i] = (result[i] * balances[i]) / PRECISION;
}
}
function _xp_mem(uint256[N_COINS] memory _balances) internal view returns (uint256[N_COINS] memory result) {
result = RATES;
for (uint256 i = 0; i < N_COINS; i++) {
result[i] = (result[i] * _balances[i]) / PRECISION;
}
}
function get_D(uint256[N_COINS] memory xp, uint256 amp) internal pure returns (uint256) {
uint256 S;
for (uint256 i = 0; i < N_COINS; i++) {
S += xp[i];
}
if (S == 0) {
return 0;
}
uint256 Dprev;
uint256 D = S;
uint256 Ann = amp * N_COINS;
for (uint256 j = 0; j < 255; j++) {
uint256 D_P = D;
for (uint256 k = 0; k < N_COINS; k++) {
D_P = (D_P * D) / (xp[k] * N_COINS); // If division by 0, this will be borked: only withdrawal will work. And that is good
}
Dprev = D;
D = ((Ann * S + D_P * N_COINS) * D) / ((Ann - 1) * D + (N_COINS + 1) * D_P);
// Equality with the precision of 1
if (D > Dprev) {
if (D - Dprev <= 1) {
break;
}
} else {
if (Dprev - D <= 1) {
break;
}
}
}
return D;
}
function get_D_mem(uint256[N_COINS] memory _balances, uint256 amp) internal view returns (uint256) {
return get_D(_xp_mem(_balances), amp);
}
function get_virtual_price() external view returns (uint256) {
/**
Returns portfolio virtual price (for calculating profit)
scaled up by 1e18
*/
uint256 D = get_D(_xp(), get_A());
/**
D is in the units similar to DAI (e.g. converted to precision 1e18)
When balanced, D = n * x_u - total virtual value of the portfolio
*/
if (D == 0) {
revert("get_virtual_price: D is zero");
}
uint256 token_supply = token.totalSupply();
return (D * PRECISION) / token_supply;
}
function calc_token_amount(uint256[N_COINS] memory amounts, bool deposit) external view returns (uint256) {
/**
Simplified method to calculate addition or reduction in token supply at
deposit or withdrawal without taking fees into account (but looking at
slippage).
Needed to prevent front-running, not for precise calculations!
*/
uint256[N_COINS] memory _balances = balances;
uint256 amp = get_A();
uint256 D0 = get_D_mem(_balances, amp);
for (uint256 i = 0; i < N_COINS; i++) {
if (deposit) {
_balances[i] += amounts[i];
} else {
_balances[i] -= amounts[i];
}
}
uint256 D1 = get_D_mem(_balances, amp);
uint256 token_amount = token.totalSupply();
uint256 difference;
if (deposit) {
difference = D1 - D0;
} else {
difference = D0 - D1;
}
return (difference * token_amount) / D0;
}
function add_liquidity(uint256[N_COINS] memory amounts, uint256 min_mint_amount) external payable nonReentrant {
//Amounts is amounts of c-tokens
require(!is_killed, "Killed");
if (!support_PLS) {
require(msg.value == 0, "Inconsistent quantity"); // Avoid sending PLS by mistake.
}
uint256[N_COINS] memory fees;
uint256 _fee = (fee * N_COINS) / (4 * (N_COINS - 1));
uint256 _admin_fee = admin_fee;
uint256 amp = get_A();
uint256 token_supply = token.totalSupply();
//Initial invariant
uint256 D0;
uint256[N_COINS] memory old_balances = balances;
if (token_supply > 0) {
D0 = get_D_mem(old_balances, amp);
}
uint256[N_COINS] memory new_balances = [old_balances[0], old_balances[1], old_balances[2]];
for (uint256 i = 0; i < N_COINS; i++) {
if (token_supply == 0) {
require(amounts[i] > 0, "Initial deposit requires all coins");
}
// balances store amounts of c-tokens
new_balances[i] = old_balances[i] + amounts[i];
}
// Invariant after change
uint256 D1 = get_D_mem(new_balances, amp);
require(D1 > D0, "D1 must be greater than D0");
// We need to recalculate the invariant accounting for fees
// to calculate fair user's share
uint256 D2 = D1;
if (token_supply > 0) {
// Only account for fees if we are not the first to deposit
for (uint256 i = 0; i < N_COINS; i++) {
uint256 ideal_balance = (D1 * old_balances[i]) / D0;
uint256 difference;
if (ideal_balance > new_balances[i]) {
difference = ideal_balance - new_balances[i];
} else {
difference = new_balances[i] - ideal_balance;
}
fees[i] = (_fee * difference) / FEE_DENOMINATOR;
balances[i] = new_balances[i] - ((fees[i] * _admin_fee) / FEE_DENOMINATOR);
new_balances[i] -= fees[i];
}
D2 = get_D_mem(new_balances, amp);
} else {
balances = new_balances;
}
// Calculate, how much pool tokens to mint
uint256 mint_amount;
if (token_supply == 0) {
mint_amount = D1; // Take the dust if there was any
} else {
mint_amount = (token_supply * (D2 - D0)) / D0;
}
require(mint_amount >= min_mint_amount, "Slippage screwed you");
// Take coins from the sender
for (uint256 i = 0; i < N_COINS; i++) {
uint256 amount = amounts[i];
address coin = coins[i];
transfer_in(coin, amount);
}
// Mint pool tokens
token.mint(msg.sender, mint_amount);
_withdraw_admin_fees();
emit AddLiquidity(msg.sender, amounts, fees, D1, token_supply + mint_amount);
}
function get_y(
uint256 i,
uint256 j,
uint256 x,
uint256[N_COINS] memory xp_
) internal view returns (uint256) {
// x in the input is converted to the same price/precision
require((i != j) && (i < N_COINS) && (j < N_COINS), "Illegal parameter");
uint256 amp = get_A();
uint256 D = get_D(xp_, amp);
uint256 c = D;
uint256 S_;
uint256 Ann = amp * N_COINS;
uint256 _x;
for (uint256 k = 0; k < N_COINS; k++) {
if (k == i) {
_x = x;
} else if (k != j) {
_x = xp_[k];
} else {
continue;
}
S_ += _x;
c = (c * D) / (_x * N_COINS);
}
c = (c * D) / (Ann * N_COINS);
uint256 b = S_ + D / Ann; // - D
uint256 y_prev;
uint256 y = D;
for (uint256 m = 0; m < 255; m++) {
y_prev = y;
y = (y * y + c) / (2 * y + b - D);
// Equality with the precision of 1
if (y > y_prev) {
if (y - y_prev <= 1) {
break;
}
} else {
if (y_prev - y <= 1) {
break;
}
}
}
return y;
}
function get_dy(
uint256 i,
uint256 j,
uint256 dx
) external view returns (uint256) {
// dx and dy in c-units
uint256[N_COINS] memory rates = RATES;
uint256[N_COINS] memory xp = _xp();
uint256 x = xp[i] + ((dx * rates[i]) / PRECISION);
uint256 y = get_y(i, j, x, xp);
uint256 dy = ((xp[j] - y - 1) * PRECISION) / rates[j];
uint256 _fee = (fee * dy) / FEE_DENOMINATOR;
return dy - _fee;
}
function get_dy_underlying(
uint256 i,
uint256 j,
uint256 dx
) external view returns (uint256) {
// dx and dy in underlying units
uint256[N_COINS] memory xp = _xp();
uint256[N_COINS] memory precisions = PRECISION_MUL;
uint256 x = xp[i] + dx * precisions[i];
uint256 y = get_y(i, j, x, xp);
uint256 dy = (xp[j] - y - 1) / precisions[j];
uint256 _fee = (fee * dy) / FEE_DENOMINATOR;
return dy - _fee;
}
function exchange(
uint256 i,
uint256 j,
uint256 dx,
uint256 min_dy
) external payable nonReentrant {
require(!is_killed, "Killed");
if (!support_PLS) {
require(msg.value == 0, "Inconsistent quantity"); // Avoid sending PLS by mistake.
}
uint256[N_COINS] memory old_balances = balances;
uint256[N_COINS] memory xp = _xp_mem(old_balances);
uint256 x = xp[i] + (dx * RATES[i]) / PRECISION;
uint256 y = get_y(i, j, x, xp);
uint256 dy = xp[j] - y - 1; // -1 just in case there were some rounding errors
uint256 dy_fee = (dy * fee) / FEE_DENOMINATOR;
// Convert all to real units
dy = ((dy - dy_fee) * PRECISION) / RATES[j];
require(dy >= min_dy, "Exchange resulted in fewer coins than expected");
uint256 dy_admin_fee = (dy_fee * admin_fee) / FEE_DENOMINATOR;
dy_admin_fee = (dy_admin_fee * PRECISION) / RATES[j];
// Change balances exactly in same way as we change actual ERC20 coin amounts
balances[i] = old_balances[i] + dx;
// When rounding errors happen, we undercharge admin fee in favor of LP
balances[j] = old_balances[j] - dy - dy_admin_fee;
address iAddress = coins[i];
if (iAddress == PLS_ADDRESS) {
require(dx == msg.value, "Inconsistent quantity");
} else {
IERC20(iAddress).safeTransferFrom(msg.sender, address(this), dx);
}
address jAddress = coins[j];
transfer_out(jAddress, dy);
emit TokenExchange(msg.sender, i, dx, j, dy);
}
function remove_liquidity(uint256 _amount, uint256[N_COINS] memory min_amounts) external nonReentrant {
uint256 total_supply = token.totalSupply();
uint256[N_COINS] memory amounts;
uint256[N_COINS] memory fees; //Fees are unused but we've got them historically in event
for (uint256 i = 0; i < N_COINS; i++) {
uint256 value = (balances[i] * _amount) / total_supply;
require(value >= min_amounts[i], "Withdrawal resulted in fewer coins than expected");
balances[i] -= value;
amounts[i] = value;
transfer_out(coins[i], value);
}
token.burnFrom(msg.sender, _amount); // dev: insufficient funds
_withdraw_admin_fees();
emit RemoveLiquidity(msg.sender, amounts, fees, total_supply - _amount);
}
function remove_liquidity_imbalance(uint256[N_COINS] memory amounts, uint256 max_burn_amount)
external
nonReentrant
{
require(!is_killed, "Killed");
uint256 token_supply = token.totalSupply();
require(token_supply > 0, "dev: zero total supply");
uint256 _fee = (fee * N_COINS) / (4 * (N_COINS - 1));
uint256 _admin_fee = admin_fee;
uint256 amp = get_A();
uint256[N_COINS] memory old_balances = balances;
uint256[N_COINS] memory new_balances = [old_balances[0], old_balances[1], old_balances[2]];
uint256 D0 = get_D_mem(old_balances, amp);
for (uint256 i = 0; i < N_COINS; i++) {
new_balances[i] -= amounts[i];
}
uint256 D1 = get_D_mem(new_balances, amp);
uint256[N_COINS] memory fees;
for (uint256 i = 0; i < N_COINS; i++) {
uint256 ideal_balance = (D1 * old_balances[i]) / D0;
uint256 difference;
if (ideal_balance > new_balances[i]) {
difference = ideal_balance - new_balances[i];
} else {
difference = new_balances[i] - ideal_balance;
}
fees[i] = (_fee * difference) / FEE_DENOMINATOR;
balances[i] = new_balances[i] - ((fees[i] * _admin_fee) / FEE_DENOMINATOR);
new_balances[i] -= fees[i];
}
uint256 D2 = get_D_mem(new_balances, amp);
uint256 token_amount = ((D0 - D2) * token_supply) / D0;
require(token_amount > 0, "token_amount must be greater than 0");
token_amount += 1; // In case of rounding errors - make it unfavorable for the "attacker"
require(token_amount <= max_burn_amount, "Slippage screwed you");
token.burnFrom(msg.sender, token_amount); // dev: insufficient funds
for (uint256 i = 0; i < N_COINS; i++) {
if (amounts[i] > 0) {
transfer_out(coins[i], amounts[i]);
}
}
token_supply -= token_amount;
_withdraw_admin_fees();
emit RemoveLiquidityImbalance(msg.sender, amounts, fees, D1, token_supply);
}
function get_y_D(
uint256 A_,
uint256 i,
uint256[N_COINS] memory xp,
uint256 D
) internal pure returns (uint256) {
/**
Calculate x[i] if one reduces D from being calculated for xp to D
Done by solving quadratic equation iteratively.
x_1**2 + x1 * (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)
*/
// x in the input is converted to the same price/precision
require(i < N_COINS, "dev: i above N_COINS");
uint256 c = D;
uint256 S_;
uint256 Ann = A_ * N_COINS;
uint256 _x;
for (uint256 k = 0; k < N_COINS; k++) {
if (k != i) {
_x = xp[k];
} else {
continue;
}
S_ += _x;
c = (c * D) / (_x * N_COINS);
}
c = (c * D) / (Ann * N_COINS);
uint256 b = S_ + D / Ann;
uint256 y_prev;
uint256 y = D;
for (uint256 k = 0; k < 255; k++) {
y_prev = y;
y = (y * y + c) / (2 * y + b - D);
// Equality with the precision of 1
if (y > y_prev) {
if (y - y_prev <= 1) {
break;
}
} else {
if (y_prev - y <= 1) {
break;
}
}
}
return y;
}
function _calc_withdraw_one_coin(uint256 _token_amount, uint256 i) internal view returns (uint256, uint256) {
// First, need to calculate
// * Get current D
// * Solve Eqn against y_i for D - _token_amount
uint256 amp = get_A();
uint256 _fee = (fee * N_COINS) / (4 * (N_COINS - 1));
uint256[N_COINS] memory precisions = PRECISION_MUL;
uint256 total_supply = token.totalSupply();
uint256[N_COINS] memory xp = _xp();
uint256 D0 = get_D(xp, amp);
uint256 D1 = D0 - (_token_amount * D0) / total_supply;
uint256[N_COINS] memory xp_reduced = xp;
uint256 new_y = get_y_D(amp, i, xp, D1);
uint256 dy_0 = (xp[i] - new_y) / precisions[i]; // w/o fees
for (uint256 k = 0; k < N_COINS; k++) {
uint256 dx_expected;
if (k == i) {
dx_expected = (xp[k] * D1) / D0 - new_y;
} else {
dx_expected = xp[k] - (xp[k] * D1) / D0;
}
xp_reduced[k] -= (_fee * dx_expected) / FEE_DENOMINATOR;
}
uint256 dy = xp_reduced[i] - get_y_D(amp, i, xp_reduced, D1);
dy = (dy - 1) / precisions[i]; // Withdraw less to account for rounding errors
return (dy, dy_0 - dy);
}
function calc_withdraw_one_coin(uint256 _token_amount, uint256 i) external view returns (uint256) {
(uint256 dy, ) = _calc_withdraw_one_coin(_token_amount, i);
return dy;
}
function remove_liquidity_one_coin(
uint256 _token_amount,
uint256 i,
uint256 min_amount
) external nonReentrant {
// Remove _amount of liquidity all in a form of coin i
require(!is_killed, "Killed");
(uint256 dy, uint256 dy_fee) = _calc_withdraw_one_coin(_token_amount, i);
require(dy >= min_amount, "Not enough coins removed");
balances[i] -= (dy + (dy_fee * admin_fee) / FEE_DENOMINATOR);
token.burnFrom(msg.sender, _token_amount); // dev: insufficient funds
transfer_out(coins[i], dy);
_withdraw_admin_fees();
emit RemoveLiquidityOne(msg.sender, i, _token_amount, dy);
}
function transfer_out(address coin_address, uint256 value) internal {
if (coin_address == PLS_ADDRESS) {
_safeTransferPLS(msg.sender, value);
} else {
IERC20(coin_address).safeTransfer(msg.sender, value);
}
}
function transfer_in(address coin_address, uint256 value) internal {
if (coin_address == PLS_ADDRESS) {
require(value == msg.value, "Inconsistent quantity");
} else {
if (value != 0) {
IERC20(coin_address).safeTransferFrom(msg.sender, address(this), value);
}
}
}
function _safeTransferPLS(address to, uint256 value) internal {
(bool success, bytes memory b) = to.call{gas: pls_gas, value: value}("");
if (!success) {
// more than likely this was a receive method error
// which does not return any bytes so instead of saying nothing,
// we can at least say that the transfer failed
if (b.length == 0) revert("PLS transfer failed");
assembly {
revert(add(32, b), mload(b))
}
}
}
// Admin functions
function set_pls_gas(uint256 _pls_gas) external onlyOwner {
require(_pls_gas >= MIN_PLS_GAS && _pls_gas <= MAX_PLS_GAS, "Illegal gas");
pls_gas = _pls_gas;
emit SetPLSGas(_pls_gas);
}
function ramp_A(uint256 _future_A, uint256 _future_time) external onlyOwner {
require(block.timestamp >= initial_A_time + MIN_RAMP_TIME, "dev : too early");
require(_future_time >= block.timestamp + MIN_RAMP_TIME, "dev: insufficient time");
uint256 _initial_A = get_A();
require(_future_A > 0 && _future_A < MAX_A, "_future_A must be between 0 and MAX_A");
require(
(_future_A >= _initial_A && _future_A <= _initial_A * MAX_A_CHANGE) ||
(_future_A < _initial_A && _future_A * MAX_A_CHANGE >= _initial_A),
"Illegal parameter _future_A"
);
initial_A = _initial_A;
future_A = _future_A;
initial_A_time = block.timestamp;
future_A_time = _future_time;
emit RampA(_initial_A, _future_A, block.timestamp, _future_time);
}
function stop_rampget_A() external onlyOwner {
uint256 current_A = get_A();
initial_A = current_A;
future_A = current_A;
initial_A_time = block.timestamp;
future_A_time = block.timestamp;
// now (block.timestamp < t1) is always False, so we return saved A
emit StopRampA(current_A, block.timestamp);
}
function commit_new_fee(uint256 new_fee, uint256 new_admin_fee) external onlyOwner {
require(admin_actions_deadline == 0, "admin_actions_deadline must be 0"); // dev: active action
require(new_fee <= MAX_FEE, "dev: fee exceeds maximum");
require(new_admin_fee <= MAX_ADMIN_FEE, "dev: admin fee exceeds maximum");
admin_actions_deadline = block.timestamp + ADMIN_ACTIONS_DELAY;
future_fee = new_fee;
future_admin_fee = new_admin_fee;
emit CommitNewFee(admin_actions_deadline, new_fee, new_admin_fee);
}
function apply_new_fee() external onlyOwner {
require(block.timestamp >= admin_actions_deadline, "dev: insufficient time");
require(admin_actions_deadline != 0, "admin_actions_deadline should not be 0");
admin_actions_deadline = 0;
fee = future_fee;
admin_fee = future_admin_fee;
emit NewFee(fee, admin_fee);
}
function revert_new_parameters() external onlyOwner {
admin_actions_deadline = 0;
emit RevertParameters();
}
function admin_balances(uint256 i) external view returns (uint256) {
if (coins[i] == PLS_ADDRESS) {
return address(this).balance - balances[i];
} else {
return IERC20(coins[i]).balanceOf(address(this)) - balances[i];
}
}
function _withdraw_admin_fees() internal {
address fee_to = IPulseXStableSwapFactory(STABLESWAP_FACTORY).fee_to();
if (fee_to == address(0)) return;
for (uint256 i = 0; i < N_COINS; i++) {
uint256 value;
// check for fee amounts, underflow safe
if (coins[i] == PLS_ADDRESS) {
uint256 balance = address(this).balance;
value = balance > balances[i] ? balance - balances[i] : 0;
if (value > 0) {
IWPLS(WPLS).deposit{ value: value }();
IWPLS(WPLS).transfer(fee_to, value);
}
} else {
uint256 balance = IERC20(coins[i]).balanceOf(address(this));
value = balance > balances[i] ? balance - balances[i] : 0;
if (value > 0) {
IERC20(coins[i]).safeTransfer(fee_to, value);
}
}
}
}
function withdraw_admin_fees() external onlyOwner {
require(is_killed, "Not killed");
_withdraw_admin_fees();
}
function donate_admin_fees() external onlyOwner {
for (uint256 i = 0; i < N_COINS; i++) {
if (coins[i] == PLS_ADDRESS) {
require(address(this).balance > 0, "Balance is zero");
balances[i] = address(this).balance;
} else {
uint256 bal = IERC20(coins[i]).balanceOf(address(this));
require(bal > 0, "Balance is zero");
balances[i] = bal;
}
}
emit DonateAdminFees();
}
function kill_me() external onlyOwner {
require(kill_deadline > block.timestamp, "Exceeded deadline");
is_killed = true;
emit Kill();
}
function unkill_me() external onlyOwner {
is_killed = false;
emit Unkill();
}
function renounceOwnership() public view override onlyOwner {
revert("Not allowed");
}
}
contracts/interfaces/IPulseXStableSwapDeployer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
struct CreateTwoPoolArgs {
address tokenA;
address tokenB;
uint256 A;
uint256 fee;
uint256 admin_fee;
address admin;
address LP;
address STABLESWAP_FACTORY;
address WPLS;
}
struct CreateThreePoolArgs {
address tokenA;
address tokenB;
address tokenC;
uint256 A;
uint256 fee;
uint256 admin_fee;
address admin;
address LP;
address STABLESWAP_FACTORY;
address WPLS;
}
interface IPulseXStableSwapDeployer {
function createPool(CreateTwoPoolArgs calldata) external returns (address);
function createPool(CreateThreePoolArgs calldata) external returns (address);
}
contracts/interfaces/IPulseXStableSwapFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
interface IPulseXStableSwapFactory {
function fee_to() external view returns (address);
}
@openzeppelin-4.5.0/contracts/access/Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)
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() {
_transferOwnership(_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 {
_transferOwnership(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");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
@openzeppelin-4.5.0/contracts/security/ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
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 making 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;
}
}
@openzeppelin-4.5.0/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)
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 `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
/**
* @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);
}
@openzeppelin-4.5.0/contracts/token/ERC20/extensions/IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
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);
}
@openzeppelin-4.5.0/contracts/token/ERC20/utils/SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)
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");
}
}
}
@openzeppelin-4.5.0/contracts/utils/Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @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
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 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);
}
}
}
}
contracts/interfaces/IPulseXStableSwapLP.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
interface IPulseXStableSwapLP {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
function mint(address _to, uint256 _amount) external;
function burnFrom(address _to, uint256 _amount) external;
function setMinter(address _newMinter) external;
}
Compiler Settings
{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"],"":["ast"]}},"optimizer":{"runs":100,"enabled":true},"libraries":{}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"error","name":"FailedDeployment","inputs":[]},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"N_COINS","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"createPool","inputs":[{"type":"tuple","name":"args","internalType":"struct CreateThreePoolArgs","components":[{"type":"address","name":"tokenA","internalType":"address"},{"type":"address","name":"tokenB","internalType":"address"},{"type":"address","name":"tokenC","internalType":"address"},{"type":"uint256","name":"A","internalType":"uint256"},{"type":"uint256","name":"fee","internalType":"uint256"},{"type":"uint256","name":"admin_fee","internalType":"uint256"},{"type":"address","name":"admin","internalType":"address"},{"type":"address","name":"LP","internalType":"address"},{"type":"address","name":"STABLESWAP_FACTORY","internalType":"address"},{"type":"address","name":"WPLS","internalType":"address"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]}]
Contract Creation Code
0x608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6155948061007e6000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c8063293577501461005c578063715018a6146100775780638da5cb5b14610081578063b4f0b00f1461009b578063f2fde38b146100ae575b600080fd5b610064600381565b6040519081526020015b60405180910390f35b61007f6100c1565b005b6000546001600160a01b03165b60405161006e919061050c565b61008e6100a9366004610520565b610100565b61007f6100bc366004610539565b610414565b6000546001600160a01b031633146100f45760405162461bcd60e51b81526004016100eb90610569565b60405180910390fd5b6100fe60006104af565b565b600080546001600160a01b0316331461012b5760405162461bcd60e51b81526004016100eb90610569565b600061013a6020840184610539565b6001600160a01b03161415801561016a5750600061015e6040840160208501610539565b6001600160a01b031614155b801561018f575060006101836060840160408501610539565b6001600160a01b031614155b6101cb5760405162461bcd60e51b815260206004820152600d60248201526c24b63632b3b0b6103a37b5b2b760991b60448201526064016100eb565b60006101da6020840184610539565b905060006101ee6040850160208601610539565b905060006102026060860160408701610539565b604080516060810182526001600160a01b038087168252858116602080840191909152908416828401529151929350916000916102409082016104ff565b601f1982820381018352601f9091011660405261026561012089016101008a01610539565b604051602001610275919061050c565b60408051601f198184030181529190526102976101408a016101208b01610539565b6040516020016102a7919061050c565b60408051601f19818403018152908290526102c69392916020016105d9565b60408051601f19818403018152908290526bffffffffffffffffffffffff19606088811b8216602085015287811b8216603485015286811b8216604885015233901b16605c830152426070830152466090830152915060009060b0016040516020818303038152906040528051906020012090506000818351602085016000f590506001600160a01b03811661036f5760405163b06ebf3d60e01b815260040160405180910390fd5b806001600160a01b0316634eac4835858b606001358c608001358d60a001358e60c00160208101906103a19190610539565b8f60e00160208101906103b49190610539565b6040518763ffffffff1660e01b81526004016103d596959493929190610600565b600060405180830381600087803b1580156103ef57600080fd5b505af1158015610403573d6000803e3d6000fd5b50929b9a5050505050505050505050565b6000546001600160a01b0316331461043e5760405162461bcd60e51b81526004016100eb90610569565b6001600160a01b0381166104a35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016100eb565b6104ac816104af565b50565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b614ef58061066a83390190565b6001600160a01b0391909116815260200190565b6000610140828403121561053357600080fd5b50919050565b60006020828403121561054b57600080fd5b81356001600160a01b038116811461056257600080fd5b9392505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6000815160005b818110156105bf57602081850181015186830152016105a5565b818111156105ce576000828601525b509290920192915050565b60006105f76105f16105eb848861059e565b8661059e565b8461059e565b95945050505050565b6101008101818860005b60038110156106325781516001600160a01b031683526020928301929091019060010161060a565b5050506060820196909652608081019490945260a08401929092526001600160a01b0390811660c08401521660e09091015291905056fe60e0604052610fbd6010553480156200001757600080fd5b5060405162004ef538038062004ef58339810160408190526200003a91620000d2565b620000453362000065565b600180553360a0526001600160a01b039182166080521660c0526200010a565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620000cd57600080fd5b919050565b60008060408385031215620000e657600080fd5b620000f183620000b5565b91506200010160208401620000b5565b90509250929050565b60805160a05160c051614d9f62000156600039600081816108f60152818161347501526134fb0152600081816107e4015261159f015260008181610706015261334f0152614d9f6000f3fe6080604052600436106103225760003560e01c80637dafa364116101a7578063d73792a9116100ed578063edfb780111610090578063edfb7801146108cd578063ef8ef56f146108e4578063f1dc3cc914610918578063f2fde38b14610938578063f3de036214610806578063f446c1d014610958578063fc0c546a1461096d578063fee3f7f91461098d57600080fd5b8063d73792a914610806578063ddca3f431461081f578063e2e7d26414610835578063e369885314610855578063e38244621461086a578063e5d9e90314610880578063e7ee486d14610897578063ecb586a5146108ad57600080fd5b8063aaf5eb6811610155578063aaf5eb6814610728578063ab5ac06114610744578063b4b577ad14610759578063bb7b8b801461076f578063bc063e1a14610784578063c66106571461079d578063ca8ca154146107bd578063d1cc8706146107d257600080fd5b80637dafa36414610642578063817348a61461066257806385f11d1e146106785780638da5cb5b146106985780639c868ac0146106ba5780639fdaea0c146106d4578063a6b0a718146106f457600080fd5b80634515cef31161026c578063556d6e9f1161021a578063556d6e9f1461056f57806358680d0b1461058f578063592ad186146105a55780635b41b908146105c55780635b5a1467146105d857806362203d74146105f85780636d4366b714610618578063715018a61461062d57600080fd5b80634515cef3146104bc5780634903b0d1146104cf5780634eac4835146104ef5780634f12fe971461050f5780634fb08c5e14610524578063524c3901146105445780635409491a1461055957600080fd5b80633046f972116102d45780633046f972146103f057806330c54085146104055780633883e1191461041a5780633897b4e01461043a578063392e53cd14610450578063396984151461046f5780633c157e6414610486578063405e28f8146104a657600080fd5b806306e9481c1461032757806314052288146103515780632081066c146103675780632092dc3e1461037d578063226840fb146103ae57806329357750146103c55780632a426896146103da575b600080fd5b34801561033357600080fd5b5061033e6201518081565b6040519081526020015b60405180910390f35b34801561035d57600080fd5b5061033e60155481565b34801561037357600080fd5b5061033e60145481565b34801561038957600080fd5b5060115461039e90600160a01b900460ff1681565b6040519015158152602001610348565b3480156103ba57600080fd5b506103c36109a3565b005b3480156103d157600080fd5b5061033e600381565b3480156103e657600080fd5b5061033e60195481565b3480156103fc57600080fd5b506103c3610a0b565b34801561041157600080fd5b506103c3610a6f565b34801561042657600080fd5b5061033e6104353660046146e0565b610ae7565b34801561044657600080fd5b5061033e6159d881565b34801561045c57600080fd5b50601a5461039e90610100900460ff1681565b34801561047b57600080fd5b5061033e620f424081565b34801561049257600080fd5b506103c36104a1366004614718565b610cae565b3480156104b257600080fd5b5061033e60165481565b6103c36104ca36600461473a565b610eb9565b3480156104db57600080fd5b5061033e6104ea366004614765565b611525565b3480156104fb57600080fd5b506103c361050a36600461479e565b61153c565b34801561051b57600080fd5b506103c3611976565b34801561053057600080fd5b5061033e61053f366004614718565b611a7b565b34801561055057600080fd5b506103c3611a91565b34801561056557600080fd5b5061033e60125481565b34801561057b57600080fd5b5061033e61058a366004614840565b611c3d565b34801561059b57600080fd5b5061033e60175481565b3480156105b157600080fd5b506103c36105c0366004614765565b611d89565b6103c36105d336600461486c565b611e42565b3480156105e457600080fd5b506103c36105f3366004614718565b612213565b34801561060457600080fd5b5061033e610613366004614765565b612390565b34801561062457600080fd5b5061033e601281565b34801561063957600080fd5b506103c36123a0565b34801561064e57600080fd5b5061033e61065d366004614765565b612405565b34801561066e57600080fd5b5061033e6108fc81565b34801561068457600080fd5b5061033e610693366004614840565b612415565b3480156106a457600080fd5b506106ad6124f3565b604051610348919061489e565b3480156106c657600080fd5b50601a5461039e9060ff1681565b3480156106e057600080fd5b506103c36106ef36600461473a565b612502565b34801561070057600080fd5b506106ad7f000000000000000000000000000000000000000000000000000000000000000081565b34801561073457600080fd5b5061033e670de0b6b3a764000081565b34801561075057600080fd5b5061033e600a81565b34801561076557600080fd5b5061033e60135481565b34801561077b57600080fd5b5061033e612ae4565b34801561079057600080fd5b5061033e64012a05f20081565b3480156107a957600080fd5b506106ad6107b8366004614765565b612be2565b3480156107c957600080fd5b506103c3612c02565b3480156107de57600080fd5b506106ad7f000000000000000000000000000000000000000000000000000000000000000081565b34801561081257600080fd5b5061033e6402540be40081565b34801561082b57600080fd5b5061033e600e5481565b34801561084157600080fd5b5061033e610850366004614765565b612c8a565b34801561086157600080fd5b506103c3612d8b565b34801561087657600080fd5b5061033e60185481565b34801561088c57600080fd5b5061033e6203f48081565b3480156108a357600080fd5b5061033e60105481565b3480156108b957600080fd5b506103c36108c83660046148b2565b612e37565b3480156108d957600080fd5b5061033e624f1a0081565b3480156108f057600080fd5b506106ad7f000000000000000000000000000000000000000000000000000000000000000081565b34801561092457600080fd5b506103c3610933366004614840565b6130d2565b34801561094457600080fd5b506103c36109533660046148df565b61329c565b34801561096457600080fd5b5061033e61333c565b34801561097957600080fd5b506011546106ad906001600160a01b031681565b34801561099957600080fd5b5061033e600f5481565b336109ac6124f3565b6001600160a01b0316146109db5760405162461bcd60e51b81526004016109d2906148fc565b60405180910390fd5b600060168190556040517f1b4883af197c705114490f8d84f9ce30bef6a6199f7b7b649e845577cf0769a19190a1565b33610a146124f3565b6001600160a01b031614610a3a5760405162461bcd60e51b81526004016109d2906148fc565b601a805460ff191690556040517f061284ffa2814ace135f62907c78a7cff0f070efe7e6a0a42740ea1da2c8bdc890600090a1565b33610a786124f3565b6001600160a01b031614610a9e5760405162461bcd60e51b81526004016109d2906148fc565b601a5460ff16610add5760405162461bcd60e51b815260206004820152600a602482015269139bdd081ada5b1b195960b21b60448201526064016109d2565b610ae561334b565b565b604080516060810191829052600091829190600b9060039082845b815481526020019060010190808311610b0257505050505090506000610b26613693565b90506000610b348383613734565b905060005b6003811015610bda578515610b8a57868160038110610b5a57610b5a614931565b6020020151848260038110610b7157610b71614931565b60200201818151610b82919061495d565b905250610bc8565b868160038110610b9c57610b9c614931565b6020020151848260038110610bb357610bb3614931565b60200201818151610bc49190614975565b9052505b80610bd28161498c565b915050610b39565b506000610be78484613734565b90506000601160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6291906149a7565b905060008715610c7d57610c768484614975565b9050610c8a565b610c878385614975565b90505b83610c9583836149c0565b610c9f91906149df565b96505050505050505b92915050565b33610cb76124f3565b6001600160a01b031614610cdd5760405162461bcd60e51b81526004016109d2906148fc565b62015180601454610cee919061495d565b421015610d2f5760405162461bcd60e51b815260206004820152600f60248201526e646576203a20746f6f206561726c7960881b60448201526064016109d2565b610d3c620151804261495d565b811015610d5b5760405162461bcd60e51b81526004016109d290614a01565b6000610d65613693565b9050600083118015610d795750620f424083105b610dd35760405162461bcd60e51b815260206004820152602560248201527f5f6675747572655f41206d757374206265206265747765656e203020616e64206044820152644d41585f4160d81b60648201526084016109d2565b808310158015610ded5750610de9600a826149c0565b8311155b80610e0c57508083108015610e0c575080610e09600a856149c0565b10155b610e585760405162461bcd60e51b815260206004820152601b60248201527f496c6c6567616c20706172616d65746572205f6675747572655f41000000000060448201526064016109d2565b60128190556013839055426014819055601583905560408051838152602081018690528082019290925260608201849052517fa2b71ec6df949300b59aab36b55e189697b750119dd349fcfa8c0f779e83c2549181900360800190a1505050565b60026001541415610edc5760405162461bcd60e51b81526004016109d290614a31565b6002600155601a5460ff1615610f045760405162461bcd60e51b81526004016109d290614a68565b601154600160a01b900460ff16610f33573415610f335760405162461bcd60e51b81526004016109d290614a88565b610f3b614596565b6000610f4960016003614975565b610f549060046149c0565b6003600e54610f6391906149c0565b610f6d91906149df565b600f549091506000610f7d613693565b90506000601160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fd4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff891906149a7565b6040805160608101918290529192506000918291600b9060039082845b81548152602001906001019080831161101557505050505090506000831115611045576110428185613734565b91505b600060405180606001604052808360006003811061106557611065614931565b602002015181526020018360016003811061108257611082614931565b602002015181526020018360026003811061109f5761109f614931565b60200201519052905060005b600381101561118b578461112a5760008b82600381106110cd576110cd614931565b60200201511161112a5760405162461bcd60e51b815260206004820152602260248201527f496e697469616c206465706f73697420726571756972657320616c6c20636f696044820152616e7360f01b60648201526084016109d2565b8a816003811061113c5761113c614931565b602002015183826003811061115357611153614931565b6020020151611162919061495d565b82826003811061117457611174614931565b6020020152806111838161498c565b9150506110ab565b5060006111988287613734565b90508381116111e95760405162461bcd60e51b815260206004820152601a60248201527f4431206d7573742062652067726561746572207468616e20443000000000000060448201526064016109d2565b8085156113975760005b60038110156113855760008686836003811061121157611211614931565b602002015161122090866149c0565b61122a91906149df565b9050600085836003811061124057611240614931565b60200201518211156112745785836003811061125e5761125e614931565b602002015161126d9083614975565b9050611299565b8186846003811061128757611287614931565b60200201516112969190614975565b90505b6402540be4006112a9828e6149c0565b6112b391906149df565b8d84600381106112c5576112c5614931565b60200201526402540be4008b8e85600381106112e3576112e3614931565b60200201516112f291906149c0565b6112fc91906149df565b86846003811061130e5761130e614931565b602002015161131d9190614975565b600b846003811061133057611330614931565b01558c836003811061134457611344614931565b602002015186846003811061135b5761135b614931565b6020020181815161136c9190614975565b90525082915061137d90508161498c565b9150506111f3565b506113908388613734565b90506113a6565b6113a4600b8460036145b4565b505b6000866113b45750816113d6565b856113bf8184614975565b6113c990896149c0565b6113d391906149df565b90505b8b8110156113f65760405162461bcd60e51b81526004016109d290614ab7565b60005b600381101561145e5760008e826003811061141657611416614931565b6020020151905060006008836003811061143257611432614931565b01546001600160a01b031690506114498183613748565b505080806114569061498c565b9150506113f9565b506011546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906114919033908590600401614ae5565b600060405180830381600087803b1580156114ab57600080fd5b505af11580156114bf573d6000803e3d6000fd5b505050506114cb61334b565b337f423f6495a08fc652425cf4ed0d1f9e37e571d9b9529b1c1c23cce780b2e7df0d8e8d866114fa868d61495d565b60405161150a9493929190614b21565b60405180910390a25050600180555050505050505050505050565b600b816003811061153557600080fd5b0154905081565b601a54610100900460ff16156115945760405162461bcd60e51b815260206004820152601f60248201527f4f7065726174696f6e733a20416c726561647920696e697469616c697a65640060448201526064016109d2565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146116075760405162461bcd60e51b815260206004820152601860248201527727b832b930ba34b7b7399d102737ba103232b83637bcb2b960411b60448201526064016109d2565b620f424085111561164f5760405162461bcd60e51b81526020600482015260126024820152715f412065786365656473206d6178696d756d60701b60448201526064016109d2565b64012a05f20084111561169b5760405162461bcd60e51b81526020600482015260146024820152735f6665652065786365656473206d6178696d756d60601b60448201526064016109d2565b6402540be4008311156116f05760405162461bcd60e51b815260206004820152601a60248201527f5f61646d696e5f6665652065786365656473206d6178696d756d00000000000060448201526064016109d2565b601a805461ff00191661010017905560005b600381101561191757600087826003811061171f5761171f614931565b60200201516001600160a01b0316141561176a5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f204164647265737360a01b60448201526064016109d2565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee88836003811061179357611793614931565b60200201516001600160a01b031614156117c257506011805460ff60a01b1916600160a01b1790556012611840565b8782600381106117d4576117d4614931565b60200201516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611816573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061183a9190614b4f565b60ff1690505b601281111561189d5760405162461bcd60e51b8152602060048201526024808201527f546865206d6178696d756d20646563696d616c2063616e6e6f742065786365656044820152630c84062760e31b60648201526084016109d2565b6118a8816012614975565b6118b390600a614c56565b600283600381106118c6576118c6614931565b0155600282600381106118db576118db614931565b01546118ef90670de0b6b3a76400006149c0565b6005836003811061190257611902614931565b0155508061190f8161498c565b915050611702565b5061192560088760036145ee565b5060128590556013859055600e849055600f839055611947624f1a004261495d565b601955601180546001600160a01b0319166001600160a01b03831617905561196e8261329c565b505050505050565b3361197f6124f3565b6001600160a01b0316146119a55760405162461bcd60e51b81526004016109d2906148fc565b6016544210156119c75760405162461bcd60e51b81526004016109d290614a01565b601654611a255760405162461bcd60e51b815260206004820152602660248201527f61646d696e5f616374696f6e735f646561646c696e652073686f756c64206e6f60448201526507420626520360d41b60648201526084016109d2565b6000601655601754600e819055601854600f8190556040517fbe12859b636aed607d5230b2cc2711f68d70e51060e6cca1f575ef5d2fcc95d192611a7192908252602082015260400190565b60405180910390a1565b600080611a8884846137a7565b50949350505050565b33611a9a6124f3565b6001600160a01b031614611ac05760405162461bcd60e51b81526004016109d2906148fc565b60005b6003811015611c115773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60088260038110611af457611af4614931565b01546001600160a01b03161415611b405760004711611b255760405162461bcd60e51b81526004016109d290614c62565b47600b8260038110611b3957611b39614931565b0155611bff565b600060088260038110611b5557611b55614931565b01546040516370a0823160e01b81526001600160a01b03909116906370a0823190611b8490309060040161489e565b602060405180830381865afa158015611ba1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc591906149a7565b905060008111611be75760405162461bcd60e51b81526004016109d290614c62565b80600b8360038110611bfb57611bfb614931565b0155505b80611c098161498c565b915050611ac3565b506040517f2c7203581ca666b8c5094c11c03f0b19b3750234a9d281bcbc88a260bcb006de90600090a1565b60408051606081019182905260009182919060059060039082845b815481526020019060010190808311611c5857505050505090506000611c7c613aa9565b90506000670de0b6b3a7640000838860038110611c9b57611c9b614931565b6020020151611caa90876149c0565b611cb491906149df565b828860038110611cc657611cc6614931565b6020020151611cd5919061495d565b90506000611ce588888486613b63565b90506000848860038110611cfb57611cfb614931565b6020020151670de0b6b3a7640000600184878c60038110611d1e57611d1e614931565b6020020151611d2d9190614975565b611d379190614975565b611d4191906149c0565b611d4b91906149df565b905060006402540be40082600e54611d6391906149c0565b611d6d91906149df565b9050611d798183614975565b96505050505050505b9392505050565b33611d926124f3565b6001600160a01b031614611db85760405162461bcd60e51b81526004016109d2906148fc565b6108fc8110158015611dcc57506159d88111155b611e065760405162461bcd60e51b815260206004820152600b60248201526a496c6c6567616c2067617360a81b60448201526064016109d2565b60108190556040518181527f77af1b8b67f1d7632023ab9483dee075be904f096186ac8a4a8a0a892119d47a906020015b60405180910390a150565b60026001541415611e655760405162461bcd60e51b81526004016109d290614a31565b6002600155601a5460ff1615611e8d5760405162461bcd60e51b81526004016109d290614a68565b601154600160a01b900460ff16611ebc573415611ebc5760405162461bcd60e51b81526004016109d290614a88565b604080516060810191829052600091600b9060039082845b815481526020019060010190808311611ed457505050505090506000611ef982613d5f565b90506000670de0b6b3a764000060058860038110611f1957611f19614931565b0154611f2590876149c0565b611f2f91906149df565b828860038110611f4157611f41614931565b6020020151611f50919061495d565b90506000611f6088888486613b63565b90506000600182858a60038110611f7957611f79614931565b6020020151611f889190614975565b611f929190614975565b905060006402540be400600e5483611faa91906149c0565b611fb491906149df565b905060058960038110611fc957611fc9614931565b0154670de0b6b3a7640000611fde8385614975565b611fe891906149c0565b611ff291906149df565b91508682101561205b5760405162461bcd60e51b815260206004820152602e60248201527f45786368616e676520726573756c74656420696e20666577657220636f696e7360448201526d081d1a185b88195e1c1958dd195960921b60648201526084016109d2565b60006402540be400600f548361207191906149c0565b61207b91906149df565b905060058a6003811061209057612090614931565b01546120a4670de0b6b3a7640000836149c0565b6120ae91906149df565b905088878c600381106120c3576120c3614931565b60200201516120d2919061495d565b600b8c600381106120e5576120e5614931565b01558083888c600381106120fb576120fb614931565b602002015161210a9190614975565b6121149190614975565b600b8b6003811061212757612127614931565b0155600060088c6003811061213e5761213e614931565b01546001600160a01b0316905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81141561218b57348a146121865760405162461bcd60e51b81526004016109d290614a88565b6121a0565b6121a06001600160a01b03821633308d613e1d565b600060088c600381106121b5576121b5614931565b01546001600160a01b031690506121cc8186613e8e565b604080518e8152602081018d90529081018d90526060810186905233907fb2e76ae99761dc136e598d4a629bb347eccb9532a5f8bbd72e18467c3c34cc989060800161150a565b3361221c6124f3565b6001600160a01b0316146122425760405162461bcd60e51b81526004016109d2906148fc565b601654156122925760405162461bcd60e51b815260206004820181905260248201527f61646d696e5f616374696f6e735f646561646c696e65206d757374206265203060448201526064016109d2565b64012a05f2008211156122e25760405162461bcd60e51b81526020600482015260186024820152776465763a206665652065786365656473206d6178696d756d60401b60448201526064016109d2565b6402540be4008111156123375760405162461bcd60e51b815260206004820152601e60248201527f6465763a2061646d696e206665652065786365656473206d6178696d756d000060448201526064016109d2565b6123446203f4804261495d565b60168190556017839055601882905560408051848152602081018490527f351fc5da2fbf480f2225debf3664a4bc90fa9923743aad58b4603f648e931fe0910160405180910390a25050565b6005816003811061153557600080fd5b336123a96124f3565b6001600160a01b0316146123cf5760405162461bcd60e51b81526004016109d2906148fc565b60405162461bcd60e51b815260206004820152600b60248201526a139bdd08185b1b1bddd95960aa1b60448201526064016109d2565b6002816003811061153557600080fd5b600080612420613aa9565b6040805160608101918290529192506000919060029060039082845b81548152602001906001019080831161243c5750505050509050600081876003811061246a5761246a614931565b602002015161247990866149c0565b83886003811061248b5761248b614931565b602002015161249a919061495d565b905060006124aa88888487613b63565b905060008388600381106124c0576124c0614931565b6020020151600183878b600381106124da576124da614931565b60200201516124e99190614975565b611d419190614975565b6000546001600160a01b031690565b600260015414156125255760405162461bcd60e51b81526004016109d290614a31565b6002600155601a5460ff161561254d5760405162461bcd60e51b81526004016109d290614a68565b601154604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612597573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125bb91906149a7565b9050600081116126065760405162461bcd60e51b81526020600482015260166024820152756465763a207a65726f20746f74616c20737570706c7960501b60448201526064016109d2565b600061261460016003614975565b61261f9060046149c0565b6003600e5461262e91906149c0565b61263891906149df565b600f549091506000612648613693565b60408051606081019182905291925060009190600b9060039082845b8154815260200190600101908083116126645750505050509050600060405180606001604052808360006003811061269e5761269e614931565b60200201518152602001836001600381106126bb576126bb614931565b60200201518152602001836002600381106126d8576126d8614931565b60200201519052905060006126ed8385613734565b905060005b600381101561274a5789816003811061270d5761270d614931565b602002015183826003811061272457612724614931565b602002018181516127359190614975565b905250806127428161498c565b9150506126f2565b5060006127578386613734565b9050612761614596565b60005b60038110156128f65760008487836003811061278257612782614931565b602002015161279190866149c0565b61279b91906149df565b905060008683600381106127b1576127b1614931565b60200201518211156127e5578683600381106127cf576127cf614931565b60200201516127de9083614975565b905061280a565b818784600381106127f8576127f8614931565b60200201516128079190614975565b90505b6402540be40061281a828d6149c0565b61282491906149df565b84846003811061283657612836614931565b60200201526402540be4008a85856003811061285457612854614931565b602002015161286391906149c0565b61286d91906149df565b87846003811061287f5761287f614931565b602002015161288e9190614975565b600b84600381106128a1576128a1614931565b01558383600381106128b5576128b5614931565b60200201518784600381106128cc576128cc614931565b602002018181516128dd9190614975565b9052508291506128ee90508161498c565b915050612764565b5060006129038588613734565b90506000848b6129138483614975565b61291d91906149c0565b61292791906149df565b9050600081116129855760405162461bcd60e51b815260206004820152602360248201527f746f6b656e5f616d6f756e74206d75737420626520677265617465722074686160448201526206e20360ec1b60648201526084016109d2565b61299060018261495d565b90508b8111156129b25760405162461bcd60e51b81526004016109d290614ab7565b60115460405163079cc67960e41b81526001600160a01b03909116906379cc6790906129e49033908590600401614ae5565b600060405180830381600087803b1580156129fe57600080fd5b505af1158015612a12573d6000803e3d6000fd5b5050505060005b6003811015612a905760008e8260038110612a3657612a36614931565b60200201511115612a7e57612a7e60088260038110612a5757612a57614931565b01546001600160a01b03168f8360038110612a7457612a74614931565b6020020151613e8e565b80612a888161498c565b915050612a19565b50612a9b818c614975565b9a50612aa561334b565b336001600160a01b03167f173599dbf9c6ca6f7c3b590df07ae98a45d74ff54065505141e7de6c46a624c28e85878f60405161150a9493929190614b21565b600080612aff612af2613aa9565b612afa613693565b613ed1565b905080612b4e5760405162461bcd60e51b815260206004820152601c60248201527f6765745f7669727475616c5f70726963653a2044206973207a65726f0000000060448201526064016109d2565b601154604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612b98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bbc91906149a7565b905080612bd1670de0b6b3a7640000846149c0565b612bdb91906149df565b9250505090565b60088160038110612bf257600080fd5b01546001600160a01b0316905081565b33612c0b6124f3565b6001600160a01b031614612c315760405162461bcd60e51b81526004016109d2906148fc565b6000612c3b613693565b6012819055601381905542601481905560158190556040519192507f46e22fb3709ad289f62ce63d469248536dbc78d82b84a3d7e74ad606dc20193891611e3791848252602082015260400190565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60088360038110612cb457612cb4614931565b01546001600160a01b03161415612ce457600b8260038110612cd857612cd8614931565b0154610ca89047614975565b600b8260038110612cf757612cf7614931565b015460088360038110612d0c57612d0c614931565b01546040516370a0823160e01b81526001600160a01b03909116906370a0823190612d3b90309060040161489e565b602060405180830381865afa158015612d58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d7c91906149a7565b610ca89190614975565b919050565b33612d946124f3565b6001600160a01b031614612dba5760405162461bcd60e51b81526004016109d2906148fc565b4260195411612dff5760405162461bcd60e51b8152602060048201526011602482015270457863656564656420646561646c696e6560781b60448201526064016109d2565b601a805460ff191660011790556040517fbe26733c2bf6ff3ea5ba8cfe744422bd49052ff9ed5685c9e81e6f9321dbaddd90600090a1565b60026001541415612e5a5760405162461bcd60e51b81526004016109d290614a31565b6002600155601154604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612ea9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ecd91906149a7565b9050612ed7614596565b612edf614596565b60005b60038110156130155760008487600b8460038110612f0257612f02614931565b0154612f0e91906149c0565b612f1891906149df565b9050858260038110612f2c57612f2c614931565b6020020151811015612f995760405162461bcd60e51b815260206004820152603060248201527f5769746864726177616c20726573756c74656420696e20666577657220636f6960448201526f1b9cc81d1a185b88195e1c1958dd195960821b60648201526084016109d2565b80600b8360038110612fad57612fad614931565b016000828254612fbd9190614975565b90915550819050848360038110612fd657612fd6614931565b602002015261300260088360038110612ff157612ff1614931565b01546001600160a01b031682613e8e565b508061300d8161498c565b915050612ee2565b5060115460405163079cc67960e41b81526001600160a01b03909116906379cc6790906130489033908990600401614ae5565b600060405180830381600087803b15801561306257600080fd5b505af1158015613076573d6000803e3d6000fd5b5050505061308261334b565b337fa49d4cf02656aebf8c771f5a8585638a2a15ee6c97cf7205d4208ed7c1df252d83836130b08988614975565b6040516130bf93929190614c8b565b60405180910390a2505060018055505050565b600260015414156130f55760405162461bcd60e51b81526004016109d290614a31565b6002600155601a5460ff161561311d5760405162461bcd60e51b81526004016109d290614a68565b60008061312a85856137a7565b91509150828210156131795760405162461bcd60e51b8152602060048201526018602482015277139bdd08195b9bdd59da0818dbda5b9cc81c995b5bdd995960421b60448201526064016109d2565b6402540be400600f548261318d91906149c0565b61319791906149df565b6131a1908361495d565b600b85600381106131b4576131b4614931565b0160008282546131c49190614975565b909155505060115460405163079cc67960e41b81526001600160a01b03909116906379cc6790906131fb9033908990600401614ae5565b600060405180830381600087803b15801561321557600080fd5b505af1158015613229573d6000803e3d6000fd5b505050506132546008856003811061324357613243614931565b01546001600160a01b031683613e8e565b61325c61334b565b604080518581526020810187905290810183905233907f5ad056f2e28a8cec232015406b843668c1e36cda598127ec3b8c59b8c72773a0906060016130bf565b336132a56124f3565b6001600160a01b0316146132cb5760405162461bcd60e51b81526004016109d2906148fc565b6001600160a01b0381166133305760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016109d2565b61333981614067565b50565b6000613346613693565b905090565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166326cfa27c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133cf9190614cb4565b90506001600160a01b0381166133e25750565b60005b600381101561368f57600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6008836003811061341857613418614931565b01546001600160a01b031614156135805747600b836003811061343d5761343d614931565b0154811161344c57600061346b565b600b836003811061345f5761345f614931565b015461346b9082614975565b9150811561357a577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b1580156134ce57600080fd5b505af11580156134e2573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb9250613535915087908690600401614ae5565b6020604051808303816000875af1158015613554573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135789190614cd1565b505b5061367c565b60006008836003811061359557613595614931565b01546040516370a0823160e01b81526001600160a01b03909116906370a08231906135c490309060040161489e565b602060405180830381865afa1580156135e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061360591906149a7565b9050600b836003811061361a5761361a614931565b01548111613629576000613648565b600b836003811061363c5761363c614931565b01546136489082614975565b9150811561367a5761367a84836008866003811061366857613668614931565b01546001600160a01b031691906140b7565b505b50806136878161498c565b9150506133e5565b5050565b6015546013546000919042821115610ca857601254601454818311156136f8576136bd8185614975565b6136c78242614975565b6136d18486614975565b6136db91906149c0565b6136e591906149df565b6136ef908361495d565b94505050505090565b6137028185614975565b61370c8242614975565b6137168585614975565b61372091906149c0565b61372a91906149df565b6136ef9083614975565b6000611d8261374284613d5f565b83613ed1565b6001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561378c5734811461368f5760405162461bcd60e51b81526004016109d290614a88565b801561368f5761368f6001600160a01b038316333084613e1d565b60008060006137b4613693565b905060006137c460016003614975565b6137cf9060046149c0565b6003600e546137de91906149c0565b6137e891906149df565b6040805160608101918290529192506000919060029060039082845b81548152602001906001019080831161380457505050505090506000601160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613873573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061389791906149a7565b905060006138a3613aa9565b905060006138b18287613ed1565b90506000836138c0838d6149c0565b6138ca91906149df565b6138d49083614975565b90508260006138e5898d84866140db565b90506000878d600381106138fb576138fb614931565b602002015182878f6003811061391357613913614931565b60200201516139229190614975565b61392c91906149df565b905060005b6003811015613a285760008e821415613983578387878a856003811061395957613959614931565b602002015161396891906149c0565b61397291906149df565b61397c9190614975565b90506139d4565b868689846003811061399757613997614931565b60200201516139a691906149c0565b6139b091906149df565b8883600381106139c2576139c2614931565b60200201516139d19190614975565b90505b6402540be4006139e4828d6149c0565b6139ee91906149df565b858360038110613a0057613a00614931565b60200201818151613a119190614975565b905250819050613a208161498c565b915050613931565b506000613a378b8f86886140db565b848f60038110613a4957613a49614931565b6020020151613a589190614975565b9050888e60038110613a6c57613a6c614931565b6020020151613a7c600183614975565b613a8691906149df565b905080613a938184614975565b9c509c5050505050505050505050509250929050565b613ab1614596565b6040805160608101918290529060059060039082845b815481526020019060010190808311613ac7575050505050905060005b6003811015613b5f57670de0b6b3a7640000600b8260038110613b0957613b09614931565b0154838360038110613b1d57613b1d614931565b6020020151613b2c91906149c0565b613b3691906149df565b828260038110613b4857613b48614931565b602002015280613b578161498c565b915050613ae4565b5090565b6000838514158015613b755750600385105b8015613b815750600384105b613bc15760405162461bcd60e51b815260206004820152601160248201527024b63632b3b0b6103830b930b6b2ba32b960791b60448201526064016109d2565b6000613bcb613693565b90506000613bd98483613ed1565b905080600080613bea6003866149c0565b90506000805b6003811015613c73578b811415613c0957899150613c33565b8a8114613c2e57888160038110613c2257613c22614931565b60200201519150613c33565b613c61565b613c3d828561495d565b9350613c4a6003836149c0565b613c5487876149c0565b613c5e91906149df565b94505b80613c6b8161498c565b915050613bf0565b50613c7f6003836149c0565b613c8986866149c0565b613c9391906149df565b93506000613ca183876149df565b613cab908561495d565b9050600086815b60ff811015613d4d578192508884836002613ccd91906149c0565b613cd7919061495d565b613ce19190614975565b88613cec84806149c0565b613cf6919061495d565b613d0091906149df565b915082821115613d25576001613d168484614975565b11613d2057613d4d565b613d3b565b6001613d318385614975565b11613d3b57613d4d565b80613d458161498c565b915050613cb2565b509d9c50505050505050505050505050565b613d67614596565b6040805160608101918290529060059060039082845b815481526020019060010190808311613d7d575050505050905060005b6003811015613e1757670de0b6b3a7640000838260038110613dbe57613dbe614931565b6020020151838360038110613dd557613dd5614931565b6020020151613de491906149c0565b613dee91906149df565b828260038110613e0057613e00614931565b602002015280613e0f8161498c565b915050613d9a565b50919050565b6040516001600160a01b0380851660248301528316604482015260648101829052613e889085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614296565b50505050565b6001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415613ebd5761368f3382614368565b61368f6001600160a01b03831633836140b7565b60008060005b6003811015613f1557848160038110613ef257613ef2614931565b6020020151613f01908361495d565b915080613f0d8161498c565b915050613ed7565b5080613f25576000915050610ca8565b60008181613f346003876149c0565b905060005b60ff81101561405b578260005b6003811015613f9a5760038a8260038110613f6357613f63614931565b6020020151613f7291906149c0565b613f7c86846149c0565b613f8691906149df565b915080613f928161498c565b915050613f46565b508394508060036001613fad919061495d565b613fb791906149c0565b84613fc3600186614975565b613fcd91906149c0565b613fd7919061495d565b84613fe36003846149c0565b613fed89876149c0565b613ff7919061495d565b61400191906149c0565b61400b91906149df565b9350848411156140315760016140218686614975565b1161402c575061405b565b614048565b600161403d8587614975565b11614048575061405b565b50806140538161498c565b915050613f39565b50909695505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6140d68363a9059cbb60e01b8484604051602401613e51929190614ae5565b505050565b6000600384106141245760405162461bcd60e51b81526020600482015260146024820152736465763a20692061626f7665204e5f434f494e5360601b60448201526064016109d2565b816000806141336003896149c0565b90506000805b60038110156141ac578881146141675787816003811061415b5761415b614931565b6020020151915061416c565b61419a565b614176828561495d565b93506141836003836149c0565b61418d88876149c0565b61419791906149df565b94505b806141a48161498c565b915050614139565b506141b86003836149c0565b6141c287866149c0565b6141cc91906149df565b935060006141da83886149df565b6141e4908561495d565b9050600087815b60ff81101561428657819250898483600261420691906149c0565b614210919061495d565b61421a9190614975565b8861422584806149c0565b61422f919061495d565b61423991906149df565b91508282111561425e57600161424f8484614975565b1161425957614286565b614274565b600161426a8385614975565b1161427457614286565b8061427e8161498c565b9150506141eb565b509b9a5050505050505050505050565b60006142eb826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166144159092919063ffffffff16565b8051909150156140d657808060200190518101906143099190614cd1565b6140d65760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d2565b600080836001600160a01b031660105484604051600060405180830381858888f193505050503d80600081146143ba576040519150601f19603f3d011682016040523d82523d6000602084013e6143bf565b606091505b509150915081613e8857805161440d5760405162461bcd60e51b8152602060048201526013602482015272141314c81d1c985b9cd9995c8819985a5b1959606a1b60448201526064016109d2565b805181602001fd5b6060614424848460008561442c565b949350505050565b60608247101561448d5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016109d2565b6001600160a01b0385163b6144e45760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d2565b600080866001600160a01b031685876040516145009190614d1a565b60006040518083038185875af1925050503d806000811461453d576040519150601f19603f3d011682016040523d82523d6000602084013e614542565b606091505b509150915061455282828661455d565b979650505050505050565b6060831561456c575081611d82565b82511561457c5782518084602001fd5b8160405162461bcd60e51b81526004016109d29190614d36565b60405180606001604052806003906020820280368337509192915050565b82600381019282156145e2579160200282015b828111156145e25782518255916020019190600101906145c7565b50613b5f929150614636565b82600381019282156145e2579160200282015b828111156145e257825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614601565b5b80821115613b5f5760008155600101614637565b6040516060810167ffffffffffffffff8111828210171561467c57634e487b7160e01b600052604160045260246000fd5b60405290565b600082601f83011261469357600080fd5b61469b61464b565b8060608401858111156146ad57600080fd5b845b818110156146c75780358452602093840193016146af565b509095945050505050565b801515811461333957600080fd5b600080608083850312156146f357600080fd5b6146fd8484614682565b9150606083013561470d816146d2565b809150509250929050565b6000806040838503121561472b57600080fd5b50508035926020909101359150565b6000806080838503121561474d57600080fd5b6147578484614682565b946060939093013593505050565b60006020828403121561477757600080fd5b5035919050565b6001600160a01b038116811461333957600080fd5b8035612d868161477e565b60008060008060008061010087890312156147b857600080fd5b87601f8801126147c757600080fd5b6147cf61464b565b80606089018a8111156147e157600080fd5b895b818110156148045780356147f68161477e565b8452602093840193016147e3565b50909750359550506080870135935060a0870135925061482660c08801614793565b915061483460e08801614793565b90509295509295509295565b60008060006060848603121561485557600080fd5b505081359360208301359350604090920135919050565b6000806000806080858703121561488257600080fd5b5050823594602084013594506040840135936060013592509050565b6001600160a01b0391909116815260200190565b600080608083850312156148c557600080fd5b823591506148d68460208501614682565b90509250929050565b6000602082840312156148f157600080fd5b8135611d828161477e565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000821982111561497057614970614947565b500190565b60008282101561498757614987614947565b500390565b60006000198214156149a0576149a0614947565b5060010190565b6000602082840312156149b957600080fd5b5051919050565b60008160001904831182151516156149da576149da614947565b500290565b6000826149fc57634e487b7160e01b600052601260045260246000fd5b500490565b6020808252601690820152756465763a20696e73756666696369656e742074696d6560501b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526006908201526512da5b1b195960d21b604082015260600190565b602080825260159082015274496e636f6e73697374656e74207175616e7469747960581b604082015260600190565b602080825260149082015273536c697070616765207363726577656420796f7560601b604082015260600190565b6001600160a01b03929092168252602082015260400190565b8060005b6003811015613e88578151845260209384019390910190600101614b02565b6101008101614b308287614afe565b614b3d6060830186614afe565b60c082019390935260e0015292915050565b600060208284031215614b6157600080fd5b815160ff81168114611d8257600080fd5b600181815b80851115614bad578160001904821115614b9357614b93614947565b80851615614ba057918102915b93841c9390800290614b77565b509250929050565b600082614bc457506001610ca8565b81614bd157506000610ca8565b8160018114614be75760028114614bf157614c0d565b6001915050610ca8565b60ff841115614c0257614c02614947565b50506001821b610ca8565b5060208310610133831016604e8410600b8410161715614c30575081810a610ca8565b614c3a8383614b72565b8060001904821115614c4e57614c4e614947565b029392505050565b6000611d828383614bb5565b6020808252600f908201526e42616c616e6365206973207a65726f60881b604082015260600190565b60e08101614c998286614afe565b614ca66060830185614afe565b8260c0830152949350505050565b600060208284031215614cc657600080fd5b8151611d828161477e565b600060208284031215614ce357600080fd5b8151611d82816146d2565b60005b83811015614d09578181015183820152602001614cf1565b83811115613e885750506000910152565b60008251614d2c818460208701614cee565b9190910192915050565b6020815260008251806020840152614d55816040850160208701614cee565b601f01601f1916919091016040019291505056fea264697066735822122043b4d24c6811b26ae9de907536abf9e8c2cd75fe2ab50063a5913e9e774c979164736f6c634300080a0033a2646970667358221220b8eeff4e8f2bd6c140b761b535b5720d9f44c18fe04d24bf9cbe459fd2c7cea164736f6c634300080a0033
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106100575760003560e01c8063293577501461005c578063715018a6146100775780638da5cb5b14610081578063b4f0b00f1461009b578063f2fde38b146100ae575b600080fd5b610064600381565b6040519081526020015b60405180910390f35b61007f6100c1565b005b6000546001600160a01b03165b60405161006e919061050c565b61008e6100a9366004610520565b610100565b61007f6100bc366004610539565b610414565b6000546001600160a01b031633146100f45760405162461bcd60e51b81526004016100eb90610569565b60405180910390fd5b6100fe60006104af565b565b600080546001600160a01b0316331461012b5760405162461bcd60e51b81526004016100eb90610569565b600061013a6020840184610539565b6001600160a01b03161415801561016a5750600061015e6040840160208501610539565b6001600160a01b031614155b801561018f575060006101836060840160408501610539565b6001600160a01b031614155b6101cb5760405162461bcd60e51b815260206004820152600d60248201526c24b63632b3b0b6103a37b5b2b760991b60448201526064016100eb565b60006101da6020840184610539565b905060006101ee6040850160208601610539565b905060006102026060860160408701610539565b604080516060810182526001600160a01b038087168252858116602080840191909152908416828401529151929350916000916102409082016104ff565b601f1982820381018352601f9091011660405261026561012089016101008a01610539565b604051602001610275919061050c565b60408051601f198184030181529190526102976101408a016101208b01610539565b6040516020016102a7919061050c565b60408051601f19818403018152908290526102c69392916020016105d9565b60408051601f19818403018152908290526bffffffffffffffffffffffff19606088811b8216602085015287811b8216603485015286811b8216604885015233901b16605c830152426070830152466090830152915060009060b0016040516020818303038152906040528051906020012090506000818351602085016000f590506001600160a01b03811661036f5760405163b06ebf3d60e01b815260040160405180910390fd5b806001600160a01b0316634eac4835858b606001358c608001358d60a001358e60c00160208101906103a19190610539565b8f60e00160208101906103b49190610539565b6040518763ffffffff1660e01b81526004016103d596959493929190610600565b600060405180830381600087803b1580156103ef57600080fd5b505af1158015610403573d6000803e3d6000fd5b50929b9a5050505050505050505050565b6000546001600160a01b0316331461043e5760405162461bcd60e51b81526004016100eb90610569565b6001600160a01b0381166104a35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016100eb565b6104ac816104af565b50565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b614ef58061066a83390190565b6001600160a01b0391909116815260200190565b6000610140828403121561053357600080fd5b50919050565b60006020828403121561054b57600080fd5b81356001600160a01b038116811461056257600080fd5b9392505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6000815160005b818110156105bf57602081850181015186830152016105a5565b818111156105ce576000828601525b509290920192915050565b60006105f76105f16105eb848861059e565b8661059e565b8461059e565b95945050505050565b6101008101818860005b60038110156106325781516001600160a01b031683526020928301929091019060010161060a565b5050506060820196909652608081019490945260a08401929092526001600160a01b0390811660c08401521660e09091015291905056fe60e0604052610fbd6010553480156200001757600080fd5b5060405162004ef538038062004ef58339810160408190526200003a91620000d2565b620000453362000065565b600180553360a0526001600160a01b039182166080521660c0526200010a565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620000cd57600080fd5b919050565b60008060408385031215620000e657600080fd5b620000f183620000b5565b91506200010160208401620000b5565b90509250929050565b60805160a05160c051614d9f62000156600039600081816108f60152818161347501526134fb0152600081816107e4015261159f015260008181610706015261334f0152614d9f6000f3fe6080604052600436106103225760003560e01c80637dafa364116101a7578063d73792a9116100ed578063edfb780111610090578063edfb7801146108cd578063ef8ef56f146108e4578063f1dc3cc914610918578063f2fde38b14610938578063f3de036214610806578063f446c1d014610958578063fc0c546a1461096d578063fee3f7f91461098d57600080fd5b8063d73792a914610806578063ddca3f431461081f578063e2e7d26414610835578063e369885314610855578063e38244621461086a578063e5d9e90314610880578063e7ee486d14610897578063ecb586a5146108ad57600080fd5b8063aaf5eb6811610155578063aaf5eb6814610728578063ab5ac06114610744578063b4b577ad14610759578063bb7b8b801461076f578063bc063e1a14610784578063c66106571461079d578063ca8ca154146107bd578063d1cc8706146107d257600080fd5b80637dafa36414610642578063817348a61461066257806385f11d1e146106785780638da5cb5b146106985780639c868ac0146106ba5780639fdaea0c146106d4578063a6b0a718146106f457600080fd5b80634515cef31161026c578063556d6e9f1161021a578063556d6e9f1461056f57806358680d0b1461058f578063592ad186146105a55780635b41b908146105c55780635b5a1467146105d857806362203d74146105f85780636d4366b714610618578063715018a61461062d57600080fd5b80634515cef3146104bc5780634903b0d1146104cf5780634eac4835146104ef5780634f12fe971461050f5780634fb08c5e14610524578063524c3901146105445780635409491a1461055957600080fd5b80633046f972116102d45780633046f972146103f057806330c54085146104055780633883e1191461041a5780633897b4e01461043a578063392e53cd14610450578063396984151461046f5780633c157e6414610486578063405e28f8146104a657600080fd5b806306e9481c1461032757806314052288146103515780632081066c146103675780632092dc3e1461037d578063226840fb146103ae57806329357750146103c55780632a426896146103da575b600080fd5b34801561033357600080fd5b5061033e6201518081565b6040519081526020015b60405180910390f35b34801561035d57600080fd5b5061033e60155481565b34801561037357600080fd5b5061033e60145481565b34801561038957600080fd5b5060115461039e90600160a01b900460ff1681565b6040519015158152602001610348565b3480156103ba57600080fd5b506103c36109a3565b005b3480156103d157600080fd5b5061033e600381565b3480156103e657600080fd5b5061033e60195481565b3480156103fc57600080fd5b506103c3610a0b565b34801561041157600080fd5b506103c3610a6f565b34801561042657600080fd5b5061033e6104353660046146e0565b610ae7565b34801561044657600080fd5b5061033e6159d881565b34801561045c57600080fd5b50601a5461039e90610100900460ff1681565b34801561047b57600080fd5b5061033e620f424081565b34801561049257600080fd5b506103c36104a1366004614718565b610cae565b3480156104b257600080fd5b5061033e60165481565b6103c36104ca36600461473a565b610eb9565b3480156104db57600080fd5b5061033e6104ea366004614765565b611525565b3480156104fb57600080fd5b506103c361050a36600461479e565b61153c565b34801561051b57600080fd5b506103c3611976565b34801561053057600080fd5b5061033e61053f366004614718565b611a7b565b34801561055057600080fd5b506103c3611a91565b34801561056557600080fd5b5061033e60125481565b34801561057b57600080fd5b5061033e61058a366004614840565b611c3d565b34801561059b57600080fd5b5061033e60175481565b3480156105b157600080fd5b506103c36105c0366004614765565b611d89565b6103c36105d336600461486c565b611e42565b3480156105e457600080fd5b506103c36105f3366004614718565b612213565b34801561060457600080fd5b5061033e610613366004614765565b612390565b34801561062457600080fd5b5061033e601281565b34801561063957600080fd5b506103c36123a0565b34801561064e57600080fd5b5061033e61065d366004614765565b612405565b34801561066e57600080fd5b5061033e6108fc81565b34801561068457600080fd5b5061033e610693366004614840565b612415565b3480156106a457600080fd5b506106ad6124f3565b604051610348919061489e565b3480156106c657600080fd5b50601a5461039e9060ff1681565b3480156106e057600080fd5b506103c36106ef36600461473a565b612502565b34801561070057600080fd5b506106ad7f000000000000000000000000000000000000000000000000000000000000000081565b34801561073457600080fd5b5061033e670de0b6b3a764000081565b34801561075057600080fd5b5061033e600a81565b34801561076557600080fd5b5061033e60135481565b34801561077b57600080fd5b5061033e612ae4565b34801561079057600080fd5b5061033e64012a05f20081565b3480156107a957600080fd5b506106ad6107b8366004614765565b612be2565b3480156107c957600080fd5b506103c3612c02565b3480156107de57600080fd5b506106ad7f000000000000000000000000000000000000000000000000000000000000000081565b34801561081257600080fd5b5061033e6402540be40081565b34801561082b57600080fd5b5061033e600e5481565b34801561084157600080fd5b5061033e610850366004614765565b612c8a565b34801561086157600080fd5b506103c3612d8b565b34801561087657600080fd5b5061033e60185481565b34801561088c57600080fd5b5061033e6203f48081565b3480156108a357600080fd5b5061033e60105481565b3480156108b957600080fd5b506103c36108c83660046148b2565b612e37565b3480156108d957600080fd5b5061033e624f1a0081565b3480156108f057600080fd5b506106ad7f000000000000000000000000000000000000000000000000000000000000000081565b34801561092457600080fd5b506103c3610933366004614840565b6130d2565b34801561094457600080fd5b506103c36109533660046148df565b61329c565b34801561096457600080fd5b5061033e61333c565b34801561097957600080fd5b506011546106ad906001600160a01b031681565b34801561099957600080fd5b5061033e600f5481565b336109ac6124f3565b6001600160a01b0316146109db5760405162461bcd60e51b81526004016109d2906148fc565b60405180910390fd5b600060168190556040517f1b4883af197c705114490f8d84f9ce30bef6a6199f7b7b649e845577cf0769a19190a1565b33610a146124f3565b6001600160a01b031614610a3a5760405162461bcd60e51b81526004016109d2906148fc565b601a805460ff191690556040517f061284ffa2814ace135f62907c78a7cff0f070efe7e6a0a42740ea1da2c8bdc890600090a1565b33610a786124f3565b6001600160a01b031614610a9e5760405162461bcd60e51b81526004016109d2906148fc565b601a5460ff16610add5760405162461bcd60e51b815260206004820152600a602482015269139bdd081ada5b1b195960b21b60448201526064016109d2565b610ae561334b565b565b604080516060810191829052600091829190600b9060039082845b815481526020019060010190808311610b0257505050505090506000610b26613693565b90506000610b348383613734565b905060005b6003811015610bda578515610b8a57868160038110610b5a57610b5a614931565b6020020151848260038110610b7157610b71614931565b60200201818151610b82919061495d565b905250610bc8565b868160038110610b9c57610b9c614931565b6020020151848260038110610bb357610bb3614931565b60200201818151610bc49190614975565b9052505b80610bd28161498c565b915050610b39565b506000610be78484613734565b90506000601160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6291906149a7565b905060008715610c7d57610c768484614975565b9050610c8a565b610c878385614975565b90505b83610c9583836149c0565b610c9f91906149df565b96505050505050505b92915050565b33610cb76124f3565b6001600160a01b031614610cdd5760405162461bcd60e51b81526004016109d2906148fc565b62015180601454610cee919061495d565b421015610d2f5760405162461bcd60e51b815260206004820152600f60248201526e646576203a20746f6f206561726c7960881b60448201526064016109d2565b610d3c620151804261495d565b811015610d5b5760405162461bcd60e51b81526004016109d290614a01565b6000610d65613693565b9050600083118015610d795750620f424083105b610dd35760405162461bcd60e51b815260206004820152602560248201527f5f6675747572655f41206d757374206265206265747765656e203020616e64206044820152644d41585f4160d81b60648201526084016109d2565b808310158015610ded5750610de9600a826149c0565b8311155b80610e0c57508083108015610e0c575080610e09600a856149c0565b10155b610e585760405162461bcd60e51b815260206004820152601b60248201527f496c6c6567616c20706172616d65746572205f6675747572655f41000000000060448201526064016109d2565b60128190556013839055426014819055601583905560408051838152602081018690528082019290925260608201849052517fa2b71ec6df949300b59aab36b55e189697b750119dd349fcfa8c0f779e83c2549181900360800190a1505050565b60026001541415610edc5760405162461bcd60e51b81526004016109d290614a31565b6002600155601a5460ff1615610f045760405162461bcd60e51b81526004016109d290614a68565b601154600160a01b900460ff16610f33573415610f335760405162461bcd60e51b81526004016109d290614a88565b610f3b614596565b6000610f4960016003614975565b610f549060046149c0565b6003600e54610f6391906149c0565b610f6d91906149df565b600f549091506000610f7d613693565b90506000601160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fd4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff891906149a7565b6040805160608101918290529192506000918291600b9060039082845b81548152602001906001019080831161101557505050505090506000831115611045576110428185613734565b91505b600060405180606001604052808360006003811061106557611065614931565b602002015181526020018360016003811061108257611082614931565b602002015181526020018360026003811061109f5761109f614931565b60200201519052905060005b600381101561118b578461112a5760008b82600381106110cd576110cd614931565b60200201511161112a5760405162461bcd60e51b815260206004820152602260248201527f496e697469616c206465706f73697420726571756972657320616c6c20636f696044820152616e7360f01b60648201526084016109d2565b8a816003811061113c5761113c614931565b602002015183826003811061115357611153614931565b6020020151611162919061495d565b82826003811061117457611174614931565b6020020152806111838161498c565b9150506110ab565b5060006111988287613734565b90508381116111e95760405162461bcd60e51b815260206004820152601a60248201527f4431206d7573742062652067726561746572207468616e20443000000000000060448201526064016109d2565b8085156113975760005b60038110156113855760008686836003811061121157611211614931565b602002015161122090866149c0565b61122a91906149df565b9050600085836003811061124057611240614931565b60200201518211156112745785836003811061125e5761125e614931565b602002015161126d9083614975565b9050611299565b8186846003811061128757611287614931565b60200201516112969190614975565b90505b6402540be4006112a9828e6149c0565b6112b391906149df565b8d84600381106112c5576112c5614931565b60200201526402540be4008b8e85600381106112e3576112e3614931565b60200201516112f291906149c0565b6112fc91906149df565b86846003811061130e5761130e614931565b602002015161131d9190614975565b600b846003811061133057611330614931565b01558c836003811061134457611344614931565b602002015186846003811061135b5761135b614931565b6020020181815161136c9190614975565b90525082915061137d90508161498c565b9150506111f3565b506113908388613734565b90506113a6565b6113a4600b8460036145b4565b505b6000866113b45750816113d6565b856113bf8184614975565b6113c990896149c0565b6113d391906149df565b90505b8b8110156113f65760405162461bcd60e51b81526004016109d290614ab7565b60005b600381101561145e5760008e826003811061141657611416614931565b6020020151905060006008836003811061143257611432614931565b01546001600160a01b031690506114498183613748565b505080806114569061498c565b9150506113f9565b506011546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906114919033908590600401614ae5565b600060405180830381600087803b1580156114ab57600080fd5b505af11580156114bf573d6000803e3d6000fd5b505050506114cb61334b565b337f423f6495a08fc652425cf4ed0d1f9e37e571d9b9529b1c1c23cce780b2e7df0d8e8d866114fa868d61495d565b60405161150a9493929190614b21565b60405180910390a25050600180555050505050505050505050565b600b816003811061153557600080fd5b0154905081565b601a54610100900460ff16156115945760405162461bcd60e51b815260206004820152601f60248201527f4f7065726174696f6e733a20416c726561647920696e697469616c697a65640060448201526064016109d2565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146116075760405162461bcd60e51b815260206004820152601860248201527727b832b930ba34b7b7399d102737ba103232b83637bcb2b960411b60448201526064016109d2565b620f424085111561164f5760405162461bcd60e51b81526020600482015260126024820152715f412065786365656473206d6178696d756d60701b60448201526064016109d2565b64012a05f20084111561169b5760405162461bcd60e51b81526020600482015260146024820152735f6665652065786365656473206d6178696d756d60601b60448201526064016109d2565b6402540be4008311156116f05760405162461bcd60e51b815260206004820152601a60248201527f5f61646d696e5f6665652065786365656473206d6178696d756d00000000000060448201526064016109d2565b601a805461ff00191661010017905560005b600381101561191757600087826003811061171f5761171f614931565b60200201516001600160a01b0316141561176a5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f204164647265737360a01b60448201526064016109d2565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee88836003811061179357611793614931565b60200201516001600160a01b031614156117c257506011805460ff60a01b1916600160a01b1790556012611840565b8782600381106117d4576117d4614931565b60200201516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611816573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061183a9190614b4f565b60ff1690505b601281111561189d5760405162461bcd60e51b8152602060048201526024808201527f546865206d6178696d756d20646563696d616c2063616e6e6f742065786365656044820152630c84062760e31b60648201526084016109d2565b6118a8816012614975565b6118b390600a614c56565b600283600381106118c6576118c6614931565b0155600282600381106118db576118db614931565b01546118ef90670de0b6b3a76400006149c0565b6005836003811061190257611902614931565b0155508061190f8161498c565b915050611702565b5061192560088760036145ee565b5060128590556013859055600e849055600f839055611947624f1a004261495d565b601955601180546001600160a01b0319166001600160a01b03831617905561196e8261329c565b505050505050565b3361197f6124f3565b6001600160a01b0316146119a55760405162461bcd60e51b81526004016109d2906148fc565b6016544210156119c75760405162461bcd60e51b81526004016109d290614a01565b601654611a255760405162461bcd60e51b815260206004820152602660248201527f61646d696e5f616374696f6e735f646561646c696e652073686f756c64206e6f60448201526507420626520360d41b60648201526084016109d2565b6000601655601754600e819055601854600f8190556040517fbe12859b636aed607d5230b2cc2711f68d70e51060e6cca1f575ef5d2fcc95d192611a7192908252602082015260400190565b60405180910390a1565b600080611a8884846137a7565b50949350505050565b33611a9a6124f3565b6001600160a01b031614611ac05760405162461bcd60e51b81526004016109d2906148fc565b60005b6003811015611c115773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60088260038110611af457611af4614931565b01546001600160a01b03161415611b405760004711611b255760405162461bcd60e51b81526004016109d290614c62565b47600b8260038110611b3957611b39614931565b0155611bff565b600060088260038110611b5557611b55614931565b01546040516370a0823160e01b81526001600160a01b03909116906370a0823190611b8490309060040161489e565b602060405180830381865afa158015611ba1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc591906149a7565b905060008111611be75760405162461bcd60e51b81526004016109d290614c62565b80600b8360038110611bfb57611bfb614931565b0155505b80611c098161498c565b915050611ac3565b506040517f2c7203581ca666b8c5094c11c03f0b19b3750234a9d281bcbc88a260bcb006de90600090a1565b60408051606081019182905260009182919060059060039082845b815481526020019060010190808311611c5857505050505090506000611c7c613aa9565b90506000670de0b6b3a7640000838860038110611c9b57611c9b614931565b6020020151611caa90876149c0565b611cb491906149df565b828860038110611cc657611cc6614931565b6020020151611cd5919061495d565b90506000611ce588888486613b63565b90506000848860038110611cfb57611cfb614931565b6020020151670de0b6b3a7640000600184878c60038110611d1e57611d1e614931565b6020020151611d2d9190614975565b611d379190614975565b611d4191906149c0565b611d4b91906149df565b905060006402540be40082600e54611d6391906149c0565b611d6d91906149df565b9050611d798183614975565b96505050505050505b9392505050565b33611d926124f3565b6001600160a01b031614611db85760405162461bcd60e51b81526004016109d2906148fc565b6108fc8110158015611dcc57506159d88111155b611e065760405162461bcd60e51b815260206004820152600b60248201526a496c6c6567616c2067617360a81b60448201526064016109d2565b60108190556040518181527f77af1b8b67f1d7632023ab9483dee075be904f096186ac8a4a8a0a892119d47a906020015b60405180910390a150565b60026001541415611e655760405162461bcd60e51b81526004016109d290614a31565b6002600155601a5460ff1615611e8d5760405162461bcd60e51b81526004016109d290614a68565b601154600160a01b900460ff16611ebc573415611ebc5760405162461bcd60e51b81526004016109d290614a88565b604080516060810191829052600091600b9060039082845b815481526020019060010190808311611ed457505050505090506000611ef982613d5f565b90506000670de0b6b3a764000060058860038110611f1957611f19614931565b0154611f2590876149c0565b611f2f91906149df565b828860038110611f4157611f41614931565b6020020151611f50919061495d565b90506000611f6088888486613b63565b90506000600182858a60038110611f7957611f79614931565b6020020151611f889190614975565b611f929190614975565b905060006402540be400600e5483611faa91906149c0565b611fb491906149df565b905060058960038110611fc957611fc9614931565b0154670de0b6b3a7640000611fde8385614975565b611fe891906149c0565b611ff291906149df565b91508682101561205b5760405162461bcd60e51b815260206004820152602e60248201527f45786368616e676520726573756c74656420696e20666577657220636f696e7360448201526d081d1a185b88195e1c1958dd195960921b60648201526084016109d2565b60006402540be400600f548361207191906149c0565b61207b91906149df565b905060058a6003811061209057612090614931565b01546120a4670de0b6b3a7640000836149c0565b6120ae91906149df565b905088878c600381106120c3576120c3614931565b60200201516120d2919061495d565b600b8c600381106120e5576120e5614931565b01558083888c600381106120fb576120fb614931565b602002015161210a9190614975565b6121149190614975565b600b8b6003811061212757612127614931565b0155600060088c6003811061213e5761213e614931565b01546001600160a01b0316905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81141561218b57348a146121865760405162461bcd60e51b81526004016109d290614a88565b6121a0565b6121a06001600160a01b03821633308d613e1d565b600060088c600381106121b5576121b5614931565b01546001600160a01b031690506121cc8186613e8e565b604080518e8152602081018d90529081018d90526060810186905233907fb2e76ae99761dc136e598d4a629bb347eccb9532a5f8bbd72e18467c3c34cc989060800161150a565b3361221c6124f3565b6001600160a01b0316146122425760405162461bcd60e51b81526004016109d2906148fc565b601654156122925760405162461bcd60e51b815260206004820181905260248201527f61646d696e5f616374696f6e735f646561646c696e65206d757374206265203060448201526064016109d2565b64012a05f2008211156122e25760405162461bcd60e51b81526020600482015260186024820152776465763a206665652065786365656473206d6178696d756d60401b60448201526064016109d2565b6402540be4008111156123375760405162461bcd60e51b815260206004820152601e60248201527f6465763a2061646d696e206665652065786365656473206d6178696d756d000060448201526064016109d2565b6123446203f4804261495d565b60168190556017839055601882905560408051848152602081018490527f351fc5da2fbf480f2225debf3664a4bc90fa9923743aad58b4603f648e931fe0910160405180910390a25050565b6005816003811061153557600080fd5b336123a96124f3565b6001600160a01b0316146123cf5760405162461bcd60e51b81526004016109d2906148fc565b60405162461bcd60e51b815260206004820152600b60248201526a139bdd08185b1b1bddd95960aa1b60448201526064016109d2565b6002816003811061153557600080fd5b600080612420613aa9565b6040805160608101918290529192506000919060029060039082845b81548152602001906001019080831161243c5750505050509050600081876003811061246a5761246a614931565b602002015161247990866149c0565b83886003811061248b5761248b614931565b602002015161249a919061495d565b905060006124aa88888487613b63565b905060008388600381106124c0576124c0614931565b6020020151600183878b600381106124da576124da614931565b60200201516124e99190614975565b611d419190614975565b6000546001600160a01b031690565b600260015414156125255760405162461bcd60e51b81526004016109d290614a31565b6002600155601a5460ff161561254d5760405162461bcd60e51b81526004016109d290614a68565b601154604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612597573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125bb91906149a7565b9050600081116126065760405162461bcd60e51b81526020600482015260166024820152756465763a207a65726f20746f74616c20737570706c7960501b60448201526064016109d2565b600061261460016003614975565b61261f9060046149c0565b6003600e5461262e91906149c0565b61263891906149df565b600f549091506000612648613693565b60408051606081019182905291925060009190600b9060039082845b8154815260200190600101908083116126645750505050509050600060405180606001604052808360006003811061269e5761269e614931565b60200201518152602001836001600381106126bb576126bb614931565b60200201518152602001836002600381106126d8576126d8614931565b60200201519052905060006126ed8385613734565b905060005b600381101561274a5789816003811061270d5761270d614931565b602002015183826003811061272457612724614931565b602002018181516127359190614975565b905250806127428161498c565b9150506126f2565b5060006127578386613734565b9050612761614596565b60005b60038110156128f65760008487836003811061278257612782614931565b602002015161279190866149c0565b61279b91906149df565b905060008683600381106127b1576127b1614931565b60200201518211156127e5578683600381106127cf576127cf614931565b60200201516127de9083614975565b905061280a565b818784600381106127f8576127f8614931565b60200201516128079190614975565b90505b6402540be40061281a828d6149c0565b61282491906149df565b84846003811061283657612836614931565b60200201526402540be4008a85856003811061285457612854614931565b602002015161286391906149c0565b61286d91906149df565b87846003811061287f5761287f614931565b602002015161288e9190614975565b600b84600381106128a1576128a1614931565b01558383600381106128b5576128b5614931565b60200201518784600381106128cc576128cc614931565b602002018181516128dd9190614975565b9052508291506128ee90508161498c565b915050612764565b5060006129038588613734565b90506000848b6129138483614975565b61291d91906149c0565b61292791906149df565b9050600081116129855760405162461bcd60e51b815260206004820152602360248201527f746f6b656e5f616d6f756e74206d75737420626520677265617465722074686160448201526206e20360ec1b60648201526084016109d2565b61299060018261495d565b90508b8111156129b25760405162461bcd60e51b81526004016109d290614ab7565b60115460405163079cc67960e41b81526001600160a01b03909116906379cc6790906129e49033908590600401614ae5565b600060405180830381600087803b1580156129fe57600080fd5b505af1158015612a12573d6000803e3d6000fd5b5050505060005b6003811015612a905760008e8260038110612a3657612a36614931565b60200201511115612a7e57612a7e60088260038110612a5757612a57614931565b01546001600160a01b03168f8360038110612a7457612a74614931565b6020020151613e8e565b80612a888161498c565b915050612a19565b50612a9b818c614975565b9a50612aa561334b565b336001600160a01b03167f173599dbf9c6ca6f7c3b590df07ae98a45d74ff54065505141e7de6c46a624c28e85878f60405161150a9493929190614b21565b600080612aff612af2613aa9565b612afa613693565b613ed1565b905080612b4e5760405162461bcd60e51b815260206004820152601c60248201527f6765745f7669727475616c5f70726963653a2044206973207a65726f0000000060448201526064016109d2565b601154604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612b98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bbc91906149a7565b905080612bd1670de0b6b3a7640000846149c0565b612bdb91906149df565b9250505090565b60088160038110612bf257600080fd5b01546001600160a01b0316905081565b33612c0b6124f3565b6001600160a01b031614612c315760405162461bcd60e51b81526004016109d2906148fc565b6000612c3b613693565b6012819055601381905542601481905560158190556040519192507f46e22fb3709ad289f62ce63d469248536dbc78d82b84a3d7e74ad606dc20193891611e3791848252602082015260400190565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60088360038110612cb457612cb4614931565b01546001600160a01b03161415612ce457600b8260038110612cd857612cd8614931565b0154610ca89047614975565b600b8260038110612cf757612cf7614931565b015460088360038110612d0c57612d0c614931565b01546040516370a0823160e01b81526001600160a01b03909116906370a0823190612d3b90309060040161489e565b602060405180830381865afa158015612d58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d7c91906149a7565b610ca89190614975565b919050565b33612d946124f3565b6001600160a01b031614612dba5760405162461bcd60e51b81526004016109d2906148fc565b4260195411612dff5760405162461bcd60e51b8152602060048201526011602482015270457863656564656420646561646c696e6560781b60448201526064016109d2565b601a805460ff191660011790556040517fbe26733c2bf6ff3ea5ba8cfe744422bd49052ff9ed5685c9e81e6f9321dbaddd90600090a1565b60026001541415612e5a5760405162461bcd60e51b81526004016109d290614a31565b6002600155601154604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612ea9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ecd91906149a7565b9050612ed7614596565b612edf614596565b60005b60038110156130155760008487600b8460038110612f0257612f02614931565b0154612f0e91906149c0565b612f1891906149df565b9050858260038110612f2c57612f2c614931565b6020020151811015612f995760405162461bcd60e51b815260206004820152603060248201527f5769746864726177616c20726573756c74656420696e20666577657220636f6960448201526f1b9cc81d1a185b88195e1c1958dd195960821b60648201526084016109d2565b80600b8360038110612fad57612fad614931565b016000828254612fbd9190614975565b90915550819050848360038110612fd657612fd6614931565b602002015261300260088360038110612ff157612ff1614931565b01546001600160a01b031682613e8e565b508061300d8161498c565b915050612ee2565b5060115460405163079cc67960e41b81526001600160a01b03909116906379cc6790906130489033908990600401614ae5565b600060405180830381600087803b15801561306257600080fd5b505af1158015613076573d6000803e3d6000fd5b5050505061308261334b565b337fa49d4cf02656aebf8c771f5a8585638a2a15ee6c97cf7205d4208ed7c1df252d83836130b08988614975565b6040516130bf93929190614c8b565b60405180910390a2505060018055505050565b600260015414156130f55760405162461bcd60e51b81526004016109d290614a31565b6002600155601a5460ff161561311d5760405162461bcd60e51b81526004016109d290614a68565b60008061312a85856137a7565b91509150828210156131795760405162461bcd60e51b8152602060048201526018602482015277139bdd08195b9bdd59da0818dbda5b9cc81c995b5bdd995960421b60448201526064016109d2565b6402540be400600f548261318d91906149c0565b61319791906149df565b6131a1908361495d565b600b85600381106131b4576131b4614931565b0160008282546131c49190614975565b909155505060115460405163079cc67960e41b81526001600160a01b03909116906379cc6790906131fb9033908990600401614ae5565b600060405180830381600087803b15801561321557600080fd5b505af1158015613229573d6000803e3d6000fd5b505050506132546008856003811061324357613243614931565b01546001600160a01b031683613e8e565b61325c61334b565b604080518581526020810187905290810183905233907f5ad056f2e28a8cec232015406b843668c1e36cda598127ec3b8c59b8c72773a0906060016130bf565b336132a56124f3565b6001600160a01b0316146132cb5760405162461bcd60e51b81526004016109d2906148fc565b6001600160a01b0381166133305760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016109d2565b61333981614067565b50565b6000613346613693565b905090565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166326cfa27c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133cf9190614cb4565b90506001600160a01b0381166133e25750565b60005b600381101561368f57600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6008836003811061341857613418614931565b01546001600160a01b031614156135805747600b836003811061343d5761343d614931565b0154811161344c57600061346b565b600b836003811061345f5761345f614931565b015461346b9082614975565b9150811561357a577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b1580156134ce57600080fd5b505af11580156134e2573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb9250613535915087908690600401614ae5565b6020604051808303816000875af1158015613554573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135789190614cd1565b505b5061367c565b60006008836003811061359557613595614931565b01546040516370a0823160e01b81526001600160a01b03909116906370a08231906135c490309060040161489e565b602060405180830381865afa1580156135e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061360591906149a7565b9050600b836003811061361a5761361a614931565b01548111613629576000613648565b600b836003811061363c5761363c614931565b01546136489082614975565b9150811561367a5761367a84836008866003811061366857613668614931565b01546001600160a01b031691906140b7565b505b50806136878161498c565b9150506133e5565b5050565b6015546013546000919042821115610ca857601254601454818311156136f8576136bd8185614975565b6136c78242614975565b6136d18486614975565b6136db91906149c0565b6136e591906149df565b6136ef908361495d565b94505050505090565b6137028185614975565b61370c8242614975565b6137168585614975565b61372091906149c0565b61372a91906149df565b6136ef9083614975565b6000611d8261374284613d5f565b83613ed1565b6001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561378c5734811461368f5760405162461bcd60e51b81526004016109d290614a88565b801561368f5761368f6001600160a01b038316333084613e1d565b60008060006137b4613693565b905060006137c460016003614975565b6137cf9060046149c0565b6003600e546137de91906149c0565b6137e891906149df565b6040805160608101918290529192506000919060029060039082845b81548152602001906001019080831161380457505050505090506000601160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613873573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061389791906149a7565b905060006138a3613aa9565b905060006138b18287613ed1565b90506000836138c0838d6149c0565b6138ca91906149df565b6138d49083614975565b90508260006138e5898d84866140db565b90506000878d600381106138fb576138fb614931565b602002015182878f6003811061391357613913614931565b60200201516139229190614975565b61392c91906149df565b905060005b6003811015613a285760008e821415613983578387878a856003811061395957613959614931565b602002015161396891906149c0565b61397291906149df565b61397c9190614975565b90506139d4565b868689846003811061399757613997614931565b60200201516139a691906149c0565b6139b091906149df565b8883600381106139c2576139c2614931565b60200201516139d19190614975565b90505b6402540be4006139e4828d6149c0565b6139ee91906149df565b858360038110613a0057613a00614931565b60200201818151613a119190614975565b905250819050613a208161498c565b915050613931565b506000613a378b8f86886140db565b848f60038110613a4957613a49614931565b6020020151613a589190614975565b9050888e60038110613a6c57613a6c614931565b6020020151613a7c600183614975565b613a8691906149df565b905080613a938184614975565b9c509c5050505050505050505050509250929050565b613ab1614596565b6040805160608101918290529060059060039082845b815481526020019060010190808311613ac7575050505050905060005b6003811015613b5f57670de0b6b3a7640000600b8260038110613b0957613b09614931565b0154838360038110613b1d57613b1d614931565b6020020151613b2c91906149c0565b613b3691906149df565b828260038110613b4857613b48614931565b602002015280613b578161498c565b915050613ae4565b5090565b6000838514158015613b755750600385105b8015613b815750600384105b613bc15760405162461bcd60e51b815260206004820152601160248201527024b63632b3b0b6103830b930b6b2ba32b960791b60448201526064016109d2565b6000613bcb613693565b90506000613bd98483613ed1565b905080600080613bea6003866149c0565b90506000805b6003811015613c73578b811415613c0957899150613c33565b8a8114613c2e57888160038110613c2257613c22614931565b60200201519150613c33565b613c61565b613c3d828561495d565b9350613c4a6003836149c0565b613c5487876149c0565b613c5e91906149df565b94505b80613c6b8161498c565b915050613bf0565b50613c7f6003836149c0565b613c8986866149c0565b613c9391906149df565b93506000613ca183876149df565b613cab908561495d565b9050600086815b60ff811015613d4d578192508884836002613ccd91906149c0565b613cd7919061495d565b613ce19190614975565b88613cec84806149c0565b613cf6919061495d565b613d0091906149df565b915082821115613d25576001613d168484614975565b11613d2057613d4d565b613d3b565b6001613d318385614975565b11613d3b57613d4d565b80613d458161498c565b915050613cb2565b509d9c50505050505050505050505050565b613d67614596565b6040805160608101918290529060059060039082845b815481526020019060010190808311613d7d575050505050905060005b6003811015613e1757670de0b6b3a7640000838260038110613dbe57613dbe614931565b6020020151838360038110613dd557613dd5614931565b6020020151613de491906149c0565b613dee91906149df565b828260038110613e0057613e00614931565b602002015280613e0f8161498c565b915050613d9a565b50919050565b6040516001600160a01b0380851660248301528316604482015260648101829052613e889085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614296565b50505050565b6001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415613ebd5761368f3382614368565b61368f6001600160a01b03831633836140b7565b60008060005b6003811015613f1557848160038110613ef257613ef2614931565b6020020151613f01908361495d565b915080613f0d8161498c565b915050613ed7565b5080613f25576000915050610ca8565b60008181613f346003876149c0565b905060005b60ff81101561405b578260005b6003811015613f9a5760038a8260038110613f6357613f63614931565b6020020151613f7291906149c0565b613f7c86846149c0565b613f8691906149df565b915080613f928161498c565b915050613f46565b508394508060036001613fad919061495d565b613fb791906149c0565b84613fc3600186614975565b613fcd91906149c0565b613fd7919061495d565b84613fe36003846149c0565b613fed89876149c0565b613ff7919061495d565b61400191906149c0565b61400b91906149df565b9350848411156140315760016140218686614975565b1161402c575061405b565b614048565b600161403d8587614975565b11614048575061405b565b50806140538161498c565b915050613f39565b50909695505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6140d68363a9059cbb60e01b8484604051602401613e51929190614ae5565b505050565b6000600384106141245760405162461bcd60e51b81526020600482015260146024820152736465763a20692061626f7665204e5f434f494e5360601b60448201526064016109d2565b816000806141336003896149c0565b90506000805b60038110156141ac578881146141675787816003811061415b5761415b614931565b6020020151915061416c565b61419a565b614176828561495d565b93506141836003836149c0565b61418d88876149c0565b61419791906149df565b94505b806141a48161498c565b915050614139565b506141b86003836149c0565b6141c287866149c0565b6141cc91906149df565b935060006141da83886149df565b6141e4908561495d565b9050600087815b60ff81101561428657819250898483600261420691906149c0565b614210919061495d565b61421a9190614975565b8861422584806149c0565b61422f919061495d565b61423991906149df565b91508282111561425e57600161424f8484614975565b1161425957614286565b614274565b600161426a8385614975565b1161427457614286565b8061427e8161498c565b9150506141eb565b509b9a5050505050505050505050565b60006142eb826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166144159092919063ffffffff16565b8051909150156140d657808060200190518101906143099190614cd1565b6140d65760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d2565b600080836001600160a01b031660105484604051600060405180830381858888f193505050503d80600081146143ba576040519150601f19603f3d011682016040523d82523d6000602084013e6143bf565b606091505b509150915081613e8857805161440d5760405162461bcd60e51b8152602060048201526013602482015272141314c81d1c985b9cd9995c8819985a5b1959606a1b60448201526064016109d2565b805181602001fd5b6060614424848460008561442c565b949350505050565b60608247101561448d5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016109d2565b6001600160a01b0385163b6144e45760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d2565b600080866001600160a01b031685876040516145009190614d1a565b60006040518083038185875af1925050503d806000811461453d576040519150601f19603f3d011682016040523d82523d6000602084013e614542565b606091505b509150915061455282828661455d565b979650505050505050565b6060831561456c575081611d82565b82511561457c5782518084602001fd5b8160405162461bcd60e51b81526004016109d29190614d36565b60405180606001604052806003906020820280368337509192915050565b82600381019282156145e2579160200282015b828111156145e25782518255916020019190600101906145c7565b50613b5f929150614636565b82600381019282156145e2579160200282015b828111156145e257825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614601565b5b80821115613b5f5760008155600101614637565b6040516060810167ffffffffffffffff8111828210171561467c57634e487b7160e01b600052604160045260246000fd5b60405290565b600082601f83011261469357600080fd5b61469b61464b565b8060608401858111156146ad57600080fd5b845b818110156146c75780358452602093840193016146af565b509095945050505050565b801515811461333957600080fd5b600080608083850312156146f357600080fd5b6146fd8484614682565b9150606083013561470d816146d2565b809150509250929050565b6000806040838503121561472b57600080fd5b50508035926020909101359150565b6000806080838503121561474d57600080fd5b6147578484614682565b946060939093013593505050565b60006020828403121561477757600080fd5b5035919050565b6001600160a01b038116811461333957600080fd5b8035612d868161477e565b60008060008060008061010087890312156147b857600080fd5b87601f8801126147c757600080fd5b6147cf61464b565b80606089018a8111156147e157600080fd5b895b818110156148045780356147f68161477e565b8452602093840193016147e3565b50909750359550506080870135935060a0870135925061482660c08801614793565b915061483460e08801614793565b90509295509295509295565b60008060006060848603121561485557600080fd5b505081359360208301359350604090920135919050565b6000806000806080858703121561488257600080fd5b5050823594602084013594506040840135936060013592509050565b6001600160a01b0391909116815260200190565b600080608083850312156148c557600080fd5b823591506148d68460208501614682565b90509250929050565b6000602082840312156148f157600080fd5b8135611d828161477e565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000821982111561497057614970614947565b500190565b60008282101561498757614987614947565b500390565b60006000198214156149a0576149a0614947565b5060010190565b6000602082840312156149b957600080fd5b5051919050565b60008160001904831182151516156149da576149da614947565b500290565b6000826149fc57634e487b7160e01b600052601260045260246000fd5b500490565b6020808252601690820152756465763a20696e73756666696369656e742074696d6560501b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526006908201526512da5b1b195960d21b604082015260600190565b602080825260159082015274496e636f6e73697374656e74207175616e7469747960581b604082015260600190565b602080825260149082015273536c697070616765207363726577656420796f7560601b604082015260600190565b6001600160a01b03929092168252602082015260400190565b8060005b6003811015613e88578151845260209384019390910190600101614b02565b6101008101614b308287614afe565b614b3d6060830186614afe565b60c082019390935260e0015292915050565b600060208284031215614b6157600080fd5b815160ff81168114611d8257600080fd5b600181815b80851115614bad578160001904821115614b9357614b93614947565b80851615614ba057918102915b93841c9390800290614b77565b509250929050565b600082614bc457506001610ca8565b81614bd157506000610ca8565b8160018114614be75760028114614bf157614c0d565b6001915050610ca8565b60ff841115614c0257614c02614947565b50506001821b610ca8565b5060208310610133831016604e8410600b8410161715614c30575081810a610ca8565b614c3a8383614b72565b8060001904821115614c4e57614c4e614947565b029392505050565b6000611d828383614bb5565b6020808252600f908201526e42616c616e6365206973207a65726f60881b604082015260600190565b60e08101614c998286614afe565b614ca66060830185614afe565b8260c0830152949350505050565b600060208284031215614cc657600080fd5b8151611d828161477e565b600060208284031215614ce357600080fd5b8151611d82816146d2565b60005b83811015614d09578181015183820152602001614cf1565b83811115613e885750506000910152565b60008251614d2c818460208701614cee565b9190910192915050565b6020815260008251806020840152614d55816040850160208701614cee565b601f01601f1916919091016040019291505056fea264697066735822122043b4d24c6811b26ae9de907536abf9e8c2cd75fe2ab50063a5913e9e774c979164736f6c634300080a0033a2646970667358221220b8eeff4e8f2bd6c140b761b535b5720d9f44c18fe04d24bf9cbe459fd2c7cea164736f6c634300080a0033