Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 100 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Approve | 26675050 | 38 days ago | IN | 0 ETH | 0.00000001 | ||||
| Approve | 26461850 | 42 days ago | IN | 0 ETH | 0.00000003 | ||||
| Approve | 26383359 | 43 days ago | IN | 0 ETH | 0.00000023 | ||||
| Approve | 26116321 | 48 days ago | IN | 0 ETH | 0.00000029 | ||||
| Approve | 25809824 | 53 days ago | IN | 0 ETH | 0.00000025 | ||||
| Approve | 25628913 | 56 days ago | IN | 0 ETH | 0.00000014 | ||||
| Approve | 22521968 | 112 days ago | IN | 0 ETH | 0.00000049 | ||||
| Approve | 22213084 | 117 days ago | IN | 0 ETH | 0.00000066 | ||||
| Approve | 21767125 | 123 days ago | IN | 0 ETH | 0 | ||||
| Approve | 21374502 | 130 days ago | IN | 0 ETH | 0.00000001 | ||||
| Approve | 21098938 | 134 days ago | IN | 0 ETH | 0.00000049 | ||||
| Approve | 20587825 | 142 days ago | IN | 0 ETH | 0.00000094 | ||||
| Approve | 18715479 | 168 days ago | IN | 0 ETH | 0.00000024 | ||||
| Approve | 17575665 | 183 days ago | IN | 0 ETH | 0.00000022 | ||||
| Approve | 17403238 | 188 days ago | IN | 0 ETH | 0.00000001 | ||||
| Approve | 16157201 | 236 days ago | IN | 0 ETH | 0.00000143 | ||||
| Approve | 15669745 | 249 days ago | IN | 0 ETH | 0.00000175 | ||||
| Approve | 15491911 | 254 days ago | IN | 0 ETH | 0.00000085 | ||||
| Approve | 15413427 | 256 days ago | IN | 0 ETH | 0.00000098 | ||||
| Approve | 15386646 | 257 days ago | IN | 0 ETH | 0.0000012 | ||||
| Approve | 15045000 | 271 days ago | IN | 0 ETH | 0.00000161 | ||||
| Approve | 14880670 | 278 days ago | IN | 0 ETH | 0.00000163 | ||||
| Approve | 14835417 | 280 days ago | IN | 0 ETH | 0.00000167 | ||||
| Approve | 14835347 | 280 days ago | IN | 0 ETH | 0.0000018 | ||||
| Permit | 14743229 | 284 days ago | IN | 0 ETH | 0.00000189 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 10402387 | 459 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
SyncSwapCryptoPoolDelegated
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.0;
import "../../libraries/Math.sol";
import "../../libraries/UnsafeMath.sol";
import "../../libraries/TransferHelper.sol";
import "../../libraries/ERC20Permit2.sol";
import "../../libraries/MetadataHelper.sol";
import "../../libraries/ReentrancyGuard.sol";
import "../../interfaces/IWETH.sol";
import "../../interfaces/IOwnable.sol";
import "../../interfaces/ICallback.sol";
import "../../interfaces/vault/IVault.sol";
import "../../interfaces/pool/ICryptoPool.sol";
import "../../interfaces/master/IPoolMaster.sol";
import "../../interfaces/master/IFeeRecipient.sol";
import "../../interfaces/master/IFeeManagerV2.sol";
import "../PoolFlashLoans.sol";
import "../crypto/ICryptoMath.sol";
import "../crypto/ICryptoView.sol";
error Overflow();
error InsufficientLiquidityMinted();
error Loss();
interface ICryptoPoolFactory {
function master() external view returns (address);
function cryptoMath() external view returns (address);
function cryptoView() external view returns (address);
function cryptoFunc() external view returns (address);
function cryptoBurn() external view returns (address);
function getDeployData() external view returns (bytes memory);
}
// This pool uses delegate call with sub implementation contracts CryptoBurn and CryptoFunc to reduce the code size.
contract SyncSwapCryptoPoolDelegated is UnsafeMath, ERC20Permit2, ReentrancyGuard {
////////////////////////////////////////////////////////
/////////////// CONSTANTS AND IMMUTABLES ///////////////
address private WETH = 0x5300000000000000000000000000000000000004; // Linea WETH
address public vault = 0x7160570BB153Edd0Ea1775EC2b2Ac9b65F1aB61B; // Linea Vault
address public master = 0x4318a74425E5353a1194CF26138Baa87B607657C; // Linea V2 Pool Master
uint24 private constant MAX_FEE = 20000;
/// @dev Pool type `3` for crypto pools.
uint16 public constant poolType = 3;
uint public constant poolVersion = 2;
address private immutable cryptoFunc;
address private immutable cryptoBurn;
address public immutable factory;
address public immutable token0;
address public immutable token1;
/// @dev Multipliers for each pooled token's precision to get to the pool precision decimals
/// which is agnostic to the pool, but usually is 18.
/// For example, TBTC has 18 decimals, so the multiplier should be 10 ** (18 - 18) = 1.
/// WBTC has 8, so the multiplier should be 10 ** (18 - 8) => 10 ** 10.
/// The value is only for crypto pools, and has no effects on non-crypto pools.
uint public immutable token0PrecisionMultiplier;
uint public immutable token1PrecisionMultiplier;
/////////////// CONSTANTS AND IMMUTABLES ///////////////
////////////////////////////////////////////////////////
ICryptoMath public MATH;
/// @dev Pool reserve of each pool token as of immediately after the most recent balance event.
/// The value is used to measure growth in invariant on mints and input tokens on swaps.
uint128 private reserve0_;
uint128 private reserve1_;
/// @dev Invariant of the pool as of immediately after the most recent liquidity event.
uint public invariantLast;
/// @dev Price scale determines the price band around which liquidity is concentrated.
uint public priceScale;
/// @dev Price target given by moving average.
/// The oracle is an exponential moving average, with a periodicity determined by MA time.
/// The aggregated prices are cached state prices (dy/dx) calculated AFTER the latest trade.
uint public cachedPriceOracle;
/// @dev The quote by the AMM for an infinitesimally small swap after the last trade.
/// It is not equivalent to the last traded price, and is computed by taking
/// the partial differential of `x` w.r.t `y`.
uint public lastPrices;
uint public lastPricesTimestamp;
/// @dev Cached (fast to read) virtual price. The cached `virtualPrice` is also used internally.
uint public virtualPrice;
/// @dev Current pool profits.
uint public xcpProfit;
/// @dev Full profit at last claim of protocol fees.
uint public xcpProfitLast = 1e18;
//uint public initialParams;
//uint public futureParams;
ICryptoPool.PoolParams public poolParams;
ICryptoPool.RebalancingParams public rebalancingParams = ICryptoPool.RebalancingParams({
allowedExtraProfit: 2000000000000,
adjustmentStep: 146000000000000,
maTime: 600,
requiredProfit: 5000,
checkLastProfit: 0
});
struct TokenAmount {
address token;
uint amount;
}
event Sync(
uint reserve0,
uint reserve1
);
event UpdatePoolProfit(
uint xcpProfit,
uint virtualPrice
);
event UpdateInvariant(
uint newInvariant
);
event UpdatePriceScale(
uint newPriceScale
);
event Swapped(
address indexed sender,
address indexed user,
address indexed tokenOut,
uint amountIn,
uint amountOut,
uint24 swapFee,
address to
);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Fee(
uint amount0,
uint amount1
);
receive() external payable {}
fallback() external payable {
address target = cryptoFunc;
// burn(bytes,address,address,bytes): 0xf66eab5b
// burnSingle(bytes,address,address,bytes): 0x27b0bcea
// calculateSingleWithdrawAmount(address,uint256,uint256,uint256,bool,bool): 0x3e5e465e
// function getVirtualPrice() external view returns (uint) 0xe25aa5fa
// function getPriceOracle() external view returns (uint) 0xfca513a8
if (msg.sig == 0xf66eab5b || msg.sig == 0x27b0bcea || msg.sig == 0x3e5e465e || msg.sig == 0xe25aa5fa || msg.sig == 0xfca513a8) {
target = cryptoBurn;
}
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), target, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/// @dev Factory must ensures that the parameters are valid.
constructor() {
(bytes memory _deployData) = ICryptoPoolFactory(msg.sender).getDeployData();
(address _token0, address _token1, uint _token0PrecisionMultiplier, uint _token1PrecisionMultiplier, uint _initialPrice) = abi.decode(
_deployData, (address, address, uint, uint, uint)
);
//address _master = ICryptoPoolFactory(msg.sender).master();
MATH = ICryptoMath(ICryptoPoolFactory(msg.sender).cryptoMath());
factory = msg.sender;
cryptoFunc = ICryptoPoolFactory(msg.sender).cryptoFunc();
cryptoBurn = ICryptoPoolFactory(msg.sender).cryptoBurn();
(token0, token1, token0PrecisionMultiplier, token1PrecisionMultiplier) = (
_token0, _token1, _token0PrecisionMultiplier, _token1PrecisionMultiplier
);
// default pool params
uint32 _a = 400000;
uint64 _gamma = 145000000000000;
poolParams = ICryptoPool.PoolParams({
initialA: _a,
futureA: _a,
initialGamma: _gamma,
futureGamma: _gamma,
initialTime: 0,
futureTime: 0
});
_setInitialPrice(_initialPrice);
// try to set symbols for the LP token
(bool _success0, string memory _symbol0) = MetadataHelper.getSymbol(_token0);
(bool _success1, string memory _symbol1) = MetadataHelper.getSymbol(_token1);
if (_success0 && _success1) {
_initialize(
string(abi.encodePacked("SyncSwap Aqua LP")),
string(abi.encodePacked(_symbol0, "/", _symbol1, "-A"))
);
} else {
_initialize("SLP", "SLP");
}
}
function _setInitialPrice(uint _initialPrice) private {
priceScale = _initialPrice;
emit UpdatePriceScale(_initialPrice);
cachedPriceOracle = _initialPrice;
lastPrices = _initialPrice;
lastPricesTimestamp = block.timestamp;
}
/// @dev Returns the verified sender address otherwise `address(0)`.
function _getVerifiedSender(address _sender) private view returns (address) {
if (_sender != msg.sender) {
// The sender from non-forwarder is invalid.
try IPoolMaster(master).isForwarder(msg.sender) returns (bool _isTrustedForwarder) {
return _isTrustedForwarder ? _sender : msg.sender;
} catch {
return msg.sender;
}
}
return msg.sender;
}
function _balances() private view returns (uint balance0, uint balance1) {
balance0 = IERC20(token0).balanceOf(address(this));
balance1 = IERC20(token1).balanceOf(address(this));
}
function _updateReserves(uint _balance0, uint _balance1) private {
if (_balance0 > type(uint128).max) {
revert Overflow();
}
if (_balance1 > type(uint128).max) {
revert Overflow();
}
(reserve0_, reserve1_) = (uint128(_balance0), uint128(_balance1));
emit Sync(_balance0, _balance1);
}
/// @dev Swaps one token for another - should be called via the router after transferring input tokens.
/// The router should ensure that sufficient output tokens are received.
function swap(
bytes memory _data,
address _sender,
address _callback,
bytes memory _callbackData
) public nonReentrant returns (TokenAmount memory _tokenAmount) {
ICallback.BaseSwapCallbackParams memory params;
(params.tokenIn, params.to, params.withdrawMode) = abi.decode(_data, (address, address, uint8));
(params.reserve0, params.reserve1) = getReserves();
(params.balance0, params.balance1) = _balances();
// Gets swap fee for the sender.
_sender = _getVerifiedSender(_sender);
// ----------- Update invariant if A, gamma are undergoing ramps ---------
// In case ramp is happening
(uint a, uint gamma, uint futureTime) = _params();
// ----------------------- Calculate dy and fees --------------------------
uint xp0;
uint xp1;
uint _k0_prev;
uint _feeAmountOut;
ICryptoMath _MATH = MATH;
if (params.tokenIn == token0) {
(params.amountOut, params.swapFee, _feeAmountOut, xp0, xp1, _k0_prev) = _getAmountOut(
GetAmountOutInputParams({
sender: _sender,
a: a,
gamma: gamma,
balance0: params.balance0,
balance1: params.balance1,
reserve0: params.reserve0,
reserve1: params.reserve1,
token0In: true,
futureTime: futureTime
}), _MATH
);
params.tokenOut = token1;
params.balance1 -= params.amountOut;
params.amountIn = params.balance0 - params.reserve0;
emit Swap(msg.sender, params.amountIn, 0, 0, params.amountOut, params.to);
emit Fee(0, _feeAmountOut);
} else {
require(params.tokenIn == token1);
(params.amountOut, params.swapFee, _feeAmountOut, xp0, xp1, _k0_prev) = _getAmountOut(
GetAmountOutInputParams({
sender: _sender,
a: a,
gamma: gamma,
balance0: params.balance0,
balance1: params.balance1,
reserve0: params.reserve0,
reserve1: params.reserve1,
token0In: false,
futureTime: futureTime
}), _MATH
);
params.tokenOut = token0;
params.balance0 -= params.amountOut;
params.amountIn = params.balance1 - params.reserve1;
emit Swap(msg.sender, 0, params.amountIn, params.amountOut, 0, params.to);
emit Fee(_feeAmountOut, 0);
}
require(params.amountIn != 0 && params.amountOut != 0);
// ------------------------ Tweak `priceScale` ----------------------------
_tweakPrice(a, gamma, xp0, xp1, 0, futureTime, _k0_prev, _MATH);
// Updates reserves with up-to-date balances (updated above).
_updateReserves(params.balance0, params.balance1);
// Transfers output tokens.
_transferTokens(params.tokenOut, params.to, params.amountOut, params.withdrawMode);
// Calls callback with data.
if (_callback != address(0)) {
// Fills additional values for callback params.
params.sender = _sender;
params.callbackData = _callbackData;
// Calculates fee amount for callback.
params.feeIn = Math.mulDivUnsafeFirstLast(params.amountIn, params.swapFee, 1e5);
ICallback(_callback).syncSwapBaseSwapCallback(params);
}
_tokenAmount.token = params.tokenOut;
_tokenAmount.amount = params.amountOut;
emit Swapped(
msg.sender,
_sender,
params.tokenOut,
params.amountIn,
params.amountOut,
params.swapFee,
params.to
);
}
struct GetAmountOutArgs {
uint xp0;
uint xp1;
uint invariant;
uint xp1PriceScale;
uint y;
}
struct GetAmountOutInputParams {
address sender;
uint a;
uint gamma;
uint balance0;
uint balance1;
uint reserve0;
uint reserve1;
bool token0In;
uint futureTime;
}
function _getAmountOut(
GetAmountOutInputParams memory p,
ICryptoMath _MATH
) private view returns (
uint _amountOut, uint24 _swapFee, uint _feeAmountOut, uint _newXp0, uint _newXp1, uint _k0_prev
) {
GetAmountOutArgs memory it;
it.xp0 = p.balance0 * token0PrecisionMultiplier;
it.xp1PriceScale = priceScale * token1PrecisionMultiplier;
it.xp1 = Math.mulDivUnsafeLast(p.balance1, it.xp1PriceScale, 1e18);
if (p.futureTime > block.timestamp) {
if (p.token0In) {
// Resue `it.y` as `xp0` here
it.y = unsafe_mul(
p.reserve0, token0PrecisionMultiplier
); // <---- already safe_mul above for `xp0`
it.invariant = _MATH.computeD(p.a, p.gamma, it.y, it.xp1, 0);
} else {
// Resue `it.y` as `xp1` here
it.y = unsafe_div(
unsafe_mul(p.reserve1, it.xp1PriceScale),
1e18
); // <---- already safe_mul above for `xp1`
it.invariant = _MATH.computeD(p.a, p.gamma, it.xp0, it.y, 0);
}
} else {
it.invariant = invariantLast;
}
if (p.token0In) {
(it.y, _k0_prev) = _MATH.getY(p.a, p.gamma, it.xp0, it.xp1, it.invariant, 1);
_amountOut = it.xp1 - it.y;
it.xp1 -= _amountOut;
_amountOut -= 1;
_amountOut = Math.mulDivUnsafeFirst(1e18, _amountOut, it.xp1PriceScale);
_swapFee = _getFee(p.sender, token0, token1, it.xp0, it.xp1);
_feeAmountOut = Math.mulDivUnsafeLast(_swapFee, _amountOut, 1e5);
_amountOut -= _feeAmountOut;
_newXp0 = it.xp0;
_newXp1 = unsafe_div(unsafe_mul(p.reserve1 - _amountOut, it.xp1PriceScale), 1e18); // <---- already safe_mul above for `xp1`
} else {
(it.y, _k0_prev) = _MATH.getY(p.a, p.gamma, it.xp0, it.xp1, it.invariant, 0);
_amountOut = it.xp0 - it.y;
it.xp0 -= _amountOut;
_amountOut -= 1;
_amountOut = Math.divUnsafeLast(_amountOut, token0PrecisionMultiplier);
_swapFee = _getFee(p.sender, token1, token0, it.xp0, it.xp1);
_feeAmountOut = Math.mulDivUnsafeLast(_swapFee, _amountOut, 1e5);
_amountOut -= _feeAmountOut;
_newXp0 = unsafe_mul(p.reserve0 - _amountOut, token0PrecisionMultiplier);
_newXp1 = it.xp1;
}
}
function _transferTokens(address token, address to, uint amount, uint8 withdrawMode) private {
if (withdrawMode == 0) {
TransferHelper.safeTransfer(token, vault, amount);
IVault(vault).deposit(token, to);
} else {
if (withdrawMode == 1 && token == WETH) {
IWETH(WETH).withdraw(amount);
TransferHelper.safeTransferETH(to, amount);
} else {
TransferHelper.safeTransfer(token, to, amount);
}
}
}
function getReserves() public view returns (uint _reserve0, uint _reserve1) {
(_reserve0, _reserve1) = (reserve0_, reserve1_);
}
function _getFeeData(
address _sender,
address _tokenIn,
address _tokenOut,
bytes memory data
) private view returns (IFeeManagerV2.FeeData memory) {
address _feeManager;
try IPoolMaster(master).feeManager() returns (address __feeManager) {
_feeManager = __feeManager;
} catch {
// leave `_feeManager` as `address(0)` and return default fee data below
}
if (_feeManager != address(0)) {
try IFeeManagerV2(_feeManager).getSwapFeeData(
address(this), _sender, _tokenIn, _tokenOut, data
) returns (IFeeManagerV2.FeeData memory feeData) {
return feeData;
} catch {
// return default fee data, see below
}
}
// return the default fee data here, if fee manager not exists or catch an error
return IFeeManagerV2.FeeData({
gamma: 230000000000000,
minFee: 260, // 0.26%
maxFee: 450 // 0.45%
});
//return IFeeManagerV2(_feeManager).getSwapFeeData(address(this), _sender, _tokenIn, _tokenOut, data);
}
function _getFee(
address _sender,
address _tokenIn,
address _tokenOut,
uint xp0,
uint xp1
) internal view returns (uint24 _fee) {
_fee = _getFeeWithData(_sender, _tokenIn, _tokenOut, xp0, xp1, abi.encode(msg.sender));
}
function _getFeeWithData(
address _sender,
address _tokenIn,
address _tokenOut,
uint xp0,
uint xp1,
bytes memory data
) internal view returns (uint24 _fee) {
IFeeManagerV2.FeeData memory feeData = _getFeeData(_sender, _tokenIn, _tokenOut, data);
uint f = xp0 + xp1;
f = unsafe_mul(feeData.gamma, 1e18) / (
unsafe_add(feeData.gamma, 1e18) - unsafe_div(4e18 * xp0 / f * xp1, f)
);
_fee = uint24(unsafe_div(
feeData.minFee * f + feeData.maxFee * (1e18 - f),
1e18
));
if (_fee > MAX_FEE) {
_fee = MAX_FEE;
}
}
function _getFeeRecipient() internal view returns (address) {
try IPoolMaster(master).getFeeRecipient() returns (address _feeRecipient) {
return _feeRecipient;
} catch {
return address(0);
}
}
function _xp(uint _reserve0, uint _reserve1) private view returns (uint xp0, uint xp1) {
xp0 = _reserve0 * token0PrecisionMultiplier;
xp1 = Math.mulDivUnsafeFirstLast(token1PrecisionMultiplier, priceScale * _reserve1, 1e18);
}
function _params() private view returns (uint a, uint gamma, uint futureTime) {
ICryptoPool.PoolParams memory params = poolParams;
gamma = params.futureGamma;
a = params.futureA;
futureTime = params.futureTime;
if (futureTime > block.timestamp) {
uint duration = futureTime - params.initialTime;
uint elapsed = block.timestamp - params.initialTime;
uint remaining = duration - elapsed;
a = (params.initialA * remaining + a * elapsed) / duration;
gamma = (params.initialGamma * remaining + gamma * elapsed) / duration;
}
}
function _getXCP(uint _invariant, uint _priceScale) private pure returns (uint) {
return Math.geometricMean(
unsafe_div(_invariant, 2),
Math.mulDivUnsafeFirst(1e18, _invariant, Math.mulUnsafeFirst(2, _priceScale))
);
}
struct TweakPriceArgs {
uint priceScale;
uint priceOracle;
uint lastPrices;
uint lastPricesTimestamp;
uint totalSupply;
uint xcpProfit;
uint virtualPrice;
uint oldVirtualPrice;
uint newInvariant;
uint norm;
}
/// @notice Tweaks `priceOracle`, `lastPrices` and conditionally adjusts `priceScale`.
/// This is called whenever there is an unbalanced liquidity operation: swap, mint, or burnSingle.
/// @dev Contains main liquidity rebalancing logic, by tweaking `priceScale`.
function _tweakPrice(
uint a,
uint gamma,
uint xp0,
uint xp1,
uint invariantUnadjusted,
uint _futureTime,
uint _k0_prev,
ICryptoMath _MATH
) private returns (uint, uint) { // returns (newInvariant, newPriceScale)
TweakPriceArgs memory it;
// ---------------------------- Read storage ------------------------------
ICryptoPool.RebalancingParams memory _rebalancingParams = rebalancingParams;
it.priceOracle = cachedPriceOracle;
it.priceScale = priceScale;
it.lastPricesTimestamp = lastPricesTimestamp;
it.totalSupply = totalSupply;
it.oldVirtualPrice = virtualPrice;
// ----------------------- Update MA if needed ----------------------------
if (it.lastPricesTimestamp < block.timestamp) {
// The moving average price oracle is calculated using the `lastPrices`
// of the trade at the previous block, and the price oracle logged
// before that trade. This can happen only once per block.
// ------------------ Calculate moving average params -----------------
// ---------------------------------------------- Update price oracles.
// ----------------- We cap state price that goes into the EMA with
// 2 x priceScale.
it.priceOracle = _MATH.getPriceOracle(
it.lastPricesTimestamp,
_rebalancingParams.maTime,
lastPrices,
it.priceScale,
it.priceOracle
);
cachedPriceOracle = it.priceOracle;
lastPricesTimestamp = block.timestamp;
}
// `priceOracle` is used further on to calculate its vector
// distance from `priceScale`. This distance is used to calculate
// the amount of adjustment to be done to the `priceScale`.
// ---------------- If `invariantUnadjusted` is 0, calculate it -----------------
if (invariantUnadjusted == 0) {
invariantUnadjusted = _MATH.computeD(a, gamma, xp0, xp1, _k0_prev);
}
// ----------------- Calculate and update `lastPrices` --------------------
lastPrices = _MATH.getLastPrices(
a, gamma, xp0, xp1, invariantUnadjusted, it.priceScale
);
// ------------------------- Update `xcpProfit` ---------------------------
uint _xp0;
uint _xp1;
if (it.oldVirtualPrice != 0) {
_xp0 = Math.divUnsafeLast(invariantUnadjusted, 2);
_xp1 = Math.mulDivUnsafeFirst(1e18, invariantUnadjusted, Math.mulUnsafeFirst(2, it.priceScale));
it.virtualPrice = Math.mulDivUnsafeFirst(1e18, Math.geometricMean(_xp0, _xp1), it.totalSupply);
it.xcpProfit = Math.divUnsafeLast(xcpProfit * it.virtualPrice, it.oldVirtualPrice);
// If A and gamma are NOT undergoing ramps (t < block.timestamp),
// ensure new `virtualPrice` is not less than `oldVirtualPrice`,
// else the pool suffers a loss.
if (_futureTime < block.timestamp) {
if (it.virtualPrice <= it.oldVirtualPrice) {
revert Loss();
}
}
} else {
it.xcpProfit = 1e18;
it.virtualPrice = 1e18;
}
xcpProfit = it.xcpProfit;
// ------------ Rebalance liquidity if there's enough profits to adjust it:
//if (Math.mulUnsafeFirst(2, it.virtualPrice) - 1e18 > it.xcpProfit + unsafe_mul(_rebalancingParams.allowedExtraProfit, 2)) {
if (it.virtualPrice > 1e18 && it.xcpProfit > 1e18 && Math.mulUnsafeFirst(1e4, it.virtualPrice - 1e18) > Math.mulUnsafeFirst(_rebalancingParams.requiredProfit, it.xcpProfit + _rebalancingParams.allowedExtraProfit - 1e18)) {
// ------------------- Get adjustment step ----------------------------
// Calculate the vector distance between `priceScale` and `priceOracle`.
it.norm = Math.mulDivUnsafeFirst(1e18, it.priceOracle, it.priceScale);
if (it.norm > 1e18) {
it.norm = unsafe_sub(it.norm, 1e18);
} else {
it.norm = unsafe_sub(1e18, it.norm);
}
// Reuse `_futureTime` as `_adjustmentStep` here to avoid stake too deep errors.
_futureTime = Math.max(_rebalancingParams.adjustmentStep, Math.divUnsafeLast(it.norm, 5));
// We only adjust prices if the vector distance between `priceOracle`
// and `priceScale` is large enough.
// This check ensures that no rebalancing occurs if the distance is low
// i.e. the pool prices are pegged to the oracle prices.
if (it.norm > _futureTime) {
// ------------------------------------- Calculate new price scale.
// Reuse `_futureTime` as `newPriceScale` to avoid stake too deep errors.
_futureTime = Math.divUnsafeLast(
it.priceScale * unsafe_sub(it.norm, _futureTime) + (_futureTime * it.priceOracle),
it.norm
); // <- norm is non-zero and gt adjustment_step; unsafe = safe
// --------------- Update stale xp (using price_scale) with p_new.
_xp0 = xp0;
_xp1 = Math.mulDivUnsafeLast(xp1, _futureTime, it.priceScale);
// unsafe_div because we did safediv before -----^
// ------------------------------------------ Update D with new xp.
// Calculate "extended constant product" invariant xCP and virtual price.
it.newInvariant = _MATH.computeD(a, gamma, _xp0, _xp1, 0);
// ------------------------------------- Convert xp to real prices.
_xp0 = Math.divUnsafeLast(it.newInvariant, 2);
_xp1 = Math.mulDivUnsafeFirst(
1e18, it.newInvariant, Math.mulUnsafeFirst(2, _futureTime)
);
// ---------- Calculate new virtual price using new xp and D.
// Reuse `oldVirtualPrice` (but it has new virtual price).
it.oldVirtualPrice = Math.mulDivUnsafeFirst(
1e18, Math.geometricMean(_xp0, _xp1), it.totalSupply
);
// ---------------------------- Proceed if we've got enough profit.
if (it.oldVirtualPrice > 1e18) {
//if (Math.mulUnsafeFirst(2, it.oldVirtualPrice) - 1e18 > it.xcpProfit) { // Note - rebalancing fees
if (Math.mulUnsafeFirst(1e4, it.oldVirtualPrice - 1e18) > Math.mulUnsafeFirst(_rebalancingParams.requiredProfit, it.xcpProfit - 1e18)) {
priceScale = _futureTime; // `newPriceScale`
emit UpdatePriceScale(_futureTime);
invariantLast = it.newInvariant;
emit UpdateInvariant(it.newInvariant);
virtualPrice = it.oldVirtualPrice;
emit UpdatePoolProfit(it.xcpProfit, it.oldVirtualPrice);
return (it.newInvariant, _futureTime);
}
}
}
}
// --------- `priceScale` was not adjusted. Update the profit counter and D.
// If we are here, the `priceScale` adjustment did not happen,
// Still need to update the profit counter and D.
invariantLast = invariantUnadjusted;
emit UpdateInvariant(invariantUnadjusted);
virtualPrice = it.virtualPrice;
emit UpdatePoolProfit(it.xcpProfit, it.virtualPrice);
return (invariantUnadjusted, it.priceScale);
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
/// @dev The callback interface for SyncSwap base pool operations.
/// Note additional checks will be required for some callbacks, see below for more information.
/// Visit the documentation https://syncswap.gitbook.io/api-documentation/ for more details.
interface ICallback {
struct BaseMintCallbackParams {
address sender;
address to;
uint reserve0;
uint reserve1;
uint balance0;
uint balance1;
uint amount0;
uint amount1;
uint fee0;
uint fee1;
uint newInvariant;
uint oldInvariant;
uint totalSupply;
uint liquidity;
uint24 swapFee;
bytes callbackData;
}
function syncSwapBaseMintCallback(BaseMintCallbackParams calldata params) external;
struct BaseBurnCallbackParams {
address sender;
address to;
uint balance0;
uint balance1;
uint liquidity;
uint totalSupply;
uint amount0;
uint amount1;
uint8 withdrawMode;
bytes callbackData;
}
function syncSwapBaseBurnCallback(BaseBurnCallbackParams calldata params) external;
struct BaseBurnSingleCallbackParams {
address sender;
address to;
address tokenIn;
address tokenOut;
uint balance0;
uint balance1;
uint liquidity;
uint totalSupply;
uint amount0;
uint amount1;
uint amountOut;
uint amountSwapped;
uint feeIn;
uint24 swapFee;
uint8 withdrawMode;
bytes callbackData;
}
function syncSwapBaseBurnSingleCallback(BaseBurnSingleCallbackParams calldata params) external;
struct BaseSwapCallbackParams {
address sender;
address to;
address tokenIn;
address tokenOut;
uint reserve0;
uint reserve1;
uint balance0;
uint balance1;
uint amountIn;
uint amountOut;
uint feeIn;
uint24 swapFee;
uint8 withdrawMode;
bytes callbackData;
}
function syncSwapBaseSwapCallback(BaseSwapCallbackParams calldata params) external;
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
interface IOwnable {
function owner() external view returns (address);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
interface IWETH {
function deposit() external payable;
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function withdraw(uint) external;
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
/// @notice The manager contract to control fees.
/// Management functions are omitted.
interface IFeeManager {
function getSwapFee(
address pool,
address sender,
address tokenIn,
address tokenOut,
bytes calldata data
) external view returns (uint24);
function getProtocolFee(address pool) external view returns (uint24);
function getFeeRecipient() external view returns (address);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
import "./IFeeManager.sol";
/// @notice The manager contract to control fees.
/// Management functions are omitted.
interface IFeeManagerV2 is IFeeManager {
struct FeeData {
uint64 gamma;
uint24 minFee;
uint24 maxFee;
}
function getSwapFeeData(
address pool,
address sender,
address tokenIn,
address tokenOut,
bytes calldata data
) external view returns (FeeData memory);
function getSwapFeeHook() external view returns (address);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
interface IFeeRecipient {
/// @dev Notifies the fee recipient after sent fees.
function notifyFees(
uint16 feeType,
address token,
uint amount,
uint feeRate,
bytes calldata data
) external;
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
interface IForwarderRegistry {
function isForwarder(address forwarder) external view returns (bool);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
import "./IFeeManager.sol";
import "./IForwarderRegistry.sol";
/// @dev The master contract to create pools and manage whitelisted factories.
/// Inheriting the fee manager interface to support fee queries.
interface IPoolMaster is IFeeManager, IForwarderRegistry {
event SetFactoryWhitelisted(address indexed factory, bool whitelisted);
event RegisterPool(
address indexed factory,
address indexed pool,
uint16 indexed poolType,
bytes data
);
event UpdateForwarderRegistry(address indexed newForwarderRegistry);
event UpdateFeeManager(address indexed newFeeManager);
function wETH() external view returns (address);
function vault() external view returns (address);
function feeManager() external view returns (address);
function pools(uint) external view returns (address);
function poolsLength() external view returns (uint);
// Forwarder Registry
function setForwarderRegistry(address) external;
// Fees
function setFeeManager(address) external;
// Factories
function isFactoryWhitelisted(address) external view returns (bool);
function setFactoryWhitelisted(address factory, bool whitelisted) external;
// Pools
function isPool(address) external view returns (bool);
function getPool(bytes32) external view returns (address);
function createPool(address factory, bytes calldata data) external returns (address pool);
function registerPool(address pool, uint16 poolType, bytes calldata data, address token0, address token1) external;
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
import "./IPool.sol";
import "../token/IERC20Permit2.sol";
interface IBasePool is IPool, IERC20Permit2 {
function token0() external view returns (address);
function token1() external view returns (address);
function reserve0() external view returns (uint);
function reserve1() external view returns (uint);
function invariantLast() external view returns (uint);
function getReserves() external view returns (uint, uint);
function getAmountOut(address tokenIn, uint amountIn, address sender) external view returns (uint amountOut);
function getAmountIn(address tokenOut, uint amountOut, address sender) external view returns (uint amountIn);
event Mint(
address indexed sender,
uint amount0,
uint amount1,
uint liquidity,
address indexed to
);
event Burn(
address indexed sender,
uint amount0,
uint amount1,
uint liquidity,
address indexed to
);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(
uint reserve0,
uint reserve1
);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
import "./IBasePool.sol";
interface IBasePoolV2 is IBasePool {
function poolVersion() external view returns (uint);
function sync() external;
event MintProtocolFee(
address indexed feeRecipient,
uint24 protocolFee,
uint liquidity,
uint totalSupply
);
event Swapped(
address indexed sender,
address indexed user,
address indexed tokenOut,
uint amountIn,
uint amountOut,
uint24 swapFee,
address to
);
event Fee(
uint amount0,
uint amount1
);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
import "./IBasePoolV2.sol";
import {ICryptoMath} from "../../pool/crypto/ICryptoMath.sol";
import {IPoolFlashLoan} from "./IPoolFlashLoan.sol";
interface ICryptoPool is IBasePoolV2, IPoolFlashLoan {
//function wETH() external view returns (address); // private immutable
function factory() external view returns(address);
function token0PrecisionMultiplier() external view returns (uint);
function token1PrecisionMultiplier() external view returns (uint);
struct PoolParams {
uint32 initialA;
uint32 futureA;
uint64 initialGamma;
uint64 futureGamma;
uint32 initialTime;
/// @dev Time when ramping is finished.
/// This value is 0 (default) when pool is first deployed, and only gets
/// populated in `rampParams` when the ramping process is initiated.
/// After ramping is finished (i.e. futureParamsTime < block.timestamp),
/// the variable is left and not set to 0.
uint32 futureTime;
}
struct RebalancingParams {
uint64 allowedExtraProfit;
uint64 adjustmentStep;
uint32 maTime;
uint16 requiredProfit;
uint8 checkLastProfit;
}
function getParams() external view returns (uint a, uint gamma, uint futureTime);
function priceScale() external view returns (uint);
function cachedPriceOracle() external view returns (uint);
function lastPrices() external view returns (uint);
function lastPricesTimestamp() external view returns (uint);
function virtualPrice() external view returns (uint);
function xcpProfit() external view returns (uint);
function xcpProfitLast() external view returns (uint);
//function poolVersion() external view returns(uint);
function poolType() external view returns(uint16);
function MATH() external view returns(ICryptoMath);
function invariantLast() external view returns(uint);
//function poolParams() external view returns(PoolParams memory);
//function rebalancingParams() external view returns(RebalancingParams memory);
function calculateSingleWithdrawAmount(address _sender,uint a,uint gamma,uint liquidity,bool isToken0Out,bool updateInvariant) external view returns (uint, uint, uint, uint, uint24);
function getVirtualPrice() external view returns(uint);
//function getLiquidityPrice() external view returns (uint);
function getPriceOracle() external returns (uint);
function rampParams(uint32 _futureA, uint64 _futureGamma, uint32 _futureTime) external;
function stopRampParams() external;
function setRebalancingParams(uint64 _allowedExtraProfit, uint64 _adjustmentStep, uint32 _maTime, uint16 _requiredProfit, uint8 _checkLastProfit) external;
function claimProtocolFee() external;
function updateCryptoMath() external;
function skim(address to) external;
// Pausable.sol - removed
//function paused() external view returns (bool);
//function setPaused(bool _status) external;
//function owner() external view returns (address);
//function transferOwnership(address newOwner) external;
event RampParams(
uint currentA,
uint futureA,
uint currentGamma,
uint futureGamma,
uint currentTime,
uint futureTime
);
event StopRampParams(
uint currentA,
uint currentGamma,
uint stopTime
);
event SetRebalancingParams(
uint allowedExtraProfit,
uint adjustmentStep,
uint maTime,
uint requiredProfit,
uint checkLastProfit
);
event UpdatePoolProfit(
uint xcpProfit,
uint virtualPrice
);
event UpdateInvariant(
uint newInvariant
);
event UpdatePriceScale(
uint newPriceScale
);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
interface IPool {
struct TokenAmount {
address token;
uint amount;
}
/// @dev Returns the address of pool master.
function master() external view returns (address);
/// @dev Returns the vault.
function vault() external view returns (address);
/// @dev Returns the pool type.
function poolType() external view returns (uint16);
/// @dev Returns the assets of the pool.
function getAssets() external view returns (address[] memory assets);
/// @dev Returns the swap fee of the pool.
function getSwapFee(address sender, address tokenIn, address tokenOut, bytes calldata data) external view returns (uint24 swapFee);
/// @dev Returns the protocol fee of the pool.
function getProtocolFee() external view returns (uint24 protocolFee);
/// @dev Mints liquidity.
function mint(
bytes calldata data,
address sender,
address callback,
bytes calldata callbackData
) external returns (uint liquidity);
/// @dev Burns liquidity.
function burn(
bytes calldata data,
address sender,
address callback,
bytes calldata callbackData
) external returns (TokenAmount[] memory tokenAmounts);
/// @dev Burns liquidity with single output token.
function burnSingle(
bytes calldata data,
address sender,
address callback,
bytes calldata callbackData
) external returns (TokenAmount memory tokenAmount);
/// @dev Swaps between tokens.
function swap(
bytes calldata data,
address sender,
address callback,
bytes calldata callbackData
) external returns (TokenAmount memory tokenAmount);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
import "../vault/IERC3156FlashLender.sol";
interface IPoolFlashLoan is IERC3156FlashLender {
/**
* @dev Emitted for each individual flash loan performed by `flashLoan`.
*/
event FlashLoan(address indexed recipient, address indexed token, uint amount, uint feeAmount);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
interface IERC165 {
/// @notice Query if a contract implements an interface
/// @param interfaceID The interface identifier, as specified in ERC-165
/// @dev Interface identification is specified in ERC-165. This function
/// uses less than 30,000 gas.
/// @return `true` if the contract implements `interfaceID` and
/// `interfaceID` is not 0xffffffff, `false` otherwise
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
import "./IERC20Base.sol";
interface IERC20 is IERC20Base {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
interface IERC20Base {
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint amount) external returns (bool);
function transfer(address to, uint amount) external returns (bool);
function transferFrom(address from, address to, uint amount) external returns (bool);
event Approval(address indexed owner, address indexed spender, uint amount);
event Transfer(address indexed from, address indexed to, uint amount);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
import "./IERC20.sol";
interface IERC20Permit is IERC20 {
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
function nonces(address owner) external view returns (uint);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
import "./IERC20Permit.sol";
interface IERC20Permit2 is IERC20Permit {
function permit2(address owner, address spender, uint amount, uint deadline, bytes calldata signature) external;
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
interface IERC3156FlashBorrower {
/**
* @dev Receive a flash loan.
* @param initiator The initiator of the loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param fee The additional amount of tokens to repay.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
* @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan"
*/
function onFlashLoan(
address initiator,
address token,
uint256 amount,
uint256 fee,
bytes calldata data
) external returns (bytes32);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
import "./IERC3156FlashBorrower.sol";
interface IERC3156FlashLender {
/**
* @dev The amount of currency available to be lent.
* @param token The loan currency.
* @return The amount of `token` that can be borrowed.
*/
function maxFlashLoan(
address token
) external view returns (uint256);
/**
* @dev The fee to be charged for a given loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @return The amount of `token` to be charged for the loan, on top of the returned principal.
*/
function flashFee(
address token,
uint256 amount
) external view returns (uint256);
/**
* @dev Initiate a flash loan.
* @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
*/
function flashLoan(
IERC3156FlashBorrower receiver,
address token,
uint256 amount,
bytes calldata data
) external returns (bool);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
import "./IFlashLoanRecipient.sol";
import "./IERC3156FlashLender.sol";
interface IFlashLoan is IERC3156FlashLender {
function flashLoanFeePercentage() external view returns (uint);
/**
* @dev Performs a 'flash loan', sending tokens to `recipient`, executing the `receiveFlashLoan` hook on it,
* and then reverting unless the tokens plus a proportional protocol fee have been returned.
*
* The `tokens` and `amounts` arrays must have the same length, and each entry in these indicates the loan amount
* for each token contract. `tokens` must be sorted in ascending order.
*
* The 'userData' field is ignored by the Vault, and forwarded as-is to `recipient` as part of the
* `receiveFlashLoan` call.
*
* Emits `FlashLoan` events.
*/
function flashLoanMultiple(
IFlashLoanRecipient recipient,
address[] memory tokens,
uint[] memory amounts,
bytes memory userData
) external;
/**
* @dev Emitted for each individual flash loan performed by `flashLoan`.
*/
event FlashLoan(address indexed recipient, address indexed token, uint amount, uint feeAmount);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.7.0 <0.9.0;
// Inspired by Aave Protocol's IFlashLoanReceiver.
interface IFlashLoanRecipient {
/**
* @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient.
*
* At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this
* call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the
* Vault, or else the entire flash loan will revert.
*
* `userData` is the same value passed in the `IVault.flashLoan` call.
*/
function receiveFlashLoan(
address[] memory tokens,
uint[] memory amounts,
uint[] memory feeAmounts,
bytes memory userData
) external;
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.0;
import "./IFlashLoan.sol";
interface IVault is IFlashLoan {
function wETH() external view returns (address);
function reserves(address token) external view returns (uint reserve);
function balanceOf(address token, address owner) external view returns (uint balance);
function deposit(address token, address to) external payable returns (uint amount);
function depositETH(address to) external payable returns (uint amount);
function transferAndDeposit(address token, address to, uint amount) external payable returns (uint);
function transfer(address token, address to, uint amount) external;
function withdraw(address token, address to, uint amount) external;
function withdrawAlternative(address token, address to, uint amount, uint8 mode) external;
function withdrawETH(address to, uint amount) external;
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.0;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*
* Based on OpenZeppelin's ECDSA library.
* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/561d1061fc568f04c7a65853538e834a889751e8/contracts/utils/cryptography/ECDSA.sol
*/
library ECDSA {
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
// Check the signature length
if (signature.length != 65) {
return address(0);
}
// Divide the signature in r, s and v variables
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
// solhint-disable-next-line no-inline-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return address(0);
}
return ecrecover(hash, v, r, s);
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.0;
import "../interfaces/token/IERC165.sol";
import "../interfaces/token/IERC20Permit2.sol";
import "./SignatureChecker.sol";
error Expired();
error InvalidSignature();
/**
* @dev A simple ERC20 implementation for pool's liquidity token, supports permit by both ECDSA signatures from
* externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like Argent.
*
* Based on Solmate's ERC20.
* https://github.com/transmissions11/solmate/blob/bff24e835192470ed38bf15dbed6084c2d723ace/src/tokens/ERC20.sol
*/
contract ERC20Permit2 is IERC165, IERC20Permit2 {
uint8 public immutable override decimals = 18;
uint public override totalSupply;
mapping(address => uint) public override balanceOf;
mapping(address => mapping(address => uint)) public override allowance;
bytes32 private constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")
mapping(address => uint) public override nonces;
// These members are actually immutable as
// `_initialize` will only indent to be called once.
string public override name;
string public override symbol;
uint private INITIAL_CHAIN_ID;
bytes32 private INITIAL_DOMAIN_SEPARATOR;
function _initialize(string memory _name, string memory _symbol) internal {
name = _name;
symbol = _symbol;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator();
}
function supportsInterface(bytes4 interfaceID) external pure override returns (bool) {
return
interfaceID == this.supportsInterface.selector || // ERC-165
interfaceID == this.permit.selector || // ERC-2612
interfaceID == this.permit2.selector; // Permit2
}
function DOMAIN_SEPARATOR() public view override returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : _computeDomainSeparator();
}
function _computeDomainSeparator() private view returns (bytes32) {
return keccak256(
abi.encode(
// keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f,
keccak256(bytes(name)),
// keccak256(bytes("1"))
0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6,
block.chainid,
address(this)
)
);
}
function _approve(address _owner, address _spender, uint _amount) private {
allowance[_owner][_spender] = _amount;
emit Approval(_owner, _spender, _amount);
}
function approve(address _spender, uint _amount) public override returns (bool) {
_approve(msg.sender, _spender, _amount);
return true;
}
function transfer(address _to, uint _amount) public override returns (bool) {
balanceOf[msg.sender] -= _amount;
// Cannot overflow because the sum of all user balances can't exceed the max uint256 value.
unchecked {
balanceOf[_to] += _amount;
}
emit Transfer(msg.sender, _to, _amount);
return true;
}
function transferFrom(address _from, address _to, uint _amount) public override returns (bool) {
uint256 _allowed = allowance[_from][msg.sender]; // Saves gas for limited approvals.
if (_allowed != type(uint).max) {
allowance[_from][msg.sender] = _allowed - _amount;
}
balanceOf[_from] -= _amount;
// Cannot overflow because the sum of all user balances can't exceed the max uint256 value.
unchecked {
balanceOf[_to] += _amount;
}
emit Transfer(_from, _to, _amount);
return true;
}
function _mint(address _to, uint _amount) internal {
totalSupply += _amount;
// Cannot overflow because the sum of all user balances can't exceed the max uint256 value.
unchecked {
balanceOf[_to] += _amount;
}
emit Transfer(address(0), _to, _amount);
}
function _burn(address _from, uint _amount) internal {
balanceOf[_from] -= _amount;
// Cannot underflow because a user's balance will never be larger than the total supply.
unchecked {
totalSupply -= _amount;
}
emit Transfer(_from, address(0), _amount);
}
modifier ensures(uint _deadline) {
// solhint-disable-next-line not-rely-on-time
if (block.timestamp > _deadline) {
revert Expired();
}
_;
}
function _permitHash(
address _owner,
address _spender,
uint _amount,
uint _deadline
) private returns (bytes32) {
return keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(abi.encode(PERMIT_TYPEHASH, _owner, _spender, _amount, nonces[_owner]++, _deadline))
)
);
}
function permit(
address _owner,
address _spender,
uint _amount,
uint _deadline,
uint8 _v,
bytes32 _r,
bytes32 _s
) public override ensures(_deadline) {
bytes32 _hash = _permitHash(_owner, _spender, _amount, _deadline);
address _recoveredAddress = ecrecover(_hash, _v, _r, _s);
if (_recoveredAddress != _owner) {
revert InvalidSignature();
}
if (_recoveredAddress == address(0)) {
revert InvalidSignature();
}
_approve(_owner, _spender, _amount);
}
function permit2(
address _owner,
address _spender,
uint _amount,
uint _deadline,
bytes calldata _signature
) public override ensures(_deadline) {
bytes32 _hash = _permitHash(_owner, _spender, _amount, _deadline);
if (!SignatureChecker.isValidSignatureNow(_owner, _hash, _signature)) {
revert InvalidSignature();
}
_approve(_owner, _spender, _amount);
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.0;
/// @dev Math functions.
/// @dev Modified from Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library Math {
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function sqrtInt(uint256 x) internal pure returns (uint256) {
if (x == 0) {
return 0;
}
uint z = (x + 1e18) / 2;
uint y = x;
for (uint i; i < 256; ) {
if (z == y) {
return y;
}
y = z;
z = (x * 1e18 / z + z) / 2;
unchecked {
++i;
}
}
revert();
}
function geometricMean(uint a, uint b) internal pure returns (uint) {
return Math.sqrt(a * b);
}
/// @notice Compares a and b and returns 'true' if the difference between a and b
/// is less than 1 or equal to each other.
/// @param a uint256 to compare with.
/// @param b uint256 to compare with.
function within1(uint256 a, uint256 b) internal pure returns (bool) {
unchecked {
if (a > b) {
return a - b <= 1;
}
return b - a <= 1;
}
}
/// @dev Returns the square root of `x`.
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// Let `y = x / 2**r`.
// We check `y >= 2**(k + 8)` but shift right by `k` bits
// each branch to ensure that if `x >= 256`, then `y >= 256`.
let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffffff, shr(r, x))))
z := shl(shr(1, r), z)
// Goal was to get `z*z*y` within a small factor of `x`. More iterations could
// get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
// We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
// That's not possible if `x < 256` but we can just verify those cases exhaustively.
// Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
// Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
// Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.
// For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
// is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
// with largest error when `s = 1` and when `s = 256` or `1/256`.
// Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
// Then we can estimate `sqrt(y)` using
// `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.
// There is no overflow risk here since `y < 2**136` after the first branch above.
z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If `x+1` is a perfect square, the Babylonian method cycles between
// `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
// Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
// If you don't care whether the floor or ceil square root is returned, you can remove this statement.
z := sub(z, lt(div(x, z), z))
}
}
// Mul Div
/// @dev Rounded down.
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
assembly {
// Store x * y in z for now.
z := mul(x, y)
// Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
revert(0, 0)
}
// Divide z by the denominator.
z := div(z, denominator)
}
}
/// @dev Rounded down.
/// This function assumes that `x` is not zero, and must be checked externally.
/// Reverts if x is zero.
function mulDivUnsafeFirst(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
assembly {
// Store x * y in z for now.
z := mul(x, y)
// Equivalent to require(denominator != 0 && (x * y) / x == y)
if iszero(and(iszero(iszero(denominator)), eq(div(z, x), y))) {
revert(0, 0)
}
// Divide z by the denominator.
z := div(z, denominator)
}
}
/// @dev Rounded down.
/// This function assumes that `denominator` is not zero, and must be checked externally.
/// This allows x to be zero.
function mulDivUnsafeLast(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
assembly {
// Store x * y in z for now.
z := mul(x, y)
// Equivalent to require(x == 0 || (x * y) / x == y)
if iszero(or(iszero(x), eq(div(z, x), y))) {
revert(0, 0)
}
// Divide z by the denominator.
z := div(z, denominator)
}
}
/// @dev Rounded down.
/// This function assumes that both `x` and `denominator` are not zero, and must be checked externally.
/// Reverts if x is zero.
function mulDivUnsafeFirstLast(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
assembly {
// Store x * y in z for now.
z := mul(x, y)
// Equivalent to require((x * y) / x == y)
if iszero(eq(div(z, x), y)) {
revert(0, 0)
}
// Divide z by the denominator.
z := div(z, denominator)
}
}
// Mul
/// @dev Optimized safe multiplication operation for minimal gas cost.
/// Equivalent to *
function mul(
uint256 x,
uint256 y
) internal pure returns (uint256 z) {
assembly {
// Store x * y in z for now.
z := mul(x, y)
// Equivalent to require(x == 0 || (x * y) / x == y)
if iszero(or(iszero(x), eq(div(z, x), y))) {
revert(0, 0)
}
}
}
/// @dev Optimized unsafe multiplication operation for minimal gas cost.
/// This function assumes that `x` is not zero, and must be checked externally.
/// Reverts if x is zero.
function mulUnsafeFirst(
uint256 x,
uint256 y
) internal pure returns (uint256 z) {
assembly {
// Store x * y in z for now.
z := mul(x, y)
// Equivalent to require((x * y) / x == y)
if iszero(eq(div(z, x), y)) {
revert(0, 0)
}
}
}
function mulUnsafe(
uint256 x,
uint256 y
) internal pure returns (uint256 z) {
assembly {
// Store x * y in z for now.
z := mul(x, y)
}
}
// Div
/// @dev Optimized safe division operation for minimal gas cost.
/// Equivalent to /
function div(
uint256 x,
uint256 y
) internal pure returns (uint256 z) {
assembly {
// Store x / y in z for now.
z := div(x, y)
// Equivalent to require(y != 0)
if iszero(y) {
revert(0, 0)
}
}
}
/// @dev Optimized unsafe division operation for minimal gas cost.
/// Division by 0 will not reverts and returns 0, and must be checked externally.
function divUnsafeLast(
uint256 x,
uint256 y
) internal pure returns (uint256 z) {
assembly {
z := div(x, y)
}
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.0;
library MetadataHelper {
/**
* @dev Returns symbol of the token.
*
* @param token The address of a ERC20 token.
*
* Return boolean indicating the status and the symbol as string;
*
* NOTE: Symbol is not the standard interface and some tokens may not support it.
* Calling against these tokens will not success, with an empty result.
*/
function getSymbol(address token) internal view returns (bool, string memory) {
// bytes4(keccak256(bytes("symbol()")))
(bool success, bytes memory returndata) = token.staticcall(abi.encodeWithSelector(0x95d89b41));
if (success) {
return (true, abi.decode(returndata, (string)));
} else {
return (false, "");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
/// @dev Public to allow external contracts to read the status.
uint256 public reentrantStatus = 1;
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(reentrantStatus == 1);
// Any calls to nonReentrant after this point will fail
reentrantStatus = 2;
_;
reentrantStatus = 1;
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.0;
import "./ECDSA.sol";
/**
* @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
* signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
* Argent and Gnosis Safe.
*
* Based on OpenZeppelin's SignatureChecker library.
* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/561d1061fc568f04c7a65853538e834a889751e8/contracts/utils/cryptography/SignatureChecker.sol
*/
library SignatureChecker {
bytes4 constant internal MAGICVALUE = 0x1626ba7e; // bytes4(keccak256("isValidSignature(bytes32,bytes)")
/**
* @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
* signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidSignatureNow(
address signer,
bytes32 hash,
bytes memory signature
) internal view returns (bool) {
(address recovered) = ECDSA.recover(hash, signature);
if (recovered == signer) {
if (recovered != address(0)) {
return true;
}
}
(bool success, bytes memory result) = signer.staticcall(
abi.encodeWithSelector(MAGICVALUE, hash, signature)
);
return (
success &&
result.length == 32 &&
abi.decode(result, (bytes32)) == bytes32(MAGICVALUE)
);
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.0;
/// @dev The ETH transfer has failed.
error ETHTransferFailed();
/// @dev The ERC20 `transferFrom` has failed.
error TransferFromFailed();
/// @dev The ERC20 `transfer` has failed.
error TransferFailed();
/// @dev The ERC20 `approve` has failed.
error ApproveFailed();
/// @dev Helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true / false.
library TransferHelper {
function safeApprove(
address token,
address to,
uint value
) internal {
// bytes4(keccak256(bytes("approve(address,uint256)")));
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
if (!success || (data.length != 0 && !abi.decode(data, (bool)))) {
revert ApproveFailed();
}
}
function safeTransfer(
address token,
address to,
uint value
) internal {
// bytes4(keccak256(bytes("transfer(address,uint256)")));
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
if (!success || (data.length != 0 && !abi.decode(data, (bool)))) {
revert TransferFailed();
}
}
function safeTransferFrom(
address token,
address from,
address to,
uint value
) internal {
// bytes4(keccak256(bytes("transferFrom(address,address,uint256)")));
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
if (!success || (data.length != 0 && !abi.decode(data, (bool)))) {
revert TransferFromFailed();
}
}
function safeTransferETH(address to, uint value) internal {
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = to.call{value: value}("");
if (!success) {
revert ETHTransferFailed();
}
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.0;
/// @dev Unchecked math functions.
contract UnsafeMath {
function unsafe_div(uint x, uint y) internal pure returns (uint z) {
assembly {
z := div(x, y)
}
}
function unsafe_mul(uint a, uint b) internal pure returns (uint) {
unchecked {
return a * b;
}
}
function unsafe_sub(uint a, uint b) internal pure returns (uint) {
unchecked {
return a - b;
}
}
function unsafe_add(uint a, uint b) internal pure returns (uint) {
unchecked {
return a + b;
}
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.0;
interface ICryptoMath {
function getY(
uint a,
uint gamma,
uint x0,
uint x1,
uint d,
uint i
) external view returns (uint y, uint k0_prev);
function computeD(
uint a,
uint gamma,
uint xp0,
uint xp1,
uint k0_prev
) external view returns (uint);
function getLastPrices(
uint a,
uint gamma,
uint xp0,
uint xp1,
uint d,
uint priceScale
) external view returns (uint);
function getPriceOracle(
uint lastTimestamp,
uint maTime,
uint lastPrices,
uint priceScale,
uint priceOracle
) external view returns (uint);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.0;
interface ICryptoView {
function getAmountOut(
address pool,
address tokenIn,
uint amountIn,
address sender,
bytes memory feeData
) external view returns (uint);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import "../interfaces/token/IERC20.sol";
import "../interfaces/master/IFeeRecipient.sol";
import "../interfaces/master/IPoolMaster.sol";
import "../interfaces/pool/IPoolFlashLoan.sol";
import "../libraries/ReentrancyGuard.sol";
import "../libraries/TransferHelper.sol";
/**
* @dev Handles Flash Loans through the Pool.
*/
abstract contract PoolFlashLoans is IPoolFlashLoan, ReentrancyGuard {
uint private constant FLASH_LOAN_FEE = 5e15; // 0.5%
bytes32 private constant ERC3156_CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
/**
* @dev Returns the protocol fee amount to charge for a flash loan of `amount`.
*/
function _calculateFlashLoanFeeAmount(uint amount) private pure returns (uint) {
return amount * FLASH_LOAN_FEE / 1e18;
}
function _payFeeAmount(address token, uint amount) private {
if (amount != 0) {
address _feeRecipient = _getFeeRecipient();
if (_feeRecipient != address(0)) {
TransferHelper.safeTransfer(token, _feeRecipient, amount);
IFeeRecipient(_feeRecipient).notifyFees(10, token, amount, FLASH_LOAN_FEE, abi.encode(2));
}
}
}
function _getFeeRecipient() internal virtual view returns (address) {}
// EIP-3156 Implementations
/**
* @dev The amount of currency available to be lent.
* @param token The loan currency.
* @return The amount of `token` that can be borrowed.
*/
function maxFlashLoan(address token) external view override returns (uint256) {
return IERC20(token).balanceOf(address(this));
}
/**
* @dev The fee to be charged for a given loan.
* @param amount The amount of tokens lent.
* @return The amount of `token` to be charged for the loan, on top of the returned principal.
*/
function flashFee(address /*token*/, uint256 amount) external pure override returns (uint256) {
return _calculateFlashLoanFeeAmount(amount);
}
/**
* @dev Initiate a flash loan.
* @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param userData Arbitrary data structure, intended to contain user-defined parameters.
*/
function flashLoan(
IERC3156FlashBorrower receiver,
address token,
uint amount,
bytes memory userData
) external override nonReentrant returns (bool) {
uint preLoanBalance = IERC20(token).balanceOf(address(this));
uint feeAmount = _calculateFlashLoanFeeAmount(amount);
require(preLoanBalance >= amount, "INSUFFICIENT_FLASH_LOAN_BALANCE");
TransferHelper.safeTransfer(token, address(receiver), amount);
require(
receiver.onFlashLoan(msg.sender, token, amount, feeAmount, userData) == ERC3156_CALLBACK_SUCCESS,
"IERC3156_CALLBACK_FAILED"
);
// Checking for loan repayment first (without accounting for fees) makes for simpler debugging, and results
// in more accurate revert reasons if the flash loan protocol fee percentage is zero.
uint postLoanBalance = IERC20(token).balanceOf(address(this));
require(postLoanBalance >= preLoanBalance, "INVALID_POST_LOAN_BALANCE");
// No need for checked arithmetic since we know the loan was fully repaid.
uint receivedFeeAmount = postLoanBalance - preLoanBalance;
require(receivedFeeAmount >= feeAmount, "INSUFFICIENT_FLASH_LOAN_FEE_AMOUNT");
_payFeeAmount(token, receivedFeeAmount);
emit FlashLoan(address(receiver), token, amount, receivedFeeAmount);
return true;
}
}{
"viaIR": false,
"optimizer": {
"enabled": true,
"runs": 200,
"details": {
"yul": false
}
},
"evmVersion": "paris",
"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"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"Expired","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"Loss","type":"error"},{"inputs":[],"name":"Overflow","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"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":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Fee","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":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"uint24","name":"swapFee","type":"uint24"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"Swapped","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newInvariant","type":"uint256"}],"name":"UpdateInvariant","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"xcpProfit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"virtualPrice","type":"uint256"}],"name":"UpdatePoolProfit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newPriceScale","type":"uint256"}],"name":"UpdatePriceScale","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MATH","outputs":[{"internalType":"contract ICryptoMath","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"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":"cachedPriceOracle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint256","name":"_reserve0","type":"uint256"},{"internalType":"uint256","name":"_reserve1","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"invariantLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPrices","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPricesTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"master","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_amount","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":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"permit2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"poolParams","outputs":[{"internalType":"uint32","name":"initialA","type":"uint32"},{"internalType":"uint32","name":"futureA","type":"uint32"},{"internalType":"uint64","name":"initialGamma","type":"uint64"},{"internalType":"uint64","name":"futureGamma","type":"uint64"},{"internalType":"uint32","name":"initialTime","type":"uint32"},{"internalType":"uint32","name":"futureTime","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolType","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceScale","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalancingParams","outputs":[{"internalType":"uint64","name":"allowedExtraProfit","type":"uint64"},{"internalType":"uint64","name":"adjustmentStep","type":"uint64"},{"internalType":"uint32","name":"maTime","type":"uint32"},{"internalType":"uint16","name":"requiredProfit","type":"uint16"},{"internalType":"uint8","name":"checkLastProfit","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reentrantStatus","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_callback","type":"address"},{"internalType":"bytes","name":"_callbackData","type":"bytes"}],"name":"swap","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct SyncSwapCryptoPoolDelegated.TokenAmount","name":"_tokenAmount","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token0PrecisionMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token1PrecisionMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"virtualPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"xcpProfit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"xcpProfitLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60126080526001600855600980546001600160a01b031990811673530000000000000000000000000000000000000417909155600a80548216737160570bb153edd0ea1775ec2b2ac9b65f1ab61b179055600b8054909116734318a74425e5353a1194cf26138baa87b607657c179055670de0b6b3a76400006015556102206040526501d1a94a2000610180526584c9462320006101a0526102586101c0526113886101e052600061020052601780546001600160b81b03191675138800000258000084c946232000000001d1a94a2000179055348015620000e057600080fd5b506000336001600160a01b031663d039f6226040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000122573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200014c919081019062000758565b90506000806000806000858060200190518101906200016c9190620007e6565b94509450945094509450336001600160a01b03166347f8e8c66040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001b5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001db91906200086a565b600c80546001600160a01b0319166001600160a01b03929092169190911790553360e0819052604080516343cad16f60e01b815290516343cad16f916004808201926020929091908290030181865afa1580156200023d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200026391906200086a565b6001600160a01b031660a052604080516354a52d0b60e11b81529051339163a94a5a169160048083019260209291908290030181865afa158015620002ac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002d291906200086a565b6001600160a01b0390811660c0908152610160849052610140859052858216610120529086166101005260408051918201815262061a80808352602083018190526583e0717e10009183018290526060830182905260006080840181905260a0909301929092527583e0717e1000000083e0717e100000061a8000061a806016556200035e8362000443565b6000806200036c8962000490565b90925090506000806200037f8a62000490565b915091508380156200038e5750815b15620003e957620003e3604051602001620003a9906200088f565b6040516020818303038152906040528483604051602001620003cd929190620008d6565b60408051601f1981840301815291905262000568565b62000431565b62000431604051806040016040528060038152602001620534c560ec1b815250604051806040016040528060038152602001620534c560ec1b8152506200056860201b60201c565b50505050505050505050505062000bf9565b600f8190556040517fcb12ab4101e9e15b90a22516ca404e94b85586dbdcf7d0792ab8da11206e61b6906200047a90839062000918565b60405180910390a1601081905560115542601255565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b1790529051600091606091839182916001600160a01b03871691620004da9162000928565b600060405180830381855afa9150503d806000811462000517576040519150601f19603f3d011682016040523d82523d6000602084013e6200051c565b606091505b509150915081156200054b5760018180602001905181019062000540919062000758565b935093505050915091565b600060405180602001604052806000815250935093505050915091565b600462000576838262000a35565b50600562000585828262000a35565b5046600655620005946200059b565b6007555050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6004604051620005cf919062000b7f565b6040519081900381206200060d92917fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6904690309060200162000ba3565b60405160208183030381529060405280519060200120905090565b634e487b7160e01b600052604160045260246000fd5b601f19601f83011681018181106001600160401b038211171562000666576200066662000628565b6040525050565b60006200067960405190565b90506200068782826200063e565b919050565b60006001600160401b03821115620006a857620006a862000628565b601f19601f83011660200192915050565b60005b83811015620006d6578181015183820152602001620006bc565b50506000910152565b6000620006f6620006f0846200068c565b6200066d565b905082815260208101848484011115620007135762000713600080fd5b62000720848285620006b9565b509392505050565b600082601f8301126200073e576200073e600080fd5b815162000750848260208601620006df565b949350505050565b6000602082840312156200076f576200076f600080fd5b81516001600160401b038111156200078a576200078a600080fd5b620007508482850162000728565b60006001600160a01b0382165b92915050565b620007b68162000798565b8114620007c257600080fd5b50565b8051620007a581620007ab565b80620007b6565b8051620007a581620007d2565b600080600080600060a08688031215620008035762000803600080fd5b6000620008118888620007c5565b95505060206200082488828901620007c5565b94505060406200083788828901620007d9565b93505060606200084a88828901620007d9565b92505060806200085d88828901620007d9565b9150509295509295909350565b600060208284031215620008815762000881600080fd5b6000620007508484620007c5565b6f053796e63537761702041717561204c560841b8152600060108201620007a5565b6000620008bc825190565b620008cc818560208601620006b9565b9290920192915050565b6000620008e48285620008b1565b602f60f81b81526001019150620008fc8284620008b1565b612d4160f01b815291506002820162000750565b805b82525050565b60208101620007a5828462000910565b6000620009368284620008b1565b9392505050565b634e487b7160e01b600052602260045260246000fd5b6002810460018216806200096857607f821691505b6020821081036200097d576200097d6200093d565b50919050565b6000620007a5620009918381565b90565b6200099f8362000983565b815460001960089490940293841b1916921b91909117905550565b6000620009c981848462000994565b505050565b81811015620009ed57620009e4600082620009ba565b600101620009ce565b5050565b601f821115620009c9576000818152602090206020601f8501048101602085101562000a1a5750805b62000a2e6020601f860104830182620009ce565b5050505050565b81516001600160401b0381111562000a515762000a5162000628565b62000a5d825462000953565b62000a6a828285620009f1565b6020601f83116001811462000aa1576000841562000a885750858201515b600019600886021c198116600286021786555062000afd565b600085815260208120601f198616915b8281101562000ad3578885015182556020948501946001909201910162000ab1565b8683101562000af05784890151600019601f89166008021c191682555b6001600288020188555050505b505050505050565b6000815462000b148162000953565b60018216801562000b2e576001811462000b445762000b76565b60ff198316865281151582028601935062000b76565b60008581526020902060005b8381101562000b6e5781548882015260019091019060200162000b50565b838801955050505b50505092915050565b600062000936828462000b05565b620009128162000983565b620009128162000798565b60a0810162000bb3828862000b8d565b62000bc2602083018762000910565b62000bd1604083018662000b8d565b62000be0606083018562000910565b62000bef608083018462000b98565b9695505050505050565b60805160a05160c05160e05161010051610120516101405161016051613ca162000cc86000396000818161056c01526119e40152600081816106d6015281816119ab01528181611a4a01528181611dc60152611e6f0152600081816107a101528181610da301528181610e9a0152818161172001528181611c7e0152611df00152600081816103fd01528181610cf701528181610f5e0152818161167b01528181611c5d0152611e120152600061076d015260006102d801526000610227015260006105000152613ca16000f3fe60806040526004361061021e5760003560e01c806391e4bb3411610123578063d21220a7116100ab578063e3bba7161161006f578063e3bba71614610846578063e7231d241461085c578063ed6c154614610872578063ee97f7f31461089f578063fbfa77cf146108bf57610225565b8063d21220a71461078f578063d505accf146107c3578063d6ea073d146107e3578063da815731146107f9578063dd62ed3e1461080e57610225565b8063a9059cbb116100f2578063a9059cbb14610682578063b1dd61b6146106a2578063baa8c7cb146106c4578063bc4041db146106f8578063c45a01551461075b57610225565b806391e4bb341461062b57806395d89b411461064157806396e591a614610656578063a0fbddaf1461066c57610225565b80632c0198cc116101a65780634e25dc47116101755780634e25dc471461055a57806370a082311461058e5780637132bb7f146105bb5780637ecebe00146105e85780638ea875f31461061557610225565b80632c0198cc146104ce578063313ce567146104ee5780633644e5151461052f578063370a48671461054457610225565b8063095ea7b3116101ed578063095ea7b3146103cb5780630dfe1681146103eb57806318160ddd1461042c57806319706b381461044257806323b872dd146104ae57610225565b806301ffc9a71461031e57806306fdde031461035457806307f293f7146103765780630902f1ac1461039957610225565b3661022557005b7f000000000000000000000000000000000000000000000000000000000000000063f66eab5b60e01b6001600160e01b031960003516148061027957506313d85e7560e11b6001600160e01b031960003516145b806102965750631f2f232f60e11b6001600160e01b031960003516145b806102b3575063712d52fd60e11b6001600160e01b031960003516145b806102d05750631f94a27560e31b6001600160e01b031960003516145b156102f857507f00000000000000000000000000000000000000000000000000000000000000005b3660008037600080366000845af43d6000803e808015610317573d6000f35b3d6000fd5b005b34801561032a57600080fd5b5061033e610339366004612dc7565b6108df565b60405161034b9190612df2565b60405180910390f35b34801561036057600080fd5b50610369610931565b60405161034b9190612e56565b34801561038257600080fd5b5061038c600e5481565b60405161034b9190612e6d565b3480156103a557600080fd5b50600d546001600160801b0380821691600160801b90041660405161034b929190612e7b565b3480156103d757600080fd5b5061033e6103e6366004612ecc565b6109bf565b3480156103f757600080fd5b5061041f7f000000000000000000000000000000000000000000000000000000000000000081565b60405161034b9190612f12565b34801561043857600080fd5b5061038c60005481565b34801561044e57600080fd5b5060165461049c9063ffffffff8082169164010000000081048216916001600160401b03600160401b8304811692600160801b810490911691600160c01b8204811691600160e01b90041686565b60405161034b96959493929190612f3b565b3480156104ba57600080fd5b5061033e6104c9366004612f8a565b6109d5565b3480156104da57600080fd5b5061031c6104e936600461302b565b610ac7565b3480156104fa57600080fd5b506105227f000000000000000000000000000000000000000000000000000000000000000081565b60405161034b91906130c9565b34801561053b57600080fd5b5061038c610b6c565b34801561055057600080fd5b5061038c60145481565b34801561056657600080fd5b5061038c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561059a57600080fd5b5061038c6105a93660046130d7565b60016020526000908152604090205481565b3480156105c757600080fd5b506105db6105d63660046131f1565b610b8b565b60405161034b91906132ac565b3480156105f457600080fd5b5061038c6106033660046130d7565b60036020526000908152604090205481565b34801561062157600080fd5b5061038c60135481565b34801561063757600080fd5b5061038c60125481565b34801561064d57600080fd5b50610369611216565b34801561066257600080fd5b5061038c60155481565b34801561067857600080fd5b5061038c600f5481565b34801561068e57600080fd5b5061033e61069d366004612ecc565b611223565b3480156106ae57600080fd5b506106b7600381565b60405161034b91906132c4565b3480156106d057600080fd5b5061038c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561070457600080fd5b5060175461074a906001600160401b0380821691600160401b810490911690600160801b810463ffffffff1690600160a01b810461ffff1690600160b01b900460ff1685565b60405161034b9594939291906132d2565b34801561076757600080fd5b5061041f7f000000000000000000000000000000000000000000000000000000000000000081565b34801561079b57600080fd5b5061041f7f000000000000000000000000000000000000000000000000000000000000000081565b3480156107cf57600080fd5b5061031c6107de366004613328565b6112aa565b3480156107ef57600080fd5b5061038c60085481565b34801561080557600080fd5b5061038c600281565b34801561081a57600080fd5b5061038c6108293660046133c7565b600260209081526000928352604080842090915290825290205481565b34801561085257600080fd5b5061038c60115481565b34801561086857600080fd5b5061038c60105481565b34801561087e57600080fd5b50600c54610892906001600160a01b031681565b60405161034b919061343c565b3480156108ab57600080fd5b50600b5461041f906001600160a01b031681565b3480156108cb57600080fd5b50600a5461041f906001600160a01b031681565b60006001600160e01b031982166301ffc9a760e01b148061091057506001600160e01b0319821663d505accf60e01b145b8061092b57506001600160e01b03198216630b00663360e21b145b92915050565b6004805461093e90613460565b80601f016020809104026020016040519081016040528092919081815260200182805461096a90613460565b80156109b75780601f1061098c576101008083540402835291602001916109b7565b820191906000526020600020905b81548152906001019060200180831161099a57829003601f168201915b505050505081565b60006109cc33848461139f565b50600192915050565b6001600160a01b03831660009081526002602090815260408083203384529091528120546000198114610a3157610a0c83826134a2565b6001600160a01b03861660009081526002602090815260408083203384529091529020555b6001600160a01b03851660009081526001602052604081208054859290610a599084906134a2565b90915550506001600160a01b03808516600081815260016020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610ab2908790612e6d565b60405180910390a360019150505b9392505050565b8280421115610ae957604051630407b05b60e31b815260040160405180910390fd5b6000610af788888888611407565b9050610b3a888286868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506114c192505050565b610b5757604051638baa579f60e01b815260040160405180910390fd5b610b6288888861139f565b5050505050505050565b60006006544614610b8457610b7f6115ed565b905090565b5060075490565b6040805180820190915260008082526020820152600854600114610bae57600080fd5b6002600881905550610c54604051806101c0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600062ffffff168152602001600060ff168152602001606081525090565b85806020019051810190610c6891906134cb565b60ff166101808401526001600160a01b039081166020840152166040820152600d546001600160801b03600160801b8204811660a0840152166080820152610cae611676565b60e083015260c0820152610cc18561179c565b94506000806000610cd061183b565b600c54604088015193965091945092506000918291829182916001600160a01b03908116917f00000000000000000000000000000000000000000000000000000000000000008216911603610e9857610d846040518061012001604052808f6001600160a01b031681526020018a81526020018981526020018b60c0015181526020018b60e0015181526020018b6080015181526020018b60a001518152602001600115158152602001888152508261196e565b62ffffff9094166101608f01526101208e018590526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660608f015260e08e018051929a50909850929650909450610de59083906134a2565b905250608089015160c08a0151610dfc91906134a2565b6101008a0181905260208a01516101208b01516040516001600160a01b039092169233927fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d82292610e5192916000918291613526565b60405180910390a37fa6205f24a082c01e6c705e20c1a026c246eedf9800b87b84440f05e8271aaf27600083604051610e8b929190613564565b60405180910390a1611051565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031689604001516001600160a01b031614610eda57600080fd5b610f3f6040518061012001604052808f6001600160a01b031681526020018a81526020018981526020018b60c0015181526020018b60e0015181526020018b6080015181526020018b60a001518152602001600015158152602001888152508261196e565b62ffffff9094166101608f01526101208e018590526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660608f015260c08e018051929a50909850929650909450610fa09083906134a2565b90525060a089015160e08a0151610fb791906134a2565b6101008a0181905260208a01516101208b01516040516001600160a01b039092169233927fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229261100e926000929091908390613572565b60405180910390a37fa6205f24a082c01e6c705e20c1a026c246eedf9800b87b84440f05e8271aaf278260006040516110489291906135a7565b60405180910390a15b61010089015115801590611069575061012089015115155b61107257600080fd5b6110838888878760008b8988611ea7565b50506110978960c001518a60e001516125fa565b6110b589606001518a602001518b61012001518c61018001516126b3565b6001600160a01b038c161561115c576001600160a01b038d1689526101a089018b90526101008901516101608a01516110f7919062ffffff16620186a06127f8565b6101408a015260405163608dbcbb60e01b81526001600160a01b038d169063608dbcbb90611129908c906004016136ea565b600060405180830381600087803b15801561114357600080fd5b505af1158015611157573d6000803e3d6000fd5b505050505b88606001518a600001906001600160a01b031690816001600160a01b0316815250508861012001518a602001818152505088606001516001600160a01b03168d6001600160a01b0316336001600160a01b03167faa077b6dc26efdfd606d4340c04a5a222ff968ec199f0b184f4c0f7a5c8e8d718c61010001518d61012001518e61016001518f602001516040516111f794939291906136fb565b60405180910390a45050600160085550959a9950505050505050505050565b6005805461093e90613460565b336000908152600160205260408120805483919083906112449084906134a2565b90915550506001600160a01b038316600081815260016020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611299908690612e6d565b60405180910390a350600192915050565b83804211156112cc57604051630407b05b60e31b815260040160405180910390fd5b60006112da89898989611407565b90506000600182878787604051600081526020016040526040516113019493929190613730565b6020604051602081039080840390855afa158015611323573d6000803e3d6000fd5b505050602060405103519050896001600160a01b0316816001600160a01b03161461136157604051638baa579f60e01b815260040160405180910390fd5b6001600160a01b03811661138857604051638baa579f60e01b815260040160405180910390fd5b6113938a8a8a61139f565b50505050505050505050565b6001600160a01b0380841660008181526002602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906113fa908590612e6d565b60405180910390a3505050565b6000611411610b6c565b6001600160a01b038616600090815260036020526040812080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c99289928992899290919061145f83613758565b919050558760405160200161147996959493929190613772565b604051602081830303815290604052805190602001206040516020016114a09291906137c1565b6040516020818303038152906040528051906020012090505b949350505050565b6000806114ce8484612810565b9050846001600160a01b0316816001600160a01b031603611502576001600160a01b03811615611502576001915050610ac0565b600080866001600160a01b0316631626ba7e60e01b878760405160240161152a9291906137f2565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516115689190613834565b600060405180830381855afa9150503d80600081146115a3576040519150601f19603f3d011682016040523d82523d6000602084013e6115a8565b606091505b50915091508180156115bb575080516020145b80156115e257508051630b135d3f60e11b906115e0908301602090810190840161384b565b145b979650505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600460405161161f91906138de565b60405190819003812061165b92917fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc690469030906020016138ea565b60405160208183030381529060405280519060200120905090565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016116c59190612f12565b602060405180830381865afa1580156116e2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611706919061384b565b6040516370a0823160e01b81529092506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190611755903090600401612f12565b602060405180830381865afa158015611772573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611796919061384b565b90509091565b60006001600160a01b038216331461183457600b54604051632af3bd5560e21b81526001600160a01b039091169063abcef554906117de903390600401612f12565b602060405180830381865afa925050508015611817575060408051601f3d908101601f191682019092526118149181019061393f565b60015b611822575033919050565b8061182d5733610ac0565b5090919050565b5033919050565b6040805160c08101825260165463ffffffff808216835264010000000082048116602084018190526001600160401b03600160401b8404811695850195909552600160801b830490941660608401819052600160c01b830482166080850152600160e01b9092041660a08301819052909142821115611968576000816080015163ffffffff16836118cc91906134a2565b90506000826080015163ffffffff16426118e691906134a2565b905060006118f482846134a2565b9050826119018389613960565b855161191490849063ffffffff16613960565b61191e919061397f565b61192891906139a8565b9650826119358388613960565b8286604001516001600160401b031661194e9190613960565b611958919061397f565b61196291906139a8565b95505050505b50909192565b6000806000806000806119a96040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b7f000000000000000000000000000000000000000000000000000000000000000089606001516119d99190613960565b8152600f54611a09907f000000000000000000000000000000000000000000000000000000000000000090613960565b6060820181905260808a0151611a2791670de0b6b3a76400006128c3565b6020820152610100890151421015611b63578860e0015115611afb5760a08901517f000000000000000000000000000000000000000000000000000000000000000002608082018190526020808b01516040808d0151928501519051636ca4fd9160e11b81526001600160a01b038d169463d949fb2294611ab0949390926000906004016139bc565b602060405180830381865afa158015611acd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af1919061384b565b6040820152611b6c565b611b1d611b0f8a60c0015183606001510290565b670de0b6b3a7640000900490565b6080820181905260208a01516040808c015184519151636ca4fd9160e11b81526001600160a01b038d169463d949fb2294611ab0949093929091906000906004016139bc565b600e5460408201525b8860e0015115611cfc576020808a01516040808c0151845193850151858301519251631a63711f60e01b81526001600160a01b038e1695631a63711f95611bbd9590949391926001906004016139fe565b6040805180830381865afa158015611bd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bfd9190613a4d565b608083018290526020830151909350611c1691906134a2565b96508681602001818151611c2a91906134a2565b905250611c386001886134a2565b9650611c51670de0b6b3a76400008883606001516128d7565b9650611cac89600001517f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000846000015185602001516128ec565b9550611cc18662ffffff1688620186a06128c3565b9450611ccd85886134a2565b965080600001519350611cf5611b0f888b60c00151611cec91906134a2565b83606001510290565b9250611e9c565b6020808a01516040808c0151845193850151858301519251631a63711f60e01b81526001600160a01b038e1695631a63711f95611d439590949391926000906004016139fe565b6040805180830381865afa158015611d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d839190613a4d565b608083018290528251909350611d9991906134a2565b96508681600001818151611dad91906134a2565b905250611dbb6001886134a2565b8951825160208401517f00000000000000000000000000000000000000000000000000000000000000009093049950611e37927f0000000000000000000000000000000000000000000000000000000000000000917f0000000000000000000000000000000000000000000000000000000000000000916128ec565b9550611e4c8662ffffff1688620186a06128c3565b9450611e5885886134a2565b9650611e92878a60a00151611e6d91906134a2565b7f00000000000000000000000000000000000000000000000000000000000000000290565b9350806020015192505b509295509295509295565b600080611f00604051806101400160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160a0810182526017546001600160401b038082168352600160401b820416602080840191909152600160801b820463ffffffff1693830193909352600160a01b810461ffff16606080840191909152600160b01b90910460ff1660808084019190915260105493850193909352600f5484526012549084018190526000549284019290925260135460e08401529042111561202d576060820151604080830151601154855160208701519351634180db7360e11b81526001600160a01b038b1695638301b6e695611fdd95919491939192600401613a9b565b602060405180830381865afa158015611ffa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201e919061384b565b60208301819052601055426012555b876000036120ad57604051636ca4fd9160e11b81526001600160a01b0386169063d949fb2290612069908f908f908f908f908d90600401613add565b602060405180830381865afa158015612086573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120aa919061384b565b97505b846001600160a01b0316630b994d458d8d8d8d8d88600001516040518763ffffffff1660e01b81526004016120e796959493929190613af8565b602060405180830381865afa158015612104573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612128919061384b565b60115560e08201516000908190156121de5760028a049150612161670de0b6b3a76400008b61215c60028860000151612925565b6128d7565b9050612183670de0b6b3a76400006121798484612936565b86608001516128d7565b60c085018190526014546121a49161219a91613960565b8560e00151900490565b60a0850152428910156121d9578360e001518460c00151116121d95760405163b50754c160e01b815260040160405180910390fd5b6121f4565b670de0b6b3a764000060a0850181905260c08501525b60a084015160145560c0840151670de0b6b3a76400001080156122225750670de0b6b3a76400008460a00151115b801561228a575061226a836060015161ffff16670de0b6b3a764000085600001516001600160401b03168760a0015161225b919061397f565b61226591906134a2565b612925565b612288612710670de0b6b3a76400008760c0015161226591906134a2565b115b1561255f576122aa670de0b6b3a7640000856020015186600001516128d7565b6101208501819052670de0b6b3a764000010156122da5761012084018051670de0b6b3a763ffff190190526122ee565b61012084018051670de0b6b3a76400000390525b61231483602001516001600160401b031661230f8661012001516005900490565b6129d1565b985088846101200151111561255f5761236084602001518a6123369190613960565b6101208601518b9003865161234b9190613960565b612355919061397f565b856101200151900490565b98508b91506123748b8a86600001516128c3565b9050866001600160a01b031663d949fb228f8f858560006040518663ffffffff1660e01b81526004016123ab9594939291906139bc565b602060405180830381865afa1580156123c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ec919061384b565b61010085018190526002808204935061241391670de0b6b3a76400009161215c908d612925565b905061242b670de0b6b3a76400006121798484612936565b60e08501819052670de0b6b3a7640000101561255f57612465836060015161ffff16670de0b6b3a76400008660a0015161226591906134a2565b612483612710670de0b6b3a76400008760e0015161226591906134a2565b111561255f57600f8990556040517fcb12ab4101e9e15b90a22516ca404e94b85586dbdcf7d0792ab8da11206e61b6906124be908b90612e6d565b60405180910390a1610100840151600e8190556040517f9e4e1b03f35e9c0cd24e1dfac3528faaaf88b254e1530b0090ce33f9d7597033916124ff91612e6d565b60405180910390a160e0840151601381905560a08501516040517f4d2cbcbcdaca7676a354e7297481cf51e67a13c8c07ad1c42928605c8ea522d0926125459291612e7b565b60405180910390a1505050610100015191508490506125ed565b600e8a90556040517f9e4e1b03f35e9c0cd24e1dfac3528faaaf88b254e1530b0090ce33f9d759703390612594908c90612e6d565b60405180910390a160c0840151601381905560a08501516040517f4d2cbcbcdaca7676a354e7297481cf51e67a13c8c07ad1c42928605c8ea522d0926125da9291612e7b565b60405180910390a1505090518793509150505b9850989650505050505050565b6001600160801b0382111561262257604051631a93c68960e11b815260040160405180910390fd5b6001600160801b0381111561264a57604051631a93c68960e11b815260040160405180910390fd5b6001600160801b03808316908216600160801b026fffffffffffffffffffffffffffffffff191617600d556040517fcf2aa50876cdfbb541206f89af0ee78d44a2abf8d328e37fa4917f982149848a906126a79084908490612e7b565b60405180910390a15050565b8060ff1660000361275157600a546126d69085906001600160a01b0316846129e0565b600a54604051631f2c13e160e31b81526001600160a01b039091169063f9609f08906127089087908790600401613b20565b6020604051808303816000875af1158015612727573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274b919061384b565b506127f2565b8060ff16600114801561277157506009546001600160a01b038581169116145b156127e757600954604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d906127a6908590600401612e6d565b600060405180830381600087803b1580156127c057600080fd5b505af11580156127d4573d6000803e3d6000fd5b505050506127e28383612ad3565b6127f2565b6127f28484846129e0565b50505050565b828202838104831461280957600080fd5b0492915050565b600081516041146128235750600061092b565b60208201516040830151606084015160001a7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0821115612869576000935050505061092b565b6001868285856040516000815260200160405260405161288c9493929190613730565b6020604051602081039080840390855afa1580156128ae573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b828202831584820484141761280957600080fd5b82820281151584820484141661280957600080fd5b600061291b8686868686336040516020016129079190612f12565b604051602081830303815290604052612b55565b9695505050505050565b818102828104821461092b57600080fd5b6000610ac06129458385613960565b70ffffffffffffffffffffffffffffffffff811160071b81811c68ffffffffffffffffff1060061b1781811c64ffffffffff1060051b1781811c62ffffff1060041b1781811c620100000160b5600192831c1b0260121c80830401811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c908190048111900390565b600081831161182d5781610ac0565b600080846001600160a01b031663a9059cbb8585604051602401612a05929190613b3b565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051612a3e9190613834565b6000604051808303816000865af19150503d8060008114612a7b576040519150601f19603f3d011682016040523d82523d6000602084013e612a80565b606091505b5091509150811580612aae5750805115801590612aae575080806020019051810190612aac919061393f565b155b15612acc576040516312171d8360e31b815260040160405180910390fd5b5050505050565b6000826001600160a01b031682604051612aec90613b49565b60006040518083038185875af1925050503d8060008114612b29576040519150601f19603f3d011682016040523d82523d6000602084013e612b2e565b606091505b5050905080612b505760405163b12d13eb60e01b815260040160405180910390fd5b505050565b600080612b6488888886612c5e565b90506000612b72858761397f565b9050612ba58582612b8b89673782dace9d900000613960565b612b9591906139a8565b612b9f9190613960565b82900490565b8251612bc1906001600160401b0316670de0b6b3a76400000190565b612bcb91906134a2565b8251612be7906001600160401b0316670de0b6b3a76400000290565b612bf191906139a8565b9050612c3b612c0882670de0b6b3a76400006134a2565b836040015162ffffff16612c1c9190613960565b82846020015162ffffff16612c319190613960565b611b0f919061397f565b9250614e2062ffffff84161115612c5257614e2092505b50509695505050505050565b6040805160608101825260008082526020820181905291810191909152600b546040805163d0fb020360e01b815290516000926001600160a01b03169163d0fb02039160048083019260209291908290030181865afa925050508015612ce1575060408051601f3d908101601f19168201909252612cde91810190613b54565b60015b15612ce95790505b6001600160a01b03811615612d7357604051635a59621b60e11b81526001600160a01b0382169063b4b2c43690612d2c9030908a908a908a908a90600401613b75565b606060405180830381865afa925050508015612d65575060408051601f3d908101601f19168201909252612d6291810190613c4a565b60015b15612d735791506114b99050565b50506040805160608101825265d12f0c4c6000815261010460208201526101c291810191909152949350505050565b6001600160e01b031981165b8114612db957600080fd5b50565b803561092b81612da2565b600060208284031215612ddc57612ddc600080fd5b60006114b98484612dbc565b8015155b82525050565b6020810161092b8284612de8565b60005b83811015612e1b578181015183820152602001612e03565b50506000910152565b6000612e2e825190565b808452602084019350612e45818560208601612e00565b601f01601f19169290920192915050565b60208082528101610ac08184612e24565b80612dec565b6020810161092b8284612e67565b60408101612e898285612e67565b610ac06020830184612e67565b60006001600160a01b03821661092b565b612dae81612e96565b803561092b81612ea7565b80612dae565b803561092b81612ebb565b60008060408385031215612ee257612ee2600080fd5b6000612eee8585612eb0565b9250506020612eff85828601612ec1565b9150509250929050565b612dec81612e96565b6020810161092b8284612f09565b63ffffffff8116612dec565b6001600160401b038116612dec565b60c08101612f498289612f20565b612f566020830188612f20565b612f636040830187612f2c565b612f706060830186612f2c565b612f7d6080830185612f20565b6115e260a0830184612f20565b600080600060608486031215612fa257612fa2600080fd5b6000612fae8686612eb0565b9350506020612fbf86828701612eb0565b9250506040612fd086828701612ec1565b9150509250925092565b60008083601f840112612fef57612fef600080fd5b5081356001600160401b0381111561300957613009600080fd5b60208301915083600182028301111561302457613024600080fd5b9250929050565b60008060008060008060a0878903121561304757613047600080fd5b60006130538989612eb0565b965050602061306489828a01612eb0565b955050604061307589828a01612ec1565b945050606061308689828a01612ec1565b93505060808701356001600160401b038111156130a5576130a5600080fd5b6130b189828a01612fda565b92509250509295509295509295565b60ff8116612dec565b6020810161092b82846130c0565b6000602082840312156130ec576130ec600080fd5b60006114b98484612eb0565b634e487b7160e01b600052604160045260246000fd5b601f19601f83011681018181106001600160401b0382111715613133576131336130f8565b6040525050565b600061314560405190565b9050613151828261310e565b919050565b60006001600160401b0382111561316f5761316f6130f8565b601f19601f83011660200192915050565b82818337506000910152565b600061319f61319a84613156565b61313a565b9050828152602081018484840111156131ba576131ba600080fd5b6131c5848285613180565b509392505050565b600082601f8301126131e1576131e1600080fd5b81356114b984826020860161318c565b6000806000806080858703121561320a5761320a600080fd5b84356001600160401b0381111561322357613223600080fd5b61322f878288016131cd565b945050602061324087828801612eb0565b935050604061325187828801612eb0565b92505060608501356001600160401b0381111561327057613270600080fd5b61327c878288016131cd565b91505092959194509250565b805160408301906132998482612f09565b5060208201516127f26020850182612e67565b6040810161092b8284613288565b61ffff8116612dec565b6020810161092b82846132ba565b60a081016132e08288612f2c565b6132ed6020830187612f2c565b6132fa6040830186612f20565b61330760608301856132ba565b61291b60808301846130c0565b60ff8116612dae565b803561092b81613314565b600080600080600080600060e0888a03121561334657613346600080fd5b60006133528a8a612eb0565b97505060206133638a828b01612eb0565b96505060406133748a828b01612ec1565b95505060606133858a828b01612ec1565b94505060806133968a828b0161331d565b93505060a06133a78a828b01612ec1565b92505060c06133b88a828b01612ec1565b91505092959891949750929550565b600080604083850312156133dd576133dd600080fd5b60006133e98585612eb0565b9250506020612eff85828601612eb0565b600061092b6001600160a01b038316613411565b90565b6001600160a01b031690565b600061092b826133fa565b600061092b8261341d565b612dec81613428565b6020810161092b8284613433565b634e487b7160e01b600052602260045260246000fd5b60028104600182168061347457607f821691505b6020821081036134865761348661344a565b50919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561092b5761092b61348c565b805161092b81612ea7565b805161092b81613314565b6000806000606084860312156134e3576134e3600080fd5b60006134ef86866134b5565b9350506020613500868287016134b5565b9250506040612fd0868287016134c0565b600061092b61340e8381565b612dec81613511565b608081016135348287612e67565b613541602083018661351d565b61354e604083018561351d565b61355b6060830184612e67565b95945050505050565b60408101612e89828561351d565b60808101613580828761351d565b61358d6020830186612e67565b61359a6040830185612e67565b61355b606083018461351d565b604081016135b58285612e67565b610ac0602083018461351d565b62ffffff8116612dec565b80516000906101c08401906135e28582612f09565b5060208301516135f56020860182612f09565b5060408301516136086040860182612f09565b50606083015161361b6060860182612f09565b50608083015161362e6080860182612e67565b5060a083015161364160a0860182612e67565b5060c083015161365460c0860182612e67565b5060e083015161366760e0860182612e67565b5061010083015161367c610100860182612e67565b50610120830151613691610120860182612e67565b506101408301516136a6610140860182612e67565b506101608301516136bb6101608601826135c2565b506101808301516136d06101808601826130c0565b506101a08301518482036101a086015261355b8282612e24565b60208082528101610ac081846135cd565b608081016137098287612e67565b6137166020830186612e67565b61372360408301856135c2565b61355b6060830184612f09565b6080810161373e8287612e67565b61374b60208301866130c0565b61354e6040830185612e67565b6000600019820361376b5761376b61348c565b5060010190565b60c081016137808289612e67565b61378d6020830188612f09565b61379a6040830187612f09565b6137a76060830186612e67565b6137b46080830185612e67565b6115e260a0830184612e67565b61190160f01b815260020160006137d88285612e67565b6020820191506137e88284612e67565b5060200192915050565b604081016138008285612e67565b81810360208301526114b98184612e24565b600061381c825190565b61382a818560208601612e00565b9290920192915050565b6000610ac08284613812565b805161092b81612ebb565b60006020828403121561386057613860600080fd5b60006114b98484613840565b6000815461387981613460565b60018216801561389057600181146138a5576138d5565b60ff19831686528115158202860193506138d5565b60008581526020902060005b838110156138cd578154888201526001909101906020016138b1565b838801955050505b50505092915050565b6000610ac0828461386c565b60a081016138f8828861351d565b6139056020830187612e67565b613912604083018661351d565b61391f6060830185612e67565b61291b6080830184612f09565b801515612dae565b805161092b8161392c565b60006020828403121561395457613954600080fd5b60006114b98484613934565b8181028082158382048514176139785761397861348c565b5092915050565b8082018082111561092b5761092b61348c565b634e487b7160e01b600052601260045260246000fd5b6000826139b7576139b7613992565b500490565b60a081016139ca8288612e67565b6139d76020830187612e67565b6139e46040830186612e67565b6139f16060830185612e67565b61291b608083018461351d565b60c08101613a0c8289612e67565b613a196020830188612e67565b613a266040830187612e67565b613a336060830186612e67565b613a406080830185612e67565b6115e260a083018461351d565b60008060408385031215613a6357613a63600080fd5b6000613a6f8585613840565b9250506020612eff85828601613840565b600061092b61340e63ffffffff841681565b612dec81613a80565b60a08101613aa98288612e67565b613ab66020830187613a92565b613ac36040830186612e67565b613ad06060830185612e67565b61291b6080830184612e67565b60a08101613aeb8288612e67565b613ab66020830187612e67565b60c08101613b068289612e67565b613b136020830188612e67565b61379a6040830187612e67565b60408101613b2e8285612f09565b610ac06020830184612f09565b60408101612e898285612f09565b600061092b8261340e565b600060208284031215613b6957613b69600080fd5b60006114b984846134b5565b60a08101613b838288612f09565b613b906020830187612f09565b613b9d6040830186612f09565b613baa6060830185612f09565b81810360808301526115e28184612e24565b6001600160401b038116612dae565b805161092b81613bbc565b62ffffff8116612dae565b805161092b81613bd6565b600060608284031215613c0157613c01600080fd5b613c0b606061313a565b90506000613c198484613bcb565b8252506020613c2a84848301613be1565b6020830152506040613c3e84828501613be1565b60408301525092915050565b600060608284031215613c5f57613c5f600080fd5b60006114b98484613bec56fea26469706673582212205a3b4e80d15975bd20f118e243514e3ab79a5f6321e693c77b65d55eeb5c8a7464736f6c63430008170033
Deployed Bytecode
0x60806040526004361061021e5760003560e01c806391e4bb3411610123578063d21220a7116100ab578063e3bba7161161006f578063e3bba71614610846578063e7231d241461085c578063ed6c154614610872578063ee97f7f31461089f578063fbfa77cf146108bf57610225565b8063d21220a71461078f578063d505accf146107c3578063d6ea073d146107e3578063da815731146107f9578063dd62ed3e1461080e57610225565b8063a9059cbb116100f2578063a9059cbb14610682578063b1dd61b6146106a2578063baa8c7cb146106c4578063bc4041db146106f8578063c45a01551461075b57610225565b806391e4bb341461062b57806395d89b411461064157806396e591a614610656578063a0fbddaf1461066c57610225565b80632c0198cc116101a65780634e25dc47116101755780634e25dc471461055a57806370a082311461058e5780637132bb7f146105bb5780637ecebe00146105e85780638ea875f31461061557610225565b80632c0198cc146104ce578063313ce567146104ee5780633644e5151461052f578063370a48671461054457610225565b8063095ea7b3116101ed578063095ea7b3146103cb5780630dfe1681146103eb57806318160ddd1461042c57806319706b381461044257806323b872dd146104ae57610225565b806301ffc9a71461031e57806306fdde031461035457806307f293f7146103765780630902f1ac1461039957610225565b3661022557005b7f000000000000000000000000fb35c48001bdb59edd14012dee73f202f53977f063f66eab5b60e01b6001600160e01b031960003516148061027957506313d85e7560e11b6001600160e01b031960003516145b806102965750631f2f232f60e11b6001600160e01b031960003516145b806102b3575063712d52fd60e11b6001600160e01b031960003516145b806102d05750631f94a27560e31b6001600160e01b031960003516145b156102f857507f0000000000000000000000006275cb52518217602a1869dbd6e7e8196455e3945b3660008037600080366000845af43d6000803e808015610317573d6000f35b3d6000fd5b005b34801561032a57600080fd5b5061033e610339366004612dc7565b6108df565b60405161034b9190612df2565b60405180910390f35b34801561036057600080fd5b50610369610931565b60405161034b9190612e56565b34801561038257600080fd5b5061038c600e5481565b60405161034b9190612e6d565b3480156103a557600080fd5b50600d546001600160801b0380821691600160801b90041660405161034b929190612e7b565b3480156103d757600080fd5b5061033e6103e6366004612ecc565b6109bf565b3480156103f757600080fd5b5061041f7f00000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a481565b60405161034b9190612f12565b34801561043857600080fd5b5061038c60005481565b34801561044e57600080fd5b5060165461049c9063ffffffff8082169164010000000081048216916001600160401b03600160401b8304811692600160801b810490911691600160c01b8204811691600160e01b90041686565b60405161034b96959493929190612f3b565b3480156104ba57600080fd5b5061033e6104c9366004612f8a565b6109d5565b3480156104da57600080fd5b5061031c6104e936600461302b565b610ac7565b3480156104fa57600080fd5b506105227f000000000000000000000000000000000000000000000000000000000000001281565b60405161034b91906130c9565b34801561053b57600080fd5b5061038c610b6c565b34801561055057600080fd5b5061038c60145481565b34801561056657600080fd5b5061038c7f000000000000000000000000000000000000000000000000000000000000000181565b34801561059a57600080fd5b5061038c6105a93660046130d7565b60016020526000908152604090205481565b3480156105c757600080fd5b506105db6105d63660046131f1565b610b8b565b60405161034b91906132ac565b3480156105f457600080fd5b5061038c6106033660046130d7565b60036020526000908152604090205481565b34801561062157600080fd5b5061038c60135481565b34801561063757600080fd5b5061038c60125481565b34801561064d57600080fd5b50610369611216565b34801561066257600080fd5b5061038c60155481565b34801561067857600080fd5b5061038c600f5481565b34801561068e57600080fd5b5061033e61069d366004612ecc565b611223565b3480156106ae57600080fd5b506106b7600381565b60405161034b91906132c4565b3480156106d057600080fd5b5061038c7f000000000000000000000000000000000000000000000000000000e8d4a5100081565b34801561070457600080fd5b5060175461074a906001600160401b0380821691600160401b810490911690600160801b810463ffffffff1690600160a01b810461ffff1690600160b01b900460ff1685565b60405161034b9594939291906132d2565b34801561076757600080fd5b5061041f7f00000000000000000000000087aeb51d606056f48d241c4072f55acd9d93701881565b34801561079b57600080fd5b5061041f7f000000000000000000000000d29687c813d741e2f938f4ac377128810e217b1b81565b3480156107cf57600080fd5b5061031c6107de366004613328565b6112aa565b3480156107ef57600080fd5b5061038c60085481565b34801561080557600080fd5b5061038c600281565b34801561081a57600080fd5b5061038c6108293660046133c7565b600260209081526000928352604080842090915290825290205481565b34801561085257600080fd5b5061038c60115481565b34801561086857600080fd5b5061038c60105481565b34801561087e57600080fd5b50600c54610892906001600160a01b031681565b60405161034b919061343c565b3480156108ab57600080fd5b50600b5461041f906001600160a01b031681565b3480156108cb57600080fd5b50600a5461041f906001600160a01b031681565b60006001600160e01b031982166301ffc9a760e01b148061091057506001600160e01b0319821663d505accf60e01b145b8061092b57506001600160e01b03198216630b00663360e21b145b92915050565b6004805461093e90613460565b80601f016020809104026020016040519081016040528092919081815260200182805461096a90613460565b80156109b75780601f1061098c576101008083540402835291602001916109b7565b820191906000526020600020905b81548152906001019060200180831161099a57829003601f168201915b505050505081565b60006109cc33848461139f565b50600192915050565b6001600160a01b03831660009081526002602090815260408083203384529091528120546000198114610a3157610a0c83826134a2565b6001600160a01b03861660009081526002602090815260408083203384529091529020555b6001600160a01b03851660009081526001602052604081208054859290610a599084906134a2565b90915550506001600160a01b03808516600081815260016020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610ab2908790612e6d565b60405180910390a360019150505b9392505050565b8280421115610ae957604051630407b05b60e31b815260040160405180910390fd5b6000610af788888888611407565b9050610b3a888286868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506114c192505050565b610b5757604051638baa579f60e01b815260040160405180910390fd5b610b6288888861139f565b5050505050505050565b60006006544614610b8457610b7f6115ed565b905090565b5060075490565b6040805180820190915260008082526020820152600854600114610bae57600080fd5b6002600881905550610c54604051806101c0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600062ffffff168152602001600060ff168152602001606081525090565b85806020019051810190610c6891906134cb565b60ff166101808401526001600160a01b039081166020840152166040820152600d546001600160801b03600160801b8204811660a0840152166080820152610cae611676565b60e083015260c0820152610cc18561179c565b94506000806000610cd061183b565b600c54604088015193965091945092506000918291829182916001600160a01b03908116917f00000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a48216911603610e9857610d846040518061012001604052808f6001600160a01b031681526020018a81526020018981526020018b60c0015181526020018b60e0015181526020018b6080015181526020018b60a001518152602001600115158152602001888152508261196e565b62ffffff9094166101608f01526101208e018590526001600160a01b037f000000000000000000000000d29687c813d741e2f938f4ac377128810e217b1b1660608f015260e08e018051929a50909850929650909450610de59083906134a2565b905250608089015160c08a0151610dfc91906134a2565b6101008a0181905260208a01516101208b01516040516001600160a01b039092169233927fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d82292610e5192916000918291613526565b60405180910390a37fa6205f24a082c01e6c705e20c1a026c246eedf9800b87b84440f05e8271aaf27600083604051610e8b929190613564565b60405180910390a1611051565b7f000000000000000000000000d29687c813d741e2f938f4ac377128810e217b1b6001600160a01b031689604001516001600160a01b031614610eda57600080fd5b610f3f6040518061012001604052808f6001600160a01b031681526020018a81526020018981526020018b60c0015181526020018b60e0015181526020018b6080015181526020018b60a001518152602001600015158152602001888152508261196e565b62ffffff9094166101608f01526101208e018590526001600160a01b037f00000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a41660608f015260c08e018051929a50909850929650909450610fa09083906134a2565b90525060a089015160e08a0151610fb791906134a2565b6101008a0181905260208a01516101208b01516040516001600160a01b039092169233927fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229261100e926000929091908390613572565b60405180910390a37fa6205f24a082c01e6c705e20c1a026c246eedf9800b87b84440f05e8271aaf278260006040516110489291906135a7565b60405180910390a15b61010089015115801590611069575061012089015115155b61107257600080fd5b6110838888878760008b8988611ea7565b50506110978960c001518a60e001516125fa565b6110b589606001518a602001518b61012001518c61018001516126b3565b6001600160a01b038c161561115c576001600160a01b038d1689526101a089018b90526101008901516101608a01516110f7919062ffffff16620186a06127f8565b6101408a015260405163608dbcbb60e01b81526001600160a01b038d169063608dbcbb90611129908c906004016136ea565b600060405180830381600087803b15801561114357600080fd5b505af1158015611157573d6000803e3d6000fd5b505050505b88606001518a600001906001600160a01b031690816001600160a01b0316815250508861012001518a602001818152505088606001516001600160a01b03168d6001600160a01b0316336001600160a01b03167faa077b6dc26efdfd606d4340c04a5a222ff968ec199f0b184f4c0f7a5c8e8d718c61010001518d61012001518e61016001518f602001516040516111f794939291906136fb565b60405180910390a45050600160085550959a9950505050505050505050565b6005805461093e90613460565b336000908152600160205260408120805483919083906112449084906134a2565b90915550506001600160a01b038316600081815260016020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611299908690612e6d565b60405180910390a350600192915050565b83804211156112cc57604051630407b05b60e31b815260040160405180910390fd5b60006112da89898989611407565b90506000600182878787604051600081526020016040526040516113019493929190613730565b6020604051602081039080840390855afa158015611323573d6000803e3d6000fd5b505050602060405103519050896001600160a01b0316816001600160a01b03161461136157604051638baa579f60e01b815260040160405180910390fd5b6001600160a01b03811661138857604051638baa579f60e01b815260040160405180910390fd5b6113938a8a8a61139f565b50505050505050505050565b6001600160a01b0380841660008181526002602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906113fa908590612e6d565b60405180910390a3505050565b6000611411610b6c565b6001600160a01b038616600090815260036020526040812080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c99289928992899290919061145f83613758565b919050558760405160200161147996959493929190613772565b604051602081830303815290604052805190602001206040516020016114a09291906137c1565b6040516020818303038152906040528051906020012090505b949350505050565b6000806114ce8484612810565b9050846001600160a01b0316816001600160a01b031603611502576001600160a01b03811615611502576001915050610ac0565b600080866001600160a01b0316631626ba7e60e01b878760405160240161152a9291906137f2565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516115689190613834565b600060405180830381855afa9150503d80600081146115a3576040519150601f19603f3d011682016040523d82523d6000602084013e6115a8565b606091505b50915091508180156115bb575080516020145b80156115e257508051630b135d3f60e11b906115e0908301602090810190840161384b565b145b979650505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600460405161161f91906138de565b60405190819003812061165b92917fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc690469030906020016138ea565b60405160208183030381529060405280519060200120905090565b6000807f00000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a46001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016116c59190612f12565b602060405180830381865afa1580156116e2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611706919061384b565b6040516370a0823160e01b81529092506001600160a01b037f000000000000000000000000d29687c813d741e2f938f4ac377128810e217b1b16906370a0823190611755903090600401612f12565b602060405180830381865afa158015611772573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611796919061384b565b90509091565b60006001600160a01b038216331461183457600b54604051632af3bd5560e21b81526001600160a01b039091169063abcef554906117de903390600401612f12565b602060405180830381865afa925050508015611817575060408051601f3d908101601f191682019092526118149181019061393f565b60015b611822575033919050565b8061182d5733610ac0565b5090919050565b5033919050565b6040805160c08101825260165463ffffffff808216835264010000000082048116602084018190526001600160401b03600160401b8404811695850195909552600160801b830490941660608401819052600160c01b830482166080850152600160e01b9092041660a08301819052909142821115611968576000816080015163ffffffff16836118cc91906134a2565b90506000826080015163ffffffff16426118e691906134a2565b905060006118f482846134a2565b9050826119018389613960565b855161191490849063ffffffff16613960565b61191e919061397f565b61192891906139a8565b9650826119358388613960565b8286604001516001600160401b031661194e9190613960565b611958919061397f565b61196291906139a8565b95505050505b50909192565b6000806000806000806119a96040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b7f000000000000000000000000000000000000000000000000000000e8d4a5100089606001516119d99190613960565b8152600f54611a09907f000000000000000000000000000000000000000000000000000000000000000190613960565b6060820181905260808a0151611a2791670de0b6b3a76400006128c3565b6020820152610100890151421015611b63578860e0015115611afb5760a08901517f000000000000000000000000000000000000000000000000000000e8d4a5100002608082018190526020808b01516040808d0151928501519051636ca4fd9160e11b81526001600160a01b038d169463d949fb2294611ab0949390926000906004016139bc565b602060405180830381865afa158015611acd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af1919061384b565b6040820152611b6c565b611b1d611b0f8a60c0015183606001510290565b670de0b6b3a7640000900490565b6080820181905260208a01516040808c015184519151636ca4fd9160e11b81526001600160a01b038d169463d949fb2294611ab0949093929091906000906004016139bc565b600e5460408201525b8860e0015115611cfc576020808a01516040808c0151845193850151858301519251631a63711f60e01b81526001600160a01b038e1695631a63711f95611bbd9590949391926001906004016139fe565b6040805180830381865afa158015611bd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bfd9190613a4d565b608083018290526020830151909350611c1691906134a2565b96508681602001818151611c2a91906134a2565b905250611c386001886134a2565b9650611c51670de0b6b3a76400008883606001516128d7565b9650611cac89600001517f00000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a47f000000000000000000000000d29687c813d741e2f938f4ac377128810e217b1b846000015185602001516128ec565b9550611cc18662ffffff1688620186a06128c3565b9450611ccd85886134a2565b965080600001519350611cf5611b0f888b60c00151611cec91906134a2565b83606001510290565b9250611e9c565b6020808a01516040808c0151845193850151858301519251631a63711f60e01b81526001600160a01b038e1695631a63711f95611d439590949391926000906004016139fe565b6040805180830381865afa158015611d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d839190613a4d565b608083018290528251909350611d9991906134a2565b96508681600001818151611dad91906134a2565b905250611dbb6001886134a2565b8951825160208401517f000000000000000000000000000000000000000000000000000000e8d4a510009093049950611e37927f000000000000000000000000d29687c813d741e2f938f4ac377128810e217b1b917f00000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a4916128ec565b9550611e4c8662ffffff1688620186a06128c3565b9450611e5885886134a2565b9650611e92878a60a00151611e6d91906134a2565b7f000000000000000000000000000000000000000000000000000000e8d4a510000290565b9350806020015192505b509295509295509295565b600080611f00604051806101400160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160a0810182526017546001600160401b038082168352600160401b820416602080840191909152600160801b820463ffffffff1693830193909352600160a01b810461ffff16606080840191909152600160b01b90910460ff1660808084019190915260105493850193909352600f5484526012549084018190526000549284019290925260135460e08401529042111561202d576060820151604080830151601154855160208701519351634180db7360e11b81526001600160a01b038b1695638301b6e695611fdd95919491939192600401613a9b565b602060405180830381865afa158015611ffa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201e919061384b565b60208301819052601055426012555b876000036120ad57604051636ca4fd9160e11b81526001600160a01b0386169063d949fb2290612069908f908f908f908f908d90600401613add565b602060405180830381865afa158015612086573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120aa919061384b565b97505b846001600160a01b0316630b994d458d8d8d8d8d88600001516040518763ffffffff1660e01b81526004016120e796959493929190613af8565b602060405180830381865afa158015612104573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612128919061384b565b60115560e08201516000908190156121de5760028a049150612161670de0b6b3a76400008b61215c60028860000151612925565b6128d7565b9050612183670de0b6b3a76400006121798484612936565b86608001516128d7565b60c085018190526014546121a49161219a91613960565b8560e00151900490565b60a0850152428910156121d9578360e001518460c00151116121d95760405163b50754c160e01b815260040160405180910390fd5b6121f4565b670de0b6b3a764000060a0850181905260c08501525b60a084015160145560c0840151670de0b6b3a76400001080156122225750670de0b6b3a76400008460a00151115b801561228a575061226a836060015161ffff16670de0b6b3a764000085600001516001600160401b03168760a0015161225b919061397f565b61226591906134a2565b612925565b612288612710670de0b6b3a76400008760c0015161226591906134a2565b115b1561255f576122aa670de0b6b3a7640000856020015186600001516128d7565b6101208501819052670de0b6b3a764000010156122da5761012084018051670de0b6b3a763ffff190190526122ee565b61012084018051670de0b6b3a76400000390525b61231483602001516001600160401b031661230f8661012001516005900490565b6129d1565b985088846101200151111561255f5761236084602001518a6123369190613960565b6101208601518b9003865161234b9190613960565b612355919061397f565b856101200151900490565b98508b91506123748b8a86600001516128c3565b9050866001600160a01b031663d949fb228f8f858560006040518663ffffffff1660e01b81526004016123ab9594939291906139bc565b602060405180830381865afa1580156123c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ec919061384b565b61010085018190526002808204935061241391670de0b6b3a76400009161215c908d612925565b905061242b670de0b6b3a76400006121798484612936565b60e08501819052670de0b6b3a7640000101561255f57612465836060015161ffff16670de0b6b3a76400008660a0015161226591906134a2565b612483612710670de0b6b3a76400008760e0015161226591906134a2565b111561255f57600f8990556040517fcb12ab4101e9e15b90a22516ca404e94b85586dbdcf7d0792ab8da11206e61b6906124be908b90612e6d565b60405180910390a1610100840151600e8190556040517f9e4e1b03f35e9c0cd24e1dfac3528faaaf88b254e1530b0090ce33f9d7597033916124ff91612e6d565b60405180910390a160e0840151601381905560a08501516040517f4d2cbcbcdaca7676a354e7297481cf51e67a13c8c07ad1c42928605c8ea522d0926125459291612e7b565b60405180910390a1505050610100015191508490506125ed565b600e8a90556040517f9e4e1b03f35e9c0cd24e1dfac3528faaaf88b254e1530b0090ce33f9d759703390612594908c90612e6d565b60405180910390a160c0840151601381905560a08501516040517f4d2cbcbcdaca7676a354e7297481cf51e67a13c8c07ad1c42928605c8ea522d0926125da9291612e7b565b60405180910390a1505090518793509150505b9850989650505050505050565b6001600160801b0382111561262257604051631a93c68960e11b815260040160405180910390fd5b6001600160801b0381111561264a57604051631a93c68960e11b815260040160405180910390fd5b6001600160801b03808316908216600160801b026fffffffffffffffffffffffffffffffff191617600d556040517fcf2aa50876cdfbb541206f89af0ee78d44a2abf8d328e37fa4917f982149848a906126a79084908490612e7b565b60405180910390a15050565b8060ff1660000361275157600a546126d69085906001600160a01b0316846129e0565b600a54604051631f2c13e160e31b81526001600160a01b039091169063f9609f08906127089087908790600401613b20565b6020604051808303816000875af1158015612727573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274b919061384b565b506127f2565b8060ff16600114801561277157506009546001600160a01b038581169116145b156127e757600954604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d906127a6908590600401612e6d565b600060405180830381600087803b1580156127c057600080fd5b505af11580156127d4573d6000803e3d6000fd5b505050506127e28383612ad3565b6127f2565b6127f28484846129e0565b50505050565b828202838104831461280957600080fd5b0492915050565b600081516041146128235750600061092b565b60208201516040830151606084015160001a7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0821115612869576000935050505061092b565b6001868285856040516000815260200160405260405161288c9493929190613730565b6020604051602081039080840390855afa1580156128ae573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b828202831584820484141761280957600080fd5b82820281151584820484141661280957600080fd5b600061291b8686868686336040516020016129079190612f12565b604051602081830303815290604052612b55565b9695505050505050565b818102828104821461092b57600080fd5b6000610ac06129458385613960565b70ffffffffffffffffffffffffffffffffff811160071b81811c68ffffffffffffffffff1060061b1781811c64ffffffffff1060051b1781811c62ffffff1060041b1781811c620100000160b5600192831c1b0260121c80830401811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c908190048111900390565b600081831161182d5781610ac0565b600080846001600160a01b031663a9059cbb8585604051602401612a05929190613b3b565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051612a3e9190613834565b6000604051808303816000865af19150503d8060008114612a7b576040519150601f19603f3d011682016040523d82523d6000602084013e612a80565b606091505b5091509150811580612aae5750805115801590612aae575080806020019051810190612aac919061393f565b155b15612acc576040516312171d8360e31b815260040160405180910390fd5b5050505050565b6000826001600160a01b031682604051612aec90613b49565b60006040518083038185875af1925050503d8060008114612b29576040519150601f19603f3d011682016040523d82523d6000602084013e612b2e565b606091505b5050905080612b505760405163b12d13eb60e01b815260040160405180910390fd5b505050565b600080612b6488888886612c5e565b90506000612b72858761397f565b9050612ba58582612b8b89673782dace9d900000613960565b612b9591906139a8565b612b9f9190613960565b82900490565b8251612bc1906001600160401b0316670de0b6b3a76400000190565b612bcb91906134a2565b8251612be7906001600160401b0316670de0b6b3a76400000290565b612bf191906139a8565b9050612c3b612c0882670de0b6b3a76400006134a2565b836040015162ffffff16612c1c9190613960565b82846020015162ffffff16612c319190613960565b611b0f919061397f565b9250614e2062ffffff84161115612c5257614e2092505b50509695505050505050565b6040805160608101825260008082526020820181905291810191909152600b546040805163d0fb020360e01b815290516000926001600160a01b03169163d0fb02039160048083019260209291908290030181865afa925050508015612ce1575060408051601f3d908101601f19168201909252612cde91810190613b54565b60015b15612ce95790505b6001600160a01b03811615612d7357604051635a59621b60e11b81526001600160a01b0382169063b4b2c43690612d2c9030908a908a908a908a90600401613b75565b606060405180830381865afa925050508015612d65575060408051601f3d908101601f19168201909252612d6291810190613c4a565b60015b15612d735791506114b99050565b50506040805160608101825265d12f0c4c6000815261010460208201526101c291810191909152949350505050565b6001600160e01b031981165b8114612db957600080fd5b50565b803561092b81612da2565b600060208284031215612ddc57612ddc600080fd5b60006114b98484612dbc565b8015155b82525050565b6020810161092b8284612de8565b60005b83811015612e1b578181015183820152602001612e03565b50506000910152565b6000612e2e825190565b808452602084019350612e45818560208601612e00565b601f01601f19169290920192915050565b60208082528101610ac08184612e24565b80612dec565b6020810161092b8284612e67565b60408101612e898285612e67565b610ac06020830184612e67565b60006001600160a01b03821661092b565b612dae81612e96565b803561092b81612ea7565b80612dae565b803561092b81612ebb565b60008060408385031215612ee257612ee2600080fd5b6000612eee8585612eb0565b9250506020612eff85828601612ec1565b9150509250929050565b612dec81612e96565b6020810161092b8284612f09565b63ffffffff8116612dec565b6001600160401b038116612dec565b60c08101612f498289612f20565b612f566020830188612f20565b612f636040830187612f2c565b612f706060830186612f2c565b612f7d6080830185612f20565b6115e260a0830184612f20565b600080600060608486031215612fa257612fa2600080fd5b6000612fae8686612eb0565b9350506020612fbf86828701612eb0565b9250506040612fd086828701612ec1565b9150509250925092565b60008083601f840112612fef57612fef600080fd5b5081356001600160401b0381111561300957613009600080fd5b60208301915083600182028301111561302457613024600080fd5b9250929050565b60008060008060008060a0878903121561304757613047600080fd5b60006130538989612eb0565b965050602061306489828a01612eb0565b955050604061307589828a01612ec1565b945050606061308689828a01612ec1565b93505060808701356001600160401b038111156130a5576130a5600080fd5b6130b189828a01612fda565b92509250509295509295509295565b60ff8116612dec565b6020810161092b82846130c0565b6000602082840312156130ec576130ec600080fd5b60006114b98484612eb0565b634e487b7160e01b600052604160045260246000fd5b601f19601f83011681018181106001600160401b0382111715613133576131336130f8565b6040525050565b600061314560405190565b9050613151828261310e565b919050565b60006001600160401b0382111561316f5761316f6130f8565b601f19601f83011660200192915050565b82818337506000910152565b600061319f61319a84613156565b61313a565b9050828152602081018484840111156131ba576131ba600080fd5b6131c5848285613180565b509392505050565b600082601f8301126131e1576131e1600080fd5b81356114b984826020860161318c565b6000806000806080858703121561320a5761320a600080fd5b84356001600160401b0381111561322357613223600080fd5b61322f878288016131cd565b945050602061324087828801612eb0565b935050604061325187828801612eb0565b92505060608501356001600160401b0381111561327057613270600080fd5b61327c878288016131cd565b91505092959194509250565b805160408301906132998482612f09565b5060208201516127f26020850182612e67565b6040810161092b8284613288565b61ffff8116612dec565b6020810161092b82846132ba565b60a081016132e08288612f2c565b6132ed6020830187612f2c565b6132fa6040830186612f20565b61330760608301856132ba565b61291b60808301846130c0565b60ff8116612dae565b803561092b81613314565b600080600080600080600060e0888a03121561334657613346600080fd5b60006133528a8a612eb0565b97505060206133638a828b01612eb0565b96505060406133748a828b01612ec1565b95505060606133858a828b01612ec1565b94505060806133968a828b0161331d565b93505060a06133a78a828b01612ec1565b92505060c06133b88a828b01612ec1565b91505092959891949750929550565b600080604083850312156133dd576133dd600080fd5b60006133e98585612eb0565b9250506020612eff85828601612eb0565b600061092b6001600160a01b038316613411565b90565b6001600160a01b031690565b600061092b826133fa565b600061092b8261341d565b612dec81613428565b6020810161092b8284613433565b634e487b7160e01b600052602260045260246000fd5b60028104600182168061347457607f821691505b6020821081036134865761348661344a565b50919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561092b5761092b61348c565b805161092b81612ea7565b805161092b81613314565b6000806000606084860312156134e3576134e3600080fd5b60006134ef86866134b5565b9350506020613500868287016134b5565b9250506040612fd0868287016134c0565b600061092b61340e8381565b612dec81613511565b608081016135348287612e67565b613541602083018661351d565b61354e604083018561351d565b61355b6060830184612e67565b95945050505050565b60408101612e89828561351d565b60808101613580828761351d565b61358d6020830186612e67565b61359a6040830185612e67565b61355b606083018461351d565b604081016135b58285612e67565b610ac0602083018461351d565b62ffffff8116612dec565b80516000906101c08401906135e28582612f09565b5060208301516135f56020860182612f09565b5060408301516136086040860182612f09565b50606083015161361b6060860182612f09565b50608083015161362e6080860182612e67565b5060a083015161364160a0860182612e67565b5060c083015161365460c0860182612e67565b5060e083015161366760e0860182612e67565b5061010083015161367c610100860182612e67565b50610120830151613691610120860182612e67565b506101408301516136a6610140860182612e67565b506101608301516136bb6101608601826135c2565b506101808301516136d06101808601826130c0565b506101a08301518482036101a086015261355b8282612e24565b60208082528101610ac081846135cd565b608081016137098287612e67565b6137166020830186612e67565b61372360408301856135c2565b61355b6060830184612f09565b6080810161373e8287612e67565b61374b60208301866130c0565b61354e6040830185612e67565b6000600019820361376b5761376b61348c565b5060010190565b60c081016137808289612e67565b61378d6020830188612f09565b61379a6040830187612f09565b6137a76060830186612e67565b6137b46080830185612e67565b6115e260a0830184612e67565b61190160f01b815260020160006137d88285612e67565b6020820191506137e88284612e67565b5060200192915050565b604081016138008285612e67565b81810360208301526114b98184612e24565b600061381c825190565b61382a818560208601612e00565b9290920192915050565b6000610ac08284613812565b805161092b81612ebb565b60006020828403121561386057613860600080fd5b60006114b98484613840565b6000815461387981613460565b60018216801561389057600181146138a5576138d5565b60ff19831686528115158202860193506138d5565b60008581526020902060005b838110156138cd578154888201526001909101906020016138b1565b838801955050505b50505092915050565b6000610ac0828461386c565b60a081016138f8828861351d565b6139056020830187612e67565b613912604083018661351d565b61391f6060830185612e67565b61291b6080830184612f09565b801515612dae565b805161092b8161392c565b60006020828403121561395457613954600080fd5b60006114b98484613934565b8181028082158382048514176139785761397861348c565b5092915050565b8082018082111561092b5761092b61348c565b634e487b7160e01b600052601260045260246000fd5b6000826139b7576139b7613992565b500490565b60a081016139ca8288612e67565b6139d76020830187612e67565b6139e46040830186612e67565b6139f16060830185612e67565b61291b608083018461351d565b60c08101613a0c8289612e67565b613a196020830188612e67565b613a266040830187612e67565b613a336060830186612e67565b613a406080830185612e67565b6115e260a083018461351d565b60008060408385031215613a6357613a63600080fd5b6000613a6f8585613840565b9250506020612eff85828601613840565b600061092b61340e63ffffffff841681565b612dec81613a80565b60a08101613aa98288612e67565b613ab66020830187613a92565b613ac36040830186612e67565b613ad06060830185612e67565b61291b6080830184612e67565b60a08101613aeb8288612e67565b613ab66020830187612e67565b60c08101613b068289612e67565b613b136020830188612e67565b61379a6040830187612e67565b60408101613b2e8285612f09565b610ac06020830184612f09565b60408101612e898285612f09565b600061092b8261340e565b600060208284031215613b6957613b69600080fd5b60006114b984846134b5565b60a08101613b838288612f09565b613b906020830187612f09565b613b9d6040830186612f09565b613baa6060830185612f09565b81810360808301526115e28184612e24565b6001600160401b038116612dae565b805161092b81613bbc565b62ffffff8116612dae565b805161092b81613bd6565b600060608284031215613c0157613c01600080fd5b613c0b606061313a565b90506000613c198484613bcb565b8252506020613c2a84848301613be1565b6020830152506040613c3e84828501613be1565b60408301525092915050565b600060608284031215613c5f57613c5f600080fd5b60006114b98484613bec56fea26469706673582212205a3b4e80d15975bd20f118e243514e3ab79a5f6321e693c77b65d55eeb5c8a7464736f6c63430008170033
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.