Overview
ETH Balance
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
1318824 | 488 days ago | 0 ETH | ||||
1318823 | 488 days ago | 0.004 ETH | ||||
1318750 | 488 days ago | 0 ETH | ||||
1318749 | 488 days ago | 0.004 ETH | ||||
1318266 | 488 days ago | 0 ETH | ||||
1318265 | 488 days ago | 0.004 ETH | ||||
1318238 | 488 days ago | 0 ETH | ||||
1318237 | 488 days ago | 0.004 ETH | ||||
1318215 | 488 days ago | 0 ETH | ||||
1318214 | 488 days ago | 0.004 ETH | ||||
1318214 | 488 days ago | 0 ETH | ||||
1318213 | 488 days ago | 0.004 ETH | ||||
1318213 | 488 days ago | 0 ETH | ||||
1318212 | 488 days ago | 0.004 ETH | ||||
1318211 | 488 days ago | 0 ETH | ||||
1318210 | 488 days ago | 0.004 ETH | ||||
1318183 | 488 days ago | 0 ETH | ||||
1318182 | 488 days ago | 0.004 ETH | ||||
1318176 | 488 days ago | 0 ETH | ||||
1318175 | 488 days ago | 0.004 ETH | ||||
1318162 | 488 days ago | 0 ETH | ||||
1318161 | 488 days ago | 0.004 ETH | ||||
1318159 | 488 days ago | 0 ETH | ||||
1318158 | 488 days ago | 0.0039 ETH | ||||
1318158 | 488 days ago | 0 ETH |
Loading...
Loading
Contract Name:
GatewayImplementationGasSplit
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; import '../vault/IVault.sol'; import './IGateway.sol'; import '../token/IDToken.sol'; import '../token/IIOU.sol'; import '../../oracle/IOracle.sol'; import '../swapper/ISwapper.sol'; import '@openzeppelin/contracts/utils/cryptography/ECDSA.sol'; import '../../library/Bytes32Map.sol'; import '../../library/ETHAndERC20.sol'; import '../../library/SafeMath.sol'; import './GatewayStorage.sol'; contract GatewayImplementationGasSplit is GatewayStorage { using Bytes32Map for mapping(uint8 => bytes32); using ETHAndERC20 for address; using SafeMath for uint256; using SafeMath for int256; error CannotDelBToken(); error BTokenDupInitialize(); error BTokenNoSwapper(); error BTokenNoOracle(); error InvalidBToken(); error InvalidBAmount(); error InvalidBPrice(); error InvalidCustodian(); error InvalidLTokenId(); error InvalidPTokenId(); error InvalidRequestId(); error InsufficientMargin(); error InvalidSignature(); error InsufficientB0(); error InsufficientGasFee(); event AddBToken(address bToken, address vault, bytes32 oracleId, uint256 collateralFactor); event DelBToken(address bToken); event UpdateBToken(address bToken); event SetGasFee(uint256 actionId, uint256 gasFee); event RequestUpdateLiquidity( uint256 requestId, uint256 lTokenId, uint256 liquidity, int256 lastCumulativePnlOnEngine, int256 cumulativePnlOnGateway, uint256 removeBAmount ); event RequestRemoveMargin( uint256 requestId, uint256 pTokenId, uint256 realMoneyMargin, int256 lastCumulativePnlOnEngine, int256 cumulativePnlOnGateway, uint256 bAmount ); event RequestTrade( uint256 requestId, uint256 pTokenId, uint256 realMoneyMargin, int256 lastCumulativePnlOnEngine, int256 cumulativePnlOnGateway, bytes32 symbolId, int256[] tradeParams ); event RequestLiquidate( uint256 requestId, uint256 pTokenId, uint256 realMoneyMargin, int256 lastCumulativePnlOnEngine, int256 cumulativePnlOnGateway ); event RequestTradeAndRemoveMargin( uint256 requestId, uint256 pTokenId, uint256 realMoneyMargin, int256 lastCumulativePnlOnEngine, int256 cumulativePnlOnGateway, uint256 bAmount, bytes32 symbolId, int256[] tradeParams ); event FinishAddLiquidity( uint256 requestId, uint256 lTokenId, uint256 liquidity, uint256 totalLiquidity ); event FinishRemoveLiquidity( uint256 requestId, uint256 lTokenId, uint256 liquidity, uint256 totalLiquidity, address bToken, uint256 bAmount ); event FinishAddMargin( uint256 requestId, uint256 pTokenId, address bToken, uint256 bAmount ); event FinishRemoveMargin( uint256 requestId, uint256 pTokenId, address bToken, uint256 bAmount ); event FinishLiquidate( uint256 requestId, uint256 pTokenId, int256 lpPnl ); uint8 constant S_CUMULATIVEPNLONGATEWAY = 1; // Cumulative pnl on Gateway uint8 constant S_LIQUIDITYTIME = 2; // Last timestamp when liquidity updated uint8 constant S_TOTALLIQUIDITY = 3; // Total liquidity on d-chain uint8 constant S_CUMULATIVETIMEPERLIQUIDITY = 4; // Cumulavie time per liquidity uint8 constant S_GATEWAYREQUESTID = 5; // Gateway request id uint8 constant S_DCHAINGASFEEPERREQUEST = 6; // dChain gas fee for executing request on dChain uint8 constant S_TOTALICHAINGASFEE = 7; // Total iChain gas fee paid by all requests uint8 constant B_VAULT = 1; // BToken vault address uint8 constant B_ORACLEID = 2; // BToken oracle id uint8 constant B_COLLATERALFACTOR = 3; // BToken collateral factor uint8 constant D_REQUESTID = 1; // Lp/Trader request id uint8 constant D_BTOKEN = 2; // Lp/Trader bToken uint8 constant D_B0AMOUNT = 3; // Lp/Trader b0Amount uint8 constant D_LASTCUMULATIVEPNLONENGINE = 4; // Lp/Trader last cumulative pnl on engine uint8 constant D_LIQUIDITY = 5; // Lp liquidity uint8 constant D_CUMULATIVETIME = 6; // Lp cumulative time uint8 constant D_LASTCUMULATIVETIMEPERLIQUIDITY = 7; // Lp last cumulative time per liquidity uint8 constant D_SINGLEPOSITION = 8; // Td single position flag uint8 constant D_LASTREQUESTICHAINGASFEE = 9; // User last request's iChain gas fee uint8 constant D_CUMULATIVEUNUSEDICHAINGASFEE = 10; // User cumulaitve iChain gas fee for requests cannot be finished, users can claim back uint256 constant ACTION_REQUESTADDLIQUIDITY = 1; uint256 constant ACTION_REQUESTREMOVELIQUIDITY = 2; uint256 constant ACTION_REQUESTREMOVEMARGIN = 3; uint256 constant ACTION_REQUESTTRADE = 4; uint256 constant ACTION_REQUESTTRADEANDREMOVEMARGIN = 5; uint256 constant UONE = 1e18; int256 constant ONE = 1e18; address constant tokenETH = address(1); IDToken internal immutable lToken; IDToken internal immutable pToken; IOracle internal immutable oracle; ISwapper internal immutable swapper; IVault internal immutable vault0; // Vault for holding reserved B0, used for payments on regular bases IIOU internal immutable iou; // IOU ERC20, issued to traders when B0 insufficent address internal immutable tokenB0; // B0, settlement base token, e.g. USDC address internal immutable dChainEventSigner; uint8 internal immutable decimalsB0; uint256 internal immutable b0ReserveRatio; int256 internal immutable liquidationRewardCutRatio; int256 internal immutable minLiquidationReward; int256 internal immutable maxLiquidationReward; constructor ( address lToken_, address pToken_, address oracle_, address swapper_, address vault0_, address iou_, address tokenB0_, address dChainEventSigner_, uint256 b0ReserveRatio_, int256 liquidationRewardCutRatio_, int256 minLiquidationReward_, int256 maxLiquidationReward_ ) { lToken = IDToken(lToken_); pToken = IDToken(pToken_); oracle = IOracle(oracle_); swapper = ISwapper(swapper_); vault0 = IVault(vault0_); iou = IIOU(iou_); tokenB0 = tokenB0_; decimalsB0 = tokenB0_.decimals(); dChainEventSigner = dChainEventSigner_; b0ReserveRatio = b0ReserveRatio_; liquidationRewardCutRatio = liquidationRewardCutRatio_; minLiquidationReward = minLiquidationReward_; maxLiquidationReward = maxLiquidationReward_; } //================================================================================ // Getters //================================================================================ function getGatewayParam() external view returns (IGateway.GatewayParam memory p) { p.lToken = address(lToken); p.pToken = address(pToken); p.oracle = address(oracle); p.swapper = address(swapper); p.vault0 = address(vault0); p.iou = address(iou); p.tokenB0 = tokenB0; p.dChainEventSigner = dChainEventSigner; p.b0ReserveRatio = b0ReserveRatio; p.liquidationRewardCutRatio = liquidationRewardCutRatio; p.minLiquidationReward = minLiquidationReward; p.maxLiquidationReward = maxLiquidationReward; } function getGatewayState() external view returns (IGateway.GatewayState memory s) { s.cumulativePnlOnGateway = _gatewayStates.getInt(S_CUMULATIVEPNLONGATEWAY); s.liquidityTime = _gatewayStates.getUint(S_LIQUIDITYTIME); s.totalLiquidity = _gatewayStates.getUint(S_TOTALLIQUIDITY); s.cumulativeTimePerLiquidity = _gatewayStates.getInt(S_CUMULATIVETIMEPERLIQUIDITY); s.gatewayRequestId = _gatewayStates.getUint(S_GATEWAYREQUESTID); s.dChainGasFeePerRequest = _gatewayStates.getUint(S_DCHAINGASFEEPERREQUEST); s.totalIChainGasFee = _gatewayStates.getUint(S_TOTALICHAINGASFEE); } function getBTokenState(address bToken) external view returns (IGateway.BTokenState memory s) { s.vault = _bTokenStates[bToken].getAddress(B_VAULT); s.oracleId = _bTokenStates[bToken].getBytes32(B_ORACLEID); s.collateralFactor = _bTokenStates[bToken].getUint(B_COLLATERALFACTOR); } function getLpState(uint256 lTokenId) external view returns (IGateway.LpState memory s) { s.requestId = _dTokenStates[lTokenId].getUint(D_REQUESTID); s.bToken = _dTokenStates[lTokenId].getAddress(D_BTOKEN); s.bAmount = IVault(_bTokenStates[s.bToken].getAddress(B_VAULT)).getBalance(lTokenId); s.b0Amount = _dTokenStates[lTokenId].getInt(D_B0AMOUNT); s.lastCumulativePnlOnEngine = _dTokenStates[lTokenId].getInt(D_LASTCUMULATIVEPNLONENGINE); s.liquidity = _dTokenStates[lTokenId].getUint(D_LIQUIDITY); s.cumulativeTime = _dTokenStates[lTokenId].getUint(D_CUMULATIVETIME); s.lastCumulativeTimePerLiquidity = _dTokenStates[lTokenId].getUint(D_LASTCUMULATIVETIMEPERLIQUIDITY); s.lastRequestIChainGasFee = _dTokenStates[lTokenId].getUint(D_LASTREQUESTICHAINGASFEE); s.cumulativeUnusedIChainGasFee = _dTokenStates[lTokenId].getUint(D_CUMULATIVEUNUSEDICHAINGASFEE); } function getTdState(uint256 pTokenId) external view returns (IGateway.TdState memory s) { s.requestId = _dTokenStates[pTokenId].getUint(D_REQUESTID); s.bToken = _dTokenStates[pTokenId].getAddress(D_BTOKEN); s.bAmount = IVault(_bTokenStates[s.bToken].getAddress(B_VAULT)).getBalance(pTokenId); s.b0Amount = _dTokenStates[pTokenId].getInt(D_B0AMOUNT); s.lastCumulativePnlOnEngine = _dTokenStates[pTokenId].getInt(D_LASTCUMULATIVEPNLONENGINE); s.singlePosition = _dTokenStates[pTokenId].getBool(D_SINGLEPOSITION); s.lastRequestIChainGasFee = _dTokenStates[pTokenId].getUint(D_LASTREQUESTICHAINGASFEE); s.cumulativeUnusedIChainGasFee = _dTokenStates[pTokenId].getUint(D_CUMULATIVEUNUSEDICHAINGASFEE); } // @notice Calculate Lp's cumulative time, used in liquidity mining reward distributions function getCumulativeTime(uint256 lTokenId) public view returns (uint256 cumulativeTimePerLiquidity, uint256 cumulativeTime) { uint256 liquidityTime = _gatewayStates.getUint(S_LIQUIDITYTIME); uint256 totalLiquidity = _gatewayStates.getUint(S_TOTALLIQUIDITY); cumulativeTimePerLiquidity = _gatewayStates.getUint(S_CUMULATIVETIMEPERLIQUIDITY); uint256 liquidity = _dTokenStates[lTokenId].getUint(D_LIQUIDITY); cumulativeTime = _dTokenStates[lTokenId].getUint(D_CUMULATIVETIME); uint256 lastCumulativeTimePerLiquidity = _dTokenStates[lTokenId].getUint(D_LASTCUMULATIVETIMEPERLIQUIDITY); if (totalLiquidity != 0) { uint256 diff1 = (block.timestamp - liquidityTime) * UONE * UONE / totalLiquidity; unchecked { cumulativeTimePerLiquidity += diff1; } if (liquidity != 0) { uint256 diff2; unchecked { diff2 = cumulativeTimePerLiquidity - lastCumulativeTimePerLiquidity; } cumulativeTime += diff2 * liquidity / UONE; } } } function getGasFees() public view returns (uint256[] memory fees) { fees = new uint256[](5); fees[0] = _gasFees[ACTION_REQUESTADDLIQUIDITY]; fees[1] = _gasFees[ACTION_REQUESTREMOVELIQUIDITY]; fees[2] = _gasFees[ACTION_REQUESTREMOVEMARGIN]; fees[3] = _gasFees[ACTION_REQUESTTRADE]; fees[4] = _gasFees[ACTION_REQUESTTRADEANDREMOVEMARGIN]; } //================================================================================ // Setters //================================================================================ // function addBToken( // address bToken, // address vault, // bytes32 oracleId, // uint256 collateralFactor // ) external _onlyAdmin_ { // if (_bTokenStates[bToken].getAddress(B_VAULT) != address(0)) { // revert BTokenDupInitialize(); // } // if (IVault(vault).asset() != bToken) { // revert InvalidBToken(); // } // if (bToken != tokenETH) { // if (!swapper.isSupportedToken(bToken)) { // revert BTokenNoSwapper(); // } // // Approve for swapper and vault // bToken.approveMax(address(swapper)); // bToken.approveMax(vault); // if (bToken == tokenB0) { // // The reserved portion for B0 will be deposited to vault0 // bToken.approveMax(address(vault0)); // } // } // // Check bToken oracle except B0 // if (bToken != tokenB0 && oracle.getValue(oracleId) == 0) { // revert BTokenNoOracle(); // } // _bTokenStates[bToken].set(B_VAULT, vault); // _bTokenStates[bToken].set(B_ORACLEID, oracleId); // _bTokenStates[bToken].set(B_COLLATERALFACTOR, collateralFactor); // emit AddBToken(bToken, vault, oracleId, collateralFactor); // } // function delBToken(address bToken) external _onlyAdmin_ { // // bToken can only be deleted when there is no deposits // if (IVault(_bTokenStates[bToken].getAddress(B_VAULT)).stTotalAmount() != 0) { // revert CannotDelBToken(); // } // _bTokenStates[bToken].del(B_VAULT); // _bTokenStates[bToken].del(B_ORACLEID); // _bTokenStates[bToken].del(B_COLLATERALFACTOR); // emit DelBToken(bToken); // } // // @dev This function can be used to change bToken collateral factor // function setBTokenParameter(address bToken, uint8 idx, bytes32 value) external _onlyAdmin_ { // _bTokenStates[bToken].set(idx, value); // emit UpdateBToken(bToken); // } // @notice Set gas fee for actionId function setGasFee(uint256 actionId, uint256 gasFee) external _onlyAdmin_ { _gasFees[actionId] = gasFee; emit SetGasFee(actionId, gasFee); } function setDChainGasFeePerRequest(uint256 dChainGasFeePerRequest) external _onlyAdmin_ { _gatewayStates.set(S_DCHAINGASFEEPERREQUEST, dChainGasFeePerRequest); } // @notic Claim dChain gasFee to account `to` function claimDChainGasFee(address to) external _onlyAdmin_ { tokenETH.transferOut(to, tokenETH.balanceOfThis() - _gatewayStates.getUint(S_TOTALICHAINGASFEE)); } // @notice Claim unused iChain gas fee for dTokenId function claimUnusedIChainGasFee(uint256 dTokenId, bool isLp) external { address owner = isLp ? lToken.ownerOf(dTokenId) : pToken.ownerOf(dTokenId); uint256 cumulativeUnusedIChainGasFee = _dTokenStates[dTokenId].getUint(D_CUMULATIVEUNUSEDICHAINGASFEE); if (cumulativeUnusedIChainGasFee > 0) { uint256 totalIChainGasFee = _gatewayStates.getUint(S_TOTALICHAINGASFEE); totalIChainGasFee -= cumulativeUnusedIChainGasFee; _gatewayStates.set(S_TOTALICHAINGASFEE, totalIChainGasFee); _dTokenStates[dTokenId].del(D_CUMULATIVEUNUSEDICHAINGASFEE); tokenETH.transferOut(owner, cumulativeUnusedIChainGasFee); } } //================================================================================ // Interactions //================================================================================ // @notice Redeem B0 for burning IOU function redeemIOU(uint256 b0Amount) external { if (b0Amount > 0) { uint256 b0Redeemed = vault0.redeem(uint256(0), b0Amount); if (b0Redeemed > 0) { iou.burn(msg.sender, b0Redeemed); tokenB0.transferOut(msg.sender, b0Redeemed); } } } /** * @notice Request to add liquidity with specified base token. * @param lTokenId The unique identifier of the LToken. * @param bToken The address of the base token to add as liquidity. * @param bAmount The amount of base tokens to add as liquidity. */ function requestAddLiquidity(uint256 lTokenId, address bToken, uint256 bAmount) external payable { if (lTokenId == 0) { lTokenId = lToken.mint(msg.sender); } else { _checkLTokenIdOwner(lTokenId, msg.sender); } _checkBTokenInitialized(bToken); Data memory data = _getData(msg.sender, lTokenId, bToken); uint256 ethAmount = _receiveGasFee(lTokenId, _gasFees[ACTION_REQUESTADDLIQUIDITY]); if (bToken == tokenETH) { bAmount = ethAmount; } if (bAmount == 0) { revert InvalidBAmount(); } if (bToken != tokenETH) { bToken.transferIn(data.account, bAmount); } _deposit(data, bAmount); _getExParams(data); uint256 newLiquidity = _getDTokenLiquidity(data); _saveData(data); uint256 requestId = _incrementRequestId(lTokenId); emit RequestUpdateLiquidity( requestId, lTokenId, newLiquidity, data.lastCumulativePnlOnEngine, data.cumulativePnlOnGateway, 0 ); } /** * @notice Request to remove liquidity with specified base token. * @param lTokenId The unique identifier of the LToken. * @param bToken The address of the base token to remove as liquidity. * @param bAmount The amount of base tokens to remove as liquidity. */ function requestRemoveLiquidity(uint256 lTokenId, address bToken, uint256 bAmount) external payable { _checkLTokenIdOwner(lTokenId, msg.sender); _receiveGasFee(lTokenId, _gasFees[ACTION_REQUESTREMOVELIQUIDITY]); if (bAmount == 0) { revert InvalidBAmount(); } Data memory data = _getData(msg.sender, lTokenId, bToken); _getExParams(data); uint256 oldLiquidity = _getDTokenLiquidity(data); uint256 newLiquidity = _getDTokenLiquidityWithRemove(data, bAmount); if (newLiquidity <= oldLiquidity / 100) { newLiquidity = 0; } uint256 requestId = _incrementRequestId(lTokenId); emit RequestUpdateLiquidity( requestId, lTokenId, newLiquidity, data.lastCumulativePnlOnEngine, data.cumulativePnlOnGateway, bAmount ); } /** * @notice Request to add margin with specified base token. * @param pTokenId The unique identifier of the PToken. * @param bToken The address of the base token to add as margin. * @param bAmount The amount of base tokens to add as margin. * @param singlePosition The flag whether trader is using singlePosition margin. * @return The unique identifier pTokenId. */ function requestAddMargin(uint256 pTokenId, address bToken, uint256 bAmount, bool singlePosition) public payable returns (uint256) { if (pTokenId == 0) { pTokenId = pToken.mint(msg.sender); if (singlePosition) { _dTokenStates[pTokenId].set(D_SINGLEPOSITION, true); } } else { _checkPTokenIdOwner(pTokenId, msg.sender); } _checkBTokenInitialized(bToken); Data memory data = _getData(msg.sender, pTokenId, bToken); if (bToken == tokenETH) { if (bAmount > msg.value) { revert InvalidBAmount(); } } if (bAmount == 0) { revert InvalidBAmount(); } if (bToken != tokenETH) { bToken.transferIn(data.account, bAmount); } _deposit(data, bAmount); _saveData(data); uint256 requestId = _incrementRequestId(pTokenId); emit FinishAddMargin( requestId, pTokenId, bToken, bAmount ); return pTokenId; } /** * @notice Request to remove margin with specified base token. * @param pTokenId The unique identifier of the PToken. * @param bToken The address of the base token to remove as margin. * @param bAmount The amount of base tokens to remove as margin. */ function requestRemoveMargin(uint256 pTokenId, address bToken, uint256 bAmount) external payable { _checkPTokenIdOwner(pTokenId, msg.sender); _receiveGasFee(pTokenId, _gasFees[ACTION_REQUESTREMOVEMARGIN]); if (bAmount == 0) { revert InvalidBAmount(); } Data memory data = _getData(msg.sender, pTokenId, bToken); _getExParams(data); uint256 oldMargin = _getDTokenLiquidity(data); uint256 newMargin = _getDTokenLiquidityWithRemove(data, bAmount); if (newMargin <= oldMargin / 100) { newMargin = 0; } uint256 requestId = _incrementRequestId(pTokenId); emit RequestRemoveMargin( requestId, pTokenId, newMargin, data.lastCumulativePnlOnEngine, data.cumulativePnlOnGateway, bAmount ); } /** * @notice Request to initiate a trade using a specified PToken, symbol identifier, and trade parameters. * @param pTokenId The unique identifier of the PToken. * @param symbolId The identifier of the trading symbol. * @param tradeParams An array of trade parameters for the trade execution. */ function requestTrade(uint256 pTokenId, bytes32 symbolId, int256[] calldata tradeParams) public payable { _checkPTokenIdOwner(pTokenId, msg.sender); _receiveGasFee(pTokenId, _gasFees[ACTION_REQUESTTRADE]); Data memory data = _getData(msg.sender, pTokenId, _dTokenStates[pTokenId].getAddress(D_BTOKEN)); _getExParams(data); uint256 realMoneyMargin = _getDTokenLiquidity(data); uint256 requestId = _incrementRequestId(pTokenId); emit RequestTrade( requestId, pTokenId, realMoneyMargin, data.lastCumulativePnlOnEngine, data.cumulativePnlOnGateway, symbolId, tradeParams ); } /** * @notice Request to liquidate a specified PToken. * @param pTokenId The unique identifier of the PToken. */ function requestLiquidate(uint256 pTokenId) external { Data memory data = _getData(pToken.ownerOf(pTokenId), pTokenId, _dTokenStates[pTokenId].getAddress(D_BTOKEN)); _getExParams(data); uint256 realMoneyMargin = _getDTokenLiquidity(data); uint256 requestId = _incrementRequestId(pTokenId); emit RequestLiquidate( requestId, pTokenId, realMoneyMargin, data.lastCumulativePnlOnEngine, data.cumulativePnlOnGateway ); } /** * @notice Request to add margin and initiate a trade in a single transaction. * @param pTokenId The unique identifier of the PToken. * @param bToken The address of the base token to add as margin. * @param bAmount The amount of base tokens to add as margin. * @param symbolId The identifier of the trading symbol for the trade. * @param tradeParams An array of trade parameters for the trade execution. * @param singlePosition The flag whether trader is using singlePosition margin. */ function requestAddMarginAndTrade( uint256 pTokenId, address bToken, uint256 bAmount, bytes32 symbolId, int256[] calldata tradeParams, bool singlePosition ) external payable { if (bToken == tokenETH) { uint256 gasFee = _gasFees[ACTION_REQUESTTRADE]; if (bAmount + gasFee > msg.value) { // revert if bAmount > msg.value - gasFee revert InvalidBAmount(); } } pTokenId = requestAddMargin(pTokenId, bToken, bAmount, singlePosition); requestTrade(pTokenId, symbolId, tradeParams); } /** * @notice Request to initiate a trade and simultaneously remove margin from a specified PToken. * @param pTokenId The unique identifier of the PToken. * @param bToken The address of the base token to remove as margin. * @param bAmount The amount of base tokens to remove as margin. * @param symbolId The identifier of the trading symbol for the trade. * @param tradeParams An array of trade parameters for the trade execution. */ function requestTradeAndRemoveMargin( uint256 pTokenId, address bToken, uint256 bAmount, bytes32 symbolId, int256[] calldata tradeParams ) external payable { _checkPTokenIdOwner(pTokenId, msg.sender); _receiveGasFee(pTokenId, _gasFees[ACTION_REQUESTTRADEANDREMOVEMARGIN]); if (bAmount == 0) { revert InvalidBAmount(); } Data memory data = _getData(msg.sender, pTokenId, bToken); _getExParams(data); uint256 oldMargin = _getDTokenLiquidity(data); uint256 newMargin = _getDTokenLiquidityWithRemove(data, bAmount); if (newMargin <= oldMargin / 100) { newMargin = 0; } uint256 requestId = _incrementRequestId(pTokenId); emit RequestTradeAndRemoveMargin( requestId, pTokenId, newMargin, data.lastCumulativePnlOnEngine, data.cumulativePnlOnGateway, bAmount, symbolId, tradeParams ); } /** * @notice Finalize the liquidity update based on event emitted on d-chain. * @param eventData The encoded event data containing information about the liquidity update, emitted on d-chain. * @param signature The signature used to verify the event data. */ function finishUpdateLiquidity(bytes memory eventData, bytes memory signature) external _reentryLock_ { _verifyEventData(eventData, signature); IGateway.VarOnExecuteUpdateLiquidity memory v = abi.decode(eventData, (IGateway.VarOnExecuteUpdateLiquidity)); _checkRequestId(v.lTokenId, v.requestId); _updateLiquidity(v.lTokenId, v.liquidity, v.totalLiquidity); // Cumulate unsettled PNL to b0Amount Data memory data = _getData(lToken.ownerOf(v.lTokenId), v.lTokenId, _dTokenStates[v.lTokenId].getAddress(D_BTOKEN)); int256 diff = v.cumulativePnlOnEngine.minusUnchecked(data.lastCumulativePnlOnEngine); data.b0Amount += diff.rescaleDown(18, decimalsB0); data.lastCumulativePnlOnEngine = v.cumulativePnlOnEngine; uint256 bAmountRemoved; if (v.bAmountToRemove != 0) { _getExParams(data); bAmountRemoved = _transferOut(data, v.liquidity == 0 ? type(uint256).max : v.bAmountToRemove, false); } _saveData(data); _transferLastRequestIChainGasFee(v.lTokenId, msg.sender); if (v.bAmountToRemove == 0) { // If bAmountToRemove == 0, it is a AddLiqudiity finalization emit FinishAddLiquidity( v.requestId, v.lTokenId, v.liquidity, v.totalLiquidity ); } else { // If bAmountToRemove != 0, it is a RemoveLiquidity finalization emit FinishRemoveLiquidity( v.requestId, v.lTokenId, v.liquidity, v.totalLiquidity, data.bToken, bAmountRemoved ); } } /** * @notice Finalize the remove of margin based on event emitted on d-chain. * @param eventData The encoded event data containing information about the margin remove, emitted on d-chain. * @param signature The signature used to verify the event data. */ function finishRemoveMargin(bytes memory eventData, bytes memory signature) external _reentryLock_ { _verifyEventData(eventData, signature); IGateway.VarOnExecuteRemoveMargin memory v = abi.decode(eventData, (IGateway.VarOnExecuteRemoveMargin)); _checkRequestId(v.pTokenId, v.requestId); // Cumulate unsettled PNL to b0Amount Data memory data = _getData(pToken.ownerOf(v.pTokenId), v.pTokenId, _dTokenStates[v.pTokenId].getAddress(D_BTOKEN)); int256 diff = v.cumulativePnlOnEngine.minusUnchecked(data.lastCumulativePnlOnEngine); data.b0Amount += diff.rescaleDown(18, decimalsB0); data.lastCumulativePnlOnEngine = v.cumulativePnlOnEngine; _getExParams(data); uint256 bAmount = _transferOut(data, v.bAmountToRemove, true); if (_getDTokenLiquidity(data) < v.requiredMargin) { revert InsufficientMargin(); } _saveData(data); _transferLastRequestIChainGasFee(v.pTokenId, msg.sender); emit FinishRemoveMargin( v.requestId, v.pTokenId, data.bToken, bAmount ); } /** * @notice Finalize the liquidation based on event emitted on d-chain. * @param eventData The encoded event data containing information about the liquidation, emitted on d-chain. * @param signature The signature used to verify the event data. */ function finishLiquidate(bytes memory eventData, bytes memory signature) external _reentryLock_ { _verifyEventData(eventData, signature); IGateway.VarOnExecuteLiquidate memory v = abi.decode(eventData, (IGateway.VarOnExecuteLiquidate)); // Cumulate unsettled PNL to b0Amount Data memory data = _getData(pToken.ownerOf(v.pTokenId), v.pTokenId, _dTokenStates[v.pTokenId].getAddress(D_BTOKEN)); int256 diff = v.cumulativePnlOnEngine.minusUnchecked(data.lastCumulativePnlOnEngine); data.b0Amount += diff.rescaleDown(18, decimalsB0); data.lastCumulativePnlOnEngine = v.cumulativePnlOnEngine; uint256 b0AmountIn; // Redeem all bToken from vault and swap into B0 { uint256 bAmount = IVault(data.vault).redeem(data.dTokenId, type(uint256).max); if (data.bToken == tokenB0) { b0AmountIn += bAmount; } else if (data.bToken == tokenETH) { (uint256 resultB0, ) = swapper.swapExactETHForB0{value:bAmount}(); b0AmountIn += resultB0; } else { (uint256 resultB0, ) = swapper.swapExactBXForB0(data.bToken, bAmount); b0AmountIn += resultB0; } } int256 lpPnl = b0AmountIn.utoi() + data.b0Amount; // All Lp's PNL by liquidating this trader int256 reward; // Calculate liquidator's reward { if (lpPnl <= minLiquidationReward) { reward = minLiquidationReward; } else { reward = SafeMath.min( (lpPnl - minLiquidationReward) * liquidationRewardCutRatio / ONE + minLiquidationReward, maxLiquidationReward ); } uint256 uReward = reward.itou(); if (uReward <= b0AmountIn) { tokenB0.transferOut(msg.sender, uReward); b0AmountIn -= uReward; } else { uint256 b0Redeemed = vault0.redeem(uint256(0), uReward - b0AmountIn); tokenB0.transferOut(msg.sender, b0AmountIn + b0Redeemed); reward = (b0AmountIn + b0Redeemed).utoi(); b0AmountIn = 0; } lpPnl -= reward; } if (b0AmountIn > 0) { vault0.deposit(uint256(0), b0AmountIn); } // Cumulate lpPnl into cumulativePnlOnGateway, // which will be distributed to all LPs on all i-chains with next request process data.cumulativePnlOnGateway = data.cumulativePnlOnGateway.addUnchecked(lpPnl.rescale(decimalsB0, 18)); data.b0Amount = 0; _saveData(data); { uint256 lastRequestIChainGasFee = _dTokenStates[v.pTokenId].getUint(D_LASTREQUESTICHAINGASFEE); uint256 cumulativeUnusedIChainGasFee = _dTokenStates[v.pTokenId].getUint(D_CUMULATIVEUNUSEDICHAINGASFEE); _dTokenStates[v.pTokenId].del(D_LASTREQUESTICHAINGASFEE); _dTokenStates[v.pTokenId].del(D_CUMULATIVEUNUSEDICHAINGASFEE); uint256 totalIChainGasFee = _gatewayStates.getUint(S_TOTALICHAINGASFEE); totalIChainGasFee -= lastRequestIChainGasFee + cumulativeUnusedIChainGasFee; _gatewayStates.set(S_TOTALICHAINGASFEE, totalIChainGasFee); } pToken.burn(v.pTokenId); emit FinishLiquidate( v.requestId, v.pTokenId, lpPnl ); } //================================================================================ // Internals //================================================================================ // Temporary struct holding intermediate values passed around functions struct Data { address account; // Lp/Trader account address uint256 dTokenId; // Lp/Trader dTokenId address bToken; // Lp/Trader bToken address int256 cumulativePnlOnGateway; // cumulative pnl on Gateway address vault; // Lp/Trader bToken's vault address int256 b0Amount; // Lp/Trader b0Amount int256 lastCumulativePnlOnEngine; // Lp/Trader last cumulative pnl on engine uint256 collateralFactor; // bToken collateral factor uint256 bPrice; // bToken price } function _getData(address account, uint256 dTokenId, address bToken) internal view returns (Data memory data) { data.account = account; data.dTokenId = dTokenId; data.bToken = bToken; data.cumulativePnlOnGateway = _gatewayStates.getInt(S_CUMULATIVEPNLONGATEWAY); data.vault = _bTokenStates[bToken].getAddress(B_VAULT); data.b0Amount = _dTokenStates[dTokenId].getInt(D_B0AMOUNT); data.lastCumulativePnlOnEngine = _dTokenStates[dTokenId].getInt(D_LASTCUMULATIVEPNLONENGINE); _checkBTokenConsistency(dTokenId, bToken); } function _saveData(Data memory data) internal { _gatewayStates.set(S_CUMULATIVEPNLONGATEWAY, data.cumulativePnlOnGateway); _dTokenStates[data.dTokenId].set(D_BTOKEN, data.bToken); _dTokenStates[data.dTokenId].set(D_B0AMOUNT, data.b0Amount); _dTokenStates[data.dTokenId].set(D_LASTCUMULATIVEPNLONENGINE, data.lastCumulativePnlOnEngine); } // @notice Check callback's requestId is the same as the current requestId stored for user // If a new request is submitted before the callback for last request, requestId will not match, // and this callback cannot be executed anymore function _checkRequestId(uint256 dTokenId, uint256 requestId) internal { uint128 userRequestId = uint128(requestId); if (_dTokenStates[dTokenId].getUint(D_REQUESTID) != uint256(userRequestId)) { revert InvalidRequestId(); } else { // increment requestId so that callback can only be executed once _dTokenStates[dTokenId].set(D_REQUESTID, uint256(userRequestId + 1)); } } // @notice Increment gateway requestId and user requestId // and returns the combined requestId for this request // The combined requestId contains 2 parts: // * Lower 128 bits stores user's requestId, only increments when request is from this user // * Higher 128 bits stores gateways's requestId, increments for all new requests in this contract function _incrementRequestId(uint256 dTokenId) internal returns (uint256) { uint128 gatewayRequestId = uint128(_gatewayStates.getUint(S_GATEWAYREQUESTID)); gatewayRequestId += 1; _gatewayStates.set(S_GATEWAYREQUESTID, uint256(gatewayRequestId)); uint128 userRequestId = uint128(_dTokenStates[dTokenId].getUint(D_REQUESTID)); userRequestId += 1; _dTokenStates[dTokenId].set(D_REQUESTID, uint256(userRequestId)); uint256 requestId = (uint256(gatewayRequestId) << 128) + uint256(userRequestId); return requestId; } function _checkBTokenInitialized(address bToken) internal view { if (_bTokenStates[bToken].getAddress(B_VAULT) == address(0)) { revert InvalidBToken(); } } function _checkBTokenConsistency(uint256 dTokenId, address bToken) internal view { address preBToken = _dTokenStates[dTokenId].getAddress(D_BTOKEN); if (preBToken != address(0) && preBToken != bToken) { uint256 stAmount = IVault(_bTokenStates[preBToken].getAddress(B_VAULT)).stAmounts(dTokenId); if (stAmount != 0) { revert InvalidBToken(); } } } function _checkLTokenIdOwner(uint256 lTokenId, address owner) internal view { if (lToken.ownerOf(lTokenId) != owner) { revert InvalidLTokenId(); } } function _checkPTokenIdOwner(uint256 pTokenId, address owner) internal view { if (pToken.ownerOf(pTokenId) != owner) { revert InvalidPTokenId(); } } function _receiveGasFee(uint256 dTokenId, uint256 gasFee) internal returns (uint256) { uint256 dChainGasFee = _gatewayStates.getUint(S_DCHAINGASFEEPERREQUEST); if (msg.value < gasFee) { revert InsufficientGasFee(); } uint256 iChainGasFee = gasFee - dChainGasFee; uint256 totalIChainGasFee = _gatewayStates.getUint(S_TOTALICHAINGASFEE) + iChainGasFee; _gatewayStates.set(S_TOTALICHAINGASFEE, totalIChainGasFee); uint256 lastRequestIChainGasFee = _dTokenStates[dTokenId].getUint(D_LASTREQUESTICHAINGASFEE); uint256 cumulativeUnusedIChainGasFee = _dTokenStates[dTokenId].getUint(D_CUMULATIVEUNUSEDICHAINGASFEE); cumulativeUnusedIChainGasFee += lastRequestIChainGasFee; lastRequestIChainGasFee = iChainGasFee; _dTokenStates[dTokenId].set(D_LASTREQUESTICHAINGASFEE, lastRequestIChainGasFee); _dTokenStates[dTokenId].set(D_CUMULATIVEUNUSEDICHAINGASFEE, cumulativeUnusedIChainGasFee); return msg.value - gasFee; } function _transferLastRequestIChainGasFee(uint256 dTokenId, address to) internal { uint256 lastRequestIChainGasFee = _dTokenStates[dTokenId].getUint(D_LASTREQUESTICHAINGASFEE); if (lastRequestIChainGasFee > 0) { uint256 totalIChainGasFee = _gatewayStates.getUint(S_TOTALICHAINGASFEE); totalIChainGasFee -= lastRequestIChainGasFee; _gatewayStates.set(S_TOTALICHAINGASFEE, totalIChainGasFee); _dTokenStates[dTokenId].del(D_LASTREQUESTICHAINGASFEE); tokenETH.transferOut(to, lastRequestIChainGasFee); } } // @dev bPrice * bAmount / UONE = b0Amount, b0Amount in decimalsB0 function _getBPrice(address bToken) internal view returns (uint256 bPrice) { if (bToken == tokenB0) { bPrice = UONE; } else { uint8 decimalsB = bToken.decimals(); bPrice = oracle.getValue(_bTokenStates[bToken].getBytes32(B_ORACLEID)).itou().rescale(decimalsB, decimalsB0); if (bPrice == 0) { revert InvalidBPrice(); } } } function _getExParams(Data memory data) internal view { data.collateralFactor = _bTokenStates[data.bToken].getUint(B_COLLATERALFACTOR); data.bPrice = _getBPrice(data.bToken); } // @notice Calculate the liquidity (in 18 decimals) associated with current dTokenId function _getDTokenLiquidity(Data memory data) internal view returns (uint256 liquidity) { uint256 b0AmountInVault = IVault(data.vault).getBalance(data.dTokenId) * data.bPrice / UONE * data.collateralFactor / UONE; uint256 b0Shortage = data.b0Amount >= 0 ? 0 : (-data.b0Amount).itou(); if (b0AmountInVault >= b0Shortage) { liquidity = b0AmountInVault.add(data.b0Amount).rescale(decimalsB0, 18); } } // @notice Calculate the liquidity (in 18 decimals) associated with current dTokenId if `bAmount` in bToken is removed function _getDTokenLiquidityWithRemove(Data memory data, uint256 bAmount) internal view returns (uint256 liquidity) { if (bAmount < type(uint256).max / data.bPrice) { // make sure bAmount * bPrice won't overflow uint256 bAmountInVault = IVault(data.vault).getBalance(data.dTokenId); if (bAmount >= bAmountInVault) { if (data.b0Amount > 0) { uint256 b0Shortage = (bAmount - bAmountInVault) * data.bPrice / UONE; uint256 b0Amount = data.b0Amount.itou(); if (b0Amount > b0Shortage) { liquidity = (b0Amount - b0Shortage).rescale(decimalsB0, 18); } } } else { uint256 b0Excessive = (bAmountInVault - bAmount) * data.bPrice / UONE * data.collateralFactor / UONE; // discounted if (data.b0Amount >= 0) { liquidity = b0Excessive.add(data.b0Amount).rescale(decimalsB0, 18); } else { uint256 b0Shortage = (-data.b0Amount).itou(); if (b0Excessive > b0Shortage) { liquidity = (b0Excessive - b0Shortage).rescale(decimalsB0, 18); } } } } } // @notice Deposit bToken with `bAmount` function _deposit(Data memory data, uint256 bAmount) internal { if (data.bToken == tokenB0) { uint256 reserved = bAmount * b0ReserveRatio / UONE; bAmount -= reserved; vault0.deposit(uint256(0), reserved); data.b0Amount += reserved.utoi(); } if (data.bToken == tokenETH) { IVault(data.vault).deposit{value: bAmount}(data.dTokenId, bAmount); } else { IVault(data.vault).deposit(data.dTokenId, bAmount); } } /** * @notice Transfer a specified amount of bToken, handling various cases. * @param data A Data struct containing information about the interaction. * @param bAmountOut The intended amount of tokens to transfer out. * @param isTd A flag indicating whether the transfer is for a trader (true) or not (false). * @return bAmount The amount of tokens actually transferred. */ function _transferOut(Data memory data, uint256 bAmountOut, bool isTd) internal returns (uint256 bAmount) { bAmount = bAmountOut; // Handle redemption of additional tokens to cover a negative B0 amount. if (bAmount < type(uint256).max / UONE && data.b0Amount < 0) { if (data.bToken == tokenB0) { // Redeem B0 tokens to cover the negative B0 amount. bAmount += (-data.b0Amount).itou(); } else { // Swap tokens to B0 to cover the negative B0 amount, with a slight excess to account for possible slippage. bAmount += (-data.b0Amount).itou() * UONE / data.bPrice * 105 / 100; } } // Redeem tokens from the vault using IVault interface. bAmount = IVault(data.vault).redeem(data.dTokenId, bAmount); // bAmount now represents the actual redeemed bToken. uint256 b0AmountIn; // Amount of B0 tokens going to reserves. uint256 b0AmountOut; // Amount of B0 tokens going to the user. uint256 iouAmount; // Amount of IOU tokens going to the trader. // Handle excessive tokens (more than bAmountOut). if (bAmount > bAmountOut) { uint256 bExcessive = bAmount - bAmountOut; uint256 b0Excessive; if (data.bToken == tokenB0) { b0Excessive = bExcessive; bAmount -= bExcessive; } else if (data.bToken == tokenETH) { (uint256 resultB0, uint256 resultBX) = swapper.swapExactETHForB0{value: bExcessive}(); b0Excessive = resultB0; bAmount -= resultBX; } else { (uint256 resultB0, uint256 resultBX) = swapper.swapExactBXForB0(data.bToken, bExcessive); b0Excessive = resultB0; bAmount -= resultBX; } b0AmountIn += b0Excessive; data.b0Amount += b0Excessive.utoi(); } // Handle filling the negative B0 balance, by swapping bToken into B0, if necessary. if (bAmount > 0 && data.b0Amount < 0) { uint256 owe = (-data.b0Amount).itou(); uint256 b0Fill; if (data.bToken == tokenB0) { if (bAmount >= owe) { b0Fill = owe; bAmount -= owe; } else { b0Fill = bAmount; bAmount = 0; } } else if (data.bToken == tokenETH) { (uint256 resultB0, uint256 resultBX) = swapper.swapETHForExactB0{value: bAmount}(owe); b0Fill = resultB0; bAmount -= resultBX; } else { (uint256 resultB0, uint256 resultBX) = swapper.swapBXForExactB0(data.bToken, owe, bAmount); b0Fill = resultB0; bAmount -= resultBX; } b0AmountIn += b0Fill; data.b0Amount += b0Fill.utoi(); } // Handle reserved portion when withdrawing all or operating token is tokenB0 if (data.b0Amount > 0) { uint256 amount; if (bAmountOut >= type(uint256).max / UONE) { // withdraw all amount = data.b0Amount.itou(); } else if (data.bToken == tokenB0 && bAmount < bAmountOut) { // shortage on tokenB0 amount = SafeMath.min(data.b0Amount.itou(), bAmountOut - bAmount); } if (amount > 0) { uint256 b0Out; if (amount > b0AmountIn) { // Redeem B0 tokens from vault0 uint256 b0Redeemed = vault0.redeem(uint256(0), amount - b0AmountIn); if (b0Redeemed < amount - b0AmountIn) { // b0 insufficent if (isTd) { iouAmount = amount - b0AmountIn - b0Redeemed; // Issue IOU for trader when B0 insufficent } else { revert InsufficientB0(); // Revert for Lp when B0 insufficent } } b0Out = b0AmountIn + b0Redeemed; b0AmountIn = 0; } else { b0Out = amount; b0AmountIn -= amount; } b0AmountOut += b0Out; data.b0Amount -= b0Out.utoi() + iouAmount.utoi(); } } // Deposit B0 tokens into the vault0, if any if (b0AmountIn > 0) { vault0.deposit(uint256(0), b0AmountIn); } // Transfer B0 tokens or swap them to the current operating token if (b0AmountOut > 0) { if (isTd) { // No swap from B0 to BX for trader if (data.bToken == tokenB0) { bAmount += b0AmountOut; } else { tokenB0.transferOut(data.account, b0AmountOut); } } else { // Swap B0 into BX for Lp if (data.bToken == tokenB0) { bAmount += b0AmountOut; } else if (data.bToken == tokenETH) { (, uint256 resultBX) = swapper.swapExactB0ForETH(b0AmountOut); bAmount += resultBX; } else { (, uint256 resultBX) = swapper.swapExactB0ForBX(data.bToken, b0AmountOut); bAmount += resultBX; } } } // Transfer the remaining bAmount to the user's account. if (bAmount > 0) { data.bToken.transferOut(data.account, bAmount); } // Mint IOU tokens for the trader, if any. if (iouAmount > 0) { iou.mint(data.account, iouAmount); } } /** * @dev Update liquidity-related state variables for a specific `lTokenId`. * @param lTokenId The ID of the corresponding lToken. * @param newLiquidity The new liquidity amount for the lToken. * @param newTotalLiquidity The new total liquidity in the engine. */ function _updateLiquidity(uint256 lTokenId, uint256 newLiquidity, uint256 newTotalLiquidity) internal { (uint256 cumulativeTimePerLiquidity, uint256 cumulativeTime) = getCumulativeTime(lTokenId); _gatewayStates.set(S_LIQUIDITYTIME, block.timestamp); _gatewayStates.set(S_TOTALLIQUIDITY, newTotalLiquidity); _gatewayStates.set(S_CUMULATIVETIMEPERLIQUIDITY, cumulativeTimePerLiquidity); _dTokenStates[lTokenId].set(D_LIQUIDITY, newLiquidity); _dTokenStates[lTokenId].set(D_CUMULATIVETIME, cumulativeTime); _dTokenStates[lTokenId].set(D_LASTCUMULATIVETIMEPERLIQUIDITY, cumulativeTimePerLiquidity); } function _verifyEventData(bytes memory eventData, bytes memory signature) internal view { bytes32 hash = ECDSA.toEthSignedMessageHash(keccak256(eventData)); if (ECDSA.recover(hash, signature) != dChainEventSigner) { revert InvalidSignature(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to * 0 before setting it to a non-zero value. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @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. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @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, and the `v` value to be either 27 or 28. * * 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] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { 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 assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. 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, and the `v` value to be either 27 or 28. * * 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. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { // 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), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; import '../../utils/Admin.sol'; import '../../utils/Implementation.sol'; import '../../utils/ReentryLock.sol'; abstract contract GatewayStorage is Admin, Implementation, ReentryLock { // stateId => value mapping(uint8 => bytes32) internal _gatewayStates; // bToken => stateId => value mapping(address => mapping(uint8 => bytes32)) internal _bTokenStates; // dTokenId => stateId => value mapping(uint256 => mapping(uint8 => bytes32)) internal _dTokenStates; // actionId => gasFee mapping(uint256 => uint256) internal _gasFees; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; interface IGateway { struct GatewayParam { address lToken; address pToken; address oracle; address swapper; address vault0; address iou; address tokenB0; address dChainEventSigner; uint256 b0ReserveRatio; int256 liquidationRewardCutRatio; int256 minLiquidationReward; int256 maxLiquidationReward; } struct GatewayState { int256 cumulativePnlOnGateway; uint256 liquidityTime; uint256 totalLiquidity; int256 cumulativeTimePerLiquidity; uint256 gatewayRequestId; uint256 dChainGasFeePerRequest; uint256 totalIChainGasFee; } struct BTokenState { address vault; bytes32 oracleId; uint256 collateralFactor; } struct LpState { uint256 requestId; address bToken; uint256 bAmount; int256 b0Amount; int256 lastCumulativePnlOnEngine; uint256 liquidity; uint256 cumulativeTime; uint256 lastCumulativeTimePerLiquidity; uint256 lastRequestIChainGasFee; uint256 cumulativeUnusedIChainGasFee; } struct TdState { uint256 requestId; address bToken; uint256 bAmount; int256 b0Amount; int256 lastCumulativePnlOnEngine; bool singlePosition; uint256 lastRequestIChainGasFee; uint256 cumulativeUnusedIChainGasFee; } struct VarOnExecuteUpdateLiquidity { uint256 requestId; uint256 lTokenId; uint256 liquidity; uint256 totalLiquidity; int256 cumulativePnlOnEngine; uint256 bAmountToRemove; } struct VarOnExecuteRemoveMargin { uint256 requestId; uint256 pTokenId; uint256 requiredMargin; int256 cumulativePnlOnEngine; uint256 bAmountToRemove; } struct VarOnExecuteLiquidate { uint256 requestId; uint256 pTokenId; int256 cumulativePnlOnEngine; } function getGatewayState() external view returns (GatewayState memory s); function getBTokenState(address bToken) external view returns (BTokenState memory s); function getLpState(uint256 lTokenId) external view returns (LpState memory s); function getTdState(uint256 pTokenId) external view returns (TdState memory s); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; import './IUniswapV2Factory.sol'; import './IUniswapV2Router02.sol'; import '../../oracle/IOracle.sol'; interface ISwapper { function factory() external view returns (IUniswapV2Factory); function router() external view returns (IUniswapV2Router02); function oracle() external view returns (IOracle); function tokenB0() external view returns (address); function tokenWETH() external view returns (address); function maxSlippageRatio() external view returns (uint256); function oracleSymbolIds(address tokenBX) external view returns (bytes32); function setPath(string memory priceSymbol, address[] calldata path) external; function getPath(address tokenBX) external view returns (address[] memory); function isSupportedToken(address tokenBX) external view returns (bool); function getTokenPrice(address tokenBX) external view returns (uint256); function swapExactB0ForBX(address tokenBX, uint256 amountB0) external returns (uint256 resultB0, uint256 resultBX); function swapExactBXForB0(address tokenBX, uint256 amountBX) external returns (uint256 resultB0, uint256 resultBX); function swapB0ForExactBX(address tokenBX, uint256 maxAmountB0, uint256 amountBX) external returns (uint256 resultB0, uint256 resultBX); function swapBXForExactB0(address tokenBX, uint256 amountB0, uint256 maxAmountBX) external returns (uint256 resultB0, uint256 resultBX); function swapExactB0ForETH(uint256 amountB0) external returns (uint256 resultB0, uint256 resultBX); function swapExactETHForB0() external payable returns (uint256 resultB0, uint256 resultBX); function swapB0ForExactETH(uint256 maxAmountB0, uint256 amountBX) external returns (uint256 resultB0, uint256 resultBX); function swapETHForExactB0(uint256 amountB0) external payable returns (uint256 resultB0, uint256 resultBX); }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface IUniswapV2Factory { event PairCreated(address indexed token0, address indexed token1, address pair, uint); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint) external view returns (address pair); function allPairsLength() external view returns (uint); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2; interface IUniswapV2Router01 { function factory() external pure returns (address); function WETH() external pure returns (address); function addLiquidity( address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB, uint liquidity); function addLiquidityETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external payable returns (uint amountToken, uint amountETH, uint liquidity); function removeLiquidity( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB); function removeLiquidityETH( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountToken, uint amountETH); function removeLiquidityWithPermit( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountA, uint amountB); function removeLiquidityETHWithPermit( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountToken, uint amountETH); function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapTokensForExactTokens( uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2; import './IUniswapV2Router01.sol'; interface IUniswapV2Router02 is IUniswapV2Router01 { function removeLiquidityETHSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountETH); function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountETH); function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; function swapExactETHForTokensSupportingFeeOnTransferTokens( uint amountOutMin, address[] calldata path, address to, uint deadline ) external payable; function swapExactTokensForETHSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; import '@openzeppelin/contracts/token/ERC721/IERC721.sol'; interface IDToken is IERC721 { function ownerOf(uint256) external view returns (address); function totalMinted() external view returns (uint160); function mint(address owner) external returns (uint256 tokenId); function burn(uint256 tokenId) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; interface IIOU is IERC20 { function vault() external view returns (address); function mint(address account, uint256 amount) external; function burn(address account, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; interface IVault { function stAmounts(uint256 dTokenId) external view returns (uint256); function stTotalAmount() external view returns (uint256); function requester() external view returns (address); function asset() external view returns (address); function getBalance(uint256 dTokenId) external view returns (uint256 balance); function deposit(uint256 dTokenId, uint256 amount) external payable returns (uint256 mintedSt); function redeem(uint256 dTokenId, uint256 amount) external returns (uint256 redeemedAmount); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; library Bytes32 { error StringExceeds31Bytes(string value); function toUint(bytes32 value) internal pure returns (uint256) { return uint256(value); } function toInt(bytes32 value) internal pure returns (int256) { return int256(uint256(value)); } function toAddress(bytes32 value) internal pure returns (address) { return address(uint160(uint256(value))); } function toBool(bytes32 value) internal pure returns (bool) { return value != bytes32(0); } /** * @notice Convert a bytes32 value to a string. * @dev This function takes an input bytes32 'value' and converts it into a string. * It dynamically determines the length of the string based on non-null characters in 'value'. * @param value The input bytes32 value to be converted. * @return The string representation of the input bytes32. */ function toString(bytes32 value) internal pure returns (string memory) { bytes memory bytesArray = new bytes(32); for (uint256 i = 0; i < 32; i++) { if (value[i] == 0) { assembly { mstore(bytesArray, i) } break; } else { bytesArray[i] = value[i]; } } return string(bytesArray); } function toBytes32(uint256 value) internal pure returns (bytes32) { return bytes32(value); } function toBytes32(int256 value) internal pure returns (bytes32) { return bytes32(uint256(value)); } function toBytes32(address value) internal pure returns (bytes32) { return bytes32(uint256(uint160(value))); } function toBytes32(bool value) internal pure returns (bytes32) { return bytes32(uint256(value ? 1 : 0)); } /** * @notice Convert a string to a bytes32 value. * @dev This function takes an input string 'value' and converts it into a bytes32 value. * It enforces a length constraint of 31 characters or less to ensure it fits within a bytes32. * The function uses inline assembly to efficiently copy the string data into the bytes32. * @param value The input string to be converted. * @return The bytes32 representation of the input string. */ function toBytes32(string memory value) internal pure returns (bytes32) { if (bytes(value).length > 31) { revert StringExceeds31Bytes(value); } bytes32 res; assembly { res := mload(add(value, 0x20)) } return res; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; import './Bytes32.sol'; library Bytes32Map { function getBytes32(mapping(uint8 => bytes32) storage store, uint8 idx) internal view returns (bytes32) { return store[idx]; } function getAddress(mapping(uint8 => bytes32) storage store, uint8 idx) internal view returns (address) { return Bytes32.toAddress(store[idx]); } function getUint(mapping(uint8 => bytes32) storage store, uint8 idx) internal view returns (uint256) { return Bytes32.toUint(store[idx]); } function getInt(mapping(uint8 => bytes32) storage store, uint8 idx) internal view returns (int256) { return Bytes32.toInt(store[idx]); } function getBool(mapping(uint8 => bytes32) storage store, uint8 idx) internal view returns (bool) { return Bytes32.toBool(store[idx]); } function getString(mapping(uint8 => bytes32) storage store, uint8 idx) internal view returns (string memory) { return Bytes32.toString(store[idx]); } function set(mapping(uint8 => bytes32) storage store, uint8 idx, bytes32 value) internal { store[idx] = value; } function set(mapping(uint8 => bytes32) storage store, uint8 idx, address value) internal { store[idx] = Bytes32.toBytes32(value); } function set(mapping(uint8 => bytes32) storage store, uint8 idx, uint256 value) internal { store[idx] = Bytes32.toBytes32(value); } function set(mapping(uint8 => bytes32) storage store, uint8 idx, int256 value) internal { store[idx] = Bytes32.toBytes32(value); } function set(mapping(uint8 => bytes32) storage store, uint8 idx, bool value) internal { store[idx] = Bytes32.toBytes32(value); } function set(mapping(uint8 => bytes32) storage store, uint8 idx, string memory value) internal { store[idx] = Bytes32.toBytes32(value); } function del(mapping(uint8 => bytes32) storage store, uint8 idx) internal { delete store[idx]; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; /// Library for operating ERC20 and ETH in one logic /// ETH is represented by address: 0x0000000000000000000000000000000000000001 library ETHAndERC20 { using SafeERC20 for IERC20; error SendEthFail(); error WrongTokenInAmount(); error WrongTokenOutAmount(); function decimals(address token) internal view returns (uint8) { return token == address(1) ? 18 : IERC20Metadata(token).decimals(); } // @notice Get the balance of ERC20 tokens or Ether held by this contract function balanceOfThis(address token) internal view returns (uint256) { return token == address(1) ? address(this).balance : IERC20(token).balanceOf(address(this)); } function approveMax(address token, address spender) internal { if (token != address(1)) { uint256 allowance = IERC20(token).allowance(address(this), spender); if (allowance != type(uint256).max) { if (allowance != 0) { IERC20(token).safeApprove(spender, 0); } IERC20(token).safeApprove(spender, type(uint256).max); } } } function unapprove(address token, address spender) internal { if (token != address(1)) { uint256 allowance = IERC20(token).allowance(address(this), spender); if (allowance != 0) { IERC20(token).safeApprove(spender, 0); } } } // @notice Transfer ERC20 tokens or Ether from 'from' to this contract function transferIn(address token, address from, uint256 amount) internal { if (token == address(1)) { if (amount != msg.value) { revert WrongTokenInAmount(); } } else { uint256 balance1 = balanceOfThis(token); IERC20(token).safeTransferFrom(from, address(this), amount); uint256 balance2 = balanceOfThis(token); if (balance2 != balance1 + amount) { revert WrongTokenInAmount(); } } } // @notice Transfer ERC20 tokens or Ether from this contract to 'to' function transferOut(address token, address to, uint256 amount) internal { uint256 balance1 = balanceOfThis(token); if (token == address(1)) { (bool success, ) = payable(to).call{value: amount}(''); if (!success) { revert SendEthFail(); } } else { IERC20(token).safeTransfer(to, amount); } uint256 balance2 = balanceOfThis(token); if (balance1 != balance2 + amount) { revert WrongTokenOutAmount(); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; library SafeMath { error UtoIOverflow(uint256); error IToUOverflow(int256); error AbsOverflow(int256); uint256 constant IMAX = 2**255 - 1; int256 constant IMIN = -2**255; function utoi(uint256 a) internal pure returns (int256) { if (a > IMAX) { revert UtoIOverflow(a); } return int256(a); } function itou(int256 a) internal pure returns (uint256) { if (a < 0) { revert IToUOverflow(a); } return uint256(a); } function abs(int256 a) internal pure returns (int256) { if (a == IMIN) { revert AbsOverflow(a); } return a >= 0 ? a : -a; } function add(uint256 a, int256 b) internal pure returns (uint256) { if (b >= 0) { return a + uint256(b); } else { return a - uint256(-b); } } function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } function max(int256 a, int256 b) internal pure returns (int256) { return a >= b ? a : b; } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a <= b ? a : b; } function min(int256 a, int256 b) internal pure returns (int256) { return a <= b ? a : b; } function divRoundingUp(uint256 a, uint256 b) internal pure returns (uint256 c) { c = a / b; if (b * c != a) { c += 1; } } // @notice Rescale a uint256 value from a base of 10^decimals1 to 10^decimals2 function rescale(uint256 value, uint256 decimals1, uint256 decimals2) internal pure returns (uint256) { return decimals1 == decimals2 ? value : value * 10**decimals2 / 10**decimals1; } // @notice Rescale value with rounding down function rescaleDown(uint256 value, uint256 decimals1, uint256 decimals2) internal pure returns (uint256) { return rescale(value, decimals1, decimals2); } // @notice Rescale value with rounding up function rescaleUp(uint256 value, uint256 decimals1, uint256 decimals2) internal pure returns (uint256) { uint256 rescaled = rescale(value, decimals1, decimals2); if (rescale(rescaled, decimals2, decimals1) != value) { rescaled += 1; } return rescaled; } function rescale(int256 value, uint256 decimals1, uint256 decimals2) internal pure returns (int256) { return decimals1 == decimals2 ? value : value * int256(10**decimals2) / int256(10**decimals1); } function rescaleDown(int256 value, uint256 decimals1, uint256 decimals2) internal pure returns (int256) { int256 rescaled = rescale(value, decimals1, decimals2); if (value < 0 && rescale(rescaled, decimals2, decimals1) != value) { rescaled -= 1; } return rescaled; } function rescaleUp(int256 value, uint256 decimals1, uint256 decimals2) internal pure returns (int256) { int256 rescaled = rescale(value, decimals1, decimals2); if (value > 0 && rescale(rescaled, decimals2, decimals1) != value) { rescaled += 1; } return rescaled; } // @notice Calculate a + b with overflow allowed function addUnchecked(int256 a, int256 b) internal pure returns (int256 c) { unchecked { c = a + b; } } // @notice Calculate a - b with overflow allowed function minusUnchecked(int256 a, int256 b) internal pure returns (int256 c) { unchecked { c = a - b; } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; import '../utils/IAdmin.sol'; import '../utils/IImplementation.sol'; import '../utils/IVerifier.sol'; interface IOracle is IAdmin, IImplementation, IVerifier { struct State { string symbol; uint256 source; uint256 delayAllowance; uint256 blockNumber; uint256 timestamp; int256 value; address chainlinkFeed; } struct Signature { bytes32 oracleId; uint256 timestamp; int256 value; uint8 v; bytes32 r; bytes32 s; } function getOracleId(string memory symbol) external pure returns (bytes32); function getState(bytes32 oracleId) external view returns (State memory s); function getValue(bytes32 oracleId) external view returns (int256); function getValueCurrentBlock(bytes32 oracleId) external view returns (int256); function setOffchainOracle(string memory symbol, uint256 delayAllowance) external; function setChainlinkOracle(string memory symbol, address feed) external; function updateOffchainValue(Signature memory sig) external; function updateOffchainValues(Signature[] memory sigs) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; abstract contract Admin { error OnlyAdmin(); event NewAdmin(address newAdmin); address public admin; modifier _onlyAdmin_() { if (msg.sender != admin) { revert OnlyAdmin(); } _; } constructor () { admin = msg.sender; emit NewAdmin(admin); } /** * @notice Set a new admin for the contract. * @dev This function allows the current admin to assign a new admin address without performing any explicit verification. * It's the current admin's responsibility to ensure that the 'newAdmin' address is correct and secure. * @param newAdmin The address of the new admin. */ function setAdmin(address newAdmin) external _onlyAdmin_ { admin = newAdmin; emit NewAdmin(newAdmin); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; interface IAdmin { function admin() external view returns (address); function setAdmin(address newAdmin) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; interface IImplementation { function setImplementation(address newImplementation) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; import './Admin.sol'; abstract contract Implementation is Admin { event NewImplementation(address newImplementation); address public implementation; // @notice Set a new implementation address for the contract function setImplementation(address newImplementation) external _onlyAdmin_ { implementation = newImplementation; emit NewImplementation(newImplementation); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; interface IVerifier { function setVerifier(address newVerifier) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; abstract contract ReentryLock { error Reentry(); bool internal _mutex; // @notice Lock for preventing reentrancy attacks modifier _reentryLock_() { if (_mutex) { revert Reentry(); } _mutex = true; _; _mutex = false; } }
{ "optimizer": { "enabled": true, "runs": 200 }, "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":[{"internalType":"address","name":"lToken_","type":"address"},{"internalType":"address","name":"pToken_","type":"address"},{"internalType":"address","name":"oracle_","type":"address"},{"internalType":"address","name":"swapper_","type":"address"},{"internalType":"address","name":"vault0_","type":"address"},{"internalType":"address","name":"iou_","type":"address"},{"internalType":"address","name":"tokenB0_","type":"address"},{"internalType":"address","name":"dChainEventSigner_","type":"address"},{"internalType":"uint256","name":"b0ReserveRatio_","type":"uint256"},{"internalType":"int256","name":"liquidationRewardCutRatio_","type":"int256"},{"internalType":"int256","name":"minLiquidationReward_","type":"int256"},{"internalType":"int256","name":"maxLiquidationReward_","type":"int256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BTokenDupInitialize","type":"error"},{"inputs":[],"name":"BTokenNoOracle","type":"error"},{"inputs":[],"name":"BTokenNoSwapper","type":"error"},{"inputs":[],"name":"CannotDelBToken","type":"error"},{"inputs":[{"internalType":"int256","name":"","type":"int256"}],"name":"IToUOverflow","type":"error"},{"inputs":[],"name":"InsufficientB0","type":"error"},{"inputs":[],"name":"InsufficientGasFee","type":"error"},{"inputs":[],"name":"InsufficientMargin","type":"error"},{"inputs":[],"name":"InvalidBAmount","type":"error"},{"inputs":[],"name":"InvalidBPrice","type":"error"},{"inputs":[],"name":"InvalidBToken","type":"error"},{"inputs":[],"name":"InvalidCustodian","type":"error"},{"inputs":[],"name":"InvalidLTokenId","type":"error"},{"inputs":[],"name":"InvalidPTokenId","type":"error"},{"inputs":[],"name":"InvalidRequestId","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"OnlyAdmin","type":"error"},{"inputs":[],"name":"Reentry","type":"error"},{"inputs":[],"name":"SendEthFail","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"UtoIOverflow","type":"error"},{"inputs":[],"name":"WrongTokenInAmount","type":"error"},{"inputs":[],"name":"WrongTokenOutAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"bToken","type":"address"},{"indexed":false,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"bytes32","name":"oracleId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"collateralFactor","type":"uint256"}],"name":"AddBToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"bToken","type":"address"}],"name":"DelBToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalLiquidity","type":"uint256"}],"name":"FinishAddLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pTokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"bToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"bAmount","type":"uint256"}],"name":"FinishAddMargin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pTokenId","type":"uint256"},{"indexed":false,"internalType":"int256","name":"lpPnl","type":"int256"}],"name":"FinishLiquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalLiquidity","type":"uint256"},{"indexed":false,"internalType":"address","name":"bToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"bAmount","type":"uint256"}],"name":"FinishRemoveLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pTokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"bToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"bAmount","type":"uint256"}],"name":"FinishRemoveMargin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newImplementation","type":"address"}],"name":"NewImplementation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"realMoneyMargin","type":"uint256"},{"indexed":false,"internalType":"int256","name":"lastCumulativePnlOnEngine","type":"int256"},{"indexed":false,"internalType":"int256","name":"cumulativePnlOnGateway","type":"int256"}],"name":"RequestLiquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"realMoneyMargin","type":"uint256"},{"indexed":false,"internalType":"int256","name":"lastCumulativePnlOnEngine","type":"int256"},{"indexed":false,"internalType":"int256","name":"cumulativePnlOnGateway","type":"int256"},{"indexed":false,"internalType":"uint256","name":"bAmount","type":"uint256"}],"name":"RequestRemoveMargin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"realMoneyMargin","type":"uint256"},{"indexed":false,"internalType":"int256","name":"lastCumulativePnlOnEngine","type":"int256"},{"indexed":false,"internalType":"int256","name":"cumulativePnlOnGateway","type":"int256"},{"indexed":false,"internalType":"bytes32","name":"symbolId","type":"bytes32"},{"indexed":false,"internalType":"int256[]","name":"tradeParams","type":"int256[]"}],"name":"RequestTrade","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"realMoneyMargin","type":"uint256"},{"indexed":false,"internalType":"int256","name":"lastCumulativePnlOnEngine","type":"int256"},{"indexed":false,"internalType":"int256","name":"cumulativePnlOnGateway","type":"int256"},{"indexed":false,"internalType":"uint256","name":"bAmount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"symbolId","type":"bytes32"},{"indexed":false,"internalType":"int256[]","name":"tradeParams","type":"int256[]"}],"name":"RequestTradeAndRemoveMargin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidity","type":"uint256"},{"indexed":false,"internalType":"int256","name":"lastCumulativePnlOnEngine","type":"int256"},{"indexed":false,"internalType":"int256","name":"cumulativePnlOnGateway","type":"int256"},{"indexed":false,"internalType":"uint256","name":"removeBAmount","type":"uint256"}],"name":"RequestUpdateLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"actionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasFee","type":"uint256"}],"name":"SetGasFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"bToken","type":"address"}],"name":"UpdateBToken","type":"event"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"claimDChainGasFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"dTokenId","type":"uint256"},{"internalType":"bool","name":"isLp","type":"bool"}],"name":"claimUnusedIChainGasFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"eventData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"finishLiquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"eventData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"finishRemoveMargin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"eventData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"finishUpdateLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"bToken","type":"address"}],"name":"getBTokenState","outputs":[{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"bytes32","name":"oracleId","type":"bytes32"},{"internalType":"uint256","name":"collateralFactor","type":"uint256"}],"internalType":"struct IGateway.BTokenState","name":"s","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"lTokenId","type":"uint256"}],"name":"getCumulativeTime","outputs":[{"internalType":"uint256","name":"cumulativeTimePerLiquidity","type":"uint256"},{"internalType":"uint256","name":"cumulativeTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGasFees","outputs":[{"internalType":"uint256[]","name":"fees","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGatewayParam","outputs":[{"components":[{"internalType":"address","name":"lToken","type":"address"},{"internalType":"address","name":"pToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"swapper","type":"address"},{"internalType":"address","name":"vault0","type":"address"},{"internalType":"address","name":"iou","type":"address"},{"internalType":"address","name":"tokenB0","type":"address"},{"internalType":"address","name":"dChainEventSigner","type":"address"},{"internalType":"uint256","name":"b0ReserveRatio","type":"uint256"},{"internalType":"int256","name":"liquidationRewardCutRatio","type":"int256"},{"internalType":"int256","name":"minLiquidationReward","type":"int256"},{"internalType":"int256","name":"maxLiquidationReward","type":"int256"}],"internalType":"struct IGateway.GatewayParam","name":"p","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGatewayState","outputs":[{"components":[{"internalType":"int256","name":"cumulativePnlOnGateway","type":"int256"},{"internalType":"uint256","name":"liquidityTime","type":"uint256"},{"internalType":"uint256","name":"totalLiquidity","type":"uint256"},{"internalType":"int256","name":"cumulativeTimePerLiquidity","type":"int256"},{"internalType":"uint256","name":"gatewayRequestId","type":"uint256"},{"internalType":"uint256","name":"dChainGasFeePerRequest","type":"uint256"},{"internalType":"uint256","name":"totalIChainGasFee","type":"uint256"}],"internalType":"struct IGateway.GatewayState","name":"s","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"lTokenId","type":"uint256"}],"name":"getLpState","outputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"address","name":"bToken","type":"address"},{"internalType":"uint256","name":"bAmount","type":"uint256"},{"internalType":"int256","name":"b0Amount","type":"int256"},{"internalType":"int256","name":"lastCumulativePnlOnEngine","type":"int256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"cumulativeTime","type":"uint256"},{"internalType":"uint256","name":"lastCumulativeTimePerLiquidity","type":"uint256"},{"internalType":"uint256","name":"lastRequestIChainGasFee","type":"uint256"},{"internalType":"uint256","name":"cumulativeUnusedIChainGasFee","type":"uint256"}],"internalType":"struct IGateway.LpState","name":"s","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pTokenId","type":"uint256"}],"name":"getTdState","outputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"address","name":"bToken","type":"address"},{"internalType":"uint256","name":"bAmount","type":"uint256"},{"internalType":"int256","name":"b0Amount","type":"int256"},{"internalType":"int256","name":"lastCumulativePnlOnEngine","type":"int256"},{"internalType":"bool","name":"singlePosition","type":"bool"},{"internalType":"uint256","name":"lastRequestIChainGasFee","type":"uint256"},{"internalType":"uint256","name":"cumulativeUnusedIChainGasFee","type":"uint256"}],"internalType":"struct IGateway.TdState","name":"s","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"b0Amount","type":"uint256"}],"name":"redeemIOU","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"lTokenId","type":"uint256"},{"internalType":"address","name":"bToken","type":"address"},{"internalType":"uint256","name":"bAmount","type":"uint256"}],"name":"requestAddLiquidity","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pTokenId","type":"uint256"},{"internalType":"address","name":"bToken","type":"address"},{"internalType":"uint256","name":"bAmount","type":"uint256"},{"internalType":"bool","name":"singlePosition","type":"bool"}],"name":"requestAddMargin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pTokenId","type":"uint256"},{"internalType":"address","name":"bToken","type":"address"},{"internalType":"uint256","name":"bAmount","type":"uint256"},{"internalType":"bytes32","name":"symbolId","type":"bytes32"},{"internalType":"int256[]","name":"tradeParams","type":"int256[]"},{"internalType":"bool","name":"singlePosition","type":"bool"}],"name":"requestAddMarginAndTrade","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pTokenId","type":"uint256"}],"name":"requestLiquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"lTokenId","type":"uint256"},{"internalType":"address","name":"bToken","type":"address"},{"internalType":"uint256","name":"bAmount","type":"uint256"}],"name":"requestRemoveLiquidity","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pTokenId","type":"uint256"},{"internalType":"address","name":"bToken","type":"address"},{"internalType":"uint256","name":"bAmount","type":"uint256"}],"name":"requestRemoveMargin","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pTokenId","type":"uint256"},{"internalType":"bytes32","name":"symbolId","type":"bytes32"},{"internalType":"int256[]","name":"tradeParams","type":"int256[]"}],"name":"requestTrade","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pTokenId","type":"uint256"},{"internalType":"address","name":"bToken","type":"address"},{"internalType":"uint256","name":"bAmount","type":"uint256"},{"internalType":"bytes32","name":"symbolId","type":"bytes32"},{"internalType":"int256[]","name":"tradeParams","type":"int256[]"}],"name":"requestTradeAndRemoveMargin","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"dChainGasFeePerRequest","type":"uint256"}],"name":"setDChainGasFeePerRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"actionId","type":"uint256"},{"internalType":"uint256","name":"gasFee","type":"uint256"}],"name":"setGasFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"setImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6102206040523480156200001257600080fd5b5060405162005fac38038062005fac83398101604081905262000035916200019a565b600080546001600160a01b031916339081179091556040519081527f71614071b88dee5e0b2ae578a9dd7b2ebbe9ae832ba419dc0242cd065a290b6c9060200160405180910390a16001600160a01b03808d166080528b811660a0528a811660c05289811660e05288811661010052878116610120528616610140819052620000be90620000f5565b60ff16610180526001600160a01b03909416610160526101a0929092526101c0526101e05261020052506200029795505050505050565b60006001600160a01b0382166001146200017457816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000148573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016e91906200026b565b62000177565b60125b92915050565b80516001600160a01b03811681146200019557600080fd5b919050565b6000806000806000806000806000806000806101808d8f031215620001be57600080fd5b620001c98d6200017d565b9b50620001d960208e016200017d565b9a50620001e960408e016200017d565b9950620001f960608e016200017d565b98506200020960808e016200017d565b97506200021960a08e016200017d565b96506200022960c08e016200017d565b95506200023960e08e016200017d565b94506101008d015193506101208d015192506101408d015191506101608d015190509295989b509295989b509295989b565b6000602082840312156200027e57600080fd5b815160ff811681146200029057600080fd5b9392505050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e05161020051615af0620004bc600039600081816105fb0152610e950152600081816105d401528181610dd101528181610df90152610e220152600081816105ad0152610e4c01526000818161058601526144d6015260008181610b37015281816110c50152818161191301528181611ff801528181612f560152818161309d0152818161313a015281816131a0015261486901526000818161055f01526132d001526000818161053701528181610c0001528181610edd01528181610fd20152818161175b015281816137420152818161389b01528181613abc01528181613d0e01528181613f8501528181613fe10152818161400f0152818161448b015261480401526000818161050f015281816116ea01526142120152600081816104e701528181610f21015281816110430152818161165101528181613d9301528181613f0001526145310152600081816104bf01528181610c6e01528181610d330152818161390c015281816139d901528181613b3d01528181613c1e0152818161408b0152614143015260008181610498015261489001526000818161047001528181610a56015281816111d6015281816112bc01528181611ab301528181611f7d01528181612337015261430101526000818161044b015281816118980152818161214b015281816123c50152612b550152615af06000f3fe60806040526004361061019c5760003560e01c8063976b4997116100ec578063db4015661161008a578063f7c60d4411610064578063f7c60d44146106ea578063f802a697146106fd578063f851a44014610784578063fa321c26146107a457600080fd5b8063db4015661461064c578063e1faff56146106b7578063ed7ebd0d146106ca57600080fd5b8063aaba0398116100c6578063aaba0398146103f6578063b77352d314610409578063c323acb614610429578063d784d4261461062c57600080fd5b8063976b4997146103945780639b1a2e94146103b6578063a67a40e9146103d657600080fd5b806360499aba11610159578063704b6c0211610133578063704b6c02146102fe57806370a1848c1461031e5780637e9459ba1461033e5780638769da2d1461035f57600080fd5b806360499aba14610291578063619cf2be146102b1578063702e6c06146102de57600080fd5b8063068689cd146101a15780630c8aeb56146101f157806316890fc2146102065780631c58d9c1146102195780633e0c7fc1146102395780635c60da1b14610259575b600080fd5b3480156101ad57600080fd5b506101c16101bc366004614fb2565b6107b7565b6040805182516001600160a01b031681526020808401519082015291810151908201526060015b60405180910390f35b6102046101ff366004614fcf565b61083e565b005b61020461021436600461505a565b610962565b34801561022557600080fd5b50610204610234366004615184565b6109ef565b34801561024557600080fd5b506102046102543660046151e8565b611297565b34801561026557600080fd5b50600154610279906001600160a01b031681565b6040516001600160a01b0390911681526020016101e8565b34801561029d57600080fd5b506102046102ac366004614fb2565b6113c6565b3480156102bd57600080fd5b506102d16102cc3660046151e8565b611421565b6040516101e89190615201565b3480156102ea57600080fd5b506102046102f93660046151e8565b61162b565b34801561030a57600080fd5b50610204610319366004614fb2565b611788565b34801561032a57600080fd5b50610204610339366004615184565b611808565b61035161034c366004615280565b611a94565b6040519081526020016101e8565b34801561036b57600080fd5b5061037f61037a3660046151e8565b611c6d565b604080519283526020830191909152016101e8565b3480156103a057600080fd5b506103a9611d72565b6040516101e891906152ca565b3480156103c257600080fd5b506102046103d1366004615184565b611f04565b3480156103e257600080fd5b506102046103f13660046151e8565b6120f6565b610204610404366004614fcf565b61212e565b34801561041557600080fd5b5061020461042436600461530e565b61231a565b34801561043557600080fd5b5060408051610180810182526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682527f0000000000000000000000000000000000000000000000000000000000000000811660208301527f00000000000000000000000000000000000000000000000000000000000000008116828401527f0000000000000000000000000000000000000000000000000000000000000000811660608301527f0000000000000000000000000000000000000000000000000000000000000000811660808301527f0000000000000000000000000000000000000000000000000000000000000000811660a08301527f0000000000000000000000000000000000000000000000000000000000000000811660c08301527f00000000000000000000000000000000000000000000000000000000000000001660e08201527f00000000000000000000000000000000000000000000000000000000000000006101008201527f00000000000000000000000000000000000000000000000000000000000000006101208201527f00000000000000000000000000000000000000000000000000000000000000006101408201527f000000000000000000000000000000000000000000000000000000000000000061016082015290516101e8919061533e565b34801561063857600080fd5b50610204610647366004614fb2565b6124b5565b34801561065857600080fd5b5061066161252e565b6040516101e89190600060e082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015292915050565b6102046106c5366004615440565b6125e4565b3480156106d657600080fd5b506102046106e53660046154b3565b6126f6565b6102046106f8366004614fcf565b612770565b34801561070957600080fd5b5061071d6107183660046151e8565b612887565b6040516101e89190815181526020808301516001600160a01b03169082015260408083015190820152606080830151908201526080808301519082015260a08083015115159082015260c0808301519082015260e091820151918101919091526101000190565b34801561079057600080fd5b50600054610279906001600160a01b031681565b6102046107b23660046154d5565b612a49565b60408051606081018252600080825260208083018290528284018290526001600160a01b038516825260039052919091206107f3906001612b16565b6001600160a01b0390811682528216600081815260036020818152604080842060028552808352908420548287015293909252908190526108349190612b16565b6040820152919050565b6108488333612b49565b600260005260056020527f89832631fb3c3307a103ba2c84ab569c64d6182a18893dcd163f0f1c2090733a5461087f908490612c09565b50806000036108a1576040516394613e9960e01b815260040160405180910390fd5b60006108ae338585612d03565b90506108b981612e18565b60006108c482612e5b565b905060006108d28385612fa2565b90506108df606483615554565b81116108e9575060005b60006108f4876131da565b60c08086015160608088015160408051868152602081018e905290810188905291820192909252608081019190915260a081018890529192507f0be79565c9c0f7b4144002bd9abeb6bd0e8f43023abae7066992c58bdff9397e91015b60405180910390a150505050505050565b6000196001600160a01b038716016109cc57600460005260056020527f3eec716f11ba9e820c81ca75eb978ffb45831ef8b7a53e5e422c26008e1ca6d554346109ab8288615568565b11156109ca576040516394613e9960e01b815260040160405180910390fd5b505b6109d887878784611a94565b96506109e687858585612a49565b50505050505050565b600154600160a01b900460ff1615610a1a576040516325dbe6e160e21b815260040160405180910390fd5b6001805460ff60a01b1916600160a01b179055610a37828261328f565b600082806020019051810190610a4d919061557b565b90506000610b0c7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636352211e84602001516040518263ffffffff1660e01b8152600401610aa691815260200190565b602060405180830381865afa158015610ac3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae791906155d7565b602080850151600081815260049092526040909120610b07906002612b16565b612d03565b90506000610b2b8260c00151846040015161332690919063ffffffff16565b9050610b5c81601260ff7f00000000000000000000000000000000000000000000000000000000000000001661332b565b8260a001818151610b6d91906155f4565b90525060408381015160c0840152608083015160208401519151637cbc237360e01b81526004810192909252600019602483015260009182916001600160a01b031690637cbc2373906044016020604051808303816000875af1158015610bd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bfc9190615614565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684604001516001600160a01b031603610c4c57610c458183615568565b9150610db0565b60016001600160a01b031684604001516001600160a01b031603610d055760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f29216e2836040518263ffffffff1660e01b8152600401604080518083038185885af1158015610ccb573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610cf0919061562d565b509050610cfd8184615568565b925050610db0565b6040848101519051633e87f49360e01b81526001600160a01b039182166004820152602481018390526000917f00000000000000000000000000000000000000000000000000000000000000001690633e87f4939060440160408051808303816000875af1158015610d7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9f919061562d565b509050610dac8184615568565b9250505b5060008360a00151610dc183613365565b610dcb91906155f4565b905060007f00000000000000000000000000000000000000000000000000000000000000008213610e1d57507f0000000000000000000000000000000000000000000000000000000000000000610ebc565b610eb97f0000000000000000000000000000000000000000000000000000000000000000670de0b6b3a76400007f0000000000000000000000000000000000000000000000000000000000000000610e758387615651565b610e7f9190615671565b610e8991906156a1565b610e9391906155f4565b7f000000000000000000000000000000000000000000000000000000000000000061339b565b90505b6000610ec7826133b2565b9050838111610f1557610f046001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633836133d8565b610f0e81856156cf565b9350611013565b60006001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016637cbc237382610f5188866156cf565b6040516001600160e01b031960e085901b168152600481019290925260248201526044016020604051808303816000875af1158015610f94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb89190615614565b9050610ff933610fc88388615568565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691906133d8565b61100b6110068287615568565b613365565b925060009450505b61101d8284615651565b92505082156110ba57604051631c57762b60e31b815260006004820152602481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e2bbb158906044016020604051808303816000875af1158015611094573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b89190615614565b505b6110f56110ec8360ff7f00000000000000000000000000000000000000000000000000000000000000001660126134bb565b60608701510190565b6060860152600060a086015261110a856134fb565b6020808701516000908152600490915260408120611129906009612b16565b60208089015160009081526004909152604081209192509061114c90600a612b16565b60208981018051600090815260048084526040808320600984528552808320839055925182528352818120600a8252909252812081905590915061119260026007612b16565b905061119e8284615568565b6111a890826156cf565b90506111b7600260078361357c565b5050506020860151604051630852cd8d60e31b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c6890602401600060405180830381600087803b15801561122257600080fd5b505af1158015611236573d6000803e3d6000fd5b505087516020808a0151604080519384529183015281018590527f8c3b5c5c5dddce5cc5abfa2cc66ec5dd06f76f9e9bb21debb1a85ad88fdbdb6f9250606001905060405180910390a150506001805460ff60a01b19169055505050505050565b6040516331a9108f60e11b815260048101829052600090611342906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015611303573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132791906155d7565b60008481526004602052604090208490610b07906002612b16565b905061134d81612e18565b600061135882612e5b565b90506000611365846131da565b60c084015160608086015160408051858152602081018a905280820188905292830193909352608082015290519192507fb299642ff40e6ba13eec0f77203c3ef9816a9f64212a40467d63db0eba259b4f919081900360a00190a150505050565b6000546001600160a01b031633146113f157604051634755657960e01b815260040160405180910390fd5b61141e8161140160026007612b16565b61140b6001613597565b61141591906156cf565b600191906133d8565b50565b6114806040518061014001604052806000815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6000828152600460205260409020611499906001612b16565b815260008281526004602052604090206114b4906002612b16565b6001600160a01b03166020808301829052600091825260039052604090206114dd906001612b16565b6001600160a01b0316631e010439836040518263ffffffff1660e01b815260040161150a91815260200190565b602060405180830381865afa158015611527573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154b9190615614565b604080830191909152600083815260046020522061156a906003612b16565b6060820152600082815260046020819052604090912061158991612b16565b608082015260008281526004602052604090206115a7906005612b16565b60a082015260008281526004602052604090206115c5906006612b16565b60c082015260008281526004602052604090206115e3906007612b16565b60e08201526000828152600460205260409020611601906009612b16565b610100820152600082815260046020526040902061162090600a612b16565b610120820152919050565b801561141e57604051637cbc237360e01b815260006004820181905260248201839052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690637cbc2373906044016020604051808303816000875af11580156116a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c69190615614565b9050801561178457604051632770a7eb60e21b8152336004820152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639dc29fac90604401600060405180830381600087803b15801561173657600080fd5b505af115801561174a573d6000803e3d6000fd5b506117849250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016905033836133d8565b5050565b6000546001600160a01b031633146117b357604051634755657960e01b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b0383169081179091556040519081527f71614071b88dee5e0b2ae578a9dd7b2ebbe9ae832ba419dc0242cd065a290b6c906020015b60405180910390a150565b600154600160a01b900460ff1615611833576040516325dbe6e160e21b815260040160405180910390fd5b6001805460ff60a01b1916600160a01b179055611850828261328f565b60008280602001905181019061186691906156e2565b905061187a8160200151826000015161361e565b61189181602001518260400151836060015161368f565b60006118e87f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636352211e84602001516040518263ffffffff1660e01b8152600401610aa691815260200190565b905060006119078260c00151846080015161332690919063ffffffff16565b905061193881601260ff7f00000000000000000000000000000000000000000000000000000000000000001661332b565b8260a00181815161194991906155f4565b905250608083015160c083015260a0830151600090156119945761196c83612e18565b611991838560400151600014611986578560a0015161198a565b6000195b6000613714565b90505b61199d836134fb565b6119ab84602001513361427b565b8360a00151600003611a105783516020808601516040808801516060808a0151835196875294860193909352908401528201527f3b963caf777561b495590bdc6ec8abd33838524d0a3aafc3f6f1b7857449d0999060800160405180910390a1611a7f565b83516020808601516040808801516060808a015189840151845197885295870194909452918501528301526001600160a01b0316608082015260a081018290527fc72ca5dc9c24b437f43b8c112e7b4e24b4a7bce4b1f405e591eee1cc32d327c29060c0015b60405180910390a15b50506001805460ff60a01b1916905550505050565b600084600003611b50576040516335313c2160e11b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636a627842906024016020604051808303816000875af1158015611b04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b289190615614565b94508115611b4b576000858152600460205260409020611b4b90600860016142ec565b611b5a565b611b5a85336142f5565b611b63846143b5565b6000611b70338787612d03565b90506000196001600160a01b03861601611ba55734841115611ba5576040516394613e9960e01b815260040160405180910390fd5b83600003611bc6576040516394613e9960e01b815260040160405180910390fd5b6001600160a01b038516600114611bee578051611bee906001600160a01b03871690866143ff565b611bf88185614489565b611c01816134fb565b6000611c0c876131da565b60408051828152602081018a90526001600160a01b038916818301526060810188905290519192507f8eee26bd33caee967b96e711aa45ef94c734251b0457a0f2213fb392c01ef53a919081900360800190a186925050505b949350505050565b60008080611c7c600280612b16565b90506000611c8c60026003612b16565b9050611c9a60026004612b16565b600086815260046020526040812091955090611cb7906005612b16565b6000878152600460205260409020909150611cd3906006612b16565b600087815260046020526040812091955090611cf0906007612b16565b90508215611d6957600083670de0b6b3a764000080611d0f88426156cf565b611d19919061575c565b611d23919061575c565b611d2d9190615554565b9687019690508215611d6757818703670de0b6b3a7640000611d4f858361575c565b611d599190615554565b611d639088615568565b9650505b505b50505050915091565b60408051600580825260c082019092526060916020820160a08036833750506001600090815260056020527f1471eb6eb2c5e789fc3de43f8ce62938c7d1836ec861730447e2ada8fd81017b54835193945092849250611dd457611dd4615773565b6020908102919091018101919091526002600052600590527f89832631fb3c3307a103ba2c84ab569c64d6182a18893dcd163f0f1c2090733a54815182906001908110611e2357611e23615773565b6020908102919091018101919091526003600052600590527fa9bc9a3a348c357ba16b37005d7e6b3236198c0e939f4af8c5f19b8deeb8ebc054815182906002908110611e7257611e72615773565b6020908102919091018101919091526004600052600590527f3eec716f11ba9e820c81ca75eb978ffb45831ef8b7a53e5e422c26008e1ca6d554815182906003908110611ec157611ec1615773565b60200260200101818152505060056000600581526020019081526020016000205481600481518110611ef557611ef5615773565b60200260200101818152505090565b600154600160a01b900460ff1615611f2f576040516325dbe6e160e21b815260040160405180910390fd5b6001805460ff60a01b1916600160a01b179055611f4c828261328f565b600082806020019051810190611f629190615789565b9050611f768160200151826000015161361e565b6000611fcd7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636352211e84602001516040518263ffffffff1660e01b8152600401610aa691815260200190565b90506000611fec8260c00151846060015161332690919063ffffffff16565b905061201d81601260ff7f00000000000000000000000000000000000000000000000000000000000000001661332b565b8260a00181815161202e91906155f4565b905250606083015160c083015261204482612e18565b60006120568385608001516001613714565b9050836040015161206684612e5b565b1015612085576040516341c092a960e01b815260040160405180910390fd5b61208e836134fb565b61209c84602001513361427b565b83516020808601516040808701518151948552928401919091526001600160a01b0390911690820152606081018290527f39f415ac8ef6b49b1ba40c4fafb2b911df1c5306c49eef15c4bc38a0128fca9890608001611a76565b6000546001600160a01b0316331461212157604051634755657960e01b815260040160405180910390fd5b61141e600260068361357c565b826000036121c7576040516335313c2160e11b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636a627842906024016020604051808303816000875af115801561219c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121c09190615614565b92506121d1565b6121d18333612b49565b6121da826143b5565b60006121e7338585612d03565b6001600090815260056020527f1471eb6eb2c5e789fc3de43f8ce62938c7d1836ec861730447e2ada8fd81017b5491925090612224908690612c09565b90506000196001600160a01b0385160161223c578092505b8260000361225d576040516394613e9960e01b815260040160405180910390fd5b6001600160a01b038416600114612285578151612285906001600160a01b03861690856143ff565b61228f8284614489565b61229882612e18565b60006122a383612e5b565b90506122ae836134fb565b60006122b9876131da565b60c08086015160608088015160408051868152602081018e9052908101889052918201929092526080810191909152600060a08201529192507f0be79565c9c0f7b4144002bd9abeb6bd0e8f43023abae7066992c58bdff9397e9101610951565b6000816123af576040516331a9108f60e11b8152600481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015612386573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123aa91906155d7565b612438565b6040516331a9108f60e11b8152600481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015612414573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243891906155d7565b60008481526004602052604081209192509061245590600a612b16565b905080156124af57600061246b60026007612b16565b905061247782826156cf565b9050612486600260078361357c565b6000858152600460209081526040808320600a84529091528120556124ad600184846133d8565b505b50505050565b6000546001600160a01b031633146124e057604051634755657960e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527f6b70829fcbe4891157f7a7496f9870927de3c8237adbe9cd39bae09b7382c409906020016117fd565b61256e6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b61257a60026001612b16565b8152612587600280612b16565b602082015261259860026003612b16565b60408201526125a960026004612b16565b60608201526125ba60026005612b16565b60808201526125cb60026006612b16565b60a08201526125dc60026007612b16565b60c082015290565b6125ee86336142f5565b600560008190526020527f458b30c2d72bfd2c6317304a4594ecbafe5f729d3111b65fdc3a33bd48e5432d54612625908790612c09565b5083600003612647576040516394613e9960e01b815260040160405180910390fd5b6000612654338888612d03565b905061265f81612e18565b600061266a82612e5b565b905060006126788388612fa2565b9050612685606483615554565b811161268f575060005b600061269a8a6131da565b90507ecae5d4a40f5ab841867a076a796230392d8ce403d409f84f18377b49a602d5818b848760c0015188606001518d8d8d8d6040516126e299989796959493929190615830565b60405180910390a150505050505050505050565b6000546001600160a01b0316331461272157604051634755657960e01b815260040160405180910390fd5b60008281526005602090815260409182902083905581518481529081018390527f7ee33d5ad485da9f8837dbf37e57c80fabc9165cc5c74f9d760028895a34badc910160405180910390a15050565b61277a83336142f5565b600360005260056020527fa9bc9a3a348c357ba16b37005d7e6b3236198c0e939f4af8c5f19b8deeb8ebc0546127b1908490612c09565b50806000036127d3576040516394613e9960e01b815260040160405180910390fd5b60006127e0338585612d03565b90506127eb81612e18565b60006127f682612e5b565b905060006128048385612fa2565b9050612811606483615554565b811161281b575060005b6000612826876131da565b60c08086015160608088015160408051868152602081018e905290810188905291820192909252608081019190915260a081018890529192507f88ad2ade0e436c3cffc2b0d1b51fb1379e5bca5dd3aaef801b234b18aa87d2a99101610951565b6128da6040518061010001604052806000815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160001515815260200160008152602001600081525090565b60008281526004602052604090206128f3906001612b16565b8152600082815260046020526040902061290e906002612b16565b6001600160a01b0316602080830182905260009182526003905260409020612937906001612b16565b6001600160a01b0316631e010439836040518263ffffffff1660e01b815260040161296491815260200190565b602060405180830381865afa158015612981573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129a59190615614565b60408083019190915260008381526004602052206129c4906003612b16565b606082015260008281526004602081905260409091206129e391612b16565b60808201526000828152600460205260409020612a019060086146ea565b151560a08201526000828152600460205260409020612a21906009612b16565b60c08201526000828152600460205260409020612a3f90600a612b16565b60e0820152919050565b612a5384336142f5565b600460005260056020527f3eec716f11ba9e820c81ca75eb978ffb45831ef8b7a53e5e422c26008e1ca6d554612a8a908590612c09565b506000848152600460205260408120612aac9033908790610b07906002612b16565b9050612ab781612e18565b6000612ac282612e5b565b90506000612acf876131da565b90507fd8eb4847ae2a642c0c24f4336eb3ac86a4cac889da47bb554f95c4d6163d80ff8188848660c0015187606001518b8b8b60405161095198979695949392919061587f565b60ff81166000908152602083905260408120545b90505b92915050565b60ff166000908152602091909152604090205490565b806001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636352211e846040518263ffffffff1660e01b8152600401612ba191815260200190565b602060405180830381865afa158015612bbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612be291906155d7565b6001600160a01b0316146117845760405163a03dca6f60e01b815260040160405180910390fd5b600080612c1860026006612b16565b905082341015612c3b5760405163e6b6589360e01b815260040160405180910390fd5b6000612c4782856156cf565b9050600081612c5860026007612b16565b612c629190615568565b9050612c71600260078361357c565b6000868152600460205260408120612c8a906009612b16565b600088815260046020526040812091925090612ca790600a612b16565b9050612cb38282615568565b6000898152600460205260409020859350909150612cd39060098461357c565b6000888152600460205260409020612ced90600a8361357c565b612cf787346156cf565b98975050505050505050565b612d6d60405180610120016040528060006001600160a01b031681526020016000815260200160006001600160a01b031681526020016000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081525090565b6001600160a01b0380851682526020820184905282166040820152612d9460026001612b16565b60608201526001600160a01b0382166000908152600360205260409020612dbc906001612b16565b6001600160a01b031660808201526000838152600460205260409020612de3906003612b16565b60a08201526000838152600460208190526040909120612e0291612b16565b60c0820152612e118383614704565b9392505050565b6040808201516001600160a01b0316600090815260036020819052919020612e3f91612b16565b60e08201526040810151612e5290614800565b61010090910152565b600080670de0b6b3a76400008360e00151670de0b6b3a764000085610100015186608001516001600160a01b0316631e01043988602001516040518263ffffffff1660e01b8152600401612eb191815260200190565b602060405180830381865afa158015612ece573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ef29190615614565b612efc919061575c565b612f069190615554565b612f10919061575c565b612f1a9190615554565b90506000808460a001511215612f4557612f408460a00151612f3b906158c5565b6133b2565b612f48565b60005b9050808210612f9b57612f987f000000000000000000000000000000000000000000000000000000000000000060ff166012612f918760a001518661497d90919063ffffffff16565b91906149aa565b92505b5050919050565b6000826101000151600019612fb79190615554565b821015612b2d5760808301516020840151604051631e01043960e01b815260048101919091526000916001600160a01b031690631e01043990602401602060405180830381865afa158015613010573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130349190615614565b90508083106130d45760008460a0015113156130cf576000670de0b6b3a7640000856101000151838661306791906156cf565b613071919061575c565b61307b9190615554565b9050600061308c8660a001516133b2565b9050818111156130cc576130c960ff7f0000000000000000000000000000000000000000000000000000000000000000166012612f9185856156cf565b93505b50505b6131d3565b6000670de0b6b3a76400008560e00151670de0b6b3a764000087610100015187866130ff91906156cf565b613109919061575c565b6131139190615554565b61311d919061575c565b6131279190615554565b905060008560a001511261317c576131757f000000000000000000000000000000000000000000000000000000000000000060ff166012612f918860a001518561497d90919063ffffffff16565b92506131d1565b600061318f8660a00151612f3b906158c5565b9050808211156131cf576131cc60ff7f0000000000000000000000000000000000000000000000000000000000000000166012612f9184866156cf565b93505b505b505b5092915050565b6000806131e960026005612b16565b90506131f66001826158e1565b905061320e600260056001600160801b03841661357c565b6000838152600460205260408120613227906001612b16565b90506132346001826158e1565b600085815260046020526040902090915061325a9060016001600160801b03841661357c565b60006132866001600160801b0383166fffffffffffffffffffffffffffffffff19608086901b16615568565b95945050505050565b815160208301207f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c91909152603c90206001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166132fa82846149dd565b6001600160a01b03161461332157604051638baa579f60e01b815260040160405180910390fd5b505050565b900390565b6000806133398585856134bb565b90506000851280156133555750846133528285876134bb565b14155b15611c6557613286600182615651565b60006001600160ff1b0382111561339757604051632a26bd1360e01b8152600481018390526024015b60405180910390fd5b5090565b6000818313156133ab5781612b2a565b5090919050565b60008082121561339757604051632a33bb3160e01b81526004810183905260240161338e565b60006133e384613597565b90506000196001600160a01b03851601613471576000836001600160a01b03168360405160006040518083038185875af1925050503d8060008114613444576040519150601f19603f3d011682016040523d82523d6000602084013e613449565b606091505b505090508061346b5760405163e277d13760e01b815260040160405180910390fd5b50613485565b6134856001600160a01b0385168484614a01565b600061349085613597565b905061349c8382615568565b82146124ad5760405163f4d4667360e01b815260040160405180910390fd5b60008183146134f3576134cf83600a6159e5565b6134da83600a6159e5565b6134e49086615671565b6134ee91906156a1565b611c65565b509192915050565b606081015161350f9060029060019061357c565b604080820151602080840151600090815260049091529190912061353591600290614a64565b60a0810151602080830151600090815260049091526040902061355a9160039061357c565b60c081015160208083015160009081526004918290526040902061141e929091905b805b60ff909216600090815260209390935250604090912055565b60006001600160a01b038216600114613617576040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa1580156135ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136129190615614565b612b2d565b4792915050565b600082815260046020526040902081906001600160801b03821690613644906001612b16565b14613662576040516302e8145360e61b815260040160405180910390fd5b613321600161367183826158e1565b600086815260046020526040902091906001600160801b031661357c565b60008061369b85611c6d565b90925090506136ac6002804261357c565b6136b9600260038561357c565b6136c6600260048461357c565b60008581526004602052604090206136e09060058661357c565b60008581526004602052604090206136fa9060068361357c565b60008581526004602052604090206124ad9060078461357c565b81613729670de0b6b3a7640000600019615554565b8110801561373b575060008460a00151125b156137f7577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684604001516001600160a01b03160361379f5761378e8460a00151612f3b906158c5565b6137989082615568565b90506137f7565b6064846101000151670de0b6b3a76400006137c18760a00151612f3b906158c5565b6137cb919061575c565b6137d59190615554565b6137e090606961575c565b6137ea9190615554565b6137f49082615568565b90505b60808401516020850151604051637cbc237360e01b81526001600160a01b0390921691637cbc237391613837918590600401918252602082015260400190565b6020604051808303816000875af1158015613856573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387a9190615614565b9050600080600085841115613a8a57600061389587866156cf565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031689604001516001600160a01b0316036138e95750806138e281876156cf565b9550613a5e565b60016001600160a01b031689604001516001600160a01b0316036139a9576000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f29216e2856040518263ffffffff1660e01b8152600401604080518083038185885af1158015613969573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061398e919061562d565b90935083925090506139a081896156cf565b97505050613a5e565b6040898101519051633e87f49360e01b81526001600160a01b0391821660048201526024810184905260009182917f000000000000000000000000000000000000000000000000000000000000000090911690633e87f4939060440160408051808303816000875af1158015613a23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a47919061562d565b9093508392509050613a5981896156cf565b975050505b613a688186615568565b9450613a7381613365565b8960a001818151613a8491906155f4565b90525050505b600084118015613a9e575060008760a00151125b15613ccf576000613ab68860a00151612f3b906158c5565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031689604001516001600160a01b031603613b1a57818610613b11575080613b0a81876156cf565b9550613ca3565b50600094613ca3565b60016001600160a01b031689604001516001600160a01b031603613be7576000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637661f4f689866040518363ffffffff1660e01b8152600401613b8a91815260200190565b604080518083038185885af1158015613ba7573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190613bcc919061562d565b9093508392509050613bde81896156cf565b97505050613ca3565b604089810151905163bf441a5960e01b81526001600160a01b039182166004820152602481018490526044810188905260009182917f00000000000000000000000000000000000000000000000000000000000000009091169063bf441a599060640160408051808303816000875af1158015613c68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c8c919061562d565b9093508392509050613c9e81896156cf565b975050505b613cad8186615568565b9450613cb881613365565b8960a001818151613cc991906155f4565b90525050505b60008760a001511315613edd576000613cf2670de0b6b3a7640000600019615554565b8710613d0c57613d058860a001516133b2565b9050613d77565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031688604001516001600160a01b0316148015613d5057508685105b15613d7757613d74613d658960a001516133b2565b613d6f878a6156cf565b614a73565b90505b8015613edb57600084821115613e8e5760006001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016637cbc237382613dc389876156cf565b6040516001600160e01b031960e085901b168152600481019290925260248201526044016020604051808303816000875af1158015613e06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e2a9190615614565b9050613e3686846156cf565b811015613e78578715613e5f5780613e4e87856156cf565b613e5891906156cf565b9350613e78565b6040516320b7831f60e11b815260040160405180910390fd5b613e828187615568565b91506000955050613e9d565b5080613e9a81866156cf565b94505b613ea78185615568565b9350613eb283613365565b613ebb82613365565b613ec591906155f4565b8960a001818151613ed69190615651565b905250505b505b8215613f7757604051631c57762b60e31b815260006004820152602481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e2bbb158906044016020604051808303816000875af1158015613f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f759190615614565b505b81156141c157841561400d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687604001516001600160a01b031603613fd157613fca8285615568565b93506141c1565b8651614008906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690846133d8565b6141c1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687604001516001600160a01b03160361405457613fca8285615568565b60016001600160a01b031687604001516001600160a01b03160361411557604051632cb4d9d960e11b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635969b3b29060240160408051808303816000875af11580156140db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140ff919061562d565b915061410d90508186615568565b9450506141c1565b604087810151905163045608af60e01b81526001600160a01b039182166004820152602481018490526000917f0000000000000000000000000000000000000000000000000000000000000000169063045608af9060440160408051808303816000875af115801561418b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141af919061562d565b91506141bd90508186615568565b9450505b83156141e457865160408801516141e4916001600160a01b0390911690866133d8565b80156142715786516040516340c10f1960e01b81526001600160a01b039182166004820152602481018390527f0000000000000000000000000000000000000000000000000000000000000000909116906340c10f1990604401600060405180830381600087803b15801561425857600080fd5b505af115801561426c573d6000803e3d6000fd5b505050505b5050509392505050565b6000828152600460205260408120614294906009612b16565b905080156133215760006142aa60026007612b16565b90506142b682826156cf565b90506142c5600260078361357c565b6000848152600460209081526040808320600984529091528120556124af600184846133d8565b61357e81614a83565b806001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636352211e846040518263ffffffff1660e01b815260040161434d91815260200190565b602060405180830381865afa15801561436a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061438e91906155d7565b6001600160a01b03161461178457604051639289a15b60e01b815260040160405180910390fd5b6001600160a01b03811660009081526003602052604081206143d8906001612b16565b6001600160a01b03160361141e57604051634033aec960e01b815260040160405180910390fd5b6000196001600160a01b038416016144315734811461332157604051630fc9bd0f60e11b815260040160405180910390fd5b600061443c84613597565b90506144536001600160a01b038516843085614a9d565b600061445e85613597565b905061446a8383615568565b81146124ad57604051630fc9bd0f60e11b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682604001516001600160a01b0316036145c6576000670de0b6b3a76400006144fb7f00000000000000000000000000000000000000000000000000000000000000008461575c565b6145059190615554565b905061451181836156cf565b604051631c57762b60e31b815260006004820152602481018390529092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e2bbb158906044016020604051808303816000875af1158015614582573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145a69190615614565b506145b081613365565b8360a0018181516145c191906155f4565b905250505b60016001600160a01b031682604001516001600160a01b0316036146675781608001516001600160a01b031663e2bbb158828460200151846040518463ffffffff1660e01b8152600401614624929190918252602082015260400190565b60206040518083038185885af1158015614642573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906133219190615614565b60808201516020830151604051631c57762b60e31b81526001600160a01b039092169163e2bbb158916146a7918590600401918252602082015260400190565b6020604051808303816000875af11580156146c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133219190615614565b60ff81166000908152602083905260408120541515612b2a565b600082815260046020526040812061471d906002612b16565b90506001600160a01b038116158015906147495750816001600160a01b0316816001600160a01b031614155b15613321576001600160a01b0381166000908152600360205260408120614771906001612b16565b6001600160a01b0316635d988967856040518263ffffffff1660e01b815260040161479e91815260200190565b602060405180830381865afa1580156147bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147df9190615614565b905080156124af57604051634033aec960e01b815260040160405180910390fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03160361484a5750670de0b6b3a7640000919050565b600061485e836001600160a01b0316614ad5565b90506149548160ff167f000000000000000000000000000000000000000000000000000000000000000060ff16612f917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663698439406148f56002600360008c6001600160a01b03166001600160a01b03168152602001908152602001600020612b3390919063ffffffff16565b6040518263ffffffff1660e01b815260040161491391815260200190565b602060405180830381865afa158015614930573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f3b9190615614565b9150816000036149775760405163089112d560e21b815260040160405180910390fd5b50919050565b6000808212614997576149908284615568565b9050612b2d565b6149a0826158c5565b61499090846156cf565b60008183146134f3576149be83600a6159e5565b6149c983600a6159e5565b6149d3908661575c565b6134ee9190615554565b60008060006149ec8585614b52565b915091506149f981614b97565b509392505050565b6040516001600160a01b03831660248201526044810182905261332190849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614ce1565b6001600160a01b03811661357e565b6000818311156133ab5781612b2a565b600081614a91576000614a94565b60015b60ff1692915050565b6040516001600160a01b03808516602483015283166044820152606481018290526124af9085906323b872dd60e01b90608401614a2d565b60006001600160a01b038216600114614b4a57816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015614b26573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061361291906159f1565b601292915050565b6000808251604103614b885760208301516040840151606085015160001a614b7c87828585614db6565b94509450505050614b90565b506000905060025b9250929050565b6000816004811115614bab57614bab615a14565b03614bb35750565b6001816004811115614bc757614bc7615a14565b03614c145760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161338e565b6002816004811115614c2857614c28615a14565b03614c755760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161338e565b6003816004811115614c8957614c89615a14565b0361141e5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161338e565b6000614d36826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614e7a9092919063ffffffff16565b9050805160001480614d57575080806020019051810190614d579190615a2a565b6133215760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161338e565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614ded5750600090506003614e71565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614e41573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614e6a57600060019250925050614e71565b9150600090505b94509492505050565b6060611c65848460008585600080866001600160a01b03168587604051614ea19190615a6b565b60006040518083038185875af1925050503d8060008114614ede576040519150601f19603f3d011682016040523d82523d6000602084013e614ee3565b606091505b5091509150614ef487838387614eff565b979650505050505050565b60608315614f6e578251600003614f67576001600160a01b0385163b614f675760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161338e565b5081611c65565b611c658383815115614f835781518083602001fd5b8060405162461bcd60e51b815260040161338e9190615a87565b6001600160a01b038116811461141e57600080fd5b600060208284031215614fc457600080fd5b8135612e1181614f9d565b600080600060608486031215614fe457600080fd5b833592506020840135614ff681614f9d565b929592945050506040919091013590565b60008083601f84011261501957600080fd5b50813567ffffffffffffffff81111561503157600080fd5b6020830191508360208260051b8501011115614b9057600080fd5b801515811461141e57600080fd5b600080600080600080600060c0888a03121561507557600080fd5b87359650602088013561508781614f9d565b95506040880135945060608801359350608088013567ffffffffffffffff8111156150b157600080fd5b6150bd8a828b01615007565b90945092505060a08801356150d18161504c565b8091505092959891949750929550565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261510857600080fd5b813567ffffffffffffffff80821115615123576151236150e1565b604051601f8301601f19908116603f0116810190828211818310171561514b5761514b6150e1565b8160405283815286602085880101111561516457600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561519757600080fd5b823567ffffffffffffffff808211156151af57600080fd5b6151bb868387016150f7565b935060208501359150808211156151d157600080fd5b506151de858286016150f7565b9150509250929050565b6000602082840312156151fa57600080fd5b5035919050565b81518152602080830151610140830191615225908401826001600160a01b03169052565b5060408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525092915050565b6000806000806080858703121561529657600080fd5b8435935060208501356152a881614f9d565b92506040850135915060608501356152bf8161504c565b939692955090935050565b6020808252825182820181905260009190848201906040850190845b81811015615302578351835292840192918401916001016152e6565b50909695505050505050565b6000806040838503121561532157600080fd5b8235915060208301356153338161504c565b809150509250929050565b81516001600160a01b031681526101808101602083015161536a60208401826001600160a01b03169052565b50604083015161538560408401826001600160a01b03169052565b5060608301516153a060608401826001600160a01b03169052565b5060808301516153bb60808401826001600160a01b03169052565b5060a08301516153d660a08401826001600160a01b03169052565b5060c08301516153f160c08401826001600160a01b03169052565b5060e083015161540c60e08401826001600160a01b03169052565b5061010083810151908301526101208084015190830152610140808401519083015261016092830151929091019190915290565b60008060008060008060a0878903121561545957600080fd5b86359550602087013561546b81614f9d565b94506040870135935060608701359250608087013567ffffffffffffffff81111561549557600080fd5b6154a189828a01615007565b979a9699509497509295939492505050565b600080604083850312156154c657600080fd5b50508035926020909101359150565b600080600080606085870312156154eb57600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561551057600080fd5b61551c87828801615007565b95989497509550505050565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60008261556357615563615528565b500490565b80820180821115612b2d57612b2d61553e565b60006060828403121561558d57600080fd5b6040516060810181811067ffffffffffffffff821117156155b0576155b06150e1565b80604052508251815260208301516020820152604083015160408201528091505092915050565b6000602082840312156155e957600080fd5b8151612e1181614f9d565b80820182811260008312801582168215821617156131d1576131d161553e565b60006020828403121561562657600080fd5b5051919050565b6000806040838503121561564057600080fd5b505080516020909101519092909150565b81810360008312801583831316838312821617156131d3576131d361553e565b80820260008212600160ff1b8414161561568d5761568d61553e565b8181058314821517612b2d57612b2d61553e565b6000826156b0576156b0615528565b600160ff1b8214600019841416156156ca576156ca61553e565b500590565b81810381811115612b2d57612b2d61553e565b600060c082840312156156f457600080fd5b60405160c0810181811067ffffffffffffffff82111715615717576157176150e1565b8060405250825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a08201528091505092915050565b8082028115828204841417612b2d57612b2d61553e565b634e487b7160e01b600052603260045260246000fd5b600060a0828403121561579b57600080fd5b60405160a0810181811067ffffffffffffffff821117156157be576157be6150e1565b806040525082518152602083015160208201526040830151604082015260608301516060820152608083015160808201528091505092915050565b8183526000602080850194508260005b8581101561582557813587529582019590820190600101615809565b509495945050505050565b60006101008b83528a60208401528960408401528860608401528760808401528660a08401528560c08401528060e084015261586f81840185876157f9565b9c9b505050505050505050505050565b8881528760208201528660408201528560608201528460808201528360a082015260e060c082015260006158b760e0830184866157f9565b9a9950505050505050505050565b6000600160ff1b82016158da576158da61553e565b5060000390565b6001600160801b038181168382160190808211156131d3576131d361553e565b600181815b8085111561593c5781600019048211156159225761592261553e565b8085161561592f57918102915b93841c9390800290615906565b509250929050565b60008261595357506001612b2d565b8161596057506000612b2d565b816001811461597657600281146159805761599c565b6001915050612b2d565b60ff8411156159915761599161553e565b50506001821b612b2d565b5060208310610133831016604e8410600b84101617156159bf575081810a612b2d565b6159c98383615901565b80600019048211156159dd576159dd61553e565b029392505050565b6000612b2a8383615944565b600060208284031215615a0357600080fd5b815160ff81168114612e1157600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215615a3c57600080fd5b8151612e118161504c565b60005b83811015615a62578181015183820152602001615a4a565b50506000910152565b60008251615a7d818460208701615a47565b9190910192915050565b6020815260008251806020840152615aa6816040850160208701615a47565b601f01601f1916919091016040019291505056fea2646970667358221220a51bc7cc468f19984b4c513e11e7ea00ac0fd17e28e0446592be85d8d888e0b164736f6c63430008140033000000000000000000000000c79102c36bbba246b8bb6ae81b50ba8544e451740000000000000000000000005a9dbbc5e6bd9ecdf81d48580d861653f12ea91e0000000000000000000000003b823dc7087d1ba9778ab8161b791b59053a0941000000000000000000000000837299b1188328b5256a0215b18074bd71c852d70000000000000000000000004489f4dd67b275a1c364cb652ab163972659d67200000000000000000000000036345041077eab2b204d9496349a6208b7b15eb3000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff000000000000000000000000a51cd97f3090f6a16cf0cdc12b0cb4b0a95b38ea00000000000000000000000000000000000000000000000002c68af0bb14000000000000000000000000000000000000000000000000000006f05b59d3b20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b1ae4d6e2ef500000
Deployed Bytecode
0x60806040526004361061019c5760003560e01c8063976b4997116100ec578063db4015661161008a578063f7c60d4411610064578063f7c60d44146106ea578063f802a697146106fd578063f851a44014610784578063fa321c26146107a457600080fd5b8063db4015661461064c578063e1faff56146106b7578063ed7ebd0d146106ca57600080fd5b8063aaba0398116100c6578063aaba0398146103f6578063b77352d314610409578063c323acb614610429578063d784d4261461062c57600080fd5b8063976b4997146103945780639b1a2e94146103b6578063a67a40e9146103d657600080fd5b806360499aba11610159578063704b6c0211610133578063704b6c02146102fe57806370a1848c1461031e5780637e9459ba1461033e5780638769da2d1461035f57600080fd5b806360499aba14610291578063619cf2be146102b1578063702e6c06146102de57600080fd5b8063068689cd146101a15780630c8aeb56146101f157806316890fc2146102065780631c58d9c1146102195780633e0c7fc1146102395780635c60da1b14610259575b600080fd5b3480156101ad57600080fd5b506101c16101bc366004614fb2565b6107b7565b6040805182516001600160a01b031681526020808401519082015291810151908201526060015b60405180910390f35b6102046101ff366004614fcf565b61083e565b005b61020461021436600461505a565b610962565b34801561022557600080fd5b50610204610234366004615184565b6109ef565b34801561024557600080fd5b506102046102543660046151e8565b611297565b34801561026557600080fd5b50600154610279906001600160a01b031681565b6040516001600160a01b0390911681526020016101e8565b34801561029d57600080fd5b506102046102ac366004614fb2565b6113c6565b3480156102bd57600080fd5b506102d16102cc3660046151e8565b611421565b6040516101e89190615201565b3480156102ea57600080fd5b506102046102f93660046151e8565b61162b565b34801561030a57600080fd5b50610204610319366004614fb2565b611788565b34801561032a57600080fd5b50610204610339366004615184565b611808565b61035161034c366004615280565b611a94565b6040519081526020016101e8565b34801561036b57600080fd5b5061037f61037a3660046151e8565b611c6d565b604080519283526020830191909152016101e8565b3480156103a057600080fd5b506103a9611d72565b6040516101e891906152ca565b3480156103c257600080fd5b506102046103d1366004615184565b611f04565b3480156103e257600080fd5b506102046103f13660046151e8565b6120f6565b610204610404366004614fcf565b61212e565b34801561041557600080fd5b5061020461042436600461530e565b61231a565b34801561043557600080fd5b5060408051610180810182526001600160a01b037f000000000000000000000000c79102c36bbba246b8bb6ae81b50ba8544e45174811682527f0000000000000000000000005a9dbbc5e6bd9ecdf81d48580d861653f12ea91e811660208301527f0000000000000000000000003b823dc7087d1ba9778ab8161b791b59053a09418116828401527f000000000000000000000000837299b1188328b5256a0215b18074bd71c852d7811660608301527f0000000000000000000000004489f4dd67b275a1c364cb652ab163972659d672811660808301527f00000000000000000000000036345041077eab2b204d9496349a6208b7b15eb3811660a08301527f000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff811660c08301527f000000000000000000000000a51cd97f3090f6a16cf0cdc12b0cb4b0a95b38ea1660e08201527f00000000000000000000000000000000000000000000000002c68af0bb1400006101008201527f00000000000000000000000000000000000000000000000006f05b59d3b200006101208201527f00000000000000000000000000000000000000000000000000000000000000006101408201527f00000000000000000000000000000000000000000000001b1ae4d6e2ef50000061016082015290516101e8919061533e565b34801561063857600080fd5b50610204610647366004614fb2565b6124b5565b34801561065857600080fd5b5061066161252e565b6040516101e89190600060e082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015292915050565b6102046106c5366004615440565b6125e4565b3480156106d657600080fd5b506102046106e53660046154b3565b6126f6565b6102046106f8366004614fcf565b612770565b34801561070957600080fd5b5061071d6107183660046151e8565b612887565b6040516101e89190815181526020808301516001600160a01b03169082015260408083015190820152606080830151908201526080808301519082015260a08083015115159082015260c0808301519082015260e091820151918101919091526101000190565b34801561079057600080fd5b50600054610279906001600160a01b031681565b6102046107b23660046154d5565b612a49565b60408051606081018252600080825260208083018290528284018290526001600160a01b038516825260039052919091206107f3906001612b16565b6001600160a01b0390811682528216600081815260036020818152604080842060028552808352908420548287015293909252908190526108349190612b16565b6040820152919050565b6108488333612b49565b600260005260056020527f89832631fb3c3307a103ba2c84ab569c64d6182a18893dcd163f0f1c2090733a5461087f908490612c09565b50806000036108a1576040516394613e9960e01b815260040160405180910390fd5b60006108ae338585612d03565b90506108b981612e18565b60006108c482612e5b565b905060006108d28385612fa2565b90506108df606483615554565b81116108e9575060005b60006108f4876131da565b60c08086015160608088015160408051868152602081018e905290810188905291820192909252608081019190915260a081018890529192507f0be79565c9c0f7b4144002bd9abeb6bd0e8f43023abae7066992c58bdff9397e91015b60405180910390a150505050505050565b6000196001600160a01b038716016109cc57600460005260056020527f3eec716f11ba9e820c81ca75eb978ffb45831ef8b7a53e5e422c26008e1ca6d554346109ab8288615568565b11156109ca576040516394613e9960e01b815260040160405180910390fd5b505b6109d887878784611a94565b96506109e687858585612a49565b50505050505050565b600154600160a01b900460ff1615610a1a576040516325dbe6e160e21b815260040160405180910390fd5b6001805460ff60a01b1916600160a01b179055610a37828261328f565b600082806020019051810190610a4d919061557b565b90506000610b0c7f0000000000000000000000005a9dbbc5e6bd9ecdf81d48580d861653f12ea91e6001600160a01b0316636352211e84602001516040518263ffffffff1660e01b8152600401610aa691815260200190565b602060405180830381865afa158015610ac3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae791906155d7565b602080850151600081815260049092526040909120610b07906002612b16565b612d03565b90506000610b2b8260c00151846040015161332690919063ffffffff16565b9050610b5c81601260ff7f00000000000000000000000000000000000000000000000000000000000000061661332b565b8260a001818151610b6d91906155f4565b90525060408381015160c0840152608083015160208401519151637cbc237360e01b81526004810192909252600019602483015260009182916001600160a01b031690637cbc2373906044016020604051808303816000875af1158015610bd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bfc9190615614565b90507f000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff6001600160a01b031684604001516001600160a01b031603610c4c57610c458183615568565b9150610db0565b60016001600160a01b031684604001516001600160a01b031603610d055760007f000000000000000000000000837299b1188328b5256a0215b18074bd71c852d76001600160a01b031663f29216e2836040518263ffffffff1660e01b8152600401604080518083038185885af1158015610ccb573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610cf0919061562d565b509050610cfd8184615568565b925050610db0565b6040848101519051633e87f49360e01b81526001600160a01b039182166004820152602481018390526000917f000000000000000000000000837299b1188328b5256a0215b18074bd71c852d71690633e87f4939060440160408051808303816000875af1158015610d7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9f919061562d565b509050610dac8184615568565b9250505b5060008360a00151610dc183613365565b610dcb91906155f4565b905060007f00000000000000000000000000000000000000000000000000000000000000008213610e1d57507f0000000000000000000000000000000000000000000000000000000000000000610ebc565b610eb97f0000000000000000000000000000000000000000000000000000000000000000670de0b6b3a76400007f00000000000000000000000000000000000000000000000006f05b59d3b20000610e758387615651565b610e7f9190615671565b610e8991906156a1565b610e9391906155f4565b7f00000000000000000000000000000000000000000000001b1ae4d6e2ef50000061339b565b90505b6000610ec7826133b2565b9050838111610f1557610f046001600160a01b037f000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff1633836133d8565b610f0e81856156cf565b9350611013565b60006001600160a01b037f0000000000000000000000004489f4dd67b275a1c364cb652ab163972659d67216637cbc237382610f5188866156cf565b6040516001600160e01b031960e085901b168152600481019290925260248201526044016020604051808303816000875af1158015610f94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb89190615614565b9050610ff933610fc88388615568565b6001600160a01b037f000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff1691906133d8565b61100b6110068287615568565b613365565b925060009450505b61101d8284615651565b92505082156110ba57604051631c57762b60e31b815260006004820152602481018490527f0000000000000000000000004489f4dd67b275a1c364cb652ab163972659d6726001600160a01b03169063e2bbb158906044016020604051808303816000875af1158015611094573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b89190615614565b505b6110f56110ec8360ff7f00000000000000000000000000000000000000000000000000000000000000061660126134bb565b60608701510190565b6060860152600060a086015261110a856134fb565b6020808701516000908152600490915260408120611129906009612b16565b60208089015160009081526004909152604081209192509061114c90600a612b16565b60208981018051600090815260048084526040808320600984528552808320839055925182528352818120600a8252909252812081905590915061119260026007612b16565b905061119e8284615568565b6111a890826156cf565b90506111b7600260078361357c565b5050506020860151604051630852cd8d60e31b815260048101919091527f0000000000000000000000005a9dbbc5e6bd9ecdf81d48580d861653f12ea91e6001600160a01b0316906342966c6890602401600060405180830381600087803b15801561122257600080fd5b505af1158015611236573d6000803e3d6000fd5b505087516020808a0151604080519384529183015281018590527f8c3b5c5c5dddce5cc5abfa2cc66ec5dd06f76f9e9bb21debb1a85ad88fdbdb6f9250606001905060405180910390a150506001805460ff60a01b19169055505050505050565b6040516331a9108f60e11b815260048101829052600090611342906001600160a01b037f0000000000000000000000005a9dbbc5e6bd9ecdf81d48580d861653f12ea91e1690636352211e90602401602060405180830381865afa158015611303573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132791906155d7565b60008481526004602052604090208490610b07906002612b16565b905061134d81612e18565b600061135882612e5b565b90506000611365846131da565b60c084015160608086015160408051858152602081018a905280820188905292830193909352608082015290519192507fb299642ff40e6ba13eec0f77203c3ef9816a9f64212a40467d63db0eba259b4f919081900360a00190a150505050565b6000546001600160a01b031633146113f157604051634755657960e01b815260040160405180910390fd5b61141e8161140160026007612b16565b61140b6001613597565b61141591906156cf565b600191906133d8565b50565b6114806040518061014001604052806000815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6000828152600460205260409020611499906001612b16565b815260008281526004602052604090206114b4906002612b16565b6001600160a01b03166020808301829052600091825260039052604090206114dd906001612b16565b6001600160a01b0316631e010439836040518263ffffffff1660e01b815260040161150a91815260200190565b602060405180830381865afa158015611527573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154b9190615614565b604080830191909152600083815260046020522061156a906003612b16565b6060820152600082815260046020819052604090912061158991612b16565b608082015260008281526004602052604090206115a7906005612b16565b60a082015260008281526004602052604090206115c5906006612b16565b60c082015260008281526004602052604090206115e3906007612b16565b60e08201526000828152600460205260409020611601906009612b16565b610100820152600082815260046020526040902061162090600a612b16565b610120820152919050565b801561141e57604051637cbc237360e01b815260006004820181905260248201839052907f0000000000000000000000004489f4dd67b275a1c364cb652ab163972659d6726001600160a01b031690637cbc2373906044016020604051808303816000875af11580156116a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c69190615614565b9050801561178457604051632770a7eb60e21b8152336004820152602481018290527f00000000000000000000000036345041077eab2b204d9496349a6208b7b15eb36001600160a01b031690639dc29fac90604401600060405180830381600087803b15801561173657600080fd5b505af115801561174a573d6000803e3d6000fd5b506117849250506001600160a01b037f000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff16905033836133d8565b5050565b6000546001600160a01b031633146117b357604051634755657960e01b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b0383169081179091556040519081527f71614071b88dee5e0b2ae578a9dd7b2ebbe9ae832ba419dc0242cd065a290b6c906020015b60405180910390a150565b600154600160a01b900460ff1615611833576040516325dbe6e160e21b815260040160405180910390fd5b6001805460ff60a01b1916600160a01b179055611850828261328f565b60008280602001905181019061186691906156e2565b905061187a8160200151826000015161361e565b61189181602001518260400151836060015161368f565b60006118e87f000000000000000000000000c79102c36bbba246b8bb6ae81b50ba8544e451746001600160a01b0316636352211e84602001516040518263ffffffff1660e01b8152600401610aa691815260200190565b905060006119078260c00151846080015161332690919063ffffffff16565b905061193881601260ff7f00000000000000000000000000000000000000000000000000000000000000061661332b565b8260a00181815161194991906155f4565b905250608083015160c083015260a0830151600090156119945761196c83612e18565b611991838560400151600014611986578560a0015161198a565b6000195b6000613714565b90505b61199d836134fb565b6119ab84602001513361427b565b8360a00151600003611a105783516020808601516040808801516060808a0151835196875294860193909352908401528201527f3b963caf777561b495590bdc6ec8abd33838524d0a3aafc3f6f1b7857449d0999060800160405180910390a1611a7f565b83516020808601516040808801516060808a015189840151845197885295870194909452918501528301526001600160a01b0316608082015260a081018290527fc72ca5dc9c24b437f43b8c112e7b4e24b4a7bce4b1f405e591eee1cc32d327c29060c0015b60405180910390a15b50506001805460ff60a01b1916905550505050565b600084600003611b50576040516335313c2160e11b81523360048201527f0000000000000000000000005a9dbbc5e6bd9ecdf81d48580d861653f12ea91e6001600160a01b031690636a627842906024016020604051808303816000875af1158015611b04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b289190615614565b94508115611b4b576000858152600460205260409020611b4b90600860016142ec565b611b5a565b611b5a85336142f5565b611b63846143b5565b6000611b70338787612d03565b90506000196001600160a01b03861601611ba55734841115611ba5576040516394613e9960e01b815260040160405180910390fd5b83600003611bc6576040516394613e9960e01b815260040160405180910390fd5b6001600160a01b038516600114611bee578051611bee906001600160a01b03871690866143ff565b611bf88185614489565b611c01816134fb565b6000611c0c876131da565b60408051828152602081018a90526001600160a01b038916818301526060810188905290519192507f8eee26bd33caee967b96e711aa45ef94c734251b0457a0f2213fb392c01ef53a919081900360800190a186925050505b949350505050565b60008080611c7c600280612b16565b90506000611c8c60026003612b16565b9050611c9a60026004612b16565b600086815260046020526040812091955090611cb7906005612b16565b6000878152600460205260409020909150611cd3906006612b16565b600087815260046020526040812091955090611cf0906007612b16565b90508215611d6957600083670de0b6b3a764000080611d0f88426156cf565b611d19919061575c565b611d23919061575c565b611d2d9190615554565b9687019690508215611d6757818703670de0b6b3a7640000611d4f858361575c565b611d599190615554565b611d639088615568565b9650505b505b50505050915091565b60408051600580825260c082019092526060916020820160a08036833750506001600090815260056020527f1471eb6eb2c5e789fc3de43f8ce62938c7d1836ec861730447e2ada8fd81017b54835193945092849250611dd457611dd4615773565b6020908102919091018101919091526002600052600590527f89832631fb3c3307a103ba2c84ab569c64d6182a18893dcd163f0f1c2090733a54815182906001908110611e2357611e23615773565b6020908102919091018101919091526003600052600590527fa9bc9a3a348c357ba16b37005d7e6b3236198c0e939f4af8c5f19b8deeb8ebc054815182906002908110611e7257611e72615773565b6020908102919091018101919091526004600052600590527f3eec716f11ba9e820c81ca75eb978ffb45831ef8b7a53e5e422c26008e1ca6d554815182906003908110611ec157611ec1615773565b60200260200101818152505060056000600581526020019081526020016000205481600481518110611ef557611ef5615773565b60200260200101818152505090565b600154600160a01b900460ff1615611f2f576040516325dbe6e160e21b815260040160405180910390fd5b6001805460ff60a01b1916600160a01b179055611f4c828261328f565b600082806020019051810190611f629190615789565b9050611f768160200151826000015161361e565b6000611fcd7f0000000000000000000000005a9dbbc5e6bd9ecdf81d48580d861653f12ea91e6001600160a01b0316636352211e84602001516040518263ffffffff1660e01b8152600401610aa691815260200190565b90506000611fec8260c00151846060015161332690919063ffffffff16565b905061201d81601260ff7f00000000000000000000000000000000000000000000000000000000000000061661332b565b8260a00181815161202e91906155f4565b905250606083015160c083015261204482612e18565b60006120568385608001516001613714565b9050836040015161206684612e5b565b1015612085576040516341c092a960e01b815260040160405180910390fd5b61208e836134fb565b61209c84602001513361427b565b83516020808601516040808701518151948552928401919091526001600160a01b0390911690820152606081018290527f39f415ac8ef6b49b1ba40c4fafb2b911df1c5306c49eef15c4bc38a0128fca9890608001611a76565b6000546001600160a01b0316331461212157604051634755657960e01b815260040160405180910390fd5b61141e600260068361357c565b826000036121c7576040516335313c2160e11b81523360048201527f000000000000000000000000c79102c36bbba246b8bb6ae81b50ba8544e451746001600160a01b031690636a627842906024016020604051808303816000875af115801561219c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121c09190615614565b92506121d1565b6121d18333612b49565b6121da826143b5565b60006121e7338585612d03565b6001600090815260056020527f1471eb6eb2c5e789fc3de43f8ce62938c7d1836ec861730447e2ada8fd81017b5491925090612224908690612c09565b90506000196001600160a01b0385160161223c578092505b8260000361225d576040516394613e9960e01b815260040160405180910390fd5b6001600160a01b038416600114612285578151612285906001600160a01b03861690856143ff565b61228f8284614489565b61229882612e18565b60006122a383612e5b565b90506122ae836134fb565b60006122b9876131da565b60c08086015160608088015160408051868152602081018e9052908101889052918201929092526080810191909152600060a08201529192507f0be79565c9c0f7b4144002bd9abeb6bd0e8f43023abae7066992c58bdff9397e9101610951565b6000816123af576040516331a9108f60e11b8152600481018490527f0000000000000000000000005a9dbbc5e6bd9ecdf81d48580d861653f12ea91e6001600160a01b031690636352211e90602401602060405180830381865afa158015612386573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123aa91906155d7565b612438565b6040516331a9108f60e11b8152600481018490527f000000000000000000000000c79102c36bbba246b8bb6ae81b50ba8544e451746001600160a01b031690636352211e90602401602060405180830381865afa158015612414573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243891906155d7565b60008481526004602052604081209192509061245590600a612b16565b905080156124af57600061246b60026007612b16565b905061247782826156cf565b9050612486600260078361357c565b6000858152600460209081526040808320600a84529091528120556124ad600184846133d8565b505b50505050565b6000546001600160a01b031633146124e057604051634755657960e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527f6b70829fcbe4891157f7a7496f9870927de3c8237adbe9cd39bae09b7382c409906020016117fd565b61256e6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b61257a60026001612b16565b8152612587600280612b16565b602082015261259860026003612b16565b60408201526125a960026004612b16565b60608201526125ba60026005612b16565b60808201526125cb60026006612b16565b60a08201526125dc60026007612b16565b60c082015290565b6125ee86336142f5565b600560008190526020527f458b30c2d72bfd2c6317304a4594ecbafe5f729d3111b65fdc3a33bd48e5432d54612625908790612c09565b5083600003612647576040516394613e9960e01b815260040160405180910390fd5b6000612654338888612d03565b905061265f81612e18565b600061266a82612e5b565b905060006126788388612fa2565b9050612685606483615554565b811161268f575060005b600061269a8a6131da565b90507ecae5d4a40f5ab841867a076a796230392d8ce403d409f84f18377b49a602d5818b848760c0015188606001518d8d8d8d6040516126e299989796959493929190615830565b60405180910390a150505050505050505050565b6000546001600160a01b0316331461272157604051634755657960e01b815260040160405180910390fd5b60008281526005602090815260409182902083905581518481529081018390527f7ee33d5ad485da9f8837dbf37e57c80fabc9165cc5c74f9d760028895a34badc910160405180910390a15050565b61277a83336142f5565b600360005260056020527fa9bc9a3a348c357ba16b37005d7e6b3236198c0e939f4af8c5f19b8deeb8ebc0546127b1908490612c09565b50806000036127d3576040516394613e9960e01b815260040160405180910390fd5b60006127e0338585612d03565b90506127eb81612e18565b60006127f682612e5b565b905060006128048385612fa2565b9050612811606483615554565b811161281b575060005b6000612826876131da565b60c08086015160608088015160408051868152602081018e905290810188905291820192909252608081019190915260a081018890529192507f88ad2ade0e436c3cffc2b0d1b51fb1379e5bca5dd3aaef801b234b18aa87d2a99101610951565b6128da6040518061010001604052806000815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160001515815260200160008152602001600081525090565b60008281526004602052604090206128f3906001612b16565b8152600082815260046020526040902061290e906002612b16565b6001600160a01b0316602080830182905260009182526003905260409020612937906001612b16565b6001600160a01b0316631e010439836040518263ffffffff1660e01b815260040161296491815260200190565b602060405180830381865afa158015612981573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129a59190615614565b60408083019190915260008381526004602052206129c4906003612b16565b606082015260008281526004602081905260409091206129e391612b16565b60808201526000828152600460205260409020612a019060086146ea565b151560a08201526000828152600460205260409020612a21906009612b16565b60c08201526000828152600460205260409020612a3f90600a612b16565b60e0820152919050565b612a5384336142f5565b600460005260056020527f3eec716f11ba9e820c81ca75eb978ffb45831ef8b7a53e5e422c26008e1ca6d554612a8a908590612c09565b506000848152600460205260408120612aac9033908790610b07906002612b16565b9050612ab781612e18565b6000612ac282612e5b565b90506000612acf876131da565b90507fd8eb4847ae2a642c0c24f4336eb3ac86a4cac889da47bb554f95c4d6163d80ff8188848660c0015187606001518b8b8b60405161095198979695949392919061587f565b60ff81166000908152602083905260408120545b90505b92915050565b60ff166000908152602091909152604090205490565b806001600160a01b03167f000000000000000000000000c79102c36bbba246b8bb6ae81b50ba8544e451746001600160a01b0316636352211e846040518263ffffffff1660e01b8152600401612ba191815260200190565b602060405180830381865afa158015612bbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612be291906155d7565b6001600160a01b0316146117845760405163a03dca6f60e01b815260040160405180910390fd5b600080612c1860026006612b16565b905082341015612c3b5760405163e6b6589360e01b815260040160405180910390fd5b6000612c4782856156cf565b9050600081612c5860026007612b16565b612c629190615568565b9050612c71600260078361357c565b6000868152600460205260408120612c8a906009612b16565b600088815260046020526040812091925090612ca790600a612b16565b9050612cb38282615568565b6000898152600460205260409020859350909150612cd39060098461357c565b6000888152600460205260409020612ced90600a8361357c565b612cf787346156cf565b98975050505050505050565b612d6d60405180610120016040528060006001600160a01b031681526020016000815260200160006001600160a01b031681526020016000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081525090565b6001600160a01b0380851682526020820184905282166040820152612d9460026001612b16565b60608201526001600160a01b0382166000908152600360205260409020612dbc906001612b16565b6001600160a01b031660808201526000838152600460205260409020612de3906003612b16565b60a08201526000838152600460208190526040909120612e0291612b16565b60c0820152612e118383614704565b9392505050565b6040808201516001600160a01b0316600090815260036020819052919020612e3f91612b16565b60e08201526040810151612e5290614800565b61010090910152565b600080670de0b6b3a76400008360e00151670de0b6b3a764000085610100015186608001516001600160a01b0316631e01043988602001516040518263ffffffff1660e01b8152600401612eb191815260200190565b602060405180830381865afa158015612ece573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ef29190615614565b612efc919061575c565b612f069190615554565b612f10919061575c565b612f1a9190615554565b90506000808460a001511215612f4557612f408460a00151612f3b906158c5565b6133b2565b612f48565b60005b9050808210612f9b57612f987f000000000000000000000000000000000000000000000000000000000000000660ff166012612f918760a001518661497d90919063ffffffff16565b91906149aa565b92505b5050919050565b6000826101000151600019612fb79190615554565b821015612b2d5760808301516020840151604051631e01043960e01b815260048101919091526000916001600160a01b031690631e01043990602401602060405180830381865afa158015613010573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130349190615614565b90508083106130d45760008460a0015113156130cf576000670de0b6b3a7640000856101000151838661306791906156cf565b613071919061575c565b61307b9190615554565b9050600061308c8660a001516133b2565b9050818111156130cc576130c960ff7f0000000000000000000000000000000000000000000000000000000000000006166012612f9185856156cf565b93505b50505b6131d3565b6000670de0b6b3a76400008560e00151670de0b6b3a764000087610100015187866130ff91906156cf565b613109919061575c565b6131139190615554565b61311d919061575c565b6131279190615554565b905060008560a001511261317c576131757f000000000000000000000000000000000000000000000000000000000000000660ff166012612f918860a001518561497d90919063ffffffff16565b92506131d1565b600061318f8660a00151612f3b906158c5565b9050808211156131cf576131cc60ff7f0000000000000000000000000000000000000000000000000000000000000006166012612f9184866156cf565b93505b505b505b5092915050565b6000806131e960026005612b16565b90506131f66001826158e1565b905061320e600260056001600160801b03841661357c565b6000838152600460205260408120613227906001612b16565b90506132346001826158e1565b600085815260046020526040902090915061325a9060016001600160801b03841661357c565b60006132866001600160801b0383166fffffffffffffffffffffffffffffffff19608086901b16615568565b95945050505050565b815160208301207f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c91909152603c90206001600160a01b037f000000000000000000000000a51cd97f3090f6a16cf0cdc12b0cb4b0a95b38ea166132fa82846149dd565b6001600160a01b03161461332157604051638baa579f60e01b815260040160405180910390fd5b505050565b900390565b6000806133398585856134bb565b90506000851280156133555750846133528285876134bb565b14155b15611c6557613286600182615651565b60006001600160ff1b0382111561339757604051632a26bd1360e01b8152600481018390526024015b60405180910390fd5b5090565b6000818313156133ab5781612b2a565b5090919050565b60008082121561339757604051632a33bb3160e01b81526004810183905260240161338e565b60006133e384613597565b90506000196001600160a01b03851601613471576000836001600160a01b03168360405160006040518083038185875af1925050503d8060008114613444576040519150601f19603f3d011682016040523d82523d6000602084013e613449565b606091505b505090508061346b5760405163e277d13760e01b815260040160405180910390fd5b50613485565b6134856001600160a01b0385168484614a01565b600061349085613597565b905061349c8382615568565b82146124ad5760405163f4d4667360e01b815260040160405180910390fd5b60008183146134f3576134cf83600a6159e5565b6134da83600a6159e5565b6134e49086615671565b6134ee91906156a1565b611c65565b509192915050565b606081015161350f9060029060019061357c565b604080820151602080840151600090815260049091529190912061353591600290614a64565b60a0810151602080830151600090815260049091526040902061355a9160039061357c565b60c081015160208083015160009081526004918290526040902061141e929091905b805b60ff909216600090815260209390935250604090912055565b60006001600160a01b038216600114613617576040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa1580156135ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136129190615614565b612b2d565b4792915050565b600082815260046020526040902081906001600160801b03821690613644906001612b16565b14613662576040516302e8145360e61b815260040160405180910390fd5b613321600161367183826158e1565b600086815260046020526040902091906001600160801b031661357c565b60008061369b85611c6d565b90925090506136ac6002804261357c565b6136b9600260038561357c565b6136c6600260048461357c565b60008581526004602052604090206136e09060058661357c565b60008581526004602052604090206136fa9060068361357c565b60008581526004602052604090206124ad9060078461357c565b81613729670de0b6b3a7640000600019615554565b8110801561373b575060008460a00151125b156137f7577f000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff6001600160a01b031684604001516001600160a01b03160361379f5761378e8460a00151612f3b906158c5565b6137989082615568565b90506137f7565b6064846101000151670de0b6b3a76400006137c18760a00151612f3b906158c5565b6137cb919061575c565b6137d59190615554565b6137e090606961575c565b6137ea9190615554565b6137f49082615568565b90505b60808401516020850151604051637cbc237360e01b81526001600160a01b0390921691637cbc237391613837918590600401918252602082015260400190565b6020604051808303816000875af1158015613856573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387a9190615614565b9050600080600085841115613a8a57600061389587866156cf565b905060007f000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff6001600160a01b031689604001516001600160a01b0316036138e95750806138e281876156cf565b9550613a5e565b60016001600160a01b031689604001516001600160a01b0316036139a9576000807f000000000000000000000000837299b1188328b5256a0215b18074bd71c852d76001600160a01b031663f29216e2856040518263ffffffff1660e01b8152600401604080518083038185885af1158015613969573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061398e919061562d565b90935083925090506139a081896156cf565b97505050613a5e565b6040898101519051633e87f49360e01b81526001600160a01b0391821660048201526024810184905260009182917f000000000000000000000000837299b1188328b5256a0215b18074bd71c852d790911690633e87f4939060440160408051808303816000875af1158015613a23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a47919061562d565b9093508392509050613a5981896156cf565b975050505b613a688186615568565b9450613a7381613365565b8960a001818151613a8491906155f4565b90525050505b600084118015613a9e575060008760a00151125b15613ccf576000613ab68860a00151612f3b906158c5565b905060007f000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff6001600160a01b031689604001516001600160a01b031603613b1a57818610613b11575080613b0a81876156cf565b9550613ca3565b50600094613ca3565b60016001600160a01b031689604001516001600160a01b031603613be7576000807f000000000000000000000000837299b1188328b5256a0215b18074bd71c852d76001600160a01b0316637661f4f689866040518363ffffffff1660e01b8152600401613b8a91815260200190565b604080518083038185885af1158015613ba7573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190613bcc919061562d565b9093508392509050613bde81896156cf565b97505050613ca3565b604089810151905163bf441a5960e01b81526001600160a01b039182166004820152602481018490526044810188905260009182917f000000000000000000000000837299b1188328b5256a0215b18074bd71c852d79091169063bf441a599060640160408051808303816000875af1158015613c68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c8c919061562d565b9093508392509050613c9e81896156cf565b975050505b613cad8186615568565b9450613cb881613365565b8960a001818151613cc991906155f4565b90525050505b60008760a001511315613edd576000613cf2670de0b6b3a7640000600019615554565b8710613d0c57613d058860a001516133b2565b9050613d77565b7f000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff6001600160a01b031688604001516001600160a01b0316148015613d5057508685105b15613d7757613d74613d658960a001516133b2565b613d6f878a6156cf565b614a73565b90505b8015613edb57600084821115613e8e5760006001600160a01b037f0000000000000000000000004489f4dd67b275a1c364cb652ab163972659d67216637cbc237382613dc389876156cf565b6040516001600160e01b031960e085901b168152600481019290925260248201526044016020604051808303816000875af1158015613e06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e2a9190615614565b9050613e3686846156cf565b811015613e78578715613e5f5780613e4e87856156cf565b613e5891906156cf565b9350613e78565b6040516320b7831f60e11b815260040160405180910390fd5b613e828187615568565b91506000955050613e9d565b5080613e9a81866156cf565b94505b613ea78185615568565b9350613eb283613365565b613ebb82613365565b613ec591906155f4565b8960a001818151613ed69190615651565b905250505b505b8215613f7757604051631c57762b60e31b815260006004820152602481018490527f0000000000000000000000004489f4dd67b275a1c364cb652ab163972659d6726001600160a01b03169063e2bbb158906044016020604051808303816000875af1158015613f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f759190615614565b505b81156141c157841561400d577f000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff6001600160a01b031687604001516001600160a01b031603613fd157613fca8285615568565b93506141c1565b8651614008906001600160a01b037f000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff1690846133d8565b6141c1565b7f000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff6001600160a01b031687604001516001600160a01b03160361405457613fca8285615568565b60016001600160a01b031687604001516001600160a01b03160361411557604051632cb4d9d960e11b8152600481018390526000907f000000000000000000000000837299b1188328b5256a0215b18074bd71c852d76001600160a01b031690635969b3b29060240160408051808303816000875af11580156140db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140ff919061562d565b915061410d90508186615568565b9450506141c1565b604087810151905163045608af60e01b81526001600160a01b039182166004820152602481018490526000917f000000000000000000000000837299b1188328b5256a0215b18074bd71c852d7169063045608af9060440160408051808303816000875af115801561418b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141af919061562d565b91506141bd90508186615568565b9450505b83156141e457865160408801516141e4916001600160a01b0390911690866133d8565b80156142715786516040516340c10f1960e01b81526001600160a01b039182166004820152602481018390527f00000000000000000000000036345041077eab2b204d9496349a6208b7b15eb3909116906340c10f1990604401600060405180830381600087803b15801561425857600080fd5b505af115801561426c573d6000803e3d6000fd5b505050505b5050509392505050565b6000828152600460205260408120614294906009612b16565b905080156133215760006142aa60026007612b16565b90506142b682826156cf565b90506142c5600260078361357c565b6000848152600460209081526040808320600984529091528120556124af600184846133d8565b61357e81614a83565b806001600160a01b03167f0000000000000000000000005a9dbbc5e6bd9ecdf81d48580d861653f12ea91e6001600160a01b0316636352211e846040518263ffffffff1660e01b815260040161434d91815260200190565b602060405180830381865afa15801561436a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061438e91906155d7565b6001600160a01b03161461178457604051639289a15b60e01b815260040160405180910390fd5b6001600160a01b03811660009081526003602052604081206143d8906001612b16565b6001600160a01b03160361141e57604051634033aec960e01b815260040160405180910390fd5b6000196001600160a01b038416016144315734811461332157604051630fc9bd0f60e11b815260040160405180910390fd5b600061443c84613597565b90506144536001600160a01b038516843085614a9d565b600061445e85613597565b905061446a8383615568565b81146124ad57604051630fc9bd0f60e11b815260040160405180910390fd5b7f000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff6001600160a01b031682604001516001600160a01b0316036145c6576000670de0b6b3a76400006144fb7f00000000000000000000000000000000000000000000000002c68af0bb1400008461575c565b6145059190615554565b905061451181836156cf565b604051631c57762b60e31b815260006004820152602481018390529092507f0000000000000000000000004489f4dd67b275a1c364cb652ab163972659d6726001600160a01b03169063e2bbb158906044016020604051808303816000875af1158015614582573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145a69190615614565b506145b081613365565b8360a0018181516145c191906155f4565b905250505b60016001600160a01b031682604001516001600160a01b0316036146675781608001516001600160a01b031663e2bbb158828460200151846040518463ffffffff1660e01b8152600401614624929190918252602082015260400190565b60206040518083038185885af1158015614642573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906133219190615614565b60808201516020830151604051631c57762b60e31b81526001600160a01b039092169163e2bbb158916146a7918590600401918252602082015260400190565b6020604051808303816000875af11580156146c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133219190615614565b60ff81166000908152602083905260408120541515612b2a565b600082815260046020526040812061471d906002612b16565b90506001600160a01b038116158015906147495750816001600160a01b0316816001600160a01b031614155b15613321576001600160a01b0381166000908152600360205260408120614771906001612b16565b6001600160a01b0316635d988967856040518263ffffffff1660e01b815260040161479e91815260200190565b602060405180830381865afa1580156147bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147df9190615614565b905080156124af57604051634033aec960e01b815260040160405180910390fd5b60007f000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff6001600160a01b0316826001600160a01b03160361484a5750670de0b6b3a7640000919050565b600061485e836001600160a01b0316614ad5565b90506149548160ff167f000000000000000000000000000000000000000000000000000000000000000660ff16612f917f0000000000000000000000003b823dc7087d1ba9778ab8161b791b59053a09416001600160a01b031663698439406148f56002600360008c6001600160a01b03166001600160a01b03168152602001908152602001600020612b3390919063ffffffff16565b6040518263ffffffff1660e01b815260040161491391815260200190565b602060405180830381865afa158015614930573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f3b9190615614565b9150816000036149775760405163089112d560e21b815260040160405180910390fd5b50919050565b6000808212614997576149908284615568565b9050612b2d565b6149a0826158c5565b61499090846156cf565b60008183146134f3576149be83600a6159e5565b6149c983600a6159e5565b6149d3908661575c565b6134ee9190615554565b60008060006149ec8585614b52565b915091506149f981614b97565b509392505050565b6040516001600160a01b03831660248201526044810182905261332190849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614ce1565b6001600160a01b03811661357e565b6000818311156133ab5781612b2a565b600081614a91576000614a94565b60015b60ff1692915050565b6040516001600160a01b03808516602483015283166044820152606481018290526124af9085906323b872dd60e01b90608401614a2d565b60006001600160a01b038216600114614b4a57816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015614b26573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061361291906159f1565b601292915050565b6000808251604103614b885760208301516040840151606085015160001a614b7c87828585614db6565b94509450505050614b90565b506000905060025b9250929050565b6000816004811115614bab57614bab615a14565b03614bb35750565b6001816004811115614bc757614bc7615a14565b03614c145760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161338e565b6002816004811115614c2857614c28615a14565b03614c755760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161338e565b6003816004811115614c8957614c89615a14565b0361141e5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161338e565b6000614d36826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614e7a9092919063ffffffff16565b9050805160001480614d57575080806020019051810190614d579190615a2a565b6133215760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161338e565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614ded5750600090506003614e71565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614e41573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614e6a57600060019250925050614e71565b9150600090505b94509492505050565b6060611c65848460008585600080866001600160a01b03168587604051614ea19190615a6b565b60006040518083038185875af1925050503d8060008114614ede576040519150601f19603f3d011682016040523d82523d6000602084013e614ee3565b606091505b5091509150614ef487838387614eff565b979650505050505050565b60608315614f6e578251600003614f67576001600160a01b0385163b614f675760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161338e565b5081611c65565b611c658383815115614f835781518083602001fd5b8060405162461bcd60e51b815260040161338e9190615a87565b6001600160a01b038116811461141e57600080fd5b600060208284031215614fc457600080fd5b8135612e1181614f9d565b600080600060608486031215614fe457600080fd5b833592506020840135614ff681614f9d565b929592945050506040919091013590565b60008083601f84011261501957600080fd5b50813567ffffffffffffffff81111561503157600080fd5b6020830191508360208260051b8501011115614b9057600080fd5b801515811461141e57600080fd5b600080600080600080600060c0888a03121561507557600080fd5b87359650602088013561508781614f9d565b95506040880135945060608801359350608088013567ffffffffffffffff8111156150b157600080fd5b6150bd8a828b01615007565b90945092505060a08801356150d18161504c565b8091505092959891949750929550565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261510857600080fd5b813567ffffffffffffffff80821115615123576151236150e1565b604051601f8301601f19908116603f0116810190828211818310171561514b5761514b6150e1565b8160405283815286602085880101111561516457600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561519757600080fd5b823567ffffffffffffffff808211156151af57600080fd5b6151bb868387016150f7565b935060208501359150808211156151d157600080fd5b506151de858286016150f7565b9150509250929050565b6000602082840312156151fa57600080fd5b5035919050565b81518152602080830151610140830191615225908401826001600160a01b03169052565b5060408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525092915050565b6000806000806080858703121561529657600080fd5b8435935060208501356152a881614f9d565b92506040850135915060608501356152bf8161504c565b939692955090935050565b6020808252825182820181905260009190848201906040850190845b81811015615302578351835292840192918401916001016152e6565b50909695505050505050565b6000806040838503121561532157600080fd5b8235915060208301356153338161504c565b809150509250929050565b81516001600160a01b031681526101808101602083015161536a60208401826001600160a01b03169052565b50604083015161538560408401826001600160a01b03169052565b5060608301516153a060608401826001600160a01b03169052565b5060808301516153bb60808401826001600160a01b03169052565b5060a08301516153d660a08401826001600160a01b03169052565b5060c08301516153f160c08401826001600160a01b03169052565b5060e083015161540c60e08401826001600160a01b03169052565b5061010083810151908301526101208084015190830152610140808401519083015261016092830151929091019190915290565b60008060008060008060a0878903121561545957600080fd5b86359550602087013561546b81614f9d565b94506040870135935060608701359250608087013567ffffffffffffffff81111561549557600080fd5b6154a189828a01615007565b979a9699509497509295939492505050565b600080604083850312156154c657600080fd5b50508035926020909101359150565b600080600080606085870312156154eb57600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561551057600080fd5b61551c87828801615007565b95989497509550505050565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60008261556357615563615528565b500490565b80820180821115612b2d57612b2d61553e565b60006060828403121561558d57600080fd5b6040516060810181811067ffffffffffffffff821117156155b0576155b06150e1565b80604052508251815260208301516020820152604083015160408201528091505092915050565b6000602082840312156155e957600080fd5b8151612e1181614f9d565b80820182811260008312801582168215821617156131d1576131d161553e565b60006020828403121561562657600080fd5b5051919050565b6000806040838503121561564057600080fd5b505080516020909101519092909150565b81810360008312801583831316838312821617156131d3576131d361553e565b80820260008212600160ff1b8414161561568d5761568d61553e565b8181058314821517612b2d57612b2d61553e565b6000826156b0576156b0615528565b600160ff1b8214600019841416156156ca576156ca61553e565b500590565b81810381811115612b2d57612b2d61553e565b600060c082840312156156f457600080fd5b60405160c0810181811067ffffffffffffffff82111715615717576157176150e1565b8060405250825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a08201528091505092915050565b8082028115828204841417612b2d57612b2d61553e565b634e487b7160e01b600052603260045260246000fd5b600060a0828403121561579b57600080fd5b60405160a0810181811067ffffffffffffffff821117156157be576157be6150e1565b806040525082518152602083015160208201526040830151604082015260608301516060820152608083015160808201528091505092915050565b8183526000602080850194508260005b8581101561582557813587529582019590820190600101615809565b509495945050505050565b60006101008b83528a60208401528960408401528860608401528760808401528660a08401528560c08401528060e084015261586f81840185876157f9565b9c9b505050505050505050505050565b8881528760208201528660408201528560608201528460808201528360a082015260e060c082015260006158b760e0830184866157f9565b9a9950505050505050505050565b6000600160ff1b82016158da576158da61553e565b5060000390565b6001600160801b038181168382160190808211156131d3576131d361553e565b600181815b8085111561593c5781600019048211156159225761592261553e565b8085161561592f57918102915b93841c9390800290615906565b509250929050565b60008261595357506001612b2d565b8161596057506000612b2d565b816001811461597657600281146159805761599c565b6001915050612b2d565b60ff8411156159915761599161553e565b50506001821b612b2d565b5060208310610133831016604e8410600b84101617156159bf575081810a612b2d565b6159c98383615901565b80600019048211156159dd576159dd61553e565b029392505050565b6000612b2a8383615944565b600060208284031215615a0357600080fd5b815160ff81168114612e1157600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215615a3c57600080fd5b8151612e118161504c565b60005b83811015615a62578181015183820152602001615a4a565b50506000910152565b60008251615a7d818460208701615a47565b9190910192915050565b6020815260008251806020840152615aa6816040850160208701615a47565b601f01601f1916919091016040019291505056fea2646970667358221220a51bc7cc468f19984b4c513e11e7ea00ac0fd17e28e0446592be85d8d888e0b164736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c79102c36bbba246b8bb6ae81b50ba8544e451740000000000000000000000005a9dbbc5e6bd9ecdf81d48580d861653f12ea91e0000000000000000000000003b823dc7087d1ba9778ab8161b791b59053a0941000000000000000000000000837299b1188328b5256a0215b18074bd71c852d70000000000000000000000004489f4dd67b275a1c364cb652ab163972659d67200000000000000000000000036345041077eab2b204d9496349a6208b7b15eb3000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff000000000000000000000000a51cd97f3090f6a16cf0cdc12b0cb4b0a95b38ea00000000000000000000000000000000000000000000000002c68af0bb14000000000000000000000000000000000000000000000000000006f05b59d3b20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b1ae4d6e2ef500000
-----Decoded View---------------
Arg [0] : lToken_ (address): 0xC79102C36BBbA246B8Bb6aE81B50ba8544e45174
Arg [1] : pToken_ (address): 0x5A9dBbC5E6BD9ECdf81D48580D861653f12Ea91E
Arg [2] : oracle_ (address): 0x3b823dc7087d1ba9778aB8161b791B59053a0941
Arg [3] : swapper_ (address): 0x837299B1188328B5256A0215B18074bd71c852D7
Arg [4] : vault0_ (address): 0x4489F4dD67B275a1c364cb652ab163972659D672
Arg [5] : iou_ (address): 0x36345041077eAb2b204D9496349a6208b7B15EB3
Arg [6] : tokenB0_ (address): 0x176211869cA2b568f2A7D4EE941E073a821EE1ff
Arg [7] : dChainEventSigner_ (address): 0xa51Cd97F3090f6a16Cf0cdC12B0cB4b0a95b38EA
Arg [8] : b0ReserveRatio_ (uint256): 200000000000000000
Arg [9] : liquidationRewardCutRatio_ (int256): 500000000000000000
Arg [10] : minLiquidationReward_ (int256): 0
Arg [11] : maxLiquidationReward_ (int256): 500000000000000000000
-----Encoded View---------------
12 Constructor Arguments found :
Arg [0] : 000000000000000000000000c79102c36bbba246b8bb6ae81b50ba8544e45174
Arg [1] : 0000000000000000000000005a9dbbc5e6bd9ecdf81d48580d861653f12ea91e
Arg [2] : 0000000000000000000000003b823dc7087d1ba9778ab8161b791b59053a0941
Arg [3] : 000000000000000000000000837299b1188328b5256a0215b18074bd71c852d7
Arg [4] : 0000000000000000000000004489f4dd67b275a1c364cb652ab163972659d672
Arg [5] : 00000000000000000000000036345041077eab2b204d9496349a6208b7b15eb3
Arg [6] : 000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff
Arg [7] : 000000000000000000000000a51cd97f3090f6a16cf0cdc12b0cb4b0a95b38ea
Arg [8] : 00000000000000000000000000000000000000000000000002c68af0bb140000
Arg [9] : 00000000000000000000000000000000000000000000000006f05b59d3b20000
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [11] : 00000000000000000000000000000000000000000000001b1ae4d6e2ef500000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.