Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 4,746 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Approve | 27526796 | 22 days ago | IN | 0 ETH | 0.00000001 | ||||
| Approve | 27526791 | 22 days ago | IN | 0 ETH | 0.00000001 | ||||
| Approve | 26442381 | 43 days ago | IN | 0 ETH | 0.00000018 | ||||
| Approve | 26442373 | 43 days ago | IN | 0 ETH | 0.00000018 | ||||
| Approve | 25702887 | 55 days ago | IN | 0 ETH | 0.00000014 | ||||
| Approve | 24803688 | 72 days ago | IN | 0 ETH | 0.00000045 | ||||
| Approve | 24546976 | 77 days ago | IN | 0 ETH | 0.00000022 | ||||
| Approve | 24546967 | 77 days ago | IN | 0 ETH | 0.00000022 | ||||
| Approve | 24427612 | 79 days ago | IN | 0 ETH | 0.00000049 | ||||
| Approve | 24037884 | 86 days ago | IN | 0 ETH | 0.00000001 | ||||
| Approve | 24037875 | 86 days ago | IN | 0 ETH | 0.00000001 | ||||
| Approve | 22754902 | 109 days ago | IN | 0 ETH | 0.00000049 | ||||
| Approve | 22754898 | 109 days ago | IN | 0 ETH | 0.00000049 | ||||
| Approve | 22150475 | 118 days ago | IN | 0 ETH | 0.00000048 | ||||
| Approve | 22144379 | 118 days ago | IN | 0 ETH | 0.00000024 | ||||
| Approve | 22140202 | 118 days ago | IN | 0 ETH | 0.00000048 | ||||
| Approve | 22140198 | 118 days ago | IN | 0 ETH | 0.00000048 | ||||
| Approve | 22121861 | 118 days ago | IN | 0 ETH | 0.00000048 | ||||
| Approve | 22008395 | 120 days ago | IN | 0 ETH | 0.00000049 | ||||
| Approve | 22008390 | 120 days ago | IN | 0 ETH | 0.00000049 | ||||
| Approve | 21983891 | 120 days ago | IN | 0 ETH | 0.00000048 | ||||
| Approve | 21778313 | 123 days ago | IN | 0 ETH | 0.00000048 | ||||
| Approve | 21778136 | 123 days ago | IN | 0 ETH | 0.00000048 | ||||
| Approve | 21636685 | 126 days ago | IN | 0 ETH | 0.00000048 | ||||
| Approve | 21558564 | 127 days ago | IN | 0 ETH | 0.00000049 |
Latest 2 internal transactions
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 5307277 | 632 days ago | Contract Creation | 0 ETH | |||
| 5307277 | 632 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Pair
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "contracts/interfaces/IPair.sol";
import "contracts/interfaces/IPairCallee.sol";
import "./factories/PairFactory.sol";
import "contracts/PairFees.sol";
// The base pair of pools, either stable or volatile
contract Pair is IPair {
string public name;
string public symbol;
uint8 public constant decimals = 18;
bool public stable;
uint256 public totalSupply;
mapping(address => mapping(address => uint256)) public allowance;
mapping(address => uint256) public balanceOf;
bytes32 internal DOMAIN_SEPARATOR;
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 internal constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
mapping(address => uint256) public nonces;
uint256 internal constant MINIMUM_LIQUIDITY = 10 ** 3;
address public token0;
address public token1;
address public fees;
uint256 public pairFee;
address factory;
// Structure to capture time period obervations every 30 minutes, used for local oracles
struct Observation {
uint256 timestamp;
uint256 reserve0Cumulative;
uint256 reserve1Cumulative;
}
// Capture oracle reading every 30 minutes
uint256 constant periodSize = 1800;
Observation[] public observations;
uint256 internal decimals0;
uint256 internal decimals1;
uint256 public reserve0;
uint256 public reserve1;
uint256 public blockTimestampLast;
uint256 public reserve0CumulativeLast;
uint256 public reserve1CumulativeLast;
// index0 and index1 are used to accumulate fees, this is split out from normal trades to keep the swap "clean"
// this further allows LP holders to easily claim fees for tokens they have/staked
uint256 public index0;
uint256 public index1;
// position assigned to each LP to track their current index0 & index1 vs the global position
mapping(address => uint256) public supplyIndex0;
mapping(address => uint256) public supplyIndex1;
// tracks the amount of unclaimed, but claimable tokens off of fees for token0 and token1
mapping(address => uint256) public claimable0;
mapping(address => uint256) public claimable1;
event Fees(address indexed sender, uint256 amount0, uint256 amount1);
event Mint(address indexed sender, uint256 amount0, uint256 amount1);
event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
event Swap(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to);
event Sync(uint256 reserve0, uint256 reserve1);
event Claim(address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1);
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
constructor() {
factory = msg.sender;
(address _token0, address _token1, bool _stable, uint256 _fee) = PairFactory(msg.sender).getInitializable();
pairFee = _fee;
(token0, token1, stable) = (_token0, _token1, _stable);
fees = address(new PairFees(_token0, _token1));
if (_stable) {
name = string(abi.encodePacked("StableV1 AMM - ", IERC20Metadata(_token0).symbol(), "/", IERC20Metadata(_token1).symbol()));
symbol = string(abi.encodePacked("sAMM-", IERC20Metadata(_token0).symbol(), "/", IERC20Metadata(_token1).symbol()));
} else {
name = string(abi.encodePacked("VolatileV1 AMM - ", IERC20Metadata(_token0).symbol(), "/", IERC20Metadata(_token1).symbol()));
symbol = string(abi.encodePacked("vAMM-", IERC20Metadata(_token0).symbol(), "/", IERC20Metadata(_token1).symbol()));
}
decimals0 = 10 ** IERC20Metadata(_token0).decimals();
decimals1 = 10 ** IERC20Metadata(_token1).decimals();
observations.push(Observation(block.timestamp, 0, 0));
_unlocked = 1;
}
// simple re-entrancy check
uint256 internal _unlocked;
modifier lock() {
require(_unlocked == 1);
_unlocked = 2;
_;
_unlocked = 1;
}
function observationLength() external view returns (uint256) {
return observations.length;
}
function lastObservation() public view returns (Observation memory) {
return observations[observations.length - 1];
}
function metadata() external view returns (uint256 dec0, uint256 dec1, uint256 r0, uint256 r1, bool st, address t0, address t1) {
return (decimals0, decimals1, reserve0, reserve1, stable, token0, token1);
}
function tokens() external view returns (address, address) {
return (token0, token1);
}
// claim accumulated but unclaimed fees (viewable via claimable0 and claimable1)
function claimFees() external returns (uint256 claimed0, uint256 claimed1) {
_updateFor(msg.sender);
claimed0 = claimable0[msg.sender];
claimed1 = claimable1[msg.sender];
if (claimed0 != 0 || claimed1 != 0) {
claimable0[msg.sender] = 0;
claimable1[msg.sender] = 0;
PairFees(fees).claimFeesFor(msg.sender, claimed0, claimed1);
emit Claim(msg.sender, msg.sender, claimed0, claimed1);
}
}
function updateFee (uint256 _newFee) external {
require(msg.sender == factory);
pairFee = _newFee;
}
// Accrue fees on token0 and token1
function _updateFees(uint256 amount0, uint256 amount1) internal {
if (amount0 != 0) {
_safeTransfer(token0, fees, amount0); // transfer the fees out to PairFees
uint256 _ratio = (amount0 * 1e18) / totalSupply; // 1e18 adjustment is removed during claim
if (_ratio != 0) {
index0 += _ratio;
}
}
if (amount1 != 0) {
_safeTransfer(token1, fees, amount1); // transfer the fees out to PairFees
uint256 _ratio = (amount1 * 1e18) / totalSupply; // 1e18 adjustment is removed during claim
if (_ratio != 0) {
index1 += _ratio;
}
}
if (amount0 != 0 || amount1 != 0) {
PairFees(fees).notifyFeeAmounts(amount0, amount1);
emit Fees(msg.sender, amount0, amount1);
}
}
// this function MUST be called on any balance changes, otherwise can be used to infinitely claim fees
// Fees are segregated from core funds, so fees can never put liquidity at risk
function _updateFor(address recipient) internal {
uint256 _supplied = balanceOf[recipient]; // get LP balance of `recipient`
if (_supplied != 0) {
uint256 _supplyIndex0 = supplyIndex0[recipient]; // get last adjusted index0 for recipient
uint256 _supplyIndex1 = supplyIndex1[recipient];
uint256 _index0 = index0; // get global index0 for accumulated fees
uint256 _index1 = index1;
supplyIndex0[recipient] = _index0; // update user current position to global position
supplyIndex1[recipient] = _index1;
uint256 _delta0 = _index0 - _supplyIndex0; // see if there is any difference that need to be accrued
uint256 _delta1 = _index1 - _supplyIndex1;
if (_delta0 != 0) {
uint256 _share = (_supplied * _delta0) / 1e18; // add accrued difference for each supplied token
claimable0[recipient] += _share;
}
if (_delta1 != 0) {
uint256 _share = (_supplied * _delta1) / 1e18;
claimable1[recipient] += _share;
}
} else {
supplyIndex0[recipient] = index0; // new users are set to the default global state
supplyIndex1[recipient] = index1;
}
}
function getReserves() public view returns (uint256 _reserve0, uint256 _reserve1, uint256 _blockTimestampLast) {
_reserve0 = reserve0;
_reserve1 = reserve1;
_blockTimestampLast = blockTimestampLast;
}
// update reserves and, on the first call per block, price accumulators
function _update(uint256 balance0, uint256 balance1, uint256 _reserve0, uint256 _reserve1) internal {
uint256 blockTimestamp = block.timestamp;
uint256 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired
if (timeElapsed != 0 && _reserve0 != 0 && _reserve1 != 0) {
reserve0CumulativeLast += _reserve0 * timeElapsed;
reserve1CumulativeLast += _reserve1 * timeElapsed;
}
Observation memory _point = lastObservation();
timeElapsed = blockTimestamp - _point.timestamp; // compare the last observation with current timestamp, if greater than 30 minutes, record a new event
if (timeElapsed > periodSize) {
observations.push(Observation(blockTimestamp, reserve0CumulativeLast, reserve1CumulativeLast));
}
reserve0 = balance0;
reserve1 = balance1;
blockTimestampLast = blockTimestamp;
emit Sync(reserve0, reserve1);
}
// produces the cumulative price using counterfactuals to save gas and avoid a call to sync.
function currentCumulativePrices()
public
view
returns (uint256 reserve0Cumulative, uint256 reserve1Cumulative, uint256 blockTimestamp)
{
blockTimestamp = block.timestamp;
reserve0Cumulative = reserve0CumulativeLast;
reserve1Cumulative = reserve1CumulativeLast;
// if time has elapsed since the last update on the pair, mock the accumulated price values
(uint256 _reserve0, uint256 _reserve1, uint256 _blockTimestampLast) = getReserves();
if (_blockTimestampLast != blockTimestamp) {
// subtraction overflow is desired
uint256 timeElapsed = blockTimestamp - _blockTimestampLast;
reserve0Cumulative += _reserve0 * timeElapsed;
reserve1Cumulative += _reserve1 * timeElapsed;
}
}
// gives the current twap price measured from amountIn * tokenIn gives amountOut
function current(address tokenIn, uint256 amountIn) external view returns (uint256 amountOut) {
Observation memory _observation = lastObservation();
(uint256 reserve0Cumulative, uint256 reserve1Cumulative, ) = currentCumulativePrices();
if (block.timestamp == _observation.timestamp) {
_observation = observations[observations.length - 2];
}
uint256 timeElapsed = block.timestamp - _observation.timestamp;
uint256 _reserve0 = (reserve0Cumulative - _observation.reserve0Cumulative) / timeElapsed;
uint256 _reserve1 = (reserve1Cumulative - _observation.reserve1Cumulative) / timeElapsed;
amountOut = _getAmountOut(amountIn, tokenIn, _reserve0, _reserve1);
}
// as per `current`, however allows user configured granularity, up to the full window size
function quote(address tokenIn, uint256 amountIn, uint256 granularity) external view returns (uint256 amountOut) {
uint256[] memory _prices = sample(tokenIn, amountIn, granularity, 1);
uint256 priceAverageCumulative;
for (uint256 i = _prices.length; i != 0; ) {
unchecked {
--i;
}
priceAverageCumulative += _prices[i];
}
return priceAverageCumulative / granularity;
}
// returns a memory set of twap prices
function prices(address tokenIn, uint256 amountIn, uint256 points) external view returns (uint256[] memory) {
return sample(tokenIn, amountIn, points, 1);
}
function sample(address tokenIn, uint256 amountIn, uint256 points, uint256 window) public view returns (uint256[] memory) {
uint256[] memory _prices = new uint256[](points);
uint256 length = observations.length - 1;
uint256 nextIndex;
uint256 index = 0;
for (uint256 i = length - (points * window); i < length; ) {
unchecked {
nextIndex = i + window;
}
uint256 timeElapsed = observations[nextIndex].timestamp - observations[i].timestamp;
uint256 _reserve0 = (observations[nextIndex].reserve0Cumulative - observations[i].reserve0Cumulative) / timeElapsed;
uint256 _reserve1 = (observations[nextIndex].reserve1Cumulative - observations[i].reserve1Cumulative) / timeElapsed;
_prices[index] = _getAmountOut(amountIn, tokenIn, _reserve0, _reserve1);
// index < length; length cannot overflow
unchecked {
++index;
}
i = nextIndex;
}
return _prices;
}
// this low-level function should be called by addLiquidity functions in Router.sol, which performs important safety checks
// standard uniswap v2 implementation
function mint(address to) external lock returns (uint256 liquidity) {
(uint256 _reserve0, uint256 _reserve1) = (reserve0, reserve1);
uint256 _balance0 = IERC20(token0).balanceOf(address(this));
uint256 _balance1 = IERC20(token1).balanceOf(address(this));
uint256 _amount0 = _balance0 - _reserve0;
uint256 _amount1 = _balance1 - _reserve1;
uint256 _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
if (_totalSupply == 0) {
liquidity = Math.sqrt(_amount0 * _amount1) - MINIMUM_LIQUIDITY;
_mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
} else {
liquidity = Math.min((_amount0 * _totalSupply) / _reserve0, (_amount1 * _totalSupply) / _reserve1);
}
require(liquidity != 0, "ILM"); // Pair: INSUFFICIENT_LIQUIDITY_MINTED
_mint(to, liquidity);
_update(_balance0, _balance1, _reserve0, _reserve1);
emit Mint(msg.sender, _amount0, _amount1);
}
// this low-level function should be called from a contract which performs important safety checks
// standard uniswap v2 implementation
function burn(address to) external lock returns (uint256 amount0, uint256 amount1) {
(uint256 _reserve0, uint256 _reserve1) = (reserve0, reserve1);
(address _token0, address _token1) = (token0, token1);
uint256 _balance0 = IERC20(_token0).balanceOf(address(this));
uint256 _balance1 = IERC20(_token1).balanceOf(address(this));
uint256 _liquidity = balanceOf[address(this)];
uint256 _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
amount0 = (_liquidity * _balance0) / _totalSupply; // using balances ensures pro-rata distribution
amount1 = (_liquidity * _balance1) / _totalSupply; // using balances ensures pro-rata distribution
require(amount0 != 0 && amount1 != 0, "ILB"); // Pair: INSUFFICIENT_LIQUIDITY_BURNED
_burn(address(this), _liquidity);
_safeTransfer(_token0, to, amount0);
_safeTransfer(_token1, to, amount1);
_balance0 = IERC20(_token0).balanceOf(address(this));
_balance1 = IERC20(_token1).balanceOf(address(this));
_update(_balance0, _balance1, _reserve0, _reserve1);
emit Burn(msg.sender, amount0, amount1, to);
}
// this low-level function should be called from a contract which performs important safety checks
function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external lock {
require(!Pausable(factory).paused());
require(amount0Out != 0 || amount1Out != 0, "IOA"); // Pair: INSUFFICIENT_OUTPUT_AMOUNT
(uint256 _reserve0, uint256 _reserve1) = (reserve0, reserve1);
require(amount0Out < _reserve0 && amount1Out < _reserve1, "IL"); // Pair: INSUFFICIENT_LIQUIDITY
uint256 _balance0;
uint256 _balance1;
{
// scope for _token{0,1}, avoids stack too deep errors
(address _token0, address _token1) = (token0, token1);
require(to != _token0 && to != _token1, "IT"); // Pair: INVALID_TO
if (amount0Out != 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
if (amount1Out != 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
if (data.length != 0) IPairCallee(to).hook(msg.sender, amount0Out, amount1Out, data); // callback, used for flash loans
_balance0 = IERC20(_token0).balanceOf(address(this));
_balance1 = IERC20(_token1).balanceOf(address(this));
}
uint256 amount0In = _balance0 > _reserve0 - amount0Out ? _balance0 - (_reserve0 - amount0Out) : 0;
uint256 amount1In = _balance1 > _reserve1 - amount1Out ? _balance1 - (_reserve1 - amount1Out) : 0;
require(amount0In != 0 || amount1In != 0, "IIA"); // Pair: INSUFFICIENT_INPUT_AMOUNT
{
// scope for reserve{0,1}Adjusted, avoids stack too deep errors
(address _token0, address _token1) = (token0, token1);
_updateFees(
IPairFactory(factory).getFeeAmount(amount0In, msg.sender, pairFee),
IPairFactory(factory).getFeeAmount(amount1In, msg.sender, pairFee)
); // accrue fees for token0 and token1 and move them out of pool
_balance0 = IERC20(_token0).balanceOf(address(this)); // since we removed tokens, we need to reconfirm balances, can also simply use previous balance - amountIn/ 10000, but doing balanceOf again as safety check
_balance1 = IERC20(_token1).balanceOf(address(this));
// The curve, either x3y+y3x for stable pools, or x*y for volatile pools
require(_k(_balance0, _balance1) >= _k(_reserve0, _reserve1), "K"); // Pair: K
}
_update(_balance0, _balance1, _reserve0, _reserve1);
emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
}
// force reserves to match balances
function sync() external lock {
_update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1);
}
function _f(uint256 x0, uint256 y) internal pure returns (uint256) {
return (x0 * ((((y * y) / 1e18) * y) / 1e18)) / 1e18 + (((((x0 * x0) / 1e18) * x0) / 1e18) * y) / 1e18;
}
function _d(uint256 x0, uint256 y) internal pure returns (uint256) {
return (3 * x0 * ((y * y) / 1e18)) / 1e18 + ((((x0 * x0) / 1e18) * x0) / 1e18);
}
function _get_y(uint256 x0, uint256 xy, uint256 y) internal pure returns (uint256) {
for (uint256 i = 255; i != 0; ) {
uint256 y_prev = y;
uint256 k = _f(x0, y);
if (k < xy) {
uint256 dy = ((xy - k) * 1e18) / _d(x0, y);
y = y + dy;
} else {
uint256 dy = ((k - xy) * 1e18) / _d(x0, y);
y = y - dy;
}
if (y > y_prev) {
if (y - y_prev <= 1) {
return y;
}
} else {
if (y_prev - y <= 1) {
return y;
}
}
unchecked {
--i;
}
}
return y;
}
function getAmountOut(uint256 amountIn, address tokenIn) external view returns (uint256) {
(uint256 _reserve0, uint256 _reserve1) = (reserve0, reserve1);
amountIn -= IPairFactory(factory).getFeeAmount(amountIn, msg.sender, pairFee); // remove fee from amount received
return _getAmountOut(amountIn, tokenIn, _reserve0, _reserve1);
}
function _getAmountOut(uint256 amountIn, address tokenIn, uint256 _reserve0, uint256 _reserve1) internal view returns (uint256) {
if (stable) {
uint256 xy = _k(_reserve0, _reserve1);
_reserve0 = (_reserve0 * 1e18) / decimals0;
_reserve1 = (_reserve1 * 1e18) / decimals1;
(uint256 reserveA, uint256 reserveB) = tokenIn == token0 ? (_reserve0, _reserve1) : (_reserve1, _reserve0);
amountIn = tokenIn == token0 ? (amountIn * 1e18) / decimals0 : (amountIn * 1e18) / decimals1;
uint256 y = reserveB - _get_y(amountIn + reserveA, xy, reserveB);
return (y * (tokenIn == token0 ? decimals1 : decimals0)) / 1e18;
} else {
(uint256 reserveA, uint256 reserveB) = tokenIn == token0 ? (_reserve0, _reserve1) : (_reserve1, _reserve0);
return (amountIn * reserveB) / (reserveA + amountIn);
}
}
function _k(uint256 x, uint256 y) internal view returns (uint256) {
if (stable) {
uint256 _x = (x * 1e18) / decimals0;
uint256 _y = (y * 1e18) / decimals1;
uint256 _a = (_x * _y) / 1e18;
uint256 _b = ((_x * _x) / 1e18 + (_y * _y) / 1e18);
return (_a * _b) / 1e18; // x3y+y3x >= k
} else {
return x * y; // xy >= k
}
}
function _mint(address dst, uint256 amount) internal {
_updateFor(dst); // balances must be updated on mint/burn/transfer
totalSupply += amount;
balanceOf[dst] += amount;
emit Transfer(address(0), dst, amount);
}
function _burn(address dst, uint256 amount) internal {
_updateFor(dst);
totalSupply -= amount;
balanceOf[dst] -= amount;
emit Transfer(dst, address(0), amount);
}
function approve(address spender, uint256 amount) external returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external {
require(deadline >= block.timestamp, "Pair: EXPIRED");
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256(bytes("1")),
block.chainid,
address(this)
)
);
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, "Pair: INVALID_SIGNATURE");
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
function transfer(address dst, uint256 amount) external returns (bool) {
_transferTokens(msg.sender, dst, amount);
return true;
}
function transferFrom(address src, address dst, uint256 amount) external returns (bool) {
address spender = msg.sender;
uint256 spenderAllowance = allowance[src][spender];
if (spender != src && spenderAllowance != type(uint256).max) {
uint256 newAllowance = spenderAllowance - amount;
allowance[src][spender] = newAllowance;
emit Approval(src, spender, newAllowance);
}
_transferTokens(src, dst, amount);
return true;
}
function _transferTokens(address src, address dst, uint256 amount) internal {
_updateFor(src); // update fee position for src
_updateFor(dst); // update fee position for dst
balanceOf[src] -= amount;
balanceOf[dst] += amount;
emit Transfer(src, dst, amount);
}
function _safeTransfer(address token, address to, uint256 value) internal {
if (value != 0) {
require(token.code.length != 0);
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))));
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
// 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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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);
/**
* @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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "../interfaces/IPairFactory.sol";
import "../Pair.sol";
contract PairFactory is IPairFactory, Pausable {
using Math for uint256;
bool internal initFlag;
uint256 public constant FEE_PRECISION = 1e18;
uint256 public constant MAX_FEE = 5e16; // 5%
uint256 public stableFee;
uint256 public volatileFee;
address public feeManager;
address public pendingFeeManager;
address public pairManager;
address public emergencyCouncil;
address public pendingEmergencyCouncil;
mapping(address => mapping(address => mapping(bool => address)))
public getPair;
mapping(address => bool) public isPair; // simplified check if its a pair, given that `stable` flag might not be available in peripherals
mapping(address => bool) private _privileged;
address internal _temp0;
address internal _temp1;
bool internal _temp;
uint256 internal _tempFee;
address[] public allPairs;
event PairCreated(
address indexed token0,
address indexed token1,
bool stable,
address pair,
uint256
);
event PrivilegedAccountStatusUpdated(address indexed account, bool _added);
modifier onlyFeeManager() {
require(msg.sender == feeManager);
_;
}
modifier onlyPairManager() {
require(msg.sender == pairManager || pairManager == address(0));
_;
}
modifier onlyEmergencyCouncil() {
require(
msg.sender == emergencyCouncil || emergencyCouncil == address(0)
);
_;
}
constructor() {
feeManager = msg.sender;
pairManager = msg.sender;
emergencyCouncil = msg.sender;
stableFee = 0.04e16; // 0.04%
volatileFee = 0.18e16; // 0.18%
initFlag = false;
}
function init(
address _fee_manager,
address _pair_manager,
address _emergency_council
) external {
require(
msg.sender == emergencyCouncil ||
msg.sender == pairManager ||
pairManager == address(0)
);
require(!initFlag, "Cant call again");
feeManager = _fee_manager;
pairManager = _pair_manager;
emergencyCouncil = _emergency_council;
initFlag = true;
}
function pause() external whenNotPaused onlyEmergencyCouncil {
_pause();
}
function unpause() external whenPaused onlyEmergencyCouncil {
_unpause();
}
function isPrivileged(address _account) external view returns (bool) {
return _privileged[_account];
}
function allPairsLength() external view returns (uint256) {
return allPairs.length;
}
function pairs() external view returns (address[] memory) {
return allPairs;
}
function setFeeManager(address _feeManager) external onlyFeeManager {
pendingFeeManager = _feeManager;
}
function setPairManager(
address _pairManager
) external onlyEmergencyCouncil {
pairManager = _pairManager;
}
function acceptFeeManager() external {
require(msg.sender == pendingFeeManager);
feeManager = pendingFeeManager;
}
function setEmergencyCouncil(
address _emergencyCouncil
) external onlyEmergencyCouncil {
pendingEmergencyCouncil = _emergencyCouncil;
}
function acceptEmergencyCouncil() external {
require(msg.sender == pendingEmergencyCouncil);
emergencyCouncil = pendingEmergencyCouncil;
}
function setFeeForPair(address _pair, uint256 _fee) external onlyFeeManager {
require(_fee <= MAX_FEE, "MF");
require(_fee != 0);
Pair(_pair).updateFee(_fee);
}
function setFee(bool _stable, uint256 _fee) external onlyFeeManager {
require(_fee <= MAX_FEE, "MF");
require(_fee != 0);
if (_stable) {
stableFee = _fee;
} else {
volatileFee = _fee;
}
}
function updatePrivilegedAccount(
address _account,
bool _addToPrivileged
) external onlyFeeManager {
require(_privileged[_account] != _addToPrivileged);
_privileged[_account] = _addToPrivileged;
emit PrivilegedAccountStatusUpdated(_account, _addToPrivileged);
}
function getDefaultFee(bool _stable) public view returns (uint256) {
return _stable ? stableFee : volatileFee;
}
function getFee(address _pair) public view returns (uint256) {
return Pair(_pair).pairFee();
}
function getFeeAmount(
uint256 _amount,
address _account,
uint256 _fee
) external view returns (uint256) {
if (_privileged[_account]) return 0;
return (_fee).mulDiv(_amount, FEE_PRECISION);
}
function pairCodeHash() external pure returns (bytes32) {
return keccak256(type(Pair).creationCode);
}
function getInitializable() external view returns (address, address, bool, uint256) {
return (_temp0, _temp1, _temp, _tempFee);
}
function createPair(
address tokenA,
address tokenB,
bool stable
) external onlyPairManager returns (address pair) {
require(tokenA != tokenB, "IA"); // Pair: IDENTICAL_ADDRESSES
(address token0, address token1) = tokenA < tokenB
? (tokenA, tokenB)
: (tokenB, tokenA);
require(token0 != address(0), "ZA"); // Pair: ZERO_ADDRESS
require(getPair[token0][token1][stable] == address(0), "PE"); // Pair: PAIR_EXISTS - single check is sufficient
bytes32 salt = keccak256(abi.encodePacked(token0, token1, stable)); // notice salt includes stable as well, 3 parameters
(_temp0, _temp1, _temp, _tempFee) = (token0, token1, stable, getDefaultFee(stable));
pair = address(new Pair{salt: salt}());
getPair[token0][token1][stable] = pair;
getPair[token1][token0][stable] = pair; // populate mapping in the reverse direction
allPairs.push(pair);
isPair[pair] = true;
emit PairCreated(token0, token1, stable, pair, allPairs.length);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IPair {
function metadata() external view returns (uint256 dec0, uint256 dec1, uint256 r0, uint256 r1, bool st, address t0, address t1);
function claimFees() external returns (uint256, uint256);
function tokens() external view returns (address, address);
function token0() external view returns (address);
function token1() external view returns (address);
function transferFrom(address src, address dst, uint256 amount) external returns (bool);
function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;
function burn(address to) external returns (uint256 amount0, uint256 amount1);
function mint(address to) external returns (uint256 liquidity);
function getReserves() external view returns (uint256 _reserve0, uint256 _reserve1, uint256 _blockTimestampLast);
function getAmountOut(uint256, address) external view returns (uint256);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function totalSupply() external view returns (uint256);
function decimals() external view returns (uint8);
function claimable0(address _user) external view returns (uint256);
function claimable1(address _user) external view returns (uint256);
function stable() external view returns (bool);
function pairFee() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IPairCallee {
function hook(address sender, uint256 amount0, uint256 amount1, bytes calldata data) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IPairFactory {
function allPairsLength() external view returns (uint256);
function isPair(address pair) external view returns (bool);
function allPairs(uint256 index) external view returns (address);
function getPair(address tokenA, address token, bool stable) external view returns (address);
function createPair(address tokenA, address tokenB, bool stable) external returns (address pair);
function getFeeAmount(uint256 _amount, address _account, uint256 _fee) external view returns (uint256);
function stableFee() external view returns (uint256);
function volatileFee() external view returns (uint256);
function isPrivileged(address _account) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
// Pair Fees contract is used as a 1:1 pair relationship to split out fees, this ensures that the curve does not need to be modified for LP shares
contract PairFees {
address internal immutable pair; // The pair it is bonded to
address internal immutable token0; // token0 of pair, saved localy and statically for gas optimization
address internal immutable token1; // Token1 of pair, saved localy and statically for gas optimization
uint256 private _reserve0;
uint256 private _reserve1;
constructor(address _token0, address _token1) {
pair = msg.sender;
token0 = _token0;
token1 = _token1;
}
function _safeTransfer(address token, address to, uint256 value) internal {
if (value != 0) {
require(token.code.length != 0);
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))));
}
}
// Allow the pair to transfer fees to users
function claimFeesFor(address recipient, uint256 amount0, uint256 amount1) external {
require(msg.sender == pair);
if (amount0 != 0) {
uint256 reserve0 = _reserve0;
if (reserve0 >= amount0) {
unchecked {
_reserve0 = reserve0 - amount0;
_safeTransfer(token0, recipient, amount0);
}
}
}
if (amount1 != 0) {
uint256 reserve1 = _reserve1;
if (reserve1 >= amount1) {
unchecked {
_reserve1 = reserve1 - amount1;
_safeTransfer(token1, recipient, amount1);
}
}
}
}
function notifyFeeAmounts(uint256 amount0, uint256 amount1) external {
require(msg.sender == pair);
if (amount0 != 0) _reserve0 = _reserve0 + amount0;
if (amount1 != 0) _reserve1 = _reserve1 + amount1;
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "shanghai",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Fees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount0Out","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1Out","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reserve0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reserve1","type":"uint256"}],"name":"Sync","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blockTimestampLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"burn","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimFees","outputs":[{"internalType":"uint256","name":"claimed0","type":"uint256"},{"internalType":"uint256","name":"claimed1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimable0","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimable1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"current","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentCumulativePrices","outputs":[{"internalType":"uint256","name":"reserve0Cumulative","type":"uint256"},{"internalType":"uint256","name":"reserve1Cumulative","type":"uint256"},{"internalType":"uint256","name":"blockTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fees","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint256","name":"_reserve0","type":"uint256"},{"internalType":"uint256","name":"_reserve1","type":"uint256"},{"internalType":"uint256","name":"_blockTimestampLast","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"index0","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"index1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastObservation","outputs":[{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"reserve0Cumulative","type":"uint256"},{"internalType":"uint256","name":"reserve1Cumulative","type":"uint256"}],"internalType":"struct Pair.Observation","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadata","outputs":[{"internalType":"uint256","name":"dec0","type":"uint256"},{"internalType":"uint256","name":"dec1","type":"uint256"},{"internalType":"uint256","name":"r0","type":"uint256"},{"internalType":"uint256","name":"r1","type":"uint256"},{"internalType":"bool","name":"st","type":"bool"},{"internalType":"address","name":"t0","type":"address"},{"internalType":"address","name":"t1","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"observationLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"observations","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"reserve0Cumulative","type":"uint256"},{"internalType":"uint256","name":"reserve1Cumulative","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pairFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"points","type":"uint256"}],"name":"prices","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"granularity","type":"uint256"}],"name":"quote","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reserve0","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reserve0CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reserve1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reserve1CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"points","type":"uint256"},{"internalType":"uint256","name":"window","type":"uint256"}],"name":"sample","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"supplyIndex0","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"supplyIndex1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount0Out","type":"uint256"},{"internalType":"uint256","name":"amount1Out","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sync","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokens","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newFee","type":"uint256"}],"name":"updateFee","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801562000010575f80fd5b50600c80546001600160a01b031916339081179091556040805163eb13c4cf60e01b815290515f928392839283929163eb13c4cf9160048083019260809291908290030181865afa15801562000068573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200008e919062000708565b600b8190556002805483151560ff19909116179055600980546001600160a01b038086166001600160a01b03199283161790925560088054928716929091169190911790556040519397509195509350915084908490620000ef90620006de565b6001600160a01b03928316815291166020820152604001604051809103905ff08015801562000120573d5f803e3d5ffd5b50600a80546001600160a01b0319166001600160a01b039290921691909117905581156200034757836001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa15801562000184573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052620001ad919081019062000794565b836001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa158015620001e9573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405262000212919081019062000794565b6040516020016200022592919062000847565b6040516020818303038152906040525f90816200024391906200092b565b50836001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa15801562000280573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052620002a9919081019062000794565b836001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa158015620002e5573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526200030e919081019062000794565b60405160200162000321929190620009f7565b604051602081830303815290604052600190816200034091906200092b565b5062000541565b836001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa15801562000383573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052620003ac919081019062000794565b836001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa158015620003e8573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405262000411919081019062000794565b6040516020016200042492919062000a47565b6040516020818303038152906040525f90816200044291906200092b565b50836001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa1580156200047f573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052620004a8919081019062000794565b836001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa158015620004e4573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526200050d919081019062000794565b6040516020016200052092919062000aa3565b604051602081830303815290604052600190816200053f91906200092b565b505b836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200057e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620005a4919062000ac4565b620005b190600a62000bfc565b600e81905550826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620005f4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200061a919062000ac4565b6200062790600a62000bfc565b600f555050604080516060810182524281525f60208201818152928201818152600d8054600180820183559190935292517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb560039093029283015592517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb682015591517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb790920191909155601b555062000c0c9050565b61043e8062003c2a83390190565b80516001600160a01b038116811462000703575f80fd5b919050565b5f805f80608085870312156200071c575f80fd5b6200072785620006ec565b93506200073760208601620006ec565b9250604085015180151581146200074c575f80fd5b6060959095015193969295505050565b634e487b7160e01b5f52604160045260245ffd5b5f5b838110156200078c57818101518382015260200162000772565b50505f910152565b5f60208284031215620007a5575f80fd5b81516001600160401b0380821115620007bc575f80fd5b818401915084601f830112620007d0575f80fd5b815181811115620007e557620007e56200075c565b604051601f8201601f19908116603f011681019083821181831017156200081057620008106200075c565b8160405282815287602084870101111562000829575f80fd5b6200083c83602083016020880162000770565b979650505050505050565b6e029ba30b13632ab189020a6a690169608d1b81525f83516200087281600f85016020880162000770565b602f60f81b600f9184019182015283516200089581601084016020880162000770565b01601001949350505050565b600181811c90821680620008b657607f821691505b602082108103620008d557634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156200092657805f5260205f20601f840160051c81016020851015620009025750805b601f840160051c820191505b8181101562000923575f81556001016200090e565b50505b505050565b81516001600160401b038111156200094757620009476200075c565b6200095f81620009588454620008a1565b84620008db565b602080601f83116001811462000995575f84156200097d5750858301515b5f19600386901b1c1916600185901b178555620009ef565b5f85815260208120601f198616915b82811015620009c557888601518255948401946001909101908401620009a4565b5085821015620009e357878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b6473414d4d2d60d81b81525f835162000a1881600585016020880162000770565b602f60f81b600591840191820152835162000a3b81600684016020880162000770565b01600601949350505050565b7002b37b630ba34b632ab189020a6a690169607d1b81525f835162000a7481601185016020880162000770565b602f60f81b601191840191820152835162000a9781601284016020880162000770565b01601201949350505050565b6476414d4d2d60d81b81525f835162000a1881600585016020880162000770565b5f6020828403121562000ad5575f80fd5b815160ff8116811462000ae6575f80fd5b9392505050565b634e487b7160e01b5f52601160045260245ffd5b600181815b8085111562000b4157815f190482111562000b255762000b2562000aed565b8085161562000b3357918102915b93841c939080029062000b06565b509250929050565b5f8262000b595750600162000bf6565b8162000b6757505f62000bf6565b816001811462000b80576002811462000b8b5762000bab565b600191505062000bf6565b60ff84111562000b9f5762000b9f62000aed565b50506001821b62000bf6565b5060208310610133831016604e8410600b841016171562000bd0575081810a62000bf6565b62000bdc838362000b01565b805f190482111562000bf25762000bf262000aed565b0290505b92915050565b5f62000ae660ff84168362000b49565b6130108062000c1a5f395ff3fe608060405234801561000f575f80fd5b5060043610610276575f3560e01c806370a0823111610156578063a9059cbb116100ca578063d294f09311610084578063d294f09314610621578063d505accf14610629578063dd62ed3e1461063c578063ebeb31db14610666578063f140a35a1461066e578063fff6cae914610681575f80fd5b8063a9059cbb146105d7578063bda39cad146105ea578063bf944dbc146105f3578063c245febc146105fc578063c5700a0214610605578063d21220a71461060e575f80fd5b806395d89b411161011b57806395d89b41146105455780639af1d35a1461054d5780639d63848a146105605780639e8cc04b146105865780639f767c8814610599578063a1ac4d13146105b8575f80fd5b806370a08231146104a25780637ecebe00146104c157806389afcb44146104e05780638a7b8cf2146105085780639012c4a814610532575f80fd5b806323b872dd116101ed578063443cb4bc116101b2578063443cb4bc146104385780634d5a9f8a14610441578063517b3f82146104605780635881c475146104735780635a76f25e146104865780636a6278421461048f575f80fd5b806323b872dd14610394578063252c09d7146103a7578063313ce567146103ba57806332c0defd146103d4578063392f37e9146103dd575f80fd5b806313345fe11161023e57806313345fe11461032057806318160ddd146103405780631df8c71714610357578063205aabf11461035f578063218cf69a1461037e57806322be3de114610387575f80fd5b8063022c0d9f1461027a57806306fdde031461028f5780630902f1ac146102ad578063095ea7b3146102d25780630dfe1681146102f5575b5f80fd5b61028d610288366004612acb565b610689565b005b610297610c99565b6040516102a49190612b79565b60405180910390f35b6010546011546012545b604080519384526020840192909252908201526060016102a4565b6102e56102e0366004612bab565b610d24565b60405190151581526020016102a4565b600854610308906001600160a01b031681565b6040516001600160a01b0390911681526020016102a4565b61033361032e366004612bd3565b610d90565b6040516102a49190612c09565b61034960035481565b6040519081526020016102a4565b6102b7610f6b565b61034961036d366004612c4c565b60186020525f908152604090205481565b610349600b5481565b6002546102e59060ff1681565b6102e56103a2366004612c65565b610fd8565b6102b76103b5366004612c9e565b61109d565b6103c2601281565b60405160ff90911681526020016102a4565b61034960155481565b600e54600f5460105460115460025460085460095460408051978852602088019690965294860193909352606085019190915260ff16151560808401526001600160a01b0390811660a08401521660c082015260e0016102a4565b61034960105481565b61034961044f366004612c4c565b60196020525f908152604090205481565b61034961046e366004612bab565b6110ce565b610333610481366004612cb5565b6111ae565b61034960115481565b61034961049d366004612c4c565b6111bd565b6103496104b0366004612c4c565b60056020525f908152604090205481565b6103496104cf366004612c4c565b60076020525f908152604090205481565b6104f36104ee366004612c4c565b6113d7565b604080519283526020830191909152016102a4565b6105106116ae565b60408051825181526020808401519082015291810151908201526060016102a4565b61028d610540366004612c9e565b611728565b610297611743565b600a54610308906001600160a01b031681565b600854600954604080516001600160a01b039384168152929091166020830152016102a4565b610349610594366004612cb5565b611750565b6103496105a7366004612c4c565b60176020525f908152604090205481565b6103496105c6366004612c4c565b601a6020525f908152604090205481565b6102e56105e5366004612bab565b6117b5565b61034960165481565b61034960135481565b61034960145481565b61034960125481565b600954610308906001600160a01b031681565b6104f36117ca565b61028d610637366004612ce5565b6118cb565b61034961064a366004612d52565b600460209081525f928352604080842090915290825290205481565b600d54610349565b61034961067c366004612d83565b611bcd565b61028d611c72565b601b54600114610697575f80fd5b6002601b55600c5460408051635c975abb60e01b815290516001600160a01b0390921691635c975abb916004808201926020929091908290030181865afa1580156106e4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107089190612da4565b15610711575f80fd5b8415158061071e57508315155b6107555760405162461bcd60e51b8152602060048201526003602482015262494f4160e81b60448201526064015b60405180910390fd5b601054601154818710801561076957508086105b61079a5760405162461bcd60e51b8152602060048201526002602482015261125360f21b604482015260640161074c565b6008546009545f9182916001600160a01b039182169190811690891682148015906107d75750806001600160a01b0316896001600160a01b031614155b6108085760405162461bcd60e51b8152602060048201526002602482015261125560f21b604482015260640161074c565b8a1561081957610819828a8d611d6d565b891561082a5761082a818a8c611d6d565b861561089257604051639a7bff7960e01b81526001600160a01b038a1690639a7bff79906108649033908f908f908e908e90600401612dc3565b5f604051808303815f87803b15801561087b575f80fd5b505af115801561088d573d5f803e3d5ffd5b505050505b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa1580156108d4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108f89190612e0e565b6040516370a0823160e01b81523060048201529094506001600160a01b038216906370a0823190602401602060405180830381865afa15801561093d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109619190612e0e565b925050505f89856109729190612e39565b831161097e575f610992565b6109888a86612e39565b6109929084612e39565b90505f61099f8a86612e39565b83116109ab575f6109bf565b6109b58a86612e39565b6109bf9084612e39565b9050811515806109ce57508015155b610a005760405162461bcd60e51b815260206004820152600360248201526249494160e81b604482015260640161074c565b600854600954600c54600b54604051633665d80d60e11b81526004810187905233602482015260448101919091526001600160a01b039384169392831692610b0d921690636ccbb01a90606401602060405180830381865afa158015610a68573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a8c9190612e0e565b600c54600b54604051633665d80d60e11b81526004810188905233602482015260448101919091526001600160a01b0390911690636ccbb01a90606401602060405180830381865afa158015610ae4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b089190612e0e565b611e5b565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015610b4f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b739190612e0e565b6040516370a0823160e01b81523060048201529096506001600160a01b038216906370a0823190602401602060405180830381865afa158015610bb8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bdc9190612e0e565b9450610be88888611fd7565b610bf28787611fd7565b1015610c245760405162461bcd60e51b81526020600482015260016024820152604b60f81b604482015260640161074c565b5050610c32848488886120cb565b60408051838152602081018390529081018c9052606081018b90526001600160a01b038a169033907fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229060800160405180910390a350506001601b55505050505050505050565b5f8054610ca590612e4c565b80601f0160208091040260200160405190810160405280929190818152602001828054610cd190612e4c565b8015610d1c5780601f10610cf357610100808354040283529160200191610d1c565b820191905f5260205f20905b815481529060010190602001808311610cff57829003601f168201915b505050505081565b335f8181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610d7e9086815260200190565b60405180910390a35060015b92915050565b60605f8367ffffffffffffffff811115610dac57610dac612e84565b604051908082528060200260200182016040528015610dd5578160200160208202803683370190505b50600d549091505f90610dea90600190612e39565b90505f8080610df98789612e98565b610e039085612e39565b90505b83811015610f5b5786810192505f600d8281548110610e2757610e27612eaf565b905f5260205f2090600302015f0154600d8581548110610e4957610e49612eaf565b905f5260205f2090600302015f0154610e629190612e39565b90505f81600d8481548110610e7957610e79612eaf565b905f5260205f20906003020160010154600d8781548110610e9c57610e9c612eaf565b905f5260205f20906003020160010154610eb69190612e39565b610ec09190612ed7565b90505f82600d8581548110610ed757610ed7612eaf565b905f5260205f20906003020160020154600d8881548110610efa57610efa612eaf565b905f5260205f20906003020160020154610f149190612e39565b610f1e9190612ed7565b9050610f2c8c8e8484612259565b888681518110610f3e57610f3e612eaf565b602002602001018181525050846001019450859350505050610e06565b509293505050505b949350505050565b601354601454425f8080610f886010546011546012549192909190565b925092509250838114610fd0575f610fa08286612e39565b9050610fac8185612e98565b610fb69088612ef6565b9650610fc28184612e98565b610fcc9087612ef6565b9550505b505050909192565b6001600160a01b0383165f8181526004602090815260408083203380855292528220549192909190821480159061101057505f198114155b15611084575f6110208583612e39565b6001600160a01b038881165f818152600460209081526040808320948916808452948252918290208590559051848152939450919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505b61108f8686866123f5565b6001925050505b9392505050565b600d81815481106110ac575f80fd5b5f91825260209091206003909102018054600182015460029092015490925083565b5f806110d86116ae565b90505f806110e4610f6b565b5084519193509150420361114957600d805461110290600290612e39565b8154811061111257611112612eaf565b905f5260205f2090600302016040518060600160405290815f82015481526020016001820154815260200160028201548152505092505b82515f906111579042612e39565b90505f8185602001518561116b9190612e39565b6111759190612ed7565b90505f828660400151856111899190612e39565b6111939190612ed7565b90506111a1888a8484612259565b9998505050505050505050565b6060610f638484846001610d90565b5f601b546001146111cc575f80fd5b6002601b556010546011546008546040516370a0823160e01b81523060048201525f916001600160a01b0316906370a0823190602401602060405180830381865afa15801561121d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112419190612e0e565b6009546040516370a0823160e01b81523060048201529192505f916001600160a01b03909116906370a0823190602401602060405180830381865afa15801561128c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112b09190612e0e565b90505f6112bd8584612e39565b90505f6112ca8584612e39565b6003549091505f81900361130a576103e86112ed6112e88486612e98565b6124b3565b6112f79190612e39565b97506113055f6103e8612597565b61133f565b61133c876113188386612e98565b6113229190612ed7565b8761132d8486612e98565b6113379190612ed7565b612627565b97505b875f036113745760405162461bcd60e51b8152602060048201526003602482015262494c4d60e81b604482015260640161074c565b61137e8989612597565b61138a858589896120cb565b604080518481526020810184905233917f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f910160405180910390a250506001601b55509395945050505050565b5f80601b546001146113e7575f80fd5b6002601b556010546011546008546009546040516370a0823160e01b81523060048201526001600160a01b0392831692909116905f9083906370a0823190602401602060405180830381865afa158015611443573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114679190612e0e565b6040516370a0823160e01b81523060048201529091505f906001600160a01b038416906370a0823190602401602060405180830381865afa1580156114ae573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114d29190612e0e565b305f9081526005602052604090205460035491925090806114f38584612e98565b6114fd9190612ed7565b99508061150a8484612e98565b6115149190612ed7565b9850891580159061152457508815155b6115565760405162461bcd60e51b815260206004820152600360248201526224a62160e91b604482015260640161074c565b611560308361263c565b61156b868c8c611d6d565b611576858c8b611d6d565b6040516370a0823160e01b81523060048201526001600160a01b038716906370a0823190602401602060405180830381865afa1580156115b8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115dc9190612e0e565b6040516370a0823160e01b81523060048201529094506001600160a01b038616906370a0823190602401602060405180830381865afa158015611621573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116459190612e0e565b925061165384848a8a6120cb565b604080518b8152602081018b90526001600160a01b038d169133917fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496910160405180910390a350505050505050506001601b81905550915091565b6116cf60405180606001604052805f81526020015f81526020015f81525090565b600d80546116df90600190612e39565b815481106116ef576116ef612eaf565b905f5260205f2090600302016040518060600160405290815f820154815260200160018201548152602001600282015481525050905090565b600c546001600160a01b0316331461173e575f80fd5b600b55565b60018054610ca590612e4c565b5f8061175f8585856001610d90565b80519091505f905b80156117a0578060019003905082818151811061178657611786612eaf565b6020026020010151826117999190612ef6565b9150611767565b506117ab8482612ed7565b9695505050505050565b5f6117c13384846123f5565b50600192915050565b5f806117d5336126c4565b5050335f90815260196020908152604080832054601a90925290912054811515806117ff57508015155b156118c757335f818152601960209081526040808320839055601a90915280822091909155600a54905163299e7ae760e11b8152600481019290925260248201849052604482018390526001600160a01b03169063533cf5ce906064015f604051808303815f87803b158015611873575f80fd5b505af1158015611885573d5f803e3d5ffd5b505060408051858152602081018590523393508392507f865ca08d59f5cb456e85cd2f7ef63664ea4f73327414e9d8152c4158b0e94645910160405180910390a35b9091565b4284101561190b5760405162461bcd60e51b815260206004820152600d60248201526c14185a5c8e8811561412549151609a1b604482015260640161074c565b7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f5f60405161193a9190612f09565b60408051918290038220828201825260018352603160f81b6020938401528151928301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160408051601f19818403018152918152815160209283012060068190556001600160a01b038a165f908152600790935290822080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918b918b918b919087611a0483612fa7565b909155506040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810187905260e00160405160208183030381529060405280519060200120604051602001611a7d92919061190160f01b81526002810192909252602282015260420190565b60408051601f1981840301815282825280516020918201205f80855291840180845281905260ff88169284019290925260608301869052608083018590529092509060019060a0016020604051602081039080840390855afa158015611ae5573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b03811615801590611b1b5750886001600160a01b0316816001600160a01b0316145b611b675760405162461bcd60e51b815260206004820152601760248201527f506169723a20494e56414c49445f5349474e4154555245000000000000000000604482015260640161074c565b6001600160a01b038981165f818152600460209081526040808320948d16808452948252918290208b905590518a81527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050505050505050565b601054601154600c54600b54604051633665d80d60e11b81526004810187905233602482015260448101919091525f9392916001600160a01b031690636ccbb01a90606401602060405180830381865afa158015611c2d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c519190612e0e565b611c5b9086612e39565b9450611c6985858484612259565b95945050505050565b601b54600114611c80575f80fd5b6002601b556008546040516370a0823160e01b8152306004820152611d66916001600160a01b0316906370a0823190602401602060405180830381865afa158015611ccd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cf19190612e0e565b6009546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015611d37573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d5b9190612e0e565b6010546011546120cb565b6001601b55565b8015611e5657826001600160a01b03163b5f03611d88575f80fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291515f92839290871691611de39190612fbf565b5f604051808303815f865af19150503d805f8114611e1c576040519150601f19603f3d011682016040523d82523d5f602084013e611e21565b606091505b5091509150818015611e4b575080511580611e4b575080806020019051810190611e4b9190612da4565b611e53575f80fd5b50505b505050565b8115611ec057600854600a54611e7e916001600160a01b03908116911684611d6d565b6003545f90611e9584670de0b6b3a7640000612e98565b611e9f9190612ed7565b90508015611ebe578060155f828254611eb89190612ef6565b90915550505b505b8015611f2557600954600a54611ee3916001600160a01b03908116911683611d6d565b6003545f90611efa83670de0b6b3a7640000612e98565b611f049190612ed7565b90508015611f23578060165f828254611f1d9190612ef6565b90915550505b505b81151580611f3257508015155b15611fd357600a54604051630ab6d72560e01b815260048101849052602481018390526001600160a01b0390911690630ab6d725906044015f604051808303815f87803b158015611f81575f80fd5b505af1158015611f93573d5f803e3d5ffd5b505060408051858152602081018590523393507f112c256902bf554b6ed882d2936687aaeb4225e8cd5b51303c90ca6cf43a860292500160405180910390a25b5050565b6002545f9060ff16156120ba57600e545f90611ffb85670de0b6b3a7640000612e98565b6120059190612ed7565b90505f600f5484670de0b6b3a764000061201f9190612e98565b6120299190612ed7565b90505f670de0b6b3a764000061203f8385612e98565b6120499190612ed7565b90505f670de0b6b3a764000061205f8480612e98565b6120699190612ed7565b670de0b6b3a764000061207c8680612e98565b6120869190612ed7565b6120909190612ef6565b9050670de0b6b3a76400006120a58284612e98565b6120af9190612ed7565b945050505050610d8a565b6120c48284612e98565b9050610d8a565b60125442905f906120dc9083612e39565b905080158015906120ec57508315155b80156120f757508215155b1561213c576121068185612e98565b60135f8282546121169190612ef6565b9091555061212690508184612e98565b60145f8282546121369190612ef6565b90915550505b5f6121456116ae565b80519091506121549084612e39565b9150610708821115612208576040805160608101825284815260135460208201908152601454928201928352600d80546001810182555f9190915291517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5600390930292830155517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb682015590517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb7909101555b60108790556011869055601283905560408051888152602081018890527fcf2aa50876cdfbb541206f89af0ee78d44a2abf8d328e37fa4917f982149848a910160405180910390a150505050505050565b6002545f9060ff16156123a6575f6122718484611fd7565b600e5490915061228985670de0b6b3a7640000612e98565b6122939190612ed7565b600f549094506122ab84670de0b6b3a7640000612e98565b6122b59190612ed7565b6008549093505f9081906001600160a01b038881169116146122d85784866122db565b85855b60085491935091506001600160a01b0388811691161461231957600f5461230a89670de0b6b3a7640000612e98565b6123149190612ed7565b612338565b600e5461232e89670de0b6b3a7640000612e98565b6123389190612ed7565b97505f61234f612348848b612ef6565b858461281c565b6123599083612e39565b600854909150670de0b6b3a7640000906001600160a01b038a811691161461238357600e54612387565b600f545b6123919083612e98565b61239b9190612ed7565b945050505050610f63565b6008545f9081906001600160a01b038781169116146123c65783856123c9565b84845b90925090506123d88783612ef6565b6123e28289612e98565b6123ec9190612ed7565b92505050610f63565b6123fe836126c4565b612407826126c4565b6001600160a01b0383165f908152600560205260408120805483929061242e908490612e39565b90915550506001600160a01b0382165f908152600560205260408120805483929061245a908490612ef6565b92505081905550816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516124a691815260200190565b60405180910390a3505050565b5f815f036124c257505f919050565b5f60016124ce8461291a565b901c6001901b905060018184816124e7576124e7612ec3565b048201901c905060018184816124ff576124ff612ec3565b048201901c9050600181848161251757612517612ec3565b048201901c9050600181848161252f5761252f612ec3565b048201901c9050600181848161254757612547612ec3565b048201901c9050600181848161255f5761255f612ec3565b048201901c9050600181848161257757612577612ec3565b048201901c90506110968182858161259157612591612ec3565b04612627565b6125a0826126c4565b8060035f8282546125b19190612ef6565b90915550506001600160a01b0382165f90815260056020526040812080548392906125dd908490612ef6565b90915550506040518181526001600160a01b038316905f907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b5f8183106126355781611096565b5090919050565b612645826126c4565b8060035f8282546126569190612e39565b90915550506001600160a01b0382165f9081526005602052604081208054839290612682908490612e39565b90915550506040518181525f906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200161261b565b6001600160a01b0381165f9081526005602052604090205480156127eb576001600160a01b0382165f9081526017602090815260408083208054601880855292852080546015546016549481905594909552829055936127248584612e39565b90505f6127318584612e39565b9050811561278a575f670de0b6b3a764000061274d848a612e98565b6127579190612ed7565b6001600160a01b038a165f90815260196020526040812080549293508392909190612783908490612ef6565b9091555050505b80156127e1575f670de0b6b3a76400006127a4838a612e98565b6127ae9190612ed7565b6001600160a01b038a165f908152601a60205260408120805492935083929091906127da908490612ef6565b9091555050505b5050505050505050565b6015546001600160a01b0383165f908152601760209081526040808320939093556016546018909152919020555050565b5f60ff5b801561291157825f61283287836129ad565b905085811015612881575f6128478887612a49565b6128518389612e39565b61286390670de0b6b3a7640000612e98565b61286d9190612ed7565b90506128798187612ef6565b9550506128c2565b5f61288c8887612a49565b6128968884612e39565b6128a890670de0b6b3a7640000612e98565b6128b29190612ed7565b90506128be8187612e39565b9550505b818511156128eb5760016128d68387612e39565b116128e657849350505050611096565b612907565b60016128f78684612e39565b1161290757849350505050611096565b50505f1901612820565b50909392505050565b5f80608083901c1561292e57608092831c92015b604083901c1561294057604092831c92015b602083901c1561295257602092831c92015b601083901c1561296457601092831c92015b600883901c1561297657600892831c92015b600483901c1561298857600492831c92015b600283901c1561299a57600292831c92015b600183901c15610d8a5760010192915050565b5f670de0b6b3a7640000828185816129c58280612e98565b6129cf9190612ed7565b6129d99190612e98565b6129e39190612ed7565b6129ed9190612e98565b6129f79190612ed7565b670de0b6b3a7640000808481612a0d8280612e98565b612a179190612ed7565b612a219190612e98565b612a2b9190612ed7565b612a359086612e98565b612a3f9190612ed7565b6110969190612ef6565b5f670de0b6b3a76400008381612a5f8280612e98565b612a699190612ed7565b612a739190612e98565b612a7d9190612ed7565b670de0b6b3a764000080612a918580612e98565b612a9b9190612ed7565b612aa6866003612e98565b612a359190612e98565b80356001600160a01b0381168114612ac6575f80fd5b919050565b5f805f805f60808688031215612adf575f80fd5b8535945060208601359350612af660408701612ab0565b9250606086013567ffffffffffffffff80821115612b12575f80fd5b818801915088601f830112612b25575f80fd5b813581811115612b33575f80fd5b896020828501011115612b44575f80fd5b9699959850939650602001949392505050565b5f5b83811015612b71578181015183820152602001612b59565b50505f910152565b602081525f8251806020840152612b97816040850160208701612b57565b601f01601f19169190910160400192915050565b5f8060408385031215612bbc575f80fd5b612bc583612ab0565b946020939093013593505050565b5f805f8060808587031215612be6575f80fd5b612bef85612ab0565b966020860135965060408601359560600135945092505050565b602080825282518282018190525f9190848201906040850190845b81811015612c4057835183529284019291840191600101612c24565b50909695505050505050565b5f60208284031215612c5c575f80fd5b61109682612ab0565b5f805f60608486031215612c77575f80fd5b612c8084612ab0565b9250612c8e60208501612ab0565b9150604084013590509250925092565b5f60208284031215612cae575f80fd5b5035919050565b5f805f60608486031215612cc7575f80fd5b612cd084612ab0565b95602085013595506040909401359392505050565b5f805f805f805f60e0888a031215612cfb575f80fd5b612d0488612ab0565b9650612d1260208901612ab0565b95506040880135945060608801359350608088013560ff81168114612d35575f80fd5b9699959850939692959460a0840135945060c09093013592915050565b5f8060408385031215612d63575f80fd5b612d6c83612ab0565b9150612d7a60208401612ab0565b90509250929050565b5f8060408385031215612d94575f80fd5b82359150612d7a60208401612ab0565b5f60208284031215612db4575f80fd5b81518015158114611096575f80fd5b60018060a01b038616815284602082015283604082015260806060820152816080820152818360a08301375f81830160a090810191909152601f909201601f19160101949350505050565b5f60208284031215612e1e575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610d8a57610d8a612e25565b600181811c90821680612e6057607f821691505b602082108103612e7e57634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52604160045260245ffd5b8082028115828204841417610d8a57610d8a612e25565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601260045260245ffd5b5f82612ef157634e487b7160e01b5f52601260045260245ffd5b500490565b80820180821115610d8a57610d8a612e25565b5f8083545f60018260011c91506001831680612f2657607f831692505b60208084108203612f4557634e487b7160e01b5f52602260045260245ffd5b818015612f595760018114612f6e57612f99565b60ff1986168952841515850289019650612f99565b5f8a8152602090205f5b86811015612f915781548b820152908501908301612f78565b505084890196505b509498975050505050505050565b5f60018201612fb857612fb8612e25565b5060010190565b5f8251612fd0818460208701612b57565b919091019291505056fea264697066735822122036b885b0a55f35c6fd558bd9f7832685402b484e29db2fc8a7ff838272824e7d64736f6c6343000817003360e060405234801561000f575f80fd5b5060405161043e38038061043e83398101604081905261002e91610064565b336080526001600160a01b0391821660a0521660c052610095565b80516001600160a01b038116811461005f575f80fd5b919050565b5f8060408385031215610075575f80fd5b61007e83610049565b915061008c60208401610049565b90509250929050565b60805160a05160c05161037a6100c45f395f61015601525f61011301525f8181606b015260d1015261037a5ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80630ab6d72514610038578063533cf5ce1461004d575b5f80fd5b61004b610046366004610270565b610060565b005b61004b61005b366004610290565b6100c6565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610094575f80fd5b81156100aa57815f546100a791906102cd565b5f555b80156100c257806001546100be91906102cd565b6001555b5050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146100fa575f80fd5b811561013b575f54828110610139578281035f556101397f00000000000000000000000000000000000000000000000000000000000000008585610183565b505b801561017e5760015481811061017c5781810360015561017c7f00000000000000000000000000000000000000000000000000000000000000008584610183565b505b505050565b801561017e57826001600160a01b03163b5f0361019e575f80fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291515f928392908716916101f991906102f2565b5f604051808303815f865af19150503d805f8114610232576040519150601f19603f3d011682016040523d82523d5f602084013e610237565b606091505b5091509150818015610261575080511580610261575080806020019051810190610261919061031e565b610269575f80fd5b5050505050565b5f8060408385031215610281575f80fd5b50508035926020909101359150565b5f805f606084860312156102a2575f80fd5b83356001600160a01b03811681146102b8575f80fd5b95602085013595506040909401359392505050565b808201808211156102ec57634e487b7160e01b5f52601160045260245ffd5b92915050565b5f82515f5b8181101561031157602081860181015185830152016102f7565b505f920191825250919050565b5f6020828403121561032e575f80fd5b8151801515811461033d575f80fd5b939250505056fea2646970667358221220ce8b8ed52dd73d28ba2b6bd2eb3ed2f5b22688aca8bf613cf7712664c0833a2764736f6c63430008170033
Deployed Bytecode
0x608060405234801561000f575f80fd5b5060043610610276575f3560e01c806370a0823111610156578063a9059cbb116100ca578063d294f09311610084578063d294f09314610621578063d505accf14610629578063dd62ed3e1461063c578063ebeb31db14610666578063f140a35a1461066e578063fff6cae914610681575f80fd5b8063a9059cbb146105d7578063bda39cad146105ea578063bf944dbc146105f3578063c245febc146105fc578063c5700a0214610605578063d21220a71461060e575f80fd5b806395d89b411161011b57806395d89b41146105455780639af1d35a1461054d5780639d63848a146105605780639e8cc04b146105865780639f767c8814610599578063a1ac4d13146105b8575f80fd5b806370a08231146104a25780637ecebe00146104c157806389afcb44146104e05780638a7b8cf2146105085780639012c4a814610532575f80fd5b806323b872dd116101ed578063443cb4bc116101b2578063443cb4bc146104385780634d5a9f8a14610441578063517b3f82146104605780635881c475146104735780635a76f25e146104865780636a6278421461048f575f80fd5b806323b872dd14610394578063252c09d7146103a7578063313ce567146103ba57806332c0defd146103d4578063392f37e9146103dd575f80fd5b806313345fe11161023e57806313345fe11461032057806318160ddd146103405780631df8c71714610357578063205aabf11461035f578063218cf69a1461037e57806322be3de114610387575f80fd5b8063022c0d9f1461027a57806306fdde031461028f5780630902f1ac146102ad578063095ea7b3146102d25780630dfe1681146102f5575b5f80fd5b61028d610288366004612acb565b610689565b005b610297610c99565b6040516102a49190612b79565b60405180910390f35b6010546011546012545b604080519384526020840192909252908201526060016102a4565b6102e56102e0366004612bab565b610d24565b60405190151581526020016102a4565b600854610308906001600160a01b031681565b6040516001600160a01b0390911681526020016102a4565b61033361032e366004612bd3565b610d90565b6040516102a49190612c09565b61034960035481565b6040519081526020016102a4565b6102b7610f6b565b61034961036d366004612c4c565b60186020525f908152604090205481565b610349600b5481565b6002546102e59060ff1681565b6102e56103a2366004612c65565b610fd8565b6102b76103b5366004612c9e565b61109d565b6103c2601281565b60405160ff90911681526020016102a4565b61034960155481565b600e54600f5460105460115460025460085460095460408051978852602088019690965294860193909352606085019190915260ff16151560808401526001600160a01b0390811660a08401521660c082015260e0016102a4565b61034960105481565b61034961044f366004612c4c565b60196020525f908152604090205481565b61034961046e366004612bab565b6110ce565b610333610481366004612cb5565b6111ae565b61034960115481565b61034961049d366004612c4c565b6111bd565b6103496104b0366004612c4c565b60056020525f908152604090205481565b6103496104cf366004612c4c565b60076020525f908152604090205481565b6104f36104ee366004612c4c565b6113d7565b604080519283526020830191909152016102a4565b6105106116ae565b60408051825181526020808401519082015291810151908201526060016102a4565b61028d610540366004612c9e565b611728565b610297611743565b600a54610308906001600160a01b031681565b600854600954604080516001600160a01b039384168152929091166020830152016102a4565b610349610594366004612cb5565b611750565b6103496105a7366004612c4c565b60176020525f908152604090205481565b6103496105c6366004612c4c565b601a6020525f908152604090205481565b6102e56105e5366004612bab565b6117b5565b61034960165481565b61034960135481565b61034960145481565b61034960125481565b600954610308906001600160a01b031681565b6104f36117ca565b61028d610637366004612ce5565b6118cb565b61034961064a366004612d52565b600460209081525f928352604080842090915290825290205481565b600d54610349565b61034961067c366004612d83565b611bcd565b61028d611c72565b601b54600114610697575f80fd5b6002601b55600c5460408051635c975abb60e01b815290516001600160a01b0390921691635c975abb916004808201926020929091908290030181865afa1580156106e4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107089190612da4565b15610711575f80fd5b8415158061071e57508315155b6107555760405162461bcd60e51b8152602060048201526003602482015262494f4160e81b60448201526064015b60405180910390fd5b601054601154818710801561076957508086105b61079a5760405162461bcd60e51b8152602060048201526002602482015261125360f21b604482015260640161074c565b6008546009545f9182916001600160a01b039182169190811690891682148015906107d75750806001600160a01b0316896001600160a01b031614155b6108085760405162461bcd60e51b8152602060048201526002602482015261125560f21b604482015260640161074c565b8a1561081957610819828a8d611d6d565b891561082a5761082a818a8c611d6d565b861561089257604051639a7bff7960e01b81526001600160a01b038a1690639a7bff79906108649033908f908f908e908e90600401612dc3565b5f604051808303815f87803b15801561087b575f80fd5b505af115801561088d573d5f803e3d5ffd5b505050505b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa1580156108d4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108f89190612e0e565b6040516370a0823160e01b81523060048201529094506001600160a01b038216906370a0823190602401602060405180830381865afa15801561093d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109619190612e0e565b925050505f89856109729190612e39565b831161097e575f610992565b6109888a86612e39565b6109929084612e39565b90505f61099f8a86612e39565b83116109ab575f6109bf565b6109b58a86612e39565b6109bf9084612e39565b9050811515806109ce57508015155b610a005760405162461bcd60e51b815260206004820152600360248201526249494160e81b604482015260640161074c565b600854600954600c54600b54604051633665d80d60e11b81526004810187905233602482015260448101919091526001600160a01b039384169392831692610b0d921690636ccbb01a90606401602060405180830381865afa158015610a68573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a8c9190612e0e565b600c54600b54604051633665d80d60e11b81526004810188905233602482015260448101919091526001600160a01b0390911690636ccbb01a90606401602060405180830381865afa158015610ae4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b089190612e0e565b611e5b565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015610b4f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b739190612e0e565b6040516370a0823160e01b81523060048201529096506001600160a01b038216906370a0823190602401602060405180830381865afa158015610bb8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bdc9190612e0e565b9450610be88888611fd7565b610bf28787611fd7565b1015610c245760405162461bcd60e51b81526020600482015260016024820152604b60f81b604482015260640161074c565b5050610c32848488886120cb565b60408051838152602081018390529081018c9052606081018b90526001600160a01b038a169033907fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229060800160405180910390a350506001601b55505050505050505050565b5f8054610ca590612e4c565b80601f0160208091040260200160405190810160405280929190818152602001828054610cd190612e4c565b8015610d1c5780601f10610cf357610100808354040283529160200191610d1c565b820191905f5260205f20905b815481529060010190602001808311610cff57829003601f168201915b505050505081565b335f8181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610d7e9086815260200190565b60405180910390a35060015b92915050565b60605f8367ffffffffffffffff811115610dac57610dac612e84565b604051908082528060200260200182016040528015610dd5578160200160208202803683370190505b50600d549091505f90610dea90600190612e39565b90505f8080610df98789612e98565b610e039085612e39565b90505b83811015610f5b5786810192505f600d8281548110610e2757610e27612eaf565b905f5260205f2090600302015f0154600d8581548110610e4957610e49612eaf565b905f5260205f2090600302015f0154610e629190612e39565b90505f81600d8481548110610e7957610e79612eaf565b905f5260205f20906003020160010154600d8781548110610e9c57610e9c612eaf565b905f5260205f20906003020160010154610eb69190612e39565b610ec09190612ed7565b90505f82600d8581548110610ed757610ed7612eaf565b905f5260205f20906003020160020154600d8881548110610efa57610efa612eaf565b905f5260205f20906003020160020154610f149190612e39565b610f1e9190612ed7565b9050610f2c8c8e8484612259565b888681518110610f3e57610f3e612eaf565b602002602001018181525050846001019450859350505050610e06565b509293505050505b949350505050565b601354601454425f8080610f886010546011546012549192909190565b925092509250838114610fd0575f610fa08286612e39565b9050610fac8185612e98565b610fb69088612ef6565b9650610fc28184612e98565b610fcc9087612ef6565b9550505b505050909192565b6001600160a01b0383165f8181526004602090815260408083203380855292528220549192909190821480159061101057505f198114155b15611084575f6110208583612e39565b6001600160a01b038881165f818152600460209081526040808320948916808452948252918290208590559051848152939450919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505b61108f8686866123f5565b6001925050505b9392505050565b600d81815481106110ac575f80fd5b5f91825260209091206003909102018054600182015460029092015490925083565b5f806110d86116ae565b90505f806110e4610f6b565b5084519193509150420361114957600d805461110290600290612e39565b8154811061111257611112612eaf565b905f5260205f2090600302016040518060600160405290815f82015481526020016001820154815260200160028201548152505092505b82515f906111579042612e39565b90505f8185602001518561116b9190612e39565b6111759190612ed7565b90505f828660400151856111899190612e39565b6111939190612ed7565b90506111a1888a8484612259565b9998505050505050505050565b6060610f638484846001610d90565b5f601b546001146111cc575f80fd5b6002601b556010546011546008546040516370a0823160e01b81523060048201525f916001600160a01b0316906370a0823190602401602060405180830381865afa15801561121d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112419190612e0e565b6009546040516370a0823160e01b81523060048201529192505f916001600160a01b03909116906370a0823190602401602060405180830381865afa15801561128c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112b09190612e0e565b90505f6112bd8584612e39565b90505f6112ca8584612e39565b6003549091505f81900361130a576103e86112ed6112e88486612e98565b6124b3565b6112f79190612e39565b97506113055f6103e8612597565b61133f565b61133c876113188386612e98565b6113229190612ed7565b8761132d8486612e98565b6113379190612ed7565b612627565b97505b875f036113745760405162461bcd60e51b8152602060048201526003602482015262494c4d60e81b604482015260640161074c565b61137e8989612597565b61138a858589896120cb565b604080518481526020810184905233917f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f910160405180910390a250506001601b55509395945050505050565b5f80601b546001146113e7575f80fd5b6002601b556010546011546008546009546040516370a0823160e01b81523060048201526001600160a01b0392831692909116905f9083906370a0823190602401602060405180830381865afa158015611443573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114679190612e0e565b6040516370a0823160e01b81523060048201529091505f906001600160a01b038416906370a0823190602401602060405180830381865afa1580156114ae573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114d29190612e0e565b305f9081526005602052604090205460035491925090806114f38584612e98565b6114fd9190612ed7565b99508061150a8484612e98565b6115149190612ed7565b9850891580159061152457508815155b6115565760405162461bcd60e51b815260206004820152600360248201526224a62160e91b604482015260640161074c565b611560308361263c565b61156b868c8c611d6d565b611576858c8b611d6d565b6040516370a0823160e01b81523060048201526001600160a01b038716906370a0823190602401602060405180830381865afa1580156115b8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115dc9190612e0e565b6040516370a0823160e01b81523060048201529094506001600160a01b038616906370a0823190602401602060405180830381865afa158015611621573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116459190612e0e565b925061165384848a8a6120cb565b604080518b8152602081018b90526001600160a01b038d169133917fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496910160405180910390a350505050505050506001601b81905550915091565b6116cf60405180606001604052805f81526020015f81526020015f81525090565b600d80546116df90600190612e39565b815481106116ef576116ef612eaf565b905f5260205f2090600302016040518060600160405290815f820154815260200160018201548152602001600282015481525050905090565b600c546001600160a01b0316331461173e575f80fd5b600b55565b60018054610ca590612e4c565b5f8061175f8585856001610d90565b80519091505f905b80156117a0578060019003905082818151811061178657611786612eaf565b6020026020010151826117999190612ef6565b9150611767565b506117ab8482612ed7565b9695505050505050565b5f6117c13384846123f5565b50600192915050565b5f806117d5336126c4565b5050335f90815260196020908152604080832054601a90925290912054811515806117ff57508015155b156118c757335f818152601960209081526040808320839055601a90915280822091909155600a54905163299e7ae760e11b8152600481019290925260248201849052604482018390526001600160a01b03169063533cf5ce906064015f604051808303815f87803b158015611873575f80fd5b505af1158015611885573d5f803e3d5ffd5b505060408051858152602081018590523393508392507f865ca08d59f5cb456e85cd2f7ef63664ea4f73327414e9d8152c4158b0e94645910160405180910390a35b9091565b4284101561190b5760405162461bcd60e51b815260206004820152600d60248201526c14185a5c8e8811561412549151609a1b604482015260640161074c565b7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f5f60405161193a9190612f09565b60408051918290038220828201825260018352603160f81b6020938401528151928301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160408051601f19818403018152918152815160209283012060068190556001600160a01b038a165f908152600790935290822080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918b918b918b919087611a0483612fa7565b909155506040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810187905260e00160405160208183030381529060405280519060200120604051602001611a7d92919061190160f01b81526002810192909252602282015260420190565b60408051601f1981840301815282825280516020918201205f80855291840180845281905260ff88169284019290925260608301869052608083018590529092509060019060a0016020604051602081039080840390855afa158015611ae5573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b03811615801590611b1b5750886001600160a01b0316816001600160a01b0316145b611b675760405162461bcd60e51b815260206004820152601760248201527f506169723a20494e56414c49445f5349474e4154555245000000000000000000604482015260640161074c565b6001600160a01b038981165f818152600460209081526040808320948d16808452948252918290208b905590518a81527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050505050505050565b601054601154600c54600b54604051633665d80d60e11b81526004810187905233602482015260448101919091525f9392916001600160a01b031690636ccbb01a90606401602060405180830381865afa158015611c2d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c519190612e0e565b611c5b9086612e39565b9450611c6985858484612259565b95945050505050565b601b54600114611c80575f80fd5b6002601b556008546040516370a0823160e01b8152306004820152611d66916001600160a01b0316906370a0823190602401602060405180830381865afa158015611ccd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cf19190612e0e565b6009546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015611d37573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d5b9190612e0e565b6010546011546120cb565b6001601b55565b8015611e5657826001600160a01b03163b5f03611d88575f80fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291515f92839290871691611de39190612fbf565b5f604051808303815f865af19150503d805f8114611e1c576040519150601f19603f3d011682016040523d82523d5f602084013e611e21565b606091505b5091509150818015611e4b575080511580611e4b575080806020019051810190611e4b9190612da4565b611e53575f80fd5b50505b505050565b8115611ec057600854600a54611e7e916001600160a01b03908116911684611d6d565b6003545f90611e9584670de0b6b3a7640000612e98565b611e9f9190612ed7565b90508015611ebe578060155f828254611eb89190612ef6565b90915550505b505b8015611f2557600954600a54611ee3916001600160a01b03908116911683611d6d565b6003545f90611efa83670de0b6b3a7640000612e98565b611f049190612ed7565b90508015611f23578060165f828254611f1d9190612ef6565b90915550505b505b81151580611f3257508015155b15611fd357600a54604051630ab6d72560e01b815260048101849052602481018390526001600160a01b0390911690630ab6d725906044015f604051808303815f87803b158015611f81575f80fd5b505af1158015611f93573d5f803e3d5ffd5b505060408051858152602081018590523393507f112c256902bf554b6ed882d2936687aaeb4225e8cd5b51303c90ca6cf43a860292500160405180910390a25b5050565b6002545f9060ff16156120ba57600e545f90611ffb85670de0b6b3a7640000612e98565b6120059190612ed7565b90505f600f5484670de0b6b3a764000061201f9190612e98565b6120299190612ed7565b90505f670de0b6b3a764000061203f8385612e98565b6120499190612ed7565b90505f670de0b6b3a764000061205f8480612e98565b6120699190612ed7565b670de0b6b3a764000061207c8680612e98565b6120869190612ed7565b6120909190612ef6565b9050670de0b6b3a76400006120a58284612e98565b6120af9190612ed7565b945050505050610d8a565b6120c48284612e98565b9050610d8a565b60125442905f906120dc9083612e39565b905080158015906120ec57508315155b80156120f757508215155b1561213c576121068185612e98565b60135f8282546121169190612ef6565b9091555061212690508184612e98565b60145f8282546121369190612ef6565b90915550505b5f6121456116ae565b80519091506121549084612e39565b9150610708821115612208576040805160608101825284815260135460208201908152601454928201928352600d80546001810182555f9190915291517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5600390930292830155517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb682015590517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb7909101555b60108790556011869055601283905560408051888152602081018890527fcf2aa50876cdfbb541206f89af0ee78d44a2abf8d328e37fa4917f982149848a910160405180910390a150505050505050565b6002545f9060ff16156123a6575f6122718484611fd7565b600e5490915061228985670de0b6b3a7640000612e98565b6122939190612ed7565b600f549094506122ab84670de0b6b3a7640000612e98565b6122b59190612ed7565b6008549093505f9081906001600160a01b038881169116146122d85784866122db565b85855b60085491935091506001600160a01b0388811691161461231957600f5461230a89670de0b6b3a7640000612e98565b6123149190612ed7565b612338565b600e5461232e89670de0b6b3a7640000612e98565b6123389190612ed7565b97505f61234f612348848b612ef6565b858461281c565b6123599083612e39565b600854909150670de0b6b3a7640000906001600160a01b038a811691161461238357600e54612387565b600f545b6123919083612e98565b61239b9190612ed7565b945050505050610f63565b6008545f9081906001600160a01b038781169116146123c65783856123c9565b84845b90925090506123d88783612ef6565b6123e28289612e98565b6123ec9190612ed7565b92505050610f63565b6123fe836126c4565b612407826126c4565b6001600160a01b0383165f908152600560205260408120805483929061242e908490612e39565b90915550506001600160a01b0382165f908152600560205260408120805483929061245a908490612ef6565b92505081905550816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516124a691815260200190565b60405180910390a3505050565b5f815f036124c257505f919050565b5f60016124ce8461291a565b901c6001901b905060018184816124e7576124e7612ec3565b048201901c905060018184816124ff576124ff612ec3565b048201901c9050600181848161251757612517612ec3565b048201901c9050600181848161252f5761252f612ec3565b048201901c9050600181848161254757612547612ec3565b048201901c9050600181848161255f5761255f612ec3565b048201901c9050600181848161257757612577612ec3565b048201901c90506110968182858161259157612591612ec3565b04612627565b6125a0826126c4565b8060035f8282546125b19190612ef6565b90915550506001600160a01b0382165f90815260056020526040812080548392906125dd908490612ef6565b90915550506040518181526001600160a01b038316905f907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b5f8183106126355781611096565b5090919050565b612645826126c4565b8060035f8282546126569190612e39565b90915550506001600160a01b0382165f9081526005602052604081208054839290612682908490612e39565b90915550506040518181525f906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200161261b565b6001600160a01b0381165f9081526005602052604090205480156127eb576001600160a01b0382165f9081526017602090815260408083208054601880855292852080546015546016549481905594909552829055936127248584612e39565b90505f6127318584612e39565b9050811561278a575f670de0b6b3a764000061274d848a612e98565b6127579190612ed7565b6001600160a01b038a165f90815260196020526040812080549293508392909190612783908490612ef6565b9091555050505b80156127e1575f670de0b6b3a76400006127a4838a612e98565b6127ae9190612ed7565b6001600160a01b038a165f908152601a60205260408120805492935083929091906127da908490612ef6565b9091555050505b5050505050505050565b6015546001600160a01b0383165f908152601760209081526040808320939093556016546018909152919020555050565b5f60ff5b801561291157825f61283287836129ad565b905085811015612881575f6128478887612a49565b6128518389612e39565b61286390670de0b6b3a7640000612e98565b61286d9190612ed7565b90506128798187612ef6565b9550506128c2565b5f61288c8887612a49565b6128968884612e39565b6128a890670de0b6b3a7640000612e98565b6128b29190612ed7565b90506128be8187612e39565b9550505b818511156128eb5760016128d68387612e39565b116128e657849350505050611096565b612907565b60016128f78684612e39565b1161290757849350505050611096565b50505f1901612820565b50909392505050565b5f80608083901c1561292e57608092831c92015b604083901c1561294057604092831c92015b602083901c1561295257602092831c92015b601083901c1561296457601092831c92015b600883901c1561297657600892831c92015b600483901c1561298857600492831c92015b600283901c1561299a57600292831c92015b600183901c15610d8a5760010192915050565b5f670de0b6b3a7640000828185816129c58280612e98565b6129cf9190612ed7565b6129d99190612e98565b6129e39190612ed7565b6129ed9190612e98565b6129f79190612ed7565b670de0b6b3a7640000808481612a0d8280612e98565b612a179190612ed7565b612a219190612e98565b612a2b9190612ed7565b612a359086612e98565b612a3f9190612ed7565b6110969190612ef6565b5f670de0b6b3a76400008381612a5f8280612e98565b612a699190612ed7565b612a739190612e98565b612a7d9190612ed7565b670de0b6b3a764000080612a918580612e98565b612a9b9190612ed7565b612aa6866003612e98565b612a359190612e98565b80356001600160a01b0381168114612ac6575f80fd5b919050565b5f805f805f60808688031215612adf575f80fd5b8535945060208601359350612af660408701612ab0565b9250606086013567ffffffffffffffff80821115612b12575f80fd5b818801915088601f830112612b25575f80fd5b813581811115612b33575f80fd5b896020828501011115612b44575f80fd5b9699959850939650602001949392505050565b5f5b83811015612b71578181015183820152602001612b59565b50505f910152565b602081525f8251806020840152612b97816040850160208701612b57565b601f01601f19169190910160400192915050565b5f8060408385031215612bbc575f80fd5b612bc583612ab0565b946020939093013593505050565b5f805f8060808587031215612be6575f80fd5b612bef85612ab0565b966020860135965060408601359560600135945092505050565b602080825282518282018190525f9190848201906040850190845b81811015612c4057835183529284019291840191600101612c24565b50909695505050505050565b5f60208284031215612c5c575f80fd5b61109682612ab0565b5f805f60608486031215612c77575f80fd5b612c8084612ab0565b9250612c8e60208501612ab0565b9150604084013590509250925092565b5f60208284031215612cae575f80fd5b5035919050565b5f805f60608486031215612cc7575f80fd5b612cd084612ab0565b95602085013595506040909401359392505050565b5f805f805f805f60e0888a031215612cfb575f80fd5b612d0488612ab0565b9650612d1260208901612ab0565b95506040880135945060608801359350608088013560ff81168114612d35575f80fd5b9699959850939692959460a0840135945060c09093013592915050565b5f8060408385031215612d63575f80fd5b612d6c83612ab0565b9150612d7a60208401612ab0565b90509250929050565b5f8060408385031215612d94575f80fd5b82359150612d7a60208401612ab0565b5f60208284031215612db4575f80fd5b81518015158114611096575f80fd5b60018060a01b038616815284602082015283604082015260806060820152816080820152818360a08301375f81830160a090810191909152601f909201601f19160101949350505050565b5f60208284031215612e1e575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610d8a57610d8a612e25565b600181811c90821680612e6057607f821691505b602082108103612e7e57634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52604160045260245ffd5b8082028115828204841417610d8a57610d8a612e25565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601260045260245ffd5b5f82612ef157634e487b7160e01b5f52601260045260245ffd5b500490565b80820180821115610d8a57610d8a612e25565b5f8083545f60018260011c91506001831680612f2657607f831692505b60208084108203612f4557634e487b7160e01b5f52602260045260245ffd5b818015612f595760018114612f6e57612f99565b60ff1986168952841515850289019650612f99565b5f8a8152602090205f5b86811015612f915781548b820152908501908301612f78565b505084890196505b509498975050505050505050565b5f60018201612fb857612fb8612e25565b5060010190565b5f8251612fd0818460208701612b57565b919091019291505056fea264697066735822122036b885b0a55f35c6fd558bd9f7832685402b484e29db2fc8a7ff838272824e7d64736f6c63430008170033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.