Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- PulseXStableSwapTwoPoolDeployer
- Optimization enabled
- true
- Compiler version
- v0.8.10+commit.fc410830
- Optimization runs
- 100
- EVM Version
- default
- Verified at
- 2024-09-04T14:00:31.595973Z
contracts/PulseXStableSwapTwoPoolDeployer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import "@openzeppelin-4.5.0/contracts/access/Ownable.sol";
import "./PulseXStableSwapTwoPool.sol";
import { CreateTwoPoolArgs } from "./interfaces/IPulseXStableSwapDeployer.sol";
error FailedDeployment();
contract PulseXStableSwapTwoPoolDeployer is Ownable {
uint256 public constant N_COINS = 2;
/**
* @notice constructor
*/
constructor() {}
/**
* @notice createPool
* @param args: CreateTwoPoolArgs struct.
*/
function createPool(CreateTwoPoolArgs calldata args) external virtual onlyOwner returns (address) {
require(args.tokenA != address(0) && args.tokenB != address(0), "Illegal token");
address t0 = args.tokenA;
address t1 = args.tokenB;
address[N_COINS] memory coins = [args.tokenA, args.tokenB];
// create swap contract
bytes memory bytecode = abi.encodePacked(
type(PulseXStableSwapTwoPool).creationCode,
abi.encode(args.STABLESWAP_FACTORY),
abi.encode(args.WPLS)
);
bytes32 salt = keccak256(abi.encodePacked(t0, t1, msg.sender, block.timestamp, block.chainid));
address swapContract;
assembly {
swapContract := create2(0, add(bytecode, 32), mload(bytecode), salt)
}
if (swapContract == address(0)) {
revert FailedDeployment();
}
PulseXStableSwapTwoPool(swapContract).initialize(coins, args.A, args.fee, args.admin_fee, args.admin, args.LP);
return swapContract;
}
}
@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);
}
}
}
}
@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/PulseXStableSwapTwoPool.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 PulseXStableSwapTwoPool is Ownable, ReentrancyGuard {
using SafeERC20 for IERC20;
uint256 public constant N_COINS = 2;
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]];
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]];
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);
}
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;
}
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);
}
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 CreateTwoPoolArgs","components":[{"type":"address","name":"tokenA","internalType":"address"},{"type":"address","name":"tokenB","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
0x608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61552b8061007e6000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c8063293577501461005c578063715018a614610077578063850787a1146100815780638da5cb5b146100a1578063f2fde38b146100b2575b600080fd5b610064600281565b6040519081526020015b60405180910390f35b61007f6100c5565b005b61009461008f3660046104ec565b610104565b60405161006e9190610505565b6000546001600160a01b0316610094565b61007f6100c0366004610519565b6103f4565b6000546001600160a01b031633146100f85760405162461bcd60e51b81526004016100ef90610549565b60405180910390fd5b610102600061048f565b565b600080546001600160a01b0316331461012f5760405162461bcd60e51b81526004016100ef90610549565b600061013e6020840184610519565b6001600160a01b03161415801561016e575060006101626040840160208501610519565b6001600160a01b031614155b6101aa5760405162461bcd60e51b815260206004820152600d60248201526c24b63632b3b0b6103a37b5b2b760991b60448201526064016100ef565b60006101b96020840184610519565b905060006101cd6040850160208601610519565b60408051808201909152909150600090806101eb6020880188610519565b6001600160a01b0316815260209081019061020c9060408901908901610519565b6001600160a01b0316905260405190915060009061022c602082016104df565b601f1982820381018352601f90910116604052610250610100880160e08901610519565b6040516020016102609190610505565b60408051601f1981840301815291905261028261012089016101008a01610519565b6040516020016102929190610505565b60408051601f19818403018152908290526102b19392916020016105b9565b60408051601f19818403018152908290526bffffffffffffffffffffffff19606087811b8216602085015286811b8216603485015233901b16604883015242605c83015246607c8301529150600090609c016040516020818303038152906040528051906020012090506000818351602085016000f590506001600160a01b0381166103505760405163b06ebf3d60e01b815260040160405180910390fd5b806001600160a01b0316634239b1c1858a604001358b606001358c608001358d60a00160208101906103829190610519565b8e60c00160208101906103959190610519565b6040518763ffffffff1660e01b81526004016103b6969594939291906105e0565b600060405180830381600087803b1580156103d057600080fd5b505af11580156103e4573d6000803e3d6000fd5b50929a9950505050505050505050565b6000546001600160a01b0316331461041e5760405162461bcd60e51b81526004016100ef90610549565b6001600160a01b0381166104835760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016100ef565b61048c8161048f565b50565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b614ead8061064983390190565b600061012082840312156104ff57600080fd5b50919050565b6001600160a01b0391909116815260200190565b60006020828403121561052b57600080fd5b81356001600160a01b038116811461054257600080fd5b9392505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6000815160005b8181101561059f5760208185018101518683015201610585565b818111156105ae576000828601525b509290920192915050565b60006105d76105d16105cb848861057e565b8661057e565b8461057e565b95945050505050565b60e08101818860005b60028110156106115781516001600160a01b03168352602092830192909101906001016105e9565b5050506040820196909652606081019490945260808401929092526001600160a01b0390811660a08401521660c09091015291905056fe60e0604052610fbd600c553480156200001757600080fd5b5060405162004ead38038062004ead8339810160408190526200003a91620000d2565b620000453362000065565b600180553360a0526001600160a01b039182166080521660c0526200010a565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620000cd57600080fd5b919050565b60008060408385031215620000e657600080fd5b620000f183620000b5565b91506200010160208401620000b5565b90509250929050565b60805160a05160c051614d5762000156600039600081816108f60152818161354b01526135d10152600081816107c401526113a30152600081816106e601526134250152614d576000f3fe6080604052600436106103225760003560e01c80637dafa364116101a7578063ddca3f43116100ed578063edfb780111610090578063edfb7801146108cd578063ef8ef56f146108e4578063f1dc3cc914610918578063f2fde38b14610938578063f3de0362146107e6578063f446c1d014610958578063fc0c546a1461096d578063fee3f7f91461098d57600080fd5b8063ddca3f43146107ff578063e2e7d26414610815578063e310327314610835578063e369885314610855578063e38244621461086a578063e5d9e90314610880578063e7ee486d14610897578063ed8e84f3146108ad57600080fd5b8063ab5ac06111610155578063ab5ac06114610724578063b4b577ad14610739578063bb7b8b801461074f578063bc063e1a14610764578063c66106571461077d578063ca8ca1541461079d578063d1cc8706146107b2578063d73792a9146107e657600080fd5b80637dafa36414610642578063817348a61461066257806385f11d1e146106785780638da5cb5b146106985780639c868ac0146106ba578063a6b0a718146106d4578063aaf5eb681461070857600080fd5b80634239b1c11161026c57806358680d0b1161021a57806358680d0b1461056f578063592ad186146105855780635b36389c146105a55780635b41b908146105c55780635b5a1467146105d857806362203d74146105f85780636d4366b714610618578063715018a61461062d57600080fd5b80634239b1c1146104af5780634903b0d1146104cf5780634f12fe97146104ef5780634fb08c5e14610504578063524c3901146105245780635409491a14610539578063556d6e9f1461054f57600080fd5b80632a426896116102d45780632a426896146103ed5780633046f9721461040357806330c54085146104185780633897b4e01461042d578063392e53cd1461044357806339698415146104625780633c157e6414610479578063405e28f81461049957600080fd5b806306e9481c146103275780630b4c7e4d1461035157806314052288146103665780632081066c1461037c5780632092dc3e14610392578063226840fb146103c357806329357750146103d8575b600080fd5b34801561033357600080fd5b5061033e6201518081565b6040519081526020015b60405180910390f35b61036461035f36600461468c565b6109a3565b005b34801561037257600080fd5b5061033e60115481565b34801561038857600080fd5b5061033e60105481565b34801561039e57600080fd5b50600d546103b390600160a01b900460ff1681565b6040519015158152602001610348565b3480156103cf57600080fd5b50610364610ffa565b3480156103e457600080fd5b5061033e600281565b3480156103f957600080fd5b5061033e60155481565b34801561040f57600080fd5b50610364611059565b34801561042457600080fd5b506103646110bd565b34801561043957600080fd5b5061033e6159d881565b34801561044f57600080fd5b506016546103b390610100900460ff1681565b34801561046e57600080fd5b5061033e620f424081565b34801561048557600080fd5b506103646104943660046146b7565b611135565b3480156104a557600080fd5b5061033e60125481565b3480156104bb57600080fd5b506103646104ca3660046146f9565b611340565b3480156104db57600080fd5b5061033e6104ea36600461479a565b611779565b3480156104fb57600080fd5b50610364611790565b34801561051057600080fd5b5061033e61051f3660046146b7565b611895565b34801561053057600080fd5b506103646118ad565b34801561054557600080fd5b5061033e600e5481565b34801561055b57600080fd5b5061033e61056a3660046147b3565b611a59565b34801561057b57600080fd5b5061033e60135481565b34801561059157600080fd5b506103646105a036600461479a565b611ba4565b3480156105b157600080fd5b506103646105c03660046147df565b611c5d565b6103646105d336600461480c565b611ef8565b3480156105e457600080fd5b506103646105f33660046146b7565b6122c8565b34801561060457600080fd5b5061033e61061336600461479a565b612445565b34801561062457600080fd5b5061033e601281565b34801561063957600080fd5b50610364612455565b34801561064e57600080fd5b5061033e61065d36600461479a565b6124ba565b34801561066e57600080fd5b5061033e6108fc81565b34801561068457600080fd5b5061033e6106933660046147b3565b6124ca565b3480156106a457600080fd5b506106ad6125a6565b604051610348919061483e565b3480156106c657600080fd5b506016546103b39060ff1681565b3480156106e057600080fd5b506106ad7f000000000000000000000000000000000000000000000000000000000000000081565b34801561071457600080fd5b5061033e670de0b6b3a764000081565b34801561073057600080fd5b5061033e600a81565b34801561074557600080fd5b5061033e600f5481565b34801561075b57600080fd5b5061033e6125b5565b34801561077057600080fd5b5061033e64012a05f20081565b34801561078957600080fd5b506106ad61079836600461479a565b6126b3565b3480156107a957600080fd5b506103646126d3565b3480156107be57600080fd5b506106ad7f000000000000000000000000000000000000000000000000000000000000000081565b3480156107f257600080fd5b5061033e6402540be40081565b34801561080b57600080fd5b5061033e600a5481565b34801561082157600080fd5b5061033e61083036600461479a565b61275b565b34801561084157600080fd5b5061036461085036600461468c565b61285c565b34801561086157600080fd5b50610364612e20565b34801561087657600080fd5b5061033e60145481565b34801561088c57600080fd5b5061033e6203f48081565b3480156108a357600080fd5b5061033e600c5481565b3480156108b957600080fd5b5061033e6108c8366004614860565b612ecc565b3480156108d957600080fd5b5061033e624f1a0081565b3480156108f057600080fd5b506106ad7f000000000000000000000000000000000000000000000000000000000000000081565b34801561092457600080fd5b506103646109333660046147b3565b613090565b34801561094457600080fd5b50610364610953366004614898565b61325a565b34801561096457600080fd5b5061033e6132fa565b34801561097957600080fd5b50600d546106ad906001600160a01b031681565b34801561099957600080fd5b5061033e600b5481565b600260015414156109cf5760405162461bcd60e51b81526004016109c6906148b5565b60405180910390fd5b600260015560165460ff16156109f75760405162461bcd60e51b81526004016109c6906148ec565b600d54600160a01b900460ff16610a26573415610a265760405162461bcd60e51b81526004016109c69061490c565b610a2e614550565b6000610a3c60016002614951565b610a47906004614968565b6002600a54610a569190614968565b610a609190614987565b600b549091506000610a70613309565b90506000600d60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ac7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aeb91906149a9565b6040805180820191829052919250600091829160089060029082845b815481526020019060010190808311610b0757505050505090506000831115610b3757610b3481856133aa565b91505b6000604051806040016040528083600060028110610b5757610b576149c2565b6020020151815260200183600160028110610b7457610b746149c2565b60200201519052905060005b6002811015610c605784610bff5760008b8260028110610ba257610ba26149c2565b602002015111610bff5760405162461bcd60e51b815260206004820152602260248201527f496e697469616c206465706f73697420726571756972657320616c6c20636f696044820152616e7360f01b60648201526084016109c6565b8a8160028110610c1157610c116149c2565b6020020151838260028110610c2857610c286149c2565b6020020151610c3791906149d8565b828260028110610c4957610c496149c2565b602002015280610c58816149f0565b915050610b80565b506000610c6d82876133aa565b9050838111610cbe5760405162461bcd60e51b815260206004820152601a60248201527f4431206d7573742062652067726561746572207468616e20443000000000000060448201526064016109c6565b808515610e6c5760005b6002811015610e5a57600086868360028110610ce657610ce66149c2565b6020020151610cf59086614968565b610cff9190614987565b90506000858360028110610d1557610d156149c2565b6020020151821115610d4957858360028110610d3357610d336149c2565b6020020151610d429083614951565b9050610d6e565b81868460028110610d5c57610d5c6149c2565b6020020151610d6b9190614951565b90505b6402540be400610d7e828e614968565b610d889190614987565b8d8460028110610d9a57610d9a6149c2565b60200201526402540be4008b8e8560028110610db857610db86149c2565b6020020151610dc79190614968565b610dd19190614987565b868460028110610de357610de36149c2565b6020020151610df29190614951565b60088460028110610e0557610e056149c2565b01558c8360028110610e1957610e196149c2565b6020020151868460028110610e3057610e306149c2565b60200201818151610e419190614951565b905250829150610e529050816149f0565b915050610cc8565b50610e6583886133aa565b9050610e7b565b610e79600884600261456e565b505b600086610e89575081610eab565b85610e948184614951565b610e9e9089614968565b610ea89190614987565b90505b8b811015610ecb5760405162461bcd60e51b81526004016109c690614a0b565b60005b6002811015610f335760008e8260028110610eeb57610eeb6149c2565b60200201519050600060068360028110610f0757610f076149c2565b01546001600160a01b03169050610f1e81836133be565b50508080610f2b906149f0565b915050610ece565b50600d546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990610f669033908590600401614a39565b600060405180830381600087803b158015610f8057600080fd5b505af1158015610f94573d6000803e3d6000fd5b50505050610fa0613421565b337f26f55a85081d24974e85c6c00045d0f0453991e95873f52bff0d21af4079a7688e8d86610fcf868d6149d8565b604051610fdf9493929190614a75565b60405180910390a25050600180555050505050505050505050565b336110036125a6565b6001600160a01b0316146110295760405162461bcd60e51b81526004016109c690614aa2565b600060128190556040517f1b4883af197c705114490f8d84f9ce30bef6a6199f7b7b649e845577cf0769a19190a1565b336110626125a6565b6001600160a01b0316146110885760405162461bcd60e51b81526004016109c690614aa2565b6016805460ff191690556040517f061284ffa2814ace135f62907c78a7cff0f070efe7e6a0a42740ea1da2c8bdc890600090a1565b336110c66125a6565b6001600160a01b0316146110ec5760405162461bcd60e51b81526004016109c690614aa2565b60165460ff1661112b5760405162461bcd60e51b815260206004820152600a602482015269139bdd081ada5b1b195960b21b60448201526064016109c6565b611133613421565b565b3361113e6125a6565b6001600160a01b0316146111645760405162461bcd60e51b81526004016109c690614aa2565b6201518060105461117591906149d8565b4210156111b65760405162461bcd60e51b815260206004820152600f60248201526e646576203a20746f6f206561726c7960881b60448201526064016109c6565b6111c362015180426149d8565b8110156111e25760405162461bcd60e51b81526004016109c690614ad7565b60006111ec613309565b90506000831180156112005750620f424083105b61125a5760405162461bcd60e51b815260206004820152602560248201527f5f6675747572655f41206d757374206265206265747765656e203020616e64206044820152644d41585f4160d81b60648201526084016109c6565b8083101580156112745750611270600a82614968565b8311155b8061129357508083108015611293575080611290600a85614968565b10155b6112df5760405162461bcd60e51b815260206004820152601b60248201527f496c6c6567616c20706172616d65746572205f6675747572655f41000000000060448201526064016109c6565b600e819055600f839055426010819055601183905560408051838152602081018690528082019290925260608201849052517fa2b71ec6df949300b59aab36b55e189697b750119dd349fcfa8c0f779e83c2549181900360800190a1505050565b601654610100900460ff16156113985760405162461bcd60e51b815260206004820152601f60248201527f4f7065726174696f6e733a20416c726561647920696e697469616c697a65640060448201526064016109c6565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461140b5760405162461bcd60e51b815260206004820152601860248201527727b832b930ba34b7b7399d102737ba103232b83637bcb2b960411b60448201526064016109c6565b620f42408511156114535760405162461bcd60e51b81526020600482015260126024820152715f412065786365656473206d6178696d756d60701b60448201526064016109c6565b64012a05f20084111561149f5760405162461bcd60e51b81526020600482015260146024820152735f6665652065786365656473206d6178696d756d60601b60448201526064016109c6565b6402540be4008311156114f45760405162461bcd60e51b815260206004820152601a60248201527f5f61646d696e5f6665652065786365656473206d6178696d756d00000000000060448201526064016109c6565b6016805461ff00191661010017905560005b600281101561171a576000878260028110611523576115236149c2565b60200201516001600160a01b0316141561156e5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f204164647265737360a01b60448201526064016109c6565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee888360028110611597576115976149c2565b60200201516001600160a01b031614156115c65750600d805460ff60a01b1916600160a01b1790556012611644565b8782600281106115d8576115d86149c2565b60200201516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561161a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163e9190614b07565b60ff1690505b60128111156116a15760405162461bcd60e51b8152602060048201526024808201527f546865206d6178696d756d20646563696d616c2063616e6e6f742065786365656044820152630c84062760e31b60648201526084016109c6565b6116ac816012614951565b6116b790600a614c0e565b600283600281106116ca576116ca6149c2565b01556002828181106116de576116de6149c2565b01546116f290670de0b6b3a7640000614968565b60048360028110611705576117056149c2565b01555080611712816149f0565b915050611506565b5061172860068760026145a8565b50600e859055600f859055600a849055600b83905561174a624f1a00426149d8565b601555600d80546001600160a01b0319166001600160a01b0383161790556117718261325a565b505050505050565b6008816002811061178957600080fd5b0154905081565b336117996125a6565b6001600160a01b0316146117bf5760405162461bcd60e51b81526004016109c690614aa2565b6012544210156117e15760405162461bcd60e51b81526004016109c690614ad7565b60125461183f5760405162461bcd60e51b815260206004820152602660248201527f61646d696e5f616374696f6e735f646561646c696e652073686f756c64206e6f60448201526507420626520360d41b60648201526084016109c6565b6000601255601354600a819055601454600b8190556040517fbe12859b636aed607d5230b2cc2711f68d70e51060e6cca1f575ef5d2fcc95d19261188b92908252602082015260400190565b60405180910390a1565b6000806118a28484613765565b509150505b92915050565b336118b66125a6565b6001600160a01b0316146118dc5760405162461bcd60e51b81526004016109c690614aa2565b60005b6002811015611a2d5773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60068260028110611910576119106149c2565b01546001600160a01b0316141561195c57600047116119415760405162461bcd60e51b81526004016109c690614c1a565b4760088260028110611955576119556149c2565b0155611a1b565b600060068260028110611971576119716149c2565b01546040516370a0823160e01b81526001600160a01b03909116906370a08231906119a090309060040161483e565b602060405180830381865afa1580156119bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e191906149a9565b905060008111611a035760405162461bcd60e51b81526004016109c690614c1a565b8060088360028110611a1757611a176149c2565b0155505b80611a25816149f0565b9150506118df565b506040517f2c7203581ca666b8c5094c11c03f0b19b3750234a9d281bcbc88a260bcb006de90600090a1565b604080518082019182905260009182919060049060029082845b815481526020019060010190808311611a7357505050505090506000611a97613a65565b90506000670de0b6b3a7640000838860028110611ab657611ab66149c2565b6020020151611ac59087614968565b611acf9190614987565b828860028110611ae157611ae16149c2565b6020020151611af091906149d8565b90506000611b0088888486613b1e565b90506000848860028110611b1657611b166149c2565b6020020151670de0b6b3a7640000600184878c60028110611b3957611b396149c2565b6020020151611b489190614951565b611b529190614951565b611b5c9190614968565b611b669190614987565b905060006402540be40082600a54611b7e9190614968565b611b889190614987565b9050611b948183614951565b96505050505050505b9392505050565b33611bad6125a6565b6001600160a01b031614611bd35760405162461bcd60e51b81526004016109c690614aa2565b6108fc8110158015611be757506159d88111155b611c215760405162461bcd60e51b815260206004820152600b60248201526a496c6c6567616c2067617360a81b60448201526064016109c6565b600c8190556040518181527f77af1b8b67f1d7632023ab9483dee075be904f096186ac8a4a8a0a892119d47a906020015b60405180910390a150565b60026001541415611c805760405162461bcd60e51b81526004016109c6906148b5565b6002600155600d54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015611ccf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf391906149a9565b9050611cfd614550565b611d05614550565b60005b6002811015611e3b576000848760088460028110611d2857611d286149c2565b0154611d349190614968565b611d3e9190614987565b9050858260028110611d5257611d526149c2565b6020020151811015611dbf5760405162461bcd60e51b815260206004820152603060248201527f5769746864726177616c20726573756c74656420696e20666577657220636f6960448201526f1b9cc81d1a185b88195e1c1958dd195960821b60648201526084016109c6565b8060088360028110611dd357611dd36149c2565b016000828254611de39190614951565b90915550819050848360028110611dfc57611dfc6149c2565b6020020152611e2860068360028110611e1757611e176149c2565b01546001600160a01b031682613d1a565b5080611e33816149f0565b915050611d08565b50600d5460405163079cc67960e41b81526001600160a01b03909116906379cc679090611e6e9033908990600401614a39565b600060405180830381600087803b158015611e8857600080fd5b505af1158015611e9c573d6000803e3d6000fd5b50505050611ea8613421565b337f7c363854ccf79623411f8995b362bce5eddff18c927edc6f5dbbb5e05819a82c8383611ed68988614951565b604051611ee593929190614c43565b60405180910390a2505060018055505050565b60026001541415611f1b5760405162461bcd60e51b81526004016109c6906148b5565b600260015560165460ff1615611f435760405162461bcd60e51b81526004016109c6906148ec565b600d54600160a01b900460ff16611f72573415611f725760405162461bcd60e51b81526004016109c69061490c565b604080518082019182905260009160089060029082845b815481526020019060010190808311611f8957505050505090506000611fae82613d5d565b90506000670de0b6b3a764000060048860028110611fce57611fce6149c2565b0154611fda9087614968565b611fe49190614987565b828860028110611ff657611ff66149c2565b602002015161200591906149d8565b9050600061201588888486613b1e565b90506000600182858a6002811061202e5761202e6149c2565b602002015161203d9190614951565b6120479190614951565b905060006402540be400600a548361205f9190614968565b6120699190614987565b90506004896002811061207e5761207e6149c2565b0154670de0b6b3a76400006120938385614951565b61209d9190614968565b6120a79190614987565b9150868210156121105760405162461bcd60e51b815260206004820152602e60248201527f45786368616e676520726573756c74656420696e20666577657220636f696e7360448201526d081d1a185b88195e1c1958dd195960921b60648201526084016109c6565b60006402540be400600b54836121269190614968565b6121309190614987565b905060048a60028110612145576121456149c2565b0154612159670de0b6b3a764000083614968565b6121639190614987565b905088878c60028110612178576121786149c2565b602002015161218791906149d8565b60088c6002811061219a5761219a6149c2565b01558083888c600281106121b0576121b06149c2565b60200201516121bf9190614951565b6121c99190614951565b60088b600281106121dc576121dc6149c2565b0155600060068c600281106121f3576121f36149c2565b01546001600160a01b0316905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81141561224057348a1461223b5760405162461bcd60e51b81526004016109c69061490c565b612255565b6122556001600160a01b03821633308d613e1a565b600060068c6002811061226a5761226a6149c2565b01546001600160a01b031690506122818186613d1a565b604080518e8152602081018d90529081018d90526060810186905233907fb2e76ae99761dc136e598d4a629bb347eccb9532a5f8bbd72e18467c3c34cc9890608001610fdf565b336122d16125a6565b6001600160a01b0316146122f75760405162461bcd60e51b81526004016109c690614aa2565b601254156123475760405162461bcd60e51b815260206004820181905260248201527f61646d696e5f616374696f6e735f646561646c696e65206d757374206265203060448201526064016109c6565b64012a05f2008211156123975760405162461bcd60e51b81526020600482015260186024820152776465763a206665652065786365656473206d6178696d756d60401b60448201526064016109c6565b6402540be4008111156123ec5760405162461bcd60e51b815260206004820152601e60248201527f6465763a2061646d696e206665652065786365656473206d6178696d756d000060448201526064016109c6565b6123f96203f480426149d8565b60128190556013839055601482905560408051848152602081018490527f351fc5da2fbf480f2225debf3664a4bc90fa9923743aad58b4603f648e931fe0910160405180910390a25050565b6004816002811061178957600080fd5b3361245e6125a6565b6001600160a01b0316146124845760405162461bcd60e51b81526004016109c690614aa2565b60405162461bcd60e51b815260206004820152600b60248201526a139bdd08185b1b1bddd95960aa1b60448201526064016109c6565b6002816002811061178957600080fd5b6000806124d5613a65565b604080518082019182905291925060009190600290819081845b8154815260200190600101908083116124ef5750505050509050600081876002811061251d5761251d6149c2565b602002015161252c9086614968565b83886002811061253e5761253e6149c2565b602002015161254d91906149d8565b9050600061255d88888487613b1e565b90506000838860028110612573576125736149c2565b6020020151600183878b6002811061258d5761258d6149c2565b602002015161259c9190614951565b611b5c9190614951565b6000546001600160a01b031690565b6000806125d06125c3613a65565b6125cb613309565b613e8b565b90508061261f5760405162461bcd60e51b815260206004820152601c60248201527f6765745f7669727475616c5f70726963653a2044206973207a65726f0000000060448201526064016109c6565b600d54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612669573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061268d91906149a9565b9050806126a2670de0b6b3a764000084614968565b6126ac9190614987565b9250505090565b600681600281106126c357600080fd5b01546001600160a01b0316905081565b336126dc6125a6565b6001600160a01b0316146127025760405162461bcd60e51b81526004016109c690614aa2565b600061270c613309565b600e819055600f81905542601081905560118190556040519192507f46e22fb3709ad289f62ce63d469248536dbc78d82b84a3d7e74ad606dc20193891611c5291848252602082015260400190565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60068360028110612785576127856149c2565b01546001600160a01b031614156127b557600882600281106127a9576127a96149c2565b01546118a79047614951565b600882600281106127c8576127c86149c2565b0154600683600281106127dd576127dd6149c2565b01546040516370a0823160e01b81526001600160a01b03909116906370a082319061280c90309060040161483e565b602060405180830381865afa158015612829573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284d91906149a9565b6118a79190614951565b919050565b6002600154141561287f5760405162461bcd60e51b81526004016109c6906148b5565b600260015560165460ff16156128a75760405162461bcd60e51b81526004016109c6906148ec565b600d54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa1580156128f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061291591906149a9565b9050600081116129605760405162461bcd60e51b81526020600482015260166024820152756465763a207a65726f20746f74616c20737570706c7960501b60448201526064016109c6565b600061296e60016002614951565b612979906004614968565b6002600a546129889190614968565b6129929190614987565b600b5490915060006129a2613309565b60408051808201918290529192506000919060089060029082845b8154815260200190600101908083116129bd575050505050905060006040518060400160405280836000600281106129f7576129f76149c2565b6020020151815260200183600160028110612a1457612a146149c2565b6020020151905290506000612a2983856133aa565b905060005b6002811015612a8657898160028110612a4957612a496149c2565b6020020151838260028110612a6057612a606149c2565b60200201818151612a719190614951565b90525080612a7e816149f0565b915050612a2e565b506000612a9383866133aa565b9050612a9d614550565b60005b6002811015612c3257600084878360028110612abe57612abe6149c2565b6020020151612acd9086614968565b612ad79190614987565b90506000868360028110612aed57612aed6149c2565b6020020151821115612b2157868360028110612b0b57612b0b6149c2565b6020020151612b1a9083614951565b9050612b46565b81878460028110612b3457612b346149c2565b6020020151612b439190614951565b90505b6402540be400612b56828d614968565b612b609190614987565b848460028110612b7257612b726149c2565b60200201526402540be4008a858560028110612b9057612b906149c2565b6020020151612b9f9190614968565b612ba99190614987565b878460028110612bbb57612bbb6149c2565b6020020151612bca9190614951565b60088460028110612bdd57612bdd6149c2565b0155838360028110612bf157612bf16149c2565b6020020151878460028110612c0857612c086149c2565b60200201818151612c199190614951565b905250829150612c2a9050816149f0565b915050612aa0565b506000612c3f85886133aa565b90506000848b612c4f8483614951565b612c599190614968565b612c639190614987565b905060008111612cc15760405162461bcd60e51b815260206004820152602360248201527f746f6b656e5f616d6f756e74206d75737420626520677265617465722074686160448201526206e20360ec1b60648201526084016109c6565b612ccc6001826149d8565b90508b811115612cee5760405162461bcd60e51b81526004016109c690614a0b565b600d5460405163079cc67960e41b81526001600160a01b03909116906379cc679090612d209033908590600401614a39565b600060405180830381600087803b158015612d3a57600080fd5b505af1158015612d4e573d6000803e3d6000fd5b5050505060005b6002811015612dcc5760008e8260028110612d7257612d726149c2565b60200201511115612dba57612dba60068260028110612d9357612d936149c2565b01546001600160a01b03168f8360028110612db057612db06149c2565b6020020151613d1a565b80612dc4816149f0565b915050612d55565b50612dd7818c614951565b9a50612de1613421565b336001600160a01b03167f2b5508378d7e19e0d5fa338419034731416c4f5b219a10379956f764317fd47e8e85878f604051610fdf9493929190614a75565b33612e296125a6565b6001600160a01b031614612e4f5760405162461bcd60e51b81526004016109c690614aa2565b4260155411612e945760405162461bcd60e51b8152602060048201526011602482015270457863656564656420646561646c696e6560781b60448201526064016109c6565b6016805460ff191660011790556040517fbe26733c2bf6ff3ea5ba8cfe744422bd49052ff9ed5685c9e81e6f9321dbaddd90600090a1565b604080518082019182905260009182919060089060029082845b815481526020019060010190808311612ee657505050505090506000612f0a613309565b90506000612f1883836133aa565b905060005b6002811015612fbe578515612f6e57868160028110612f3e57612f3e6149c2565b6020020151848260028110612f5557612f556149c2565b60200201818151612f6691906149d8565b905250612fac565b868160028110612f8057612f806149c2565b6020020151848260028110612f9757612f976149c2565b60200201818151612fa89190614951565b9052505b80612fb6816149f0565b915050612f1d565b506000612fcb84846133aa565b90506000600d60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613022573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304691906149a9565b9050600087156130615761305a8484614951565b905061306e565b61306b8385614951565b90505b836130798383614968565b6130839190614987565b9998505050505050505050565b600260015414156130b35760405162461bcd60e51b81526004016109c6906148b5565b600260015560165460ff16156130db5760405162461bcd60e51b81526004016109c6906148ec565b6000806130e88585613765565b91509150828210156131375760405162461bcd60e51b8152602060048201526018602482015277139bdd08195b9bdd59da0818dbda5b9cc81c995b5bdd995960421b60448201526064016109c6565b6402540be400600b548261314b9190614968565b6131559190614987565b61315f90836149d8565b60088560028110613172576131726149c2565b0160008282546131829190614951565b9091555050600d5460405163079cc67960e41b81526001600160a01b03909116906379cc6790906131b99033908990600401614a39565b600060405180830381600087803b1580156131d357600080fd5b505af11580156131e7573d6000803e3d6000fd5b5050505061321260068560028110613201576132016149c2565b01546001600160a01b031683613d1a565b61321a613421565b604080518581526020810187905290810183905233907f5ad056f2e28a8cec232015406b843668c1e36cda598127ec3b8c59b8c72773a090606001611ee5565b336132636125a6565b6001600160a01b0316146132895760405162461bcd60e51b81526004016109c690614aa2565b6001600160a01b0381166132ee5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016109c6565b6132f781614021565b50565b6000613304613309565b905090565b601154600f5460009190428211156118a757600e546010548183111561336e576133338185614951565b61333d8242614951565b6133478486614951565b6133519190614968565b61335b9190614987565b61336590836149d8565b94505050505090565b6133788185614951565b6133828242614951565b61338c8585614951565b6133969190614968565b6133a09190614987565b6133659083614951565b6000611b9d6133b884613d5d565b83613e8b565b6001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415613406573481146134025760405162461bcd60e51b81526004016109c69061490c565b5050565b8015613402576134026001600160a01b038316333084613e1a565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166326cfa27c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613481573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134a59190614c6c565b90506001600160a01b0381166134b85750565b60005b600281101561340257600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee600683600281106134ee576134ee6149c2565b01546001600160a01b03161415613656574760088360028110613513576135136149c2565b01548111613522576000613541565b60088360028110613535576135356149c2565b01546135419082614951565b91508115613650577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b1580156135a457600080fd5b505af11580156135b8573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb925061360b915087908690600401614a39565b6020604051808303816000875af115801561362a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061364e9190614c89565b505b50613752565b60006006836002811061366b5761366b6149c2565b01546040516370a0823160e01b81526001600160a01b03909116906370a082319061369a90309060040161483e565b602060405180830381865afa1580156136b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136db91906149a9565b9050600883600281106136f0576136f06149c2565b015481116136ff57600061371e565b60088360028110613712576137126149c2565b015461371e9082614951565b915081156137505761375084836006866002811061373e5761373e6149c2565b01546001600160a01b03169190614071565b505b508061375d816149f0565b9150506134bb565b6000806000613772613309565b9050600061378260016002614951565b61378d906004614968565b6002600a5461379c9190614968565b6137a69190614987565b604080518082019182905291925060009190600290819081845b8154815260200190600101908083116137c057505050505090506000600d60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561382f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061385391906149a9565b9050600061385f613a65565b9050600061386d8287613e8b565b905060008361387c838d614968565b6138869190614987565b6138909083614951565b90508260006138a1898d8486614095565b90506000878d600281106138b7576138b76149c2565b602002015182878f600281106138cf576138cf6149c2565b60200201516138de9190614951565b6138e89190614987565b905060005b60028110156139e45760008e82141561393f578387878a8560028110613915576139156149c2565b60200201516139249190614968565b61392e9190614987565b6139389190614951565b9050613990565b8686898460028110613953576139536149c2565b60200201516139629190614968565b61396c9190614987565b88836002811061397e5761397e6149c2565b602002015161398d9190614951565b90505b6402540be4006139a0828d614968565b6139aa9190614987565b8583600281106139bc576139bc6149c2565b602002018181516139cd9190614951565b9052508190506139dc816149f0565b9150506138ed565b5060006139f38b8f8688614095565b848f60028110613a0557613a056149c2565b6020020151613a149190614951565b9050888e60028110613a2857613a286149c2565b6020020151613a38600183614951565b613a429190614987565b905080613a4f8184614951565b9c509c5050505050505050505050509250929050565b613a6d614550565b60408051808201918290529060049060029082845b815481526020019060010190808311613a82575050505050905060005b6002811015613b1a57670de0b6b3a764000060088260028110613ac457613ac46149c2565b0154838360028110613ad857613ad86149c2565b6020020151613ae79190614968565b613af19190614987565b828260028110613b0357613b036149c2565b602002015280613b12816149f0565b915050613a9f565b5090565b6000838514158015613b305750600285105b8015613b3c5750600284105b613b7c5760405162461bcd60e51b815260206004820152601160248201527024b63632b3b0b6103830b930b6b2ba32b960791b60448201526064016109c6565b6000613b86613309565b90506000613b948483613e8b565b905080600080613ba5600286614968565b90506000805b6002811015613c2e578b811415613bc457899150613bee565b8a8114613be957888160028110613bdd57613bdd6149c2565b60200201519150613bee565b613c1c565b613bf882856149d8565b9350613c05600283614968565b613c0f8787614968565b613c199190614987565b94505b80613c26816149f0565b915050613bab565b50613c3a600283614968565b613c448686614968565b613c4e9190614987565b93506000613c5c8387614987565b613c6690856149d8565b9050600086815b60ff811015613d08578192508884836002613c889190614968565b613c9291906149d8565b613c9c9190614951565b88613ca78480614968565b613cb191906149d8565b613cbb9190614987565b915082821115613ce0576001613cd18484614951565b11613cdb57613d08565b613cf6565b6001613cec8385614951565b11613cf657613d08565b80613d00816149f0565b915050613c6d565b509d9c50505050505050505050505050565b6001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415613d49576134023382614250565b6134026001600160a01b0383163383614071565b613d65614550565b60408051808201918290529060049060029082845b815481526020019060010190808311613d7a575050505050905060005b6002811015613e1457670de0b6b3a7640000838260028110613dbb57613dbb6149c2565b6020020151838360028110613dd257613dd26149c2565b6020020151613de19190614968565b613deb9190614987565b828260028110613dfd57613dfd6149c2565b602002015280613e0c816149f0565b915050613d97565b50919050565b6040516001600160a01b0380851660248301528316604482015260648101829052613e859085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526142fd565b50505050565b60008060005b6002811015613ecf57848160028110613eac57613eac6149c2565b6020020151613ebb90836149d8565b915080613ec7816149f0565b915050613e91565b5080613edf5760009150506118a7565b60008181613eee600287614968565b905060005b60ff811015614015578260005b6002811015613f545760028a8260028110613f1d57613f1d6149c2565b6020020151613f2c9190614968565b613f368684614968565b613f409190614987565b915080613f4c816149f0565b915050613f00565b508394508060026001613f6791906149d8565b613f719190614968565b84613f7d600186614951565b613f879190614968565b613f9191906149d8565b84613f9d600284614968565b613fa78987614968565b613fb191906149d8565b613fbb9190614968565b613fc59190614987565b935084841115613feb576001613fdb8686614951565b11613fe65750614015565b614002565b6001613ff78587614951565b116140025750614015565b508061400d816149f0565b915050613ef3565b50909695505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6140908363a9059cbb60e01b8484604051602401613e4e929190614a39565b505050565b6000600284106140de5760405162461bcd60e51b81526020600482015260146024820152736465763a20692061626f7665204e5f434f494e5360601b60448201526064016109c6565b816000806140ed600289614968565b90506000805b60028110156141665788811461412157878160028110614115576141156149c2565b60200201519150614126565b614154565b61413082856149d8565b935061413d600283614968565b6141478887614968565b6141519190614987565b94505b8061415e816149f0565b9150506140f3565b50614172600283614968565b61417c8786614968565b6141869190614987565b935060006141948388614987565b61419e90856149d8565b9050600087815b60ff8110156142405781925089848360026141c09190614968565b6141ca91906149d8565b6141d49190614951565b886141df8480614968565b6141e991906149d8565b6141f39190614987565b9150828211156142185760016142098484614951565b1161421357614240565b61422e565b60016142248385614951565b1161422e57614240565b80614238816149f0565b9150506141a5565b509b9a5050505050505050505050565b600080836001600160a01b0316600c5484604051600060405180830381858888f193505050503d80600081146142a2576040519150601f19603f3d011682016040523d82523d6000602084013e6142a7565b606091505b509150915081613e855780516142f55760405162461bcd60e51b8152602060048201526013602482015272141314c81d1c985b9cd9995c8819985a5b1959606a1b60448201526064016109c6565b805181602001fd5b6000614352826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166143cf9092919063ffffffff16565b80519091501561409057808060200190518101906143709190614c89565b6140905760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109c6565b60606143de84846000856143e6565b949350505050565b6060824710156144475760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016109c6565b6001600160a01b0385163b61449e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109c6565b600080866001600160a01b031685876040516144ba9190614cd2565b60006040518083038185875af1925050503d80600081146144f7576040519150601f19603f3d011682016040523d82523d6000602084013e6144fc565b606091505b509150915061450c828286614517565b979650505050505050565b60608315614526575081611b9d565b8251156145365782518084602001fd5b8160405162461bcd60e51b81526004016109c69190614cee565b60405180604001604052806002906020820280368337509192915050565b826002810192821561459c579160200282015b8281111561459c578251825591602001919060010190614581565b50613b1a9291506145f0565b826002810192821561459c579160200282015b8281111561459c57825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906145bb565b5b80821115613b1a57600081556001016145f1565b6040805190810167ffffffffffffffff8111828210171561463657634e487b7160e01b600052604160045260246000fd5b60405290565b600082601f83011261464d57600080fd5b614655614605565b80604084018581111561466757600080fd5b845b81811015614681578035845260209384019301614669565b509095945050505050565b6000806060838503121561469f57600080fd5b6146a9848461463c565b946040939093013593505050565b600080604083850312156146ca57600080fd5b50508035926020909101359150565b6001600160a01b03811681146132f757600080fd5b8035612857816146d9565b60008060008060008060e0878903121561471257600080fd5b87601f88011261472157600080fd5b614729614605565b80604089018a81111561473b57600080fd5b895b8181101561475e578035614750816146d9565b84526020938401930161473d565b5090975035955050606087013593506080870135925061478060a088016146ee565b915061478e60c088016146ee565b90509295509295509295565b6000602082840312156147ac57600080fd5b5035919050565b6000806000606084860312156147c857600080fd5b505081359360208301359350604090920135919050565b600080606083850312156147f257600080fd5b82359150614803846020850161463c565b90509250929050565b6000806000806080858703121561482257600080fd5b5050823594602084013594506040840135936060013592509050565b6001600160a01b0391909116815260200190565b80151581146132f757600080fd5b6000806060838503121561487357600080fd5b61487d848461463c565b9150604083013561488d81614852565b809150509250929050565b6000602082840312156148aa57600080fd5b8135611b9d816146d9565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526006908201526512da5b1b195960d21b604082015260600190565b602080825260159082015274496e636f6e73697374656e74207175616e7469747960581b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000828210156149635761496361493b565b500390565b60008160001904831182151516156149825761498261493b565b500290565b6000826149a457634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156149bb57600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b600082198211156149eb576149eb61493b565b500190565b6000600019821415614a0457614a0461493b565b5060010190565b602080825260149082015273536c697070616765207363726577656420796f7560601b604082015260600190565b6001600160a01b03929092168252602082015260400190565b8060005b6002811015613e85578151845260209384019390910190600101614a56565b60c08101614a838287614a52565b614a906040830186614a52565b608082019390935260a0015292915050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601690820152756465763a20696e73756666696369656e742074696d6560501b604082015260600190565b600060208284031215614b1957600080fd5b815160ff81168114611b9d57600080fd5b600181815b80851115614b65578160001904821115614b4b57614b4b61493b565b80851615614b5857918102915b93841c9390800290614b2f565b509250929050565b600082614b7c575060016118a7565b81614b89575060006118a7565b8160018114614b9f5760028114614ba957614bc5565b60019150506118a7565b60ff841115614bba57614bba61493b565b50506001821b6118a7565b5060208310610133831016604e8410600b8410161715614be8575081810a6118a7565b614bf28383614b2a565b8060001904821115614c0657614c0661493b565b029392505050565b6000611b9d8383614b6d565b6020808252600f908201526e42616c616e6365206973207a65726f60881b604082015260600190565b60a08101614c518286614a52565b614c5e6040830185614a52565b826080830152949350505050565b600060208284031215614c7e57600080fd5b8151611b9d816146d9565b600060208284031215614c9b57600080fd5b8151611b9d81614852565b60005b83811015614cc1578181015183820152602001614ca9565b83811115613e855750506000910152565b60008251614ce4818460208701614ca6565b9190910192915050565b6020815260008251806020840152614d0d816040850160208701614ca6565b601f01601f1916919091016040019291505056fea26469706673582212206a8cedd5a3ddb983489f6470c0ea7676e0458d221bc62f1bf8f03581ffeca56464736f6c634300080a0033a264697066735822122074b45d0324d7e491ca87b61d105e5c19965bbe1d764d78890e92d4d33e9c699664736f6c634300080a0033
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106100575760003560e01c8063293577501461005c578063715018a614610077578063850787a1146100815780638da5cb5b146100a1578063f2fde38b146100b2575b600080fd5b610064600281565b6040519081526020015b60405180910390f35b61007f6100c5565b005b61009461008f3660046104ec565b610104565b60405161006e9190610505565b6000546001600160a01b0316610094565b61007f6100c0366004610519565b6103f4565b6000546001600160a01b031633146100f85760405162461bcd60e51b81526004016100ef90610549565b60405180910390fd5b610102600061048f565b565b600080546001600160a01b0316331461012f5760405162461bcd60e51b81526004016100ef90610549565b600061013e6020840184610519565b6001600160a01b03161415801561016e575060006101626040840160208501610519565b6001600160a01b031614155b6101aa5760405162461bcd60e51b815260206004820152600d60248201526c24b63632b3b0b6103a37b5b2b760991b60448201526064016100ef565b60006101b96020840184610519565b905060006101cd6040850160208601610519565b60408051808201909152909150600090806101eb6020880188610519565b6001600160a01b0316815260209081019061020c9060408901908901610519565b6001600160a01b0316905260405190915060009061022c602082016104df565b601f1982820381018352601f90910116604052610250610100880160e08901610519565b6040516020016102609190610505565b60408051601f1981840301815291905261028261012089016101008a01610519565b6040516020016102929190610505565b60408051601f19818403018152908290526102b19392916020016105b9565b60408051601f19818403018152908290526bffffffffffffffffffffffff19606087811b8216602085015286811b8216603485015233901b16604883015242605c83015246607c8301529150600090609c016040516020818303038152906040528051906020012090506000818351602085016000f590506001600160a01b0381166103505760405163b06ebf3d60e01b815260040160405180910390fd5b806001600160a01b0316634239b1c1858a604001358b606001358c608001358d60a00160208101906103829190610519565b8e60c00160208101906103959190610519565b6040518763ffffffff1660e01b81526004016103b6969594939291906105e0565b600060405180830381600087803b1580156103d057600080fd5b505af11580156103e4573d6000803e3d6000fd5b50929a9950505050505050505050565b6000546001600160a01b0316331461041e5760405162461bcd60e51b81526004016100ef90610549565b6001600160a01b0381166104835760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016100ef565b61048c8161048f565b50565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b614ead8061064983390190565b600061012082840312156104ff57600080fd5b50919050565b6001600160a01b0391909116815260200190565b60006020828403121561052b57600080fd5b81356001600160a01b038116811461054257600080fd5b9392505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6000815160005b8181101561059f5760208185018101518683015201610585565b818111156105ae576000828601525b509290920192915050565b60006105d76105d16105cb848861057e565b8661057e565b8461057e565b95945050505050565b60e08101818860005b60028110156106115781516001600160a01b03168352602092830192909101906001016105e9565b5050506040820196909652606081019490945260808401929092526001600160a01b0390811660a08401521660c09091015291905056fe60e0604052610fbd600c553480156200001757600080fd5b5060405162004ead38038062004ead8339810160408190526200003a91620000d2565b620000453362000065565b600180553360a0526001600160a01b039182166080521660c0526200010a565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620000cd57600080fd5b919050565b60008060408385031215620000e657600080fd5b620000f183620000b5565b91506200010160208401620000b5565b90509250929050565b60805160a05160c051614d5762000156600039600081816108f60152818161354b01526135d10152600081816107c401526113a30152600081816106e601526134250152614d576000f3fe6080604052600436106103225760003560e01c80637dafa364116101a7578063ddca3f43116100ed578063edfb780111610090578063edfb7801146108cd578063ef8ef56f146108e4578063f1dc3cc914610918578063f2fde38b14610938578063f3de0362146107e6578063f446c1d014610958578063fc0c546a1461096d578063fee3f7f91461098d57600080fd5b8063ddca3f43146107ff578063e2e7d26414610815578063e310327314610835578063e369885314610855578063e38244621461086a578063e5d9e90314610880578063e7ee486d14610897578063ed8e84f3146108ad57600080fd5b8063ab5ac06111610155578063ab5ac06114610724578063b4b577ad14610739578063bb7b8b801461074f578063bc063e1a14610764578063c66106571461077d578063ca8ca1541461079d578063d1cc8706146107b2578063d73792a9146107e657600080fd5b80637dafa36414610642578063817348a61461066257806385f11d1e146106785780638da5cb5b146106985780639c868ac0146106ba578063a6b0a718146106d4578063aaf5eb681461070857600080fd5b80634239b1c11161026c57806358680d0b1161021a57806358680d0b1461056f578063592ad186146105855780635b36389c146105a55780635b41b908146105c55780635b5a1467146105d857806362203d74146105f85780636d4366b714610618578063715018a61461062d57600080fd5b80634239b1c1146104af5780634903b0d1146104cf5780634f12fe97146104ef5780634fb08c5e14610504578063524c3901146105245780635409491a14610539578063556d6e9f1461054f57600080fd5b80632a426896116102d45780632a426896146103ed5780633046f9721461040357806330c54085146104185780633897b4e01461042d578063392e53cd1461044357806339698415146104625780633c157e6414610479578063405e28f81461049957600080fd5b806306e9481c146103275780630b4c7e4d1461035157806314052288146103665780632081066c1461037c5780632092dc3e14610392578063226840fb146103c357806329357750146103d8575b600080fd5b34801561033357600080fd5b5061033e6201518081565b6040519081526020015b60405180910390f35b61036461035f36600461468c565b6109a3565b005b34801561037257600080fd5b5061033e60115481565b34801561038857600080fd5b5061033e60105481565b34801561039e57600080fd5b50600d546103b390600160a01b900460ff1681565b6040519015158152602001610348565b3480156103cf57600080fd5b50610364610ffa565b3480156103e457600080fd5b5061033e600281565b3480156103f957600080fd5b5061033e60155481565b34801561040f57600080fd5b50610364611059565b34801561042457600080fd5b506103646110bd565b34801561043957600080fd5b5061033e6159d881565b34801561044f57600080fd5b506016546103b390610100900460ff1681565b34801561046e57600080fd5b5061033e620f424081565b34801561048557600080fd5b506103646104943660046146b7565b611135565b3480156104a557600080fd5b5061033e60125481565b3480156104bb57600080fd5b506103646104ca3660046146f9565b611340565b3480156104db57600080fd5b5061033e6104ea36600461479a565b611779565b3480156104fb57600080fd5b50610364611790565b34801561051057600080fd5b5061033e61051f3660046146b7565b611895565b34801561053057600080fd5b506103646118ad565b34801561054557600080fd5b5061033e600e5481565b34801561055b57600080fd5b5061033e61056a3660046147b3565b611a59565b34801561057b57600080fd5b5061033e60135481565b34801561059157600080fd5b506103646105a036600461479a565b611ba4565b3480156105b157600080fd5b506103646105c03660046147df565b611c5d565b6103646105d336600461480c565b611ef8565b3480156105e457600080fd5b506103646105f33660046146b7565b6122c8565b34801561060457600080fd5b5061033e61061336600461479a565b612445565b34801561062457600080fd5b5061033e601281565b34801561063957600080fd5b50610364612455565b34801561064e57600080fd5b5061033e61065d36600461479a565b6124ba565b34801561066e57600080fd5b5061033e6108fc81565b34801561068457600080fd5b5061033e6106933660046147b3565b6124ca565b3480156106a457600080fd5b506106ad6125a6565b604051610348919061483e565b3480156106c657600080fd5b506016546103b39060ff1681565b3480156106e057600080fd5b506106ad7f000000000000000000000000000000000000000000000000000000000000000081565b34801561071457600080fd5b5061033e670de0b6b3a764000081565b34801561073057600080fd5b5061033e600a81565b34801561074557600080fd5b5061033e600f5481565b34801561075b57600080fd5b5061033e6125b5565b34801561077057600080fd5b5061033e64012a05f20081565b34801561078957600080fd5b506106ad61079836600461479a565b6126b3565b3480156107a957600080fd5b506103646126d3565b3480156107be57600080fd5b506106ad7f000000000000000000000000000000000000000000000000000000000000000081565b3480156107f257600080fd5b5061033e6402540be40081565b34801561080b57600080fd5b5061033e600a5481565b34801561082157600080fd5b5061033e61083036600461479a565b61275b565b34801561084157600080fd5b5061036461085036600461468c565b61285c565b34801561086157600080fd5b50610364612e20565b34801561087657600080fd5b5061033e60145481565b34801561088c57600080fd5b5061033e6203f48081565b3480156108a357600080fd5b5061033e600c5481565b3480156108b957600080fd5b5061033e6108c8366004614860565b612ecc565b3480156108d957600080fd5b5061033e624f1a0081565b3480156108f057600080fd5b506106ad7f000000000000000000000000000000000000000000000000000000000000000081565b34801561092457600080fd5b506103646109333660046147b3565b613090565b34801561094457600080fd5b50610364610953366004614898565b61325a565b34801561096457600080fd5b5061033e6132fa565b34801561097957600080fd5b50600d546106ad906001600160a01b031681565b34801561099957600080fd5b5061033e600b5481565b600260015414156109cf5760405162461bcd60e51b81526004016109c6906148b5565b60405180910390fd5b600260015560165460ff16156109f75760405162461bcd60e51b81526004016109c6906148ec565b600d54600160a01b900460ff16610a26573415610a265760405162461bcd60e51b81526004016109c69061490c565b610a2e614550565b6000610a3c60016002614951565b610a47906004614968565b6002600a54610a569190614968565b610a609190614987565b600b549091506000610a70613309565b90506000600d60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ac7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aeb91906149a9565b6040805180820191829052919250600091829160089060029082845b815481526020019060010190808311610b0757505050505090506000831115610b3757610b3481856133aa565b91505b6000604051806040016040528083600060028110610b5757610b576149c2565b6020020151815260200183600160028110610b7457610b746149c2565b60200201519052905060005b6002811015610c605784610bff5760008b8260028110610ba257610ba26149c2565b602002015111610bff5760405162461bcd60e51b815260206004820152602260248201527f496e697469616c206465706f73697420726571756972657320616c6c20636f696044820152616e7360f01b60648201526084016109c6565b8a8160028110610c1157610c116149c2565b6020020151838260028110610c2857610c286149c2565b6020020151610c3791906149d8565b828260028110610c4957610c496149c2565b602002015280610c58816149f0565b915050610b80565b506000610c6d82876133aa565b9050838111610cbe5760405162461bcd60e51b815260206004820152601a60248201527f4431206d7573742062652067726561746572207468616e20443000000000000060448201526064016109c6565b808515610e6c5760005b6002811015610e5a57600086868360028110610ce657610ce66149c2565b6020020151610cf59086614968565b610cff9190614987565b90506000858360028110610d1557610d156149c2565b6020020151821115610d4957858360028110610d3357610d336149c2565b6020020151610d429083614951565b9050610d6e565b81868460028110610d5c57610d5c6149c2565b6020020151610d6b9190614951565b90505b6402540be400610d7e828e614968565b610d889190614987565b8d8460028110610d9a57610d9a6149c2565b60200201526402540be4008b8e8560028110610db857610db86149c2565b6020020151610dc79190614968565b610dd19190614987565b868460028110610de357610de36149c2565b6020020151610df29190614951565b60088460028110610e0557610e056149c2565b01558c8360028110610e1957610e196149c2565b6020020151868460028110610e3057610e306149c2565b60200201818151610e419190614951565b905250829150610e529050816149f0565b915050610cc8565b50610e6583886133aa565b9050610e7b565b610e79600884600261456e565b505b600086610e89575081610eab565b85610e948184614951565b610e9e9089614968565b610ea89190614987565b90505b8b811015610ecb5760405162461bcd60e51b81526004016109c690614a0b565b60005b6002811015610f335760008e8260028110610eeb57610eeb6149c2565b60200201519050600060068360028110610f0757610f076149c2565b01546001600160a01b03169050610f1e81836133be565b50508080610f2b906149f0565b915050610ece565b50600d546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990610f669033908590600401614a39565b600060405180830381600087803b158015610f8057600080fd5b505af1158015610f94573d6000803e3d6000fd5b50505050610fa0613421565b337f26f55a85081d24974e85c6c00045d0f0453991e95873f52bff0d21af4079a7688e8d86610fcf868d6149d8565b604051610fdf9493929190614a75565b60405180910390a25050600180555050505050505050505050565b336110036125a6565b6001600160a01b0316146110295760405162461bcd60e51b81526004016109c690614aa2565b600060128190556040517f1b4883af197c705114490f8d84f9ce30bef6a6199f7b7b649e845577cf0769a19190a1565b336110626125a6565b6001600160a01b0316146110885760405162461bcd60e51b81526004016109c690614aa2565b6016805460ff191690556040517f061284ffa2814ace135f62907c78a7cff0f070efe7e6a0a42740ea1da2c8bdc890600090a1565b336110c66125a6565b6001600160a01b0316146110ec5760405162461bcd60e51b81526004016109c690614aa2565b60165460ff1661112b5760405162461bcd60e51b815260206004820152600a602482015269139bdd081ada5b1b195960b21b60448201526064016109c6565b611133613421565b565b3361113e6125a6565b6001600160a01b0316146111645760405162461bcd60e51b81526004016109c690614aa2565b6201518060105461117591906149d8565b4210156111b65760405162461bcd60e51b815260206004820152600f60248201526e646576203a20746f6f206561726c7960881b60448201526064016109c6565b6111c362015180426149d8565b8110156111e25760405162461bcd60e51b81526004016109c690614ad7565b60006111ec613309565b90506000831180156112005750620f424083105b61125a5760405162461bcd60e51b815260206004820152602560248201527f5f6675747572655f41206d757374206265206265747765656e203020616e64206044820152644d41585f4160d81b60648201526084016109c6565b8083101580156112745750611270600a82614968565b8311155b8061129357508083108015611293575080611290600a85614968565b10155b6112df5760405162461bcd60e51b815260206004820152601b60248201527f496c6c6567616c20706172616d65746572205f6675747572655f41000000000060448201526064016109c6565b600e819055600f839055426010819055601183905560408051838152602081018690528082019290925260608201849052517fa2b71ec6df949300b59aab36b55e189697b750119dd349fcfa8c0f779e83c2549181900360800190a1505050565b601654610100900460ff16156113985760405162461bcd60e51b815260206004820152601f60248201527f4f7065726174696f6e733a20416c726561647920696e697469616c697a65640060448201526064016109c6565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461140b5760405162461bcd60e51b815260206004820152601860248201527727b832b930ba34b7b7399d102737ba103232b83637bcb2b960411b60448201526064016109c6565b620f42408511156114535760405162461bcd60e51b81526020600482015260126024820152715f412065786365656473206d6178696d756d60701b60448201526064016109c6565b64012a05f20084111561149f5760405162461bcd60e51b81526020600482015260146024820152735f6665652065786365656473206d6178696d756d60601b60448201526064016109c6565b6402540be4008311156114f45760405162461bcd60e51b815260206004820152601a60248201527f5f61646d696e5f6665652065786365656473206d6178696d756d00000000000060448201526064016109c6565b6016805461ff00191661010017905560005b600281101561171a576000878260028110611523576115236149c2565b60200201516001600160a01b0316141561156e5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f204164647265737360a01b60448201526064016109c6565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee888360028110611597576115976149c2565b60200201516001600160a01b031614156115c65750600d805460ff60a01b1916600160a01b1790556012611644565b8782600281106115d8576115d86149c2565b60200201516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561161a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163e9190614b07565b60ff1690505b60128111156116a15760405162461bcd60e51b8152602060048201526024808201527f546865206d6178696d756d20646563696d616c2063616e6e6f742065786365656044820152630c84062760e31b60648201526084016109c6565b6116ac816012614951565b6116b790600a614c0e565b600283600281106116ca576116ca6149c2565b01556002828181106116de576116de6149c2565b01546116f290670de0b6b3a7640000614968565b60048360028110611705576117056149c2565b01555080611712816149f0565b915050611506565b5061172860068760026145a8565b50600e859055600f859055600a849055600b83905561174a624f1a00426149d8565b601555600d80546001600160a01b0319166001600160a01b0383161790556117718261325a565b505050505050565b6008816002811061178957600080fd5b0154905081565b336117996125a6565b6001600160a01b0316146117bf5760405162461bcd60e51b81526004016109c690614aa2565b6012544210156117e15760405162461bcd60e51b81526004016109c690614ad7565b60125461183f5760405162461bcd60e51b815260206004820152602660248201527f61646d696e5f616374696f6e735f646561646c696e652073686f756c64206e6f60448201526507420626520360d41b60648201526084016109c6565b6000601255601354600a819055601454600b8190556040517fbe12859b636aed607d5230b2cc2711f68d70e51060e6cca1f575ef5d2fcc95d19261188b92908252602082015260400190565b60405180910390a1565b6000806118a28484613765565b509150505b92915050565b336118b66125a6565b6001600160a01b0316146118dc5760405162461bcd60e51b81526004016109c690614aa2565b60005b6002811015611a2d5773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60068260028110611910576119106149c2565b01546001600160a01b0316141561195c57600047116119415760405162461bcd60e51b81526004016109c690614c1a565b4760088260028110611955576119556149c2565b0155611a1b565b600060068260028110611971576119716149c2565b01546040516370a0823160e01b81526001600160a01b03909116906370a08231906119a090309060040161483e565b602060405180830381865afa1580156119bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e191906149a9565b905060008111611a035760405162461bcd60e51b81526004016109c690614c1a565b8060088360028110611a1757611a176149c2565b0155505b80611a25816149f0565b9150506118df565b506040517f2c7203581ca666b8c5094c11c03f0b19b3750234a9d281bcbc88a260bcb006de90600090a1565b604080518082019182905260009182919060049060029082845b815481526020019060010190808311611a7357505050505090506000611a97613a65565b90506000670de0b6b3a7640000838860028110611ab657611ab66149c2565b6020020151611ac59087614968565b611acf9190614987565b828860028110611ae157611ae16149c2565b6020020151611af091906149d8565b90506000611b0088888486613b1e565b90506000848860028110611b1657611b166149c2565b6020020151670de0b6b3a7640000600184878c60028110611b3957611b396149c2565b6020020151611b489190614951565b611b529190614951565b611b5c9190614968565b611b669190614987565b905060006402540be40082600a54611b7e9190614968565b611b889190614987565b9050611b948183614951565b96505050505050505b9392505050565b33611bad6125a6565b6001600160a01b031614611bd35760405162461bcd60e51b81526004016109c690614aa2565b6108fc8110158015611be757506159d88111155b611c215760405162461bcd60e51b815260206004820152600b60248201526a496c6c6567616c2067617360a81b60448201526064016109c6565b600c8190556040518181527f77af1b8b67f1d7632023ab9483dee075be904f096186ac8a4a8a0a892119d47a906020015b60405180910390a150565b60026001541415611c805760405162461bcd60e51b81526004016109c6906148b5565b6002600155600d54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015611ccf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf391906149a9565b9050611cfd614550565b611d05614550565b60005b6002811015611e3b576000848760088460028110611d2857611d286149c2565b0154611d349190614968565b611d3e9190614987565b9050858260028110611d5257611d526149c2565b6020020151811015611dbf5760405162461bcd60e51b815260206004820152603060248201527f5769746864726177616c20726573756c74656420696e20666577657220636f6960448201526f1b9cc81d1a185b88195e1c1958dd195960821b60648201526084016109c6565b8060088360028110611dd357611dd36149c2565b016000828254611de39190614951565b90915550819050848360028110611dfc57611dfc6149c2565b6020020152611e2860068360028110611e1757611e176149c2565b01546001600160a01b031682613d1a565b5080611e33816149f0565b915050611d08565b50600d5460405163079cc67960e41b81526001600160a01b03909116906379cc679090611e6e9033908990600401614a39565b600060405180830381600087803b158015611e8857600080fd5b505af1158015611e9c573d6000803e3d6000fd5b50505050611ea8613421565b337f7c363854ccf79623411f8995b362bce5eddff18c927edc6f5dbbb5e05819a82c8383611ed68988614951565b604051611ee593929190614c43565b60405180910390a2505060018055505050565b60026001541415611f1b5760405162461bcd60e51b81526004016109c6906148b5565b600260015560165460ff1615611f435760405162461bcd60e51b81526004016109c6906148ec565b600d54600160a01b900460ff16611f72573415611f725760405162461bcd60e51b81526004016109c69061490c565b604080518082019182905260009160089060029082845b815481526020019060010190808311611f8957505050505090506000611fae82613d5d565b90506000670de0b6b3a764000060048860028110611fce57611fce6149c2565b0154611fda9087614968565b611fe49190614987565b828860028110611ff657611ff66149c2565b602002015161200591906149d8565b9050600061201588888486613b1e565b90506000600182858a6002811061202e5761202e6149c2565b602002015161203d9190614951565b6120479190614951565b905060006402540be400600a548361205f9190614968565b6120699190614987565b90506004896002811061207e5761207e6149c2565b0154670de0b6b3a76400006120938385614951565b61209d9190614968565b6120a79190614987565b9150868210156121105760405162461bcd60e51b815260206004820152602e60248201527f45786368616e676520726573756c74656420696e20666577657220636f696e7360448201526d081d1a185b88195e1c1958dd195960921b60648201526084016109c6565b60006402540be400600b54836121269190614968565b6121309190614987565b905060048a60028110612145576121456149c2565b0154612159670de0b6b3a764000083614968565b6121639190614987565b905088878c60028110612178576121786149c2565b602002015161218791906149d8565b60088c6002811061219a5761219a6149c2565b01558083888c600281106121b0576121b06149c2565b60200201516121bf9190614951565b6121c99190614951565b60088b600281106121dc576121dc6149c2565b0155600060068c600281106121f3576121f36149c2565b01546001600160a01b0316905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81141561224057348a1461223b5760405162461bcd60e51b81526004016109c69061490c565b612255565b6122556001600160a01b03821633308d613e1a565b600060068c6002811061226a5761226a6149c2565b01546001600160a01b031690506122818186613d1a565b604080518e8152602081018d90529081018d90526060810186905233907fb2e76ae99761dc136e598d4a629bb347eccb9532a5f8bbd72e18467c3c34cc9890608001610fdf565b336122d16125a6565b6001600160a01b0316146122f75760405162461bcd60e51b81526004016109c690614aa2565b601254156123475760405162461bcd60e51b815260206004820181905260248201527f61646d696e5f616374696f6e735f646561646c696e65206d757374206265203060448201526064016109c6565b64012a05f2008211156123975760405162461bcd60e51b81526020600482015260186024820152776465763a206665652065786365656473206d6178696d756d60401b60448201526064016109c6565b6402540be4008111156123ec5760405162461bcd60e51b815260206004820152601e60248201527f6465763a2061646d696e206665652065786365656473206d6178696d756d000060448201526064016109c6565b6123f96203f480426149d8565b60128190556013839055601482905560408051848152602081018490527f351fc5da2fbf480f2225debf3664a4bc90fa9923743aad58b4603f648e931fe0910160405180910390a25050565b6004816002811061178957600080fd5b3361245e6125a6565b6001600160a01b0316146124845760405162461bcd60e51b81526004016109c690614aa2565b60405162461bcd60e51b815260206004820152600b60248201526a139bdd08185b1b1bddd95960aa1b60448201526064016109c6565b6002816002811061178957600080fd5b6000806124d5613a65565b604080518082019182905291925060009190600290819081845b8154815260200190600101908083116124ef5750505050509050600081876002811061251d5761251d6149c2565b602002015161252c9086614968565b83886002811061253e5761253e6149c2565b602002015161254d91906149d8565b9050600061255d88888487613b1e565b90506000838860028110612573576125736149c2565b6020020151600183878b6002811061258d5761258d6149c2565b602002015161259c9190614951565b611b5c9190614951565b6000546001600160a01b031690565b6000806125d06125c3613a65565b6125cb613309565b613e8b565b90508061261f5760405162461bcd60e51b815260206004820152601c60248201527f6765745f7669727475616c5f70726963653a2044206973207a65726f0000000060448201526064016109c6565b600d54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612669573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061268d91906149a9565b9050806126a2670de0b6b3a764000084614968565b6126ac9190614987565b9250505090565b600681600281106126c357600080fd5b01546001600160a01b0316905081565b336126dc6125a6565b6001600160a01b0316146127025760405162461bcd60e51b81526004016109c690614aa2565b600061270c613309565b600e819055600f81905542601081905560118190556040519192507f46e22fb3709ad289f62ce63d469248536dbc78d82b84a3d7e74ad606dc20193891611c5291848252602082015260400190565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60068360028110612785576127856149c2565b01546001600160a01b031614156127b557600882600281106127a9576127a96149c2565b01546118a79047614951565b600882600281106127c8576127c86149c2565b0154600683600281106127dd576127dd6149c2565b01546040516370a0823160e01b81526001600160a01b03909116906370a082319061280c90309060040161483e565b602060405180830381865afa158015612829573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284d91906149a9565b6118a79190614951565b919050565b6002600154141561287f5760405162461bcd60e51b81526004016109c6906148b5565b600260015560165460ff16156128a75760405162461bcd60e51b81526004016109c6906148ec565b600d54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa1580156128f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061291591906149a9565b9050600081116129605760405162461bcd60e51b81526020600482015260166024820152756465763a207a65726f20746f74616c20737570706c7960501b60448201526064016109c6565b600061296e60016002614951565b612979906004614968565b6002600a546129889190614968565b6129929190614987565b600b5490915060006129a2613309565b60408051808201918290529192506000919060089060029082845b8154815260200190600101908083116129bd575050505050905060006040518060400160405280836000600281106129f7576129f76149c2565b6020020151815260200183600160028110612a1457612a146149c2565b6020020151905290506000612a2983856133aa565b905060005b6002811015612a8657898160028110612a4957612a496149c2565b6020020151838260028110612a6057612a606149c2565b60200201818151612a719190614951565b90525080612a7e816149f0565b915050612a2e565b506000612a9383866133aa565b9050612a9d614550565b60005b6002811015612c3257600084878360028110612abe57612abe6149c2565b6020020151612acd9086614968565b612ad79190614987565b90506000868360028110612aed57612aed6149c2565b6020020151821115612b2157868360028110612b0b57612b0b6149c2565b6020020151612b1a9083614951565b9050612b46565b81878460028110612b3457612b346149c2565b6020020151612b439190614951565b90505b6402540be400612b56828d614968565b612b609190614987565b848460028110612b7257612b726149c2565b60200201526402540be4008a858560028110612b9057612b906149c2565b6020020151612b9f9190614968565b612ba99190614987565b878460028110612bbb57612bbb6149c2565b6020020151612bca9190614951565b60088460028110612bdd57612bdd6149c2565b0155838360028110612bf157612bf16149c2565b6020020151878460028110612c0857612c086149c2565b60200201818151612c199190614951565b905250829150612c2a9050816149f0565b915050612aa0565b506000612c3f85886133aa565b90506000848b612c4f8483614951565b612c599190614968565b612c639190614987565b905060008111612cc15760405162461bcd60e51b815260206004820152602360248201527f746f6b656e5f616d6f756e74206d75737420626520677265617465722074686160448201526206e20360ec1b60648201526084016109c6565b612ccc6001826149d8565b90508b811115612cee5760405162461bcd60e51b81526004016109c690614a0b565b600d5460405163079cc67960e41b81526001600160a01b03909116906379cc679090612d209033908590600401614a39565b600060405180830381600087803b158015612d3a57600080fd5b505af1158015612d4e573d6000803e3d6000fd5b5050505060005b6002811015612dcc5760008e8260028110612d7257612d726149c2565b60200201511115612dba57612dba60068260028110612d9357612d936149c2565b01546001600160a01b03168f8360028110612db057612db06149c2565b6020020151613d1a565b80612dc4816149f0565b915050612d55565b50612dd7818c614951565b9a50612de1613421565b336001600160a01b03167f2b5508378d7e19e0d5fa338419034731416c4f5b219a10379956f764317fd47e8e85878f604051610fdf9493929190614a75565b33612e296125a6565b6001600160a01b031614612e4f5760405162461bcd60e51b81526004016109c690614aa2565b4260155411612e945760405162461bcd60e51b8152602060048201526011602482015270457863656564656420646561646c696e6560781b60448201526064016109c6565b6016805460ff191660011790556040517fbe26733c2bf6ff3ea5ba8cfe744422bd49052ff9ed5685c9e81e6f9321dbaddd90600090a1565b604080518082019182905260009182919060089060029082845b815481526020019060010190808311612ee657505050505090506000612f0a613309565b90506000612f1883836133aa565b905060005b6002811015612fbe578515612f6e57868160028110612f3e57612f3e6149c2565b6020020151848260028110612f5557612f556149c2565b60200201818151612f6691906149d8565b905250612fac565b868160028110612f8057612f806149c2565b6020020151848260028110612f9757612f976149c2565b60200201818151612fa89190614951565b9052505b80612fb6816149f0565b915050612f1d565b506000612fcb84846133aa565b90506000600d60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613022573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304691906149a9565b9050600087156130615761305a8484614951565b905061306e565b61306b8385614951565b90505b836130798383614968565b6130839190614987565b9998505050505050505050565b600260015414156130b35760405162461bcd60e51b81526004016109c6906148b5565b600260015560165460ff16156130db5760405162461bcd60e51b81526004016109c6906148ec565b6000806130e88585613765565b91509150828210156131375760405162461bcd60e51b8152602060048201526018602482015277139bdd08195b9bdd59da0818dbda5b9cc81c995b5bdd995960421b60448201526064016109c6565b6402540be400600b548261314b9190614968565b6131559190614987565b61315f90836149d8565b60088560028110613172576131726149c2565b0160008282546131829190614951565b9091555050600d5460405163079cc67960e41b81526001600160a01b03909116906379cc6790906131b99033908990600401614a39565b600060405180830381600087803b1580156131d357600080fd5b505af11580156131e7573d6000803e3d6000fd5b5050505061321260068560028110613201576132016149c2565b01546001600160a01b031683613d1a565b61321a613421565b604080518581526020810187905290810183905233907f5ad056f2e28a8cec232015406b843668c1e36cda598127ec3b8c59b8c72773a090606001611ee5565b336132636125a6565b6001600160a01b0316146132895760405162461bcd60e51b81526004016109c690614aa2565b6001600160a01b0381166132ee5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016109c6565b6132f781614021565b50565b6000613304613309565b905090565b601154600f5460009190428211156118a757600e546010548183111561336e576133338185614951565b61333d8242614951565b6133478486614951565b6133519190614968565b61335b9190614987565b61336590836149d8565b94505050505090565b6133788185614951565b6133828242614951565b61338c8585614951565b6133969190614968565b6133a09190614987565b6133659083614951565b6000611b9d6133b884613d5d565b83613e8b565b6001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415613406573481146134025760405162461bcd60e51b81526004016109c69061490c565b5050565b8015613402576134026001600160a01b038316333084613e1a565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166326cfa27c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613481573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134a59190614c6c565b90506001600160a01b0381166134b85750565b60005b600281101561340257600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee600683600281106134ee576134ee6149c2565b01546001600160a01b03161415613656574760088360028110613513576135136149c2565b01548111613522576000613541565b60088360028110613535576135356149c2565b01546135419082614951565b91508115613650577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b1580156135a457600080fd5b505af11580156135b8573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb925061360b915087908690600401614a39565b6020604051808303816000875af115801561362a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061364e9190614c89565b505b50613752565b60006006836002811061366b5761366b6149c2565b01546040516370a0823160e01b81526001600160a01b03909116906370a082319061369a90309060040161483e565b602060405180830381865afa1580156136b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136db91906149a9565b9050600883600281106136f0576136f06149c2565b015481116136ff57600061371e565b60088360028110613712576137126149c2565b015461371e9082614951565b915081156137505761375084836006866002811061373e5761373e6149c2565b01546001600160a01b03169190614071565b505b508061375d816149f0565b9150506134bb565b6000806000613772613309565b9050600061378260016002614951565b61378d906004614968565b6002600a5461379c9190614968565b6137a69190614987565b604080518082019182905291925060009190600290819081845b8154815260200190600101908083116137c057505050505090506000600d60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561382f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061385391906149a9565b9050600061385f613a65565b9050600061386d8287613e8b565b905060008361387c838d614968565b6138869190614987565b6138909083614951565b90508260006138a1898d8486614095565b90506000878d600281106138b7576138b76149c2565b602002015182878f600281106138cf576138cf6149c2565b60200201516138de9190614951565b6138e89190614987565b905060005b60028110156139e45760008e82141561393f578387878a8560028110613915576139156149c2565b60200201516139249190614968565b61392e9190614987565b6139389190614951565b9050613990565b8686898460028110613953576139536149c2565b60200201516139629190614968565b61396c9190614987565b88836002811061397e5761397e6149c2565b602002015161398d9190614951565b90505b6402540be4006139a0828d614968565b6139aa9190614987565b8583600281106139bc576139bc6149c2565b602002018181516139cd9190614951565b9052508190506139dc816149f0565b9150506138ed565b5060006139f38b8f8688614095565b848f60028110613a0557613a056149c2565b6020020151613a149190614951565b9050888e60028110613a2857613a286149c2565b6020020151613a38600183614951565b613a429190614987565b905080613a4f8184614951565b9c509c5050505050505050505050509250929050565b613a6d614550565b60408051808201918290529060049060029082845b815481526020019060010190808311613a82575050505050905060005b6002811015613b1a57670de0b6b3a764000060088260028110613ac457613ac46149c2565b0154838360028110613ad857613ad86149c2565b6020020151613ae79190614968565b613af19190614987565b828260028110613b0357613b036149c2565b602002015280613b12816149f0565b915050613a9f565b5090565b6000838514158015613b305750600285105b8015613b3c5750600284105b613b7c5760405162461bcd60e51b815260206004820152601160248201527024b63632b3b0b6103830b930b6b2ba32b960791b60448201526064016109c6565b6000613b86613309565b90506000613b948483613e8b565b905080600080613ba5600286614968565b90506000805b6002811015613c2e578b811415613bc457899150613bee565b8a8114613be957888160028110613bdd57613bdd6149c2565b60200201519150613bee565b613c1c565b613bf882856149d8565b9350613c05600283614968565b613c0f8787614968565b613c199190614987565b94505b80613c26816149f0565b915050613bab565b50613c3a600283614968565b613c448686614968565b613c4e9190614987565b93506000613c5c8387614987565b613c6690856149d8565b9050600086815b60ff811015613d08578192508884836002613c889190614968565b613c9291906149d8565b613c9c9190614951565b88613ca78480614968565b613cb191906149d8565b613cbb9190614987565b915082821115613ce0576001613cd18484614951565b11613cdb57613d08565b613cf6565b6001613cec8385614951565b11613cf657613d08565b80613d00816149f0565b915050613c6d565b509d9c50505050505050505050505050565b6001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415613d49576134023382614250565b6134026001600160a01b0383163383614071565b613d65614550565b60408051808201918290529060049060029082845b815481526020019060010190808311613d7a575050505050905060005b6002811015613e1457670de0b6b3a7640000838260028110613dbb57613dbb6149c2565b6020020151838360028110613dd257613dd26149c2565b6020020151613de19190614968565b613deb9190614987565b828260028110613dfd57613dfd6149c2565b602002015280613e0c816149f0565b915050613d97565b50919050565b6040516001600160a01b0380851660248301528316604482015260648101829052613e859085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526142fd565b50505050565b60008060005b6002811015613ecf57848160028110613eac57613eac6149c2565b6020020151613ebb90836149d8565b915080613ec7816149f0565b915050613e91565b5080613edf5760009150506118a7565b60008181613eee600287614968565b905060005b60ff811015614015578260005b6002811015613f545760028a8260028110613f1d57613f1d6149c2565b6020020151613f2c9190614968565b613f368684614968565b613f409190614987565b915080613f4c816149f0565b915050613f00565b508394508060026001613f6791906149d8565b613f719190614968565b84613f7d600186614951565b613f879190614968565b613f9191906149d8565b84613f9d600284614968565b613fa78987614968565b613fb191906149d8565b613fbb9190614968565b613fc59190614987565b935084841115613feb576001613fdb8686614951565b11613fe65750614015565b614002565b6001613ff78587614951565b116140025750614015565b508061400d816149f0565b915050613ef3565b50909695505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6140908363a9059cbb60e01b8484604051602401613e4e929190614a39565b505050565b6000600284106140de5760405162461bcd60e51b81526020600482015260146024820152736465763a20692061626f7665204e5f434f494e5360601b60448201526064016109c6565b816000806140ed600289614968565b90506000805b60028110156141665788811461412157878160028110614115576141156149c2565b60200201519150614126565b614154565b61413082856149d8565b935061413d600283614968565b6141478887614968565b6141519190614987565b94505b8061415e816149f0565b9150506140f3565b50614172600283614968565b61417c8786614968565b6141869190614987565b935060006141948388614987565b61419e90856149d8565b9050600087815b60ff8110156142405781925089848360026141c09190614968565b6141ca91906149d8565b6141d49190614951565b886141df8480614968565b6141e991906149d8565b6141f39190614987565b9150828211156142185760016142098484614951565b1161421357614240565b61422e565b60016142248385614951565b1161422e57614240565b80614238816149f0565b9150506141a5565b509b9a5050505050505050505050565b600080836001600160a01b0316600c5484604051600060405180830381858888f193505050503d80600081146142a2576040519150601f19603f3d011682016040523d82523d6000602084013e6142a7565b606091505b509150915081613e855780516142f55760405162461bcd60e51b8152602060048201526013602482015272141314c81d1c985b9cd9995c8819985a5b1959606a1b60448201526064016109c6565b805181602001fd5b6000614352826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166143cf9092919063ffffffff16565b80519091501561409057808060200190518101906143709190614c89565b6140905760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109c6565b60606143de84846000856143e6565b949350505050565b6060824710156144475760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016109c6565b6001600160a01b0385163b61449e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109c6565b600080866001600160a01b031685876040516144ba9190614cd2565b60006040518083038185875af1925050503d80600081146144f7576040519150601f19603f3d011682016040523d82523d6000602084013e6144fc565b606091505b509150915061450c828286614517565b979650505050505050565b60608315614526575081611b9d565b8251156145365782518084602001fd5b8160405162461bcd60e51b81526004016109c69190614cee565b60405180604001604052806002906020820280368337509192915050565b826002810192821561459c579160200282015b8281111561459c578251825591602001919060010190614581565b50613b1a9291506145f0565b826002810192821561459c579160200282015b8281111561459c57825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906145bb565b5b80821115613b1a57600081556001016145f1565b6040805190810167ffffffffffffffff8111828210171561463657634e487b7160e01b600052604160045260246000fd5b60405290565b600082601f83011261464d57600080fd5b614655614605565b80604084018581111561466757600080fd5b845b81811015614681578035845260209384019301614669565b509095945050505050565b6000806060838503121561469f57600080fd5b6146a9848461463c565b946040939093013593505050565b600080604083850312156146ca57600080fd5b50508035926020909101359150565b6001600160a01b03811681146132f757600080fd5b8035612857816146d9565b60008060008060008060e0878903121561471257600080fd5b87601f88011261472157600080fd5b614729614605565b80604089018a81111561473b57600080fd5b895b8181101561475e578035614750816146d9565b84526020938401930161473d565b5090975035955050606087013593506080870135925061478060a088016146ee565b915061478e60c088016146ee565b90509295509295509295565b6000602082840312156147ac57600080fd5b5035919050565b6000806000606084860312156147c857600080fd5b505081359360208301359350604090920135919050565b600080606083850312156147f257600080fd5b82359150614803846020850161463c565b90509250929050565b6000806000806080858703121561482257600080fd5b5050823594602084013594506040840135936060013592509050565b6001600160a01b0391909116815260200190565b80151581146132f757600080fd5b6000806060838503121561487357600080fd5b61487d848461463c565b9150604083013561488d81614852565b809150509250929050565b6000602082840312156148aa57600080fd5b8135611b9d816146d9565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526006908201526512da5b1b195960d21b604082015260600190565b602080825260159082015274496e636f6e73697374656e74207175616e7469747960581b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000828210156149635761496361493b565b500390565b60008160001904831182151516156149825761498261493b565b500290565b6000826149a457634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156149bb57600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b600082198211156149eb576149eb61493b565b500190565b6000600019821415614a0457614a0461493b565b5060010190565b602080825260149082015273536c697070616765207363726577656420796f7560601b604082015260600190565b6001600160a01b03929092168252602082015260400190565b8060005b6002811015613e85578151845260209384019390910190600101614a56565b60c08101614a838287614a52565b614a906040830186614a52565b608082019390935260a0015292915050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601690820152756465763a20696e73756666696369656e742074696d6560501b604082015260600190565b600060208284031215614b1957600080fd5b815160ff81168114611b9d57600080fd5b600181815b80851115614b65578160001904821115614b4b57614b4b61493b565b80851615614b5857918102915b93841c9390800290614b2f565b509250929050565b600082614b7c575060016118a7565b81614b89575060006118a7565b8160018114614b9f5760028114614ba957614bc5565b60019150506118a7565b60ff841115614bba57614bba61493b565b50506001821b6118a7565b5060208310610133831016604e8410600b8410161715614be8575081810a6118a7565b614bf28383614b2a565b8060001904821115614c0657614c0661493b565b029392505050565b6000611b9d8383614b6d565b6020808252600f908201526e42616c616e6365206973207a65726f60881b604082015260600190565b60a08101614c518286614a52565b614c5e6040830185614a52565b826080830152949350505050565b600060208284031215614c7e57600080fd5b8151611b9d816146d9565b600060208284031215614c9b57600080fd5b8151611b9d81614852565b60005b83811015614cc1578181015183820152602001614ca9565b83811115613e855750506000910152565b60008251614ce4818460208701614ca6565b9190910192915050565b6020815260008251806020840152614d0d816040850160208701614ca6565b601f01601f1916919091016040019291505056fea26469706673582212206a8cedd5a3ddb983489f6470c0ea7676e0458d221bc62f1bf8f03581ffeca56464736f6c634300080a0033a264697066735822122074b45d0324d7e491ca87b61d105e5c19965bbe1d764d78890e92d4d33e9c699664736f6c634300080a0033