Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- Lens
- Optimization enabled
- true
- Compiler version
- v0.8.17+commit.8df45f5f
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2024-07-26T17:59:09.186240Z
Constructor Arguments
0x0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000d38220cff996a73e9110aaca64e02d581b83a0cd000000000000000000000000e6505f92583103af7ed9974dec451a7af4e3a3be0000000000000000000000003daabdd029879fe3316c092364156a04fff868e400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000b52ab55f9325b4522c3bdac692d4f21b0cba05ee0000000000000000000000005896c198e445e269021b04d7c84fa46dc2cedcd80000000000000000000000001218b178e170e8cfb3ba5ada853aaf4579845347
contracts/Lens.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8; import "./Exponential-0.8.sol"; import "./Tokenomics/rewards/CTokenRewards.sol"; interface Comptroller { function isComptroller() external view returns (bool); function getAllMarkets() external view returns (address[] memory); function oracle() external view returns (PriceOracle); function markets(address) external view returns (bool, uint); function supplyRewardSpeeds(uint8, address) external view returns (uint); function borrowRewardSpeeds(uint8, address) external view returns (uint); function borrowCaps(address) external view returns (uint); function checkMembership(address account, CToken cToken) external view returns (bool); function rewardAccrued(uint8, address) external view returns (uint); function rewardBorrowState(uint8, address) external view returns (uint224, uint32); function rewardSupplyState(uint8, address) external view returns (uint224, uint32); function rewardBorrowerIndex(uint8, address, address) external view returns (uint); function rewardSupplierIndex(uint8, address, address) external view returns (uint); function initialIndexConstant() external view returns (uint224); function mintGuardianPaused(address market) external view returns (bool); function borrowGuardianPaused(address market) external view returns (bool); function getAllRewardTokens() external view returns (address[] memory rewardTokens); } interface CToken { function borrowRatePerTimestamp() external view returns (uint); function supplyRatePerTimestamp() external view returns (uint); function exchangeRateStored() external view returns (uint); function reserveFactorMantissa() external view returns (uint); function totalSupply() external view returns (uint); function totalBorrows() external view returns (uint); function underlying() external view returns (address); function balanceOf(address) external view returns (uint); function allowance(address, address) external view returns (uint); function borrowBalanceStored(address) external view returns (uint); function decimals() external view returns (uint); function totalReserves() external view returns (uint); function getCash() external view returns (uint); function borrowIndex() external view returns (uint); } interface PriceOracle { function getUnderlyingPrice(CToken cToken) external view returns (uint); } interface PriceOracleV2 { function isPriceOracle() external pure returns (bool); function getUnderlyingPrice(CToken cToken) external view returns (uint); function getPrice(address token) external view returns (uint); function getEtherPrice() external view returns (uint); } interface UnderlyingToken { function decimals() external view returns (uint); function balanceOf(address) external view returns (uint); function allowance(address, address) external view returns (uint); } interface PangolinLPToken { function balanceOf(address) external view returns (uint); function allowance(address, address) external view returns (uint); function totalSupply() external view returns (uint); function getReserves() external view returns (uint112, uint112, uint32); function kLast() external view returns (uint); } interface PglStakingContract { function pglTokenAddress() external view returns (address); function totalSupplies() external view returns (uint); function rewardSpeeds(uint) external view returns (uint); function supplyAmount(address) external view returns (uint); function rewardIndex(uint) external view returns (uint); function supplierRewardIndex(address, uint) external view returns (uint); function accruedReward(address, uint) external view returns (uint); } interface GenesisPoolStakingContract { function genesisPoolCTokenAddress() external view returns (address); function totalSupplies() external view returns (uint); function rewardSpeed() external view returns (uint); function supplyAmount(address) external view returns (uint); function accrualBlockTimestamp() external view returns (uint); function rewardIndex() external view returns (uint); function supplierRewardIndex(address) external view returns (uint); function accruedReward(address) external view returns (uint); } struct ProtocolTokens { address esProtocolAddress; address protocolAddress; } contract Lens is ExponentialNoError { Comptroller immutable public comptroller; PglStakingContract immutable public pglStakingContract; GenesisPoolStakingContract[] public genesisPoolStakingContracts; CTokenRewards[] public cTokenRewardsContracts; address immutable public esProtocolAddress; address immutable public protocolAddress; address immutable public pangolinRouter; PriceOracleV2 immutable public priceOracleV2; constructor(address comptrollerAddress, address pglStakingContractAddress, address pangolinRouterAddress, GenesisPoolStakingContract[] memory genesisPoolStakingContracts_, CTokenRewards[] memory cTokenRewardsContracts_, ProtocolTokens memory protocolTokens, PriceOracleV2 priceOracleV2_) { comptroller = Comptroller(comptrollerAddress); pglStakingContract = PglStakingContract(pglStakingContractAddress); genesisPoolStakingContracts = genesisPoolStakingContracts_; cTokenRewardsContracts = cTokenRewardsContracts_; esProtocolAddress = protocolTokens.esProtocolAddress; protocolAddress = protocolTokens.protocolAddress; require(priceOracleV2_.isPriceOracle(), 'Invalid priceOracle'); priceOracleV2 = priceOracleV2_; require(comptroller.isComptroller(), 'Invalid comptroller address'); require((pglStakingContractAddress == address(0) && pangolinRouterAddress == address(0)) || pglStakingContract.pglTokenAddress() != address(0), 'Invalid pglStakingContract'); pangolinRouter = pangolinRouterAddress; } struct MarketMetadata { /// @dev Market (CToken) address address market; /// @dev Interest rate model's supply rate uint supplyRate; /// @dev Interest rate model's borrow rate uint borrowRate; /// @dev Token price (decimal count 36 - underlying decimals) uint price; /// @dev CToken to underlying token exchange rate (18 - CToken decimals + underlying decimals) uint exchangeRate; /// @dev Reserve factor percentage (18 decimals) uint reserveFactor; /// @dev Maximum total borrowable amount for the market, denominated in the underlying asset uint borrowCap; /// @dev Total supply, denominated in CTokens uint totalSupply; /// @dev Total supply, denominated in the underlying token uint totalUnderlyingSupply; /// @dev Total borrows, denominated in the underlying token uint totalBorrows; /// @dev Collateral factor (18 decimals) uint collateralFactor; /// @dev Underlying token address address underlyingToken; /// @dev Underlying token decimal count uint underlyingTokenDecimals; /// @dev Market CToken decimal count uint cTokenDecimals; /// @dev Amount of rewards rewarded to suppliers every second uint[] supplyRewardSpeeds; /// @dev Amount of rewards rewarded to borrowers every second uint[] borrowRewardSpeeds; /// @dev Total amount of reserves of the underlying held in this market uint totalReserves; /// @dev Cash balance of this cToken in the underlying token (underlying token's decimals) uint cash; /// @dev Indicates if adding supply is paused bool mintPaused; /// @dev Indicates if borrowing is paused bool borrowPaused; } struct AccountSnapshot { AccountMarketSnapshot[] accountMarketSnapshots; AccountRewards rewards; } struct AccountRewards { /// @dev Rewards that can be claimed through the comptroller contract AccountComptrollerRewards comptroller; /// @dev Rewards that can be claimed through the contract for CTokenRewards AccountCTokenRewards[] cTokenRewards; /// @dev Rewards that can be claimed through the genesis pools contracts AccountGenesisPoolRewards[] genesisPools; } struct AccountMarketSnapshot { /// @dev Market address address market; /// @dev Account's wallet balance for the underlying token uint balance; /// @dev The allowed maximum expenditure of the underlying token by the market contract uint allowance; /// @dev Account's supply balance, denominated in the underlying token uint supplyBalance; /// @dev Account's borrow balance, denominated in the underlying token uint borrowBalance; /// @dev Indicates if a market is avaiable as collateral on the account bool collateralEnabled; } struct ComptrollerReward{ uint8 rewardType; uint unclaimedAmount; } struct AccountComptrollerRewards { ComptrollerReward[] unclaimedRewards; /// @dev List of all markets in which the user has unclaimed rewards address[] markets; } struct AccountRewardErc20Info { /// @dev Amount of unclaimed token rewards (18 decimals) uint amount; /// @dev Address of the associated reward token address rewardTokenAddress; } struct AccountCTokenRewards { /// @dev The contract where the rewards can be claimed CTokenRewards rewardContract; /// @dev Amount of unclaimed native token rewards (18 decimals) uint unclaimedNativeToken; /// @dev Info about unclaimed ERC20 token rewards AccountRewardErc20Info[] unclaimedErc20; } struct AccountGenesisPoolRewards { /// @dev Address of the genesis pool where the rewards can be claimed GenesisPoolStakingContract poolAddress; /// @dev The address of the cToken deposited to the genesis pool address cTokenAddress; /// @dev Amount of unclaimed esProtocol token rewards (18 decimals) uint unclaimedEsProtocolToken; } struct AccountPglSnapshot { /// @dev The PGL balance of the user's wallet (PGL token`s decimals) uint balance; /// @dev The amount of PGL tokens the user has deposited (PGL token`s decimals) uint deposited; /// @dev Unclaimed protocol token rewards (18 decimals) uint unclaimedProtocolToken; /// @dev The allowed maximum expenditure of the user's PGL tokens by the staking contract (PGL token`s decimals) uint pglStakingContractAllowance; /// @dev The allowed maximum expenditure of the user's protocol tokens (actual protocol tokens, not cTokens) by the pangolin router (18 decimals) uint pangolinRouterProtocolTokenAllowance; } struct AccountGenesisPoolSnapshot { /// @dev Address of the genesis pool GenesisPoolStakingContract poolAddress; /// @dev The address of the cToken deposited to the genesis pool address cTokenAddress; /// @dev Amount of unclaimed esProtocol token rewards (18 decimals) uint unclaimedEsProtocolToken; /// @dev The cToken balance of the user's wallet (CToken`s decimals) uint balance; /// @dev The amount of GenesisPool tokens the user has deposited (GenesisPool token`s decimals) uint deposited; /// @dev The allowed maximum expenditure of the user's GenesisPool tokens by the staking contract (GenesisPool token`s decimals) uint stakingContractAllowance; } struct MarketPglSnapshot { /// @dev Total PGL token amount deposited into the staking contract (PGL token's decimals) uint totalDepositedPglTokenAmount; /// @dev total supply of PGL tokens (18 decimals) uint pglTokenTotalSupply; /// @dev amount of protocol tokens in the pool (18 decimals) uint pglProtocolTokenReserves; /// @dev amount of native tokens in the pool (18 decimals) uint pglNativeTokenReserves; /// @dev reserve0 * reserve1 uint kLast; /// @dev APR (18 decimals, 1e18 means 100%) uint apr; } struct MarketGenesisPoolSnapshot { /// @dev Address of the genesis pool GenesisPoolStakingContract poolAddress; /// @dev The address of the cToken deposited to the genesis pool address cTokenAddress; /// @dev Total cToken amount deposited into the staking contract (CToken's decimals) uint totalDepositedCTokenAmount; /// @dev Total supply of cToken (CToken's decimals) uint cTokenTotalSupply; /// @dev Exchange rate from the cToken to the underlying token (18 decimals) uint cTokenExchangeRate; /// @dev price of underlying token of the deposited cToken (18 decimals) uint underlyingTokenPrice; /// @dev Reward accrual speeds as tokens per second (ESProtocol's decimals) uint esProtocolRewardSpeed; /// @dev APR (18 decimals, 1e18 means 100%) uint apr; } /** * @notice Get prices for the base tokens used by the protocol (the ProtocolToken and the network native token) * @return protocolTokenPrice Price of the protocolToken (18 decimals) * @return nativeTokenPrice Price of the native token (18 decimals) */ function getPrices() external view returns (uint protocolTokenPrice, uint nativeTokenPrice) { nativeTokenPrice = priceOracleV2.getEtherPrice(); protocolTokenPrice = priceOracleV2.getPrice(protocolAddress); } /** * @notice Get metadata for a specific market * @param market The ctoken address which metadata will be fetched for * @return Market metadata */ function getMarketMetadata(CToken market) external view returns (MarketMetadata memory) { return _getMarketMetadata(market); } /** * @notice Get metadata for all markets * @return Market metadata for all markets */ function getMarketMetadataForAllMarkets() external view returns (MarketMetadata[] memory) { address[] memory allMarkets = comptroller.getAllMarkets(); uint marketCount = allMarkets.length; MarketMetadata[] memory metadata = new MarketMetadata[](marketCount); for (uint i; i < marketCount;) { metadata[i] = _getMarketMetadata(CToken(allMarkets[i])); unchecked { ++i; } } return metadata; } /** * @notice Get account-specific data for supply and borrow positions * @param account Account for the snapshot * @return Account snapshot array */ function getAccountSnapshot(address account) external view returns (AccountSnapshot memory) { return _getAccountSnapshot(account); } /** * @notice Calculate an account snapshot for a specific market * @param account The account which the snapshot will belong to * @param market The specific market which a snapshot will be calculated for the given account * @return Account snapshot */ function getAccountMarketSnapshot(address account, CToken market) external view returns (AccountMarketSnapshot memory) { return _getAccountMarketSnapshot(account, market); } /** * @notice Calculate account-specific GenesisPool staking snapshots for each GenesisPool * @param account The account which the snapshot will belong to * @return snapshots Account snapshot array for GenesisPool data */ function getAccountGenesisPoolSnapshot(address account) external view returns (AccountGenesisPoolSnapshot[] memory snapshots) { uint genesisPoolCount = genesisPoolStakingContracts.length; snapshots = new AccountGenesisPoolSnapshot[](genesisPoolCount); for (uint i; i < genesisPoolCount;) { snapshots[i] = _getAccountGenesisPoolSnapshot(account, genesisPoolStakingContracts[i]); unchecked { ++i; } } } /** * @notice Calculate the GenesisPool market snapshots * @return Market snapshot for GenesisPool data */ function getMarketGenesisPoolSnapshots() external view returns (MarketGenesisPoolSnapshot[] memory) { uint genesisPoolCount = genesisPoolStakingContracts.length; MarketGenesisPoolSnapshot[] memory snapshots = new MarketGenesisPoolSnapshot[](genesisPoolCount); for (uint i; i < genesisPoolCount;) { snapshots[i] = _getMarketGenesisPoolSnapshot(genesisPoolStakingContracts[i]); unchecked { ++i; } } return snapshots; } function _getMarketMetadata(CToken market) internal view returns (MarketMetadata memory) { address marketAddress = address(market); (, uint collateralFactor) = comptroller.markets(marketAddress); address underlyingToken; uint underlyingTokenDecimals; underlyingToken = market.underlying(); underlyingTokenDecimals = UnderlyingToken(underlyingToken).decimals(); uint totalSupply = market.totalSupply(); uint totalUnderlyingTokenSupply = _cTokenBalanceToUnderlying(totalSupply, market); uint rewards = comptroller.getAllRewardTokens().length; uint[] memory supplyRewardSpeeds = new uint[](rewards); uint[] memory borrowRewardSpeeds = new uint[](rewards); for(uint8 r; r < rewards; r++){ supplyRewardSpeeds[r] = comptroller.supplyRewardSpeeds(r, marketAddress); borrowRewardSpeeds[r] = comptroller.borrowRewardSpeeds(r, marketAddress); } MarketMetadata memory metadata = MarketMetadata( marketAddress, market.supplyRatePerTimestamp(), market.borrowRatePerTimestamp(), comptroller.oracle().getUnderlyingPrice(market), market.exchangeRateStored(), market.reserveFactorMantissa(), comptroller.borrowCaps(marketAddress), totalSupply, totalUnderlyingTokenSupply, market.totalBorrows(), collateralFactor, underlyingToken, underlyingTokenDecimals, market.decimals(), supplyRewardSpeeds, borrowRewardSpeeds, market.totalReserves(), market.getCash(), comptroller.mintGuardianPaused(marketAddress), comptroller.borrowGuardianPaused(marketAddress) ); return metadata; } function _getAccountSnapshot(address account) internal view returns (AccountSnapshot memory) { address[] memory allMarkets = comptroller.getAllMarkets(); uint marketCount = allMarkets.length; AccountMarketSnapshot[] memory snapshots = new AccountMarketSnapshot[](marketCount); for (uint i; i < marketCount;) { snapshots[i] = _getAccountMarketSnapshot(account, CToken(allMarkets[i])); unchecked { ++i; } } AccountComptrollerRewards memory comprollerRewards = _getAccountComptrollerRewards(account); AccountCTokenRewards[] memory cTokenRewards = _getAccountCTokenRewards(account); AccountGenesisPoolRewards[] memory genesisPoolRewards = _getAccountGenesisPoolsRewards(account); return AccountSnapshot( snapshots, AccountRewards( comprollerRewards, cTokenRewards, genesisPoolRewards ) ); } function _getAccountComptrollerRewards(address account) internal view returns (AccountComptrollerRewards memory) { ( ComptrollerReward[] memory unclaimedRewards, address[] memory marketsWithClaimableRewards ) = getComptrollerClaimableRewards(account); return AccountComptrollerRewards(unclaimedRewards, marketsWithClaimableRewards); } function _getAccountCTokenRewards(address account) internal view returns (AccountCTokenRewards[] memory cTokenRewards) { unchecked { uint numCTokenContracts = cTokenRewardsContracts.length; cTokenRewards = new AccountCTokenRewards[](numCTokenContracts); for (uint i; i < numCTokenContracts;++i) { cTokenRewards[i] = getCTokenClaimableRewards(account, cTokenRewardsContracts[i]); } } } function _getAccountGenesisPoolsRewards(address account) internal view returns (AccountGenesisPoolRewards[] memory genesisPoolsRewards) { unchecked { uint numGenesisPoolsContracts = genesisPoolStakingContracts.length; genesisPoolsRewards = new AccountGenesisPoolRewards[](numGenesisPoolsContracts); for (uint i; i < numGenesisPoolsContracts;++i) { genesisPoolsRewards[i] = getGenesisPoolsClaimableRewards(account, genesisPoolStakingContracts[i]); } } } function _getAccountMarketSnapshot(address account, CToken market) internal view returns (AccountMarketSnapshot memory) { uint balance; uint allowance; UnderlyingToken underlyingToken = UnderlyingToken(market.underlying()); balance = underlyingToken.balanceOf(account); allowance = underlyingToken.allowance(account, address(market)); uint cTokenBalance = market.balanceOf(account); uint supplyBalance = _cTokenBalanceToUnderlying(cTokenBalance, market); bool collateralEnabled = comptroller.checkMembership(account, market); return AccountMarketSnapshot( address(market), balance, allowance, supplyBalance, market.borrowBalanceStored(account), collateralEnabled ); } function _getAccountGenesisPoolSnapshot(address account, GenesisPoolStakingContract genesisPoolContract) internal view returns (AccountGenesisPoolSnapshot memory) { CToken cToken = CToken(genesisPoolContract.genesisPoolCTokenAddress()); uint balance = cToken.balanceOf(account); uint deposited = genesisPoolContract.supplyAmount(account); uint unclaimedProtocolToken = updateAndDistributeGenesisPoolRewards(account, genesisPoolContract); uint genesisPoolContractAllowance = cToken.allowance(account, address(genesisPoolContract)); return AccountGenesisPoolSnapshot( genesisPoolContract, address(cToken), unclaimedProtocolToken, balance, deposited, genesisPoolContractAllowance ); } function _getMarketGenesisPoolSnapshot(GenesisPoolStakingContract genesisPoolStakingContract) internal view returns (MarketGenesisPoolSnapshot memory) { CToken cToken = CToken(genesisPoolStakingContract.genesisPoolCTokenAddress()); PriceOracle oracle = comptroller.oracle(); uint totalDepositedCTokenAmount = genesisPoolStakingContract.totalSupplies(); uint cTokenTotalSupply = cToken.totalSupply(); uint cTokenExchangeRate = cToken.exchangeRateStored(); uint underlyingTokenPrice = oracle.getUnderlyingPrice(cToken); uint esProtocolRewardSpeed = genesisPoolStakingContract.rewardSpeed(); uint apr = _calculateAPR( esProtocolRewardSpeed, priceOracleV2.getPrice(protocolAddress), _cTokenBalanceToUnderlying(totalDepositedCTokenAmount, cToken), underlyingTokenPrice ); return MarketGenesisPoolSnapshot( genesisPoolStakingContract, address(cToken), totalDepositedCTokenAmount, cTokenTotalSupply, cTokenExchangeRate, underlyingTokenPrice, esProtocolRewardSpeed, apr ); } function _calculatePglAPR( uint protocolTokenRewardSpeed, uint protocolTokenReserves, uint nativeTokenReserves, uint protocolTokenPrice, uint nativeTokenPrice, uint pglTotalSupply, uint totalDepositedPGLTokenAmount ) internal pure returns (uint usdPerStakedPglValue) { uint protocolTokenReservesValue = (protocolTokenReserves * protocolTokenPrice); uint nativeTokenReserveValue = (nativeTokenReserves * nativeTokenPrice); uint pglPrice = (protocolTokenReservesValue + nativeTokenReserveValue) / pglTotalSupply; usdPerStakedPglValue = _calculateAPR( protocolTokenRewardSpeed, protocolTokenPrice, totalDepositedPGLTokenAmount, pglPrice ); } function _calculateAPR( uint protocolTokenRewardSpeed, uint protocolTokenPrice, uint totalDepositedTokenAmount, uint depositedTokenPrice ) internal pure returns (uint) { uint totalStakedValue = totalDepositedTokenAmount * depositedTokenPrice / 1e18; if(totalStakedValue == 0){ return 0; } uint protocolTokenUsdValuePerYear = protocolTokenRewardSpeed * (60 * 60 * 24 * 365) * protocolTokenPrice; return protocolTokenUsdValuePerYear / totalStakedValue; } function getComptrollerClaimableRewards(address user) internal view returns (ComptrollerReward[] memory, address[] memory) { uint8 rewards = uint8(comptroller.getAllRewardTokens().length); uint marketsCount = comptroller.getAllMarkets().length; ComptrollerReward[] memory unclaimedRewards = new ComptrollerReward[](rewards); address[] memory rewardMarkets = new address[](marketsCount); uint uniqueRewardMarketCount; for(uint8 r; r < rewards; r++){ (uint claimableAmount, address[] memory markets) = getComptrollerClaimableReward(user, r); unclaimedRewards[r] = ComptrollerReward(r, claimableAmount); for (uint i; i < markets.length;++i) { bool duplicate = false; for (uint j; j < uniqueRewardMarketCount;++j) { if(rewardMarkets[j] == markets[i]) { duplicate = true; break; } } if (!duplicate) { rewardMarkets[uniqueRewardMarketCount] = markets[i]; ++uniqueRewardMarketCount; } } } address[] memory marketsWithClaimableRewards = new address[](uniqueRewardMarketCount); for (uint i; i < uniqueRewardMarketCount; ++i) { marketsWithClaimableRewards[i] = rewardMarkets[i]; } return (unclaimedRewards, marketsWithClaimableRewards); } function getComptrollerClaimableReward(address user, uint8 rewardType) public view returns (uint, address[] memory) { address[] memory markets = comptroller.getAllMarkets(); uint numMarkets = markets.length; uint accrued = comptroller.rewardAccrued(rewardType, user); uint totalMarketAccrued; address[] memory rawMarketsWithRewards = new address[](numMarkets); uint numMarketsWithRewards; for (uint i; i < numMarkets;) { CToken market = CToken(markets[i]); totalMarketAccrued = updateAndDistributeSupplierReward(rewardType, market, user); totalMarketAccrued += updateAndDistributeBorrowerReward(rewardType, market, user); accrued += totalMarketAccrued; if (totalMarketAccrued > 0) { rawMarketsWithRewards[numMarketsWithRewards++] = address(market); } unchecked { ++i; } } address[] memory marketsWithRewards = new address[](numMarketsWithRewards); for (uint i; i < numMarketsWithRewards;) { marketsWithRewards[i] = rawMarketsWithRewards[i]; unchecked { ++i; } } return (accrued, marketsWithRewards); } function getCTokenClaimableRewards(address account, CTokenRewards cTokenRewards) internal view returns (AccountCTokenRewards memory) { uint rewardTokensLength = cTokenRewards.rewardTokensLength(); uint unclaimedNative = cTokenRewards.userPendingEther(account); AccountRewardErc20Info[] memory unclaimedErc20 = new AccountRewardErc20Info[](rewardTokensLength); for (uint i; i < rewardTokensLength;) { address rewardTokenAddress = cTokenRewards.rewardTokenAt(i); uint unclaimedAmount = cTokenRewards.userPendingRewards(IERC20(rewardTokenAddress), account); unclaimedErc20[i] = AccountRewardErc20Info(unclaimedAmount, rewardTokenAddress); unchecked { ++i; } } return AccountCTokenRewards(cTokenRewards, unclaimedNative, unclaimedErc20); } function getGenesisPoolsClaimableRewards(address account, GenesisPoolStakingContract genesisPoolContract) internal view returns (AccountGenesisPoolRewards memory) { uint unclaimedRewards = updateAndDistributeGenesisPoolRewards(account, genesisPoolContract); return AccountGenesisPoolRewards(genesisPoolContract, genesisPoolContract.genesisPoolCTokenAddress(), unclaimedRewards); } function updateAndDistributeGenesisPoolRewards(address recipient, GenesisPoolStakingContract genesisPool) internal view returns (uint unclaimedRewards) { uint rewardIndex = accrueRewardGenesisPool(genesisPool); uint rewardIndexDelta = rewardIndex - genesisPool.supplierRewardIndex(recipient); uint accruedAmount = rewardIndexDelta * genesisPool.supplyAmount(recipient) / 1e36; unclaimedRewards = genesisPool.accruedReward(recipient) + accruedAmount; } function accrueRewardGenesisPool(GenesisPoolStakingContract genesisPoolContract) internal view returns (uint) { uint blockTimestampDelta = block.timestamp - genesisPoolContract.accrualBlockTimestamp(); uint totalSupplies = genesisPoolContract.totalSupplies(); uint rewardSpeed = genesisPoolContract.rewardSpeed(); uint rewardIndex = genesisPoolContract.rewardIndex(); if (blockTimestampDelta == 0 || totalSupplies == 0 || rewardSpeed == 0) { return rewardIndex; } uint accrued = rewardSpeed * blockTimestampDelta; uint accruedPerCToken = (accrued * 1e36) / totalSupplies; return rewardIndex + accruedPerCToken; } function updateRewardBorrowIndex( uint8 rewardType, CToken cToken, Exp memory marketBorrowIndex ) internal view returns (uint224) { (uint224 borrowStateIndex, uint32 borrowStateTimestamp) = comptroller.rewardBorrowState(rewardType, address(cToken)); uint borrowSpeed = comptroller.borrowRewardSpeeds(rewardType, address(cToken)); uint32 blockTimestamp = uint32(block.timestamp); uint deltaTimestamps = sub_(blockTimestamp, uint(borrowStateTimestamp)); if (deltaTimestamps > 0 && borrowSpeed > 0) { uint borrowAmount = div_(cToken.totalBorrows(), marketBorrowIndex); uint rewardAccrued = mul_(deltaTimestamps, borrowSpeed); Double memory ratio = borrowAmount > 0 ? fraction(rewardAccrued, borrowAmount) : Double({ mantissa: 0 }); Double memory index = add_(Double({ mantissa: borrowStateIndex }), ratio); return uint224(index.mantissa); } return borrowStateIndex; } function updateRewardSupplyIndex( uint8 rewardType, CToken cToken ) internal view returns (uint) { (uint224 supplyStateIndex, uint32 supplyStateTimestamp) = comptroller.rewardSupplyState(rewardType, address(cToken)); uint supplySpeed = comptroller.supplyRewardSpeeds(rewardType, address(cToken)); uint32 blockTimestamp = uint32(block.timestamp); uint deltaTimestamps = sub_(blockTimestamp, uint(supplyStateTimestamp)); if (deltaTimestamps > 0 && supplySpeed > 0) { uint supplyTokens = cToken.totalSupply(); uint rewardAccrued = mul_(deltaTimestamps, supplySpeed); Double memory ratio = supplyTokens > 0 ? fraction(rewardAccrued, supplyTokens) : Double({ mantissa: 0 }); Double memory index = add_(Double({ mantissa: supplyStateIndex }), ratio); return index.mantissa; } return supplyStateIndex; } function distributeBorrowerReward( uint8 rewardType, CToken cToken, address borrower, uint borrowStateIndex, Exp memory marketBorrowIndex ) internal view returns (uint) { Double memory borrowIndex = Double({ mantissa: borrowStateIndex }); Double memory borrowerIndex = Double({ mantissa: comptroller.rewardBorrowerIndex(rewardType, address(cToken), borrower) }); if (borrowerIndex.mantissa > 0) { Double memory deltaIndex = sub_(borrowIndex, borrowerIndex); uint borrowerAmount = div_(cToken.borrowBalanceStored(borrower), marketBorrowIndex); uint borrowerDelta = mul_(borrowerAmount, deltaIndex); return borrowerDelta; } return 0; } function distributeSupplierReward( uint8 rewardType, CToken cToken, address supplier, uint supplyStateIndex ) internal view returns (uint) { Double memory supplyIndex = Double({ mantissa: supplyStateIndex }); Double memory supplierIndex = Double({ mantissa: comptroller.rewardSupplierIndex(rewardType, address(cToken), supplier) }); if (supplierIndex.mantissa == 0 && supplyIndex.mantissa > 0) { supplierIndex.mantissa = comptroller.initialIndexConstant(); } Double memory deltaIndex = sub_(supplyIndex, supplierIndex); uint supplierTokens = cToken.balanceOf(supplier); uint supplierDelta = mul_(supplierTokens, deltaIndex); return supplierDelta; } function updateAndDistributeBorrowerReward( uint8 rewardType, CToken cToken, address borrower ) internal view returns (uint) { Exp memory marketBorrowIndex = Exp({ mantissa: cToken.borrowIndex() }); uint borrowStateIndex = updateRewardBorrowIndex(rewardType, cToken, marketBorrowIndex); return distributeBorrowerReward(rewardType, cToken, borrower, borrowStateIndex, marketBorrowIndex); } function updateAndDistributeSupplierReward( uint8 rewardType, CToken cToken, address supplier ) internal view returns (uint) { uint supplyStateIndex = updateRewardSupplyIndex(rewardType, cToken); return distributeSupplierReward(rewardType, cToken, supplier, supplyStateIndex); } function _cTokenBalanceToUnderlying(uint cTokenBalance, CToken market) internal view returns (uint) { uint exchangeRate = market.exchangeRateStored(); return cTokenBalance * exchangeRate / 10 ** 18; } }
@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol
// 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)); } }
@openzeppelin/contracts/utils/Address.sol
// 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); } } }
@openzeppelin/contracts/utils/structs/EnumerableSet.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol) pragma solidity ^0.8.0; import "./OwnableUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership} and {acceptOwnership}. * * This module is used through inheritance. It will make available all functions * from parent (Ownable). */ abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable { function __Ownable2Step_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable2Step_init_unchained() internal onlyInitializing { } address private _pendingOwner; event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); /** * @dev Returns the address of the pending owner. */ function pendingOwner() public view virtual returns (address) { return _pendingOwner; } /** * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual override onlyOwner { _pendingOwner = newOwner; emit OwnershipTransferStarted(owner(), newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual override { delete _pendingOwner; super._transferOwnership(newOwner); } /** * @dev The new owner accepts the ownership transfer. */ function acceptOwnership() public virtual { address sender = _msgSender(); require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner"); _transferOwnership(sender); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol
// 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 AddressUpgradeable { /** * @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); } } }
@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
@openzeppelin/contracts/token/ERC20/IERC20.sol
// 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); }
@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol
// 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); }
contracts/Exponential-0.8.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8; /** * @title Exponential module for storing fixed-precision decimals * @author RBL * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: * `Exp({mantissa: 5100000000000000000})`. */ contract ExponentialNoError { uint constant expScale = 1e18; uint constant doubleScale = 1e36; uint constant halfExpScale = expScale/2; uint constant mantissaOne = expScale; struct Exp { uint mantissa; } struct Double { uint mantissa; } /** * @dev Truncates the given exp to a whole number value. * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 */ function truncate(Exp memory exp) pure internal returns (uint) { // Note: We are not using careful math here as we're performing a division that cannot fail return exp.mantissa / expScale; } /** * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. */ function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { Exp memory product = mul_(a, scalar); return truncate(product); } /** * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. */ function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { Exp memory product = mul_(a, scalar); return add_(truncate(product), addend); } /** * @dev Checks if first Exp is less than second Exp. */ function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa < right.mantissa; } /** * @dev Checks if left Exp <= right Exp. */ function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa <= right.mantissa; } /** * @dev Checks if left Exp > right Exp. */ function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa > right.mantissa; } /** * @dev returns true if Exp is exactly zero */ function isZeroExp(Exp memory value) pure internal returns (bool) { return value.mantissa == 0; } function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { require(n < 2**224, errorMessage); return uint224(n); } function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { require(n < 2**32, errorMessage); return uint32(n); } function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: add_(a.mantissa, b.mantissa)}); } function add_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: add_(a.mantissa, b.mantissa)}); } function add_(uint a, uint b) pure internal returns (uint) { return a + b; } function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); } function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: sub_(a.mantissa, b.mantissa)}); } function sub_(uint a, uint b) pure internal returns (uint) { return a - b; } function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); } function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { return Exp({mantissa: mul_(a.mantissa, b)}); } function mul_(uint a, Exp memory b) pure internal returns (uint) { return mul_(a, b.mantissa) / expScale; } function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); } function mul_(Double memory a, uint b) pure internal returns (Double memory) { return Double({mantissa: mul_(a.mantissa, b)}); } function mul_(uint a, Double memory b) pure internal returns (uint) { return mul_(a, b.mantissa) / doubleScale; } function mul_(uint a, uint b) pure internal returns (uint) { return a * b; } function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); } function div_(Exp memory a, uint b) pure internal returns (Exp memory) { return Exp({mantissa: div_(a.mantissa, b)}); } function div_(uint a, Exp memory b) pure internal returns (uint) { return div_(mul_(a, expScale), b.mantissa); } function div_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); } function div_(Double memory a, uint b) pure internal returns (Double memory) { return Double({mantissa: div_(a.mantissa, b)}); } function div_(uint a, Double memory b) pure internal returns (uint) { return div_(mul_(a, doubleScale), b.mantissa); } function div_(uint a, uint b) pure internal returns (uint) { return a / b; } function fraction(uint a, uint b) pure internal returns (Double memory) { return Double({mantissa: div_(mul_(a, doubleScale), b)}); } }
contracts/Tokenomics/rewards/CTokenRewards.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8; import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "./CTokenRewardsStorage.sol"; /** * @title CToken liquidity incentive rewards * @notice First version of the CTokenRewards contract that receives manual reward allocations for specific users. * @dev This contract does no proportional allocation or any other logic to distribute the rewards, it's basically a vault so the users can claim rewards */ contract CTokenRewards is Initializable, Ownable2StepUpgradeable, ReentrancyGuardUpgradeable, CTokenRewardsStorageV1 { using SafeERC20 for IERC20; using EnumerableSet for EnumerableSet.AddressSet; /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /** * @notice Standard Initializable method */ function initialize() initializer public { __Ownable_init(); __ReentrancyGuard_init(); } /** * Deposits reward tokens allocating different shares to different users * @notice The total amount of reward tokens allocated will be transfered from the caller to the contract during this call, * so make sure to have enough allowance on the reward token for this contract and enough balance. * Also, if the number of users is too big, this function should be called in smaller batches so it does not run out of gas * @param rewardToken The token being rewarded to users * @param users Users that are being allocated rewards * @param amounts Amounts of token reward allocated to the user on the same index * @dev The arrays of users and amounts should have the same length */ function depositTokens(address rewardToken, address[] calldata users, uint256[] calldata amounts) external onlyOwner { require(users.length > 0 && users.length == amounts.length, "Invalid input"); require(rewardToken != address(0), "Invalid reward token"); uint256 totalAmount; IERC20 rewardTokenContract = IERC20(rewardToken); uint256 i; uint256 userCount = users.length; for (; i < userCount;) { address user = users[i]; uint256 amount = amounts[i]; require(amount > 0, "Amount must be greater than zero"); userPendingRewards[rewardTokenContract][user] = userPendingRewards[rewardTokenContract][user] + amount; totalAmount = totalAmount + amount; emit TokensDeposited(rewardToken, user, amount); unchecked { ++i; } } rewardTokens.add(rewardToken); uint balanceBefore = rewardTokenContract.balanceOf(address(this)); // Transfer tokens from caller to contract rewardTokenContract.safeTransferFrom(msg.sender, address(this), totalAmount); uint actualTransferredAmount = rewardTokenContract.balanceOf(address(this)) - balanceBefore; require(actualTransferredAmount >= totalAmount, "Invalid deposit"); } /** * Claims the available rewards for the specified reward token * @notice All the available rewards for the token will be claimed to the caller of the function. So only end users should call it * @param token The token to claim */ function claimTokens(address token) external nonReentrant { require(token != address(0), "Invalid token address"); IERC20 tokenContract = IERC20(token); uint256 amount = userPendingRewards[tokenContract][msg.sender]; require(amount > 0, "No tokens to claim"); userPendingRewards[tokenContract][msg.sender] = 0; userClaimedRewards[tokenContract][msg.sender] = userClaimedRewards[tokenContract][msg.sender] + amount; emit TokensClaimed(msg.sender, token, amount); // Transfer tokens to user tokenContract.safeTransfer(msg.sender, amount); } /** * Deposits ether rewards allocating different shares to different users * @notice The total amount of ether allocated will be transfered from the caller to the contract during this call, * so make sure to have enough ether balance. * Also, if the number of users is too big, this function should be called in smaller batches so it does not run out of gas * @param users Users that are being allocated rewards * @param amounts Amounts of ether allocated to the user on the same index * @dev The arrays of users and amounts should have the same length */ function depositEther(address[] calldata users, uint256[] calldata amounts) external payable onlyOwner { require(users.length > 0 && users.length == amounts.length, "Invalid input"); uint256 totalAmount; uint256 i; uint256 userCount = users.length; for ( ; i < userCount; ) { address user = users[i]; uint256 amount = amounts[i]; require(amount > 0, "Amount must be greater than zero"); userPendingEther[user] = userPendingEther[user] + amount; totalAmount = totalAmount + amount; emit EtherDeposited(user, amount); unchecked { ++i; } } require(totalAmount == msg.value, "insufficient amount"); } /** * Claims the available ether rewards * @notice All the available ether be claimed to the caller of the function. So only end users should call it */ function claimEther() external nonReentrant{ uint256 amount = userPendingEther[msg.sender]; require(amount > 0, "No ether to claim"); userPendingEther[msg.sender] = 0; userClaimedEther[msg.sender] = userClaimedEther[msg.sender] + amount; emit EtherClaimed(msg.sender, amount); // Transfer Ether to user (bool success, ) = payable(msg.sender).call{value: amount, gas: 4029}(""); require(success, "Transfer failed."); } /** * @dev Checks if an index exists */ modifier validateRewardTokensIndex(uint256 index) { require(index < rewardTokens.length(), "validateRewardTokensIndex: index exists?"); _; } /** * @dev Returns the number of rewards tokens */ function rewardTokensLength() external view returns (uint256) { return rewardTokens.length(); } /** * @dev Returns rewards token address from given index */ function rewardTokenAt(uint256 index) external view validateRewardTokensIndex(index) returns (address) { return address(rewardTokens.at(index)); } }
contracts/Tokenomics/rewards/CTokenRewardsStorage.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8; pragma abicoder v2; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; /** * First storage model of the CTokenRewards. * @dev For future storage changes, new versions should be created and inherit from the previous one */ contract CTokenRewardsStorageV1 { /// User's pending rewards by reward token address mapping(IERC20 => mapping(address => uint256)) public userPendingRewards; /// User's claimed rewards by reward token address mapping(IERC20 => mapping(address => uint256)) public userClaimedRewards; /// User's pending ether rewards mapping(address => uint256) public userPendingEther; /// User's claimed ether rewards mapping(address => uint256) public userClaimedEther; /// @dev All tokens ever distributed will be present even though no pending rewards are available EnumerableSet.AddressSet internal rewardTokens; /** * @notice Event for every new reward allocation * @param token the reward token address * @param user the user that have been allocated rewards to * @param amount the amount of rewards that have been allocated to the user */ event TokensDeposited(address indexed token, address indexed user, uint256 amount); /** * @notice Event for every an user claims allocated rewards * @param user the user that claimed the rewards * @param token the reward token address * @param amount the amount of reward tokens that have been claimed */ event TokensClaimed(address indexed user, address indexed token, uint256 amount); /** * @notice Event for every new ether reward allocation * @param user the user that have been allocated rewards to * @param amount the amount of rewards that have been allocated to the user */ event EtherDeposited(address indexed user, uint256 amount); /** * @notice Event for every an user claims allocated ether rewards * @param user the user that claimed the rewards * @param amount the amount of ether that have been claimed */ event EtherClaimed(address indexed user, uint256 amount); }
Compiler Settings
{"outputSelection":{"*":{"*":["*"],"":["*"]}},"optimizer":{"runs":200,"enabled":true},"libraries":{}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"comptrollerAddress","internalType":"address"},{"type":"address","name":"pglStakingContractAddress","internalType":"address"},{"type":"address","name":"pangolinRouterAddress","internalType":"address"},{"type":"address[]","name":"genesisPoolStakingContracts_","internalType":"contract GenesisPoolStakingContract[]"},{"type":"address[]","name":"cTokenRewardsContracts_","internalType":"contract CTokenRewards[]"},{"type":"tuple","name":"protocolTokens","internalType":"struct ProtocolTokens","components":[{"type":"address","name":"esProtocolAddress","internalType":"address"},{"type":"address","name":"protocolAddress","internalType":"address"}]},{"type":"address","name":"priceOracleV2_","internalType":"contract PriceOracleV2"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract CTokenRewards"}],"name":"cTokenRewardsContracts","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract Comptroller"}],"name":"comptroller","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"esProtocolAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract GenesisPoolStakingContract"}],"name":"genesisPoolStakingContracts","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"snapshots","internalType":"struct Lens.AccountGenesisPoolSnapshot[]","components":[{"type":"address","name":"poolAddress","internalType":"contract GenesisPoolStakingContract"},{"type":"address","name":"cTokenAddress","internalType":"address"},{"type":"uint256","name":"unclaimedEsProtocolToken","internalType":"uint256"},{"type":"uint256","name":"balance","internalType":"uint256"},{"type":"uint256","name":"deposited","internalType":"uint256"},{"type":"uint256","name":"stakingContractAllowance","internalType":"uint256"}]}],"name":"getAccountGenesisPoolSnapshot","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct Lens.AccountMarketSnapshot","components":[{"type":"address","name":"market","internalType":"address"},{"type":"uint256","name":"balance","internalType":"uint256"},{"type":"uint256","name":"allowance","internalType":"uint256"},{"type":"uint256","name":"supplyBalance","internalType":"uint256"},{"type":"uint256","name":"borrowBalance","internalType":"uint256"},{"type":"bool","name":"collateralEnabled","internalType":"bool"}]}],"name":"getAccountMarketSnapshot","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"market","internalType":"contract CToken"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct Lens.AccountSnapshot","components":[{"type":"tuple[]","name":"accountMarketSnapshots","internalType":"struct Lens.AccountMarketSnapshot[]","components":[{"type":"address","name":"market","internalType":"address"},{"type":"uint256","name":"balance","internalType":"uint256"},{"type":"uint256","name":"allowance","internalType":"uint256"},{"type":"uint256","name":"supplyBalance","internalType":"uint256"},{"type":"uint256","name":"borrowBalance","internalType":"uint256"},{"type":"bool","name":"collateralEnabled","internalType":"bool"}]},{"type":"tuple","name":"rewards","internalType":"struct Lens.AccountRewards","components":[{"type":"tuple","name":"comptroller","internalType":"struct Lens.AccountComptrollerRewards","components":[{"type":"tuple[]","name":"unclaimedRewards","internalType":"struct Lens.ComptrollerReward[]","components":[{"type":"uint8","name":"rewardType","internalType":"uint8"},{"type":"uint256","name":"unclaimedAmount","internalType":"uint256"}]},{"type":"address[]","name":"markets","internalType":"address[]"}]},{"type":"tuple[]","name":"cTokenRewards","internalType":"struct Lens.AccountCTokenRewards[]","components":[{"type":"address","name":"rewardContract","internalType":"contract CTokenRewards"},{"type":"uint256","name":"unclaimedNativeToken","internalType":"uint256"},{"type":"tuple[]","name":"unclaimedErc20","internalType":"struct Lens.AccountRewardErc20Info[]","components":[{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"address","name":"rewardTokenAddress","internalType":"address"}]}]},{"type":"tuple[]","name":"genesisPools","internalType":"struct Lens.AccountGenesisPoolRewards[]","components":[{"type":"address","name":"poolAddress","internalType":"contract GenesisPoolStakingContract"},{"type":"address","name":"cTokenAddress","internalType":"address"},{"type":"uint256","name":"unclaimedEsProtocolToken","internalType":"uint256"}]}]}]}],"name":"getAccountSnapshot","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address[]","name":"","internalType":"address[]"}],"name":"getComptrollerClaimableReward","inputs":[{"type":"address","name":"user","internalType":"address"},{"type":"uint8","name":"rewardType","internalType":"uint8"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct Lens.MarketGenesisPoolSnapshot[]","components":[{"type":"address","name":"poolAddress","internalType":"contract GenesisPoolStakingContract"},{"type":"address","name":"cTokenAddress","internalType":"address"},{"type":"uint256","name":"totalDepositedCTokenAmount","internalType":"uint256"},{"type":"uint256","name":"cTokenTotalSupply","internalType":"uint256"},{"type":"uint256","name":"cTokenExchangeRate","internalType":"uint256"},{"type":"uint256","name":"underlyingTokenPrice","internalType":"uint256"},{"type":"uint256","name":"esProtocolRewardSpeed","internalType":"uint256"},{"type":"uint256","name":"apr","internalType":"uint256"}]}],"name":"getMarketGenesisPoolSnapshots","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct Lens.MarketMetadata","components":[{"type":"address","name":"market","internalType":"address"},{"type":"uint256","name":"supplyRate","internalType":"uint256"},{"type":"uint256","name":"borrowRate","internalType":"uint256"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"exchangeRate","internalType":"uint256"},{"type":"uint256","name":"reserveFactor","internalType":"uint256"},{"type":"uint256","name":"borrowCap","internalType":"uint256"},{"type":"uint256","name":"totalSupply","internalType":"uint256"},{"type":"uint256","name":"totalUnderlyingSupply","internalType":"uint256"},{"type":"uint256","name":"totalBorrows","internalType":"uint256"},{"type":"uint256","name":"collateralFactor","internalType":"uint256"},{"type":"address","name":"underlyingToken","internalType":"address"},{"type":"uint256","name":"underlyingTokenDecimals","internalType":"uint256"},{"type":"uint256","name":"cTokenDecimals","internalType":"uint256"},{"type":"uint256[]","name":"supplyRewardSpeeds","internalType":"uint256[]"},{"type":"uint256[]","name":"borrowRewardSpeeds","internalType":"uint256[]"},{"type":"uint256","name":"totalReserves","internalType":"uint256"},{"type":"uint256","name":"cash","internalType":"uint256"},{"type":"bool","name":"mintPaused","internalType":"bool"},{"type":"bool","name":"borrowPaused","internalType":"bool"}]}],"name":"getMarketMetadata","inputs":[{"type":"address","name":"market","internalType":"contract CToken"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct Lens.MarketMetadata[]","components":[{"type":"address","name":"market","internalType":"address"},{"type":"uint256","name":"supplyRate","internalType":"uint256"},{"type":"uint256","name":"borrowRate","internalType":"uint256"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"exchangeRate","internalType":"uint256"},{"type":"uint256","name":"reserveFactor","internalType":"uint256"},{"type":"uint256","name":"borrowCap","internalType":"uint256"},{"type":"uint256","name":"totalSupply","internalType":"uint256"},{"type":"uint256","name":"totalUnderlyingSupply","internalType":"uint256"},{"type":"uint256","name":"totalBorrows","internalType":"uint256"},{"type":"uint256","name":"collateralFactor","internalType":"uint256"},{"type":"address","name":"underlyingToken","internalType":"address"},{"type":"uint256","name":"underlyingTokenDecimals","internalType":"uint256"},{"type":"uint256","name":"cTokenDecimals","internalType":"uint256"},{"type":"uint256[]","name":"supplyRewardSpeeds","internalType":"uint256[]"},{"type":"uint256[]","name":"borrowRewardSpeeds","internalType":"uint256[]"},{"type":"uint256","name":"totalReserves","internalType":"uint256"},{"type":"uint256","name":"cash","internalType":"uint256"},{"type":"bool","name":"mintPaused","internalType":"bool"},{"type":"bool","name":"borrowPaused","internalType":"bool"}]}],"name":"getMarketMetadataForAllMarkets","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"protocolTokenPrice","internalType":"uint256"},{"type":"uint256","name":"nativeTokenPrice","internalType":"uint256"}],"name":"getPrices","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"pangolinRouter","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract PglStakingContract"}],"name":"pglStakingContract","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract PriceOracleV2"}],"name":"priceOracleV2","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"protocolAddress","inputs":[]}]
Contract Creation Code
0x6101406040523480156200001257600080fd5b5060405162004a1b38038062004a1b833981016040819052620000359162000524565b6001600160a01b03808816608052861660a05283516200005d9060009060208701906200031f565b508251620000739060019060208601906200031f565b5081516001600160a01b0390811660c052602080840151821660e052604080516333198ddd60e11b81529051928416926366331bba926004808401939192918290030181865afa158015620000cc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000f291906200065f565b620001445760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642070726963654f7261636c650000000000000000000000000060448201526064015b60405180910390fd5b806001600160a01b0316610120816001600160a01b0316815250506080516001600160a01b0316627e3dd26040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200019f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001c591906200065f565b620002135760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420636f6d7074726f6c6c65722061646472657373000000000060448201526064016200013b565b6001600160a01b0386161580156200023257506001600160a01b038516155b80620002b7575060006001600160a01b031660a0516001600160a01b03166392d8282f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000285573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ab91906200068a565b6001600160a01b031614155b620003055760405162461bcd60e51b815260206004820152601a60248201527f496e76616c69642070676c5374616b696e67436f6e747261637400000000000060448201526064016200013b565b505050506001600160a01b03166101005250620006aa9050565b82805482825590600052602060002090810192821562000377579160200282015b828111156200037757825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019062000340565b506200038592915062000389565b5090565b5b808211156200038557600081556001016200038a565b6001600160a01b0381168114620003b657600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715620003fa57620003fa620003b9565b604052919050565b60006001600160401b038211156200041e576200041e620003b9565b5060051b60200190565b600082601f8301126200043a57600080fd5b81516020620004536200044d8362000402565b620003cf565b82815260059290921b840181019181810190868411156200047357600080fd5b8286015b848110156200049b5780516200048d81620003a0565b835291830191830162000477565b509695505050505050565b600060408284031215620004b957600080fd5b604080519081016001600160401b0381118282101715620004de57620004de620003b9565b80604052508091508251620004f381620003a0565b815260208301516200050581620003a0565b6020919091015292915050565b80516200051f81620003a0565b919050565b6000806000806000806000610100888a0312156200054157600080fd5b87516200054e81620003a0565b809750506020808901516200056381620003a0565b60408a01519097506200057681620003a0565b60608a01519096506001600160401b03808211156200059457600080fd5b818b0191508b601f830112620005a957600080fd5b8151620005ba6200044d8262000402565b81815260059190911b8301840190848101908e831115620005da57600080fd5b938501935b8285101562000605578451620005f581620003a0565b82529385019390850190620005df565b60808e015190995094505050808311156200061f57600080fd5b50506200062f8a828b0162000428565b935050620006418960a08a01620004a6565b91506200065160e0890162000512565b905092959891949750929550565b6000602082840312156200067257600080fd5b815180151581146200068357600080fd5b9392505050565b6000602082840312156200069d57600080fd5b81516200068381620003a0565b60805160a05160c05160e051610100516101205161425d620007be600039600081816101c30152818161060c015281816106ce0152611a6e0152600061017501526000818161010a015281816106a30152611a3a0152600061014e015260006102f801526000818161019c0152818161040c0152818161079a0152818161083e01528181610c9601528181610e4601528181610f7e0152818161102d015281816111c5015281816113b501528181611616015281816116aa0152818161179b01528181611b4501528181611eca0152818161250d015281816125a1015281816127920152818161281701528181612942015281816129d601528181612bc701528181612f050152612f90015261425d6000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c8063ba2a7bcb11610097578063c6626af911610066578063c6626af91461029f578063d7094980146102b2578063daf9a852146102d2578063f7abb299146102f357600080fd5b8063ba2a7bcb1461022d578063bd9a548b14610242578063c37f68e21461025f578063c5171f421461027f57600080fd5b8063663f21d3116100d3578063663f21d3146101be5780638b701eb0146101e55780638fb3dfee146102055780639e613b591461021857600080fd5b80630676c1b7146101055780632b109a9b146101495780635af0cd90146101705780635fe3b56714610197575b600080fd5b61012c7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b61012c7f000000000000000000000000000000000000000000000000000000000000000081565b61012c7f000000000000000000000000000000000000000000000000000000000000000081565b61012c7f000000000000000000000000000000000000000000000000000000000000000081565b61012c7f000000000000000000000000000000000000000000000000000000000000000081565b6101f86101f336600461393d565b61031a565b604051610140919061395a565b61012c6102133660046139de565b6103dc565b610220610406565b6040516101409190613b5e565b610235610545565b6040516101409190613bb3565b61024a610607565b60408051928352602083019190915201610140565b61027261026d36600461393d565b610741565b6040516101409190613dc6565b61029261028d366004613ecf565b610758565b6040516101409190613f08565b61012c6102ad3660046139de565b610771565b6102c56102c036600461393d565b610781565b6040516101409190613f16565b6102e56102e0366004613f29565b610792565b604051610140929190613f5d565b61012c7f000000000000000000000000000000000000000000000000000000000000000081565b600054606090806001600160401b0381111561033857610338613f76565b60405190808252806020026020018201604052801561037157816020015b61035e613750565b8152602001906001900390816103565790505b50915060005b818110156103d5576103b0846000838154811061039657610396613f8c565b6000918252602090912001546001600160a01b0316610a57565b8382815181106103c2576103c2613f8c565b6020908102919091010152600101610377565b5050919050565b600081815481106103ec57600080fd5b6000918252602090912001546001600160a01b0316905081565b606060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b0772d0b6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610468573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104909190810190613fb2565b80519091506000816001600160401b038111156104af576104af613f76565b6040519080825280602002602001820160405280156104e857816020015b6104d5613798565b8152602001906001900390816104cd5790505b50905060005b8281101561053d5761051884828151811061050b5761050b613f8c565b6020026020010151610c6a565b82828151811061052a5761052a613f8c565b60209081029190910101526001016104ee565b509392505050565b60008054606091816001600160401b0381111561056457610564613f76565b60405190808252806020026020018201604052801561059d57816020015b61058a613847565b8152602001906001900390816105825790505b50905060005b82811015610600576105db600082815481106105c1576105c1613f8c565b6000918252602090912001546001600160a01b0316611729565b8282815181106105ed576105ed613f8c565b60209081029190910101526001016105a3565b5092915050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ca7c4dba6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610668573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068c919061406a565b6040516341976e0960e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192507f0000000000000000000000000000000000000000000000000000000000000000909116906341976e0990602401602060405180830381865afa158015610717573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061073b919061406a565b91509091565b61074961389e565b61075282611b39565b92915050565b6107606138e4565b61076a8383611ccc565b9392505050565b600181815481106103ec57600080fd5b610789613798565b61075282610c6a565b6000606060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b0772d0b6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156107f6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261081e9190810190613fb2565b80516040516305b9783d60e01b8152919250906000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906305b9783d906108759089908b90600401614083565b602060405180830381865afa158015610892573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b6919061406a565b9050600080836001600160401b038111156108d3576108d3613f76565b6040519080825280602002602001820160405280156108fc578160200160208202803683370190505b5090506000805b858110156109a757600087828151811061091f5761091f613f8c565b602002602001015190506109348b828e611fe2565b94506109418b828e612006565b61094b90866140b5565b945061095785876140b5565b9550841561099e5780848461096b816140c8565b95508151811061097d5761097d613f8c565b60200260200101906001600160a01b031690816001600160a01b0316815250505b50600101610903565b506000816001600160401b038111156109c2576109c2613f76565b6040519080825280602002602001820160405280156109eb578160200160208202803683370190505b50905060005b82811015610a4557838181518110610a0b57610a0b613f8c565b6020026020010151828281518110610a2557610a25613f8c565b6001600160a01b03909216602092830291909101909101526001016109f1565b50939a93995092975050505050505050565b610a5f613750565b6000826001600160a01b0316639a59a0716040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac391906140e1565b6040516370a0823160e01b81526001600160a01b0386811660048301529192506000918316906370a0823190602401602060405180830381865afa158015610b0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b33919061406a565b60405163044c28db60e21b81526001600160a01b038781166004830152919250600091861690631130a36c90602401602060405180830381865afa158015610b7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba3919061406a565b90506000610bb187876120a9565b604051636eb1769f60e11b81526001600160a01b038981166004830152888116602483015291925060009186169063dd62ed3e90604401602060405180830381865afa158015610c05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c29919061406a565b6040805160c0810182526001600160a01b03808b168252979097166020880152860192909252506060840192909252608083015260a0820152905092915050565b610c72613798565b604051638e8f294b60e01b81526001600160a01b03808416600483015283916000917f00000000000000000000000000000000000000000000000000000000000000001690638e8f294b906024016040805180830381865afa158015610cdc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d00919061410e565b915050600080856001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6891906140e1565b9150816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610da8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcc919061406a565b90506000866001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e32919061406a565b90506000610e40828961223e565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166312edb24c6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610ea2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610eca9190810190613fb2565b5190506000816001600160401b03811115610ee757610ee7613f76565b604051908082528060200260200182016040528015610f10578160200160208202803683370190505b5090506000826001600160401b03811115610f2d57610f2d613f76565b604051908082528060200260200182016040528015610f56578160200160208202803683370190505b50905060005b838160ff1610156110d75760405163cf9cfb6160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cf9cfb6190610fb59084908e90600401614083565b602060405180830381865afa158015610fd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff6919061406a565b838260ff168151811061100b5761100b613f8c565b60209081029190910101526040516361bb7d6d60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c376fada906110649084908e90600401614083565b602060405180830381865afa158015611081573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a5919061406a565b828260ff16815181106110ba576110ba613f8c565b6020908102919091010152806110cf8161413a565b915050610f5c565b5060006040518061028001604052808b6001600160a01b031681526020018d6001600160a01b031663d3bd2c726040518163ffffffff1660e01b8152600401602060405180830381865afa158015611133573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611157919061406a565b81526020018d6001600160a01b031663cd91801c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561119a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111be919061406a565b81526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637dc0d1d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015611221573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124591906140e1565b6001600160a01b031663fc57d4df8f6040518263ffffffff1660e01b815260040161127f91906001600160a01b0391909116815260200190565b602060405180830381865afa15801561129c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c0919061406a565b81526020018d6001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611303573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611327919061406a565b81526020018d6001600160a01b031663173b99046040518163ffffffff1660e01b8152600401602060405180830381865afa15801561136a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138e919061406a565b815260405163252c221960e11b81526001600160a01b038d811660048301526020909201917f00000000000000000000000000000000000000000000000000000000000000001690634a58443290602401602060405180830381865afa1580156113fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611420919061406a565b81526020018781526020018681526020018d6001600160a01b03166347bd37186040518163ffffffff1660e01b8152600401602060405180830381865afa15801561146f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611493919061406a565b81526020018a8152602001896001600160a01b031681526020018881526020018d6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114f1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611515919061406a565b81526020018481526020018381526020018d6001600160a01b0316638f840ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611564573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611588919061406a565b81526020018d6001600160a01b0316633b1d21a26040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ef919061406a565b815260405163731f0c2b60e01b81526001600160a01b038d811660048301526020909201917f0000000000000000000000000000000000000000000000000000000000000000169063731f0c2b90602401602060405180830381865afa15801561165d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116819190614159565b15158152604051636d154ea560e01b81526001600160a01b038d811660048301526020909201917f00000000000000000000000000000000000000000000000000000000000000001690636d154ea590602401602060405180830381865afa1580156116f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117159190614159565b151590529c9b505050505050505050505050565b611731613847565b6000826001600160a01b0316639a59a0716040518163ffffffff1660e01b8152600401602060405180830381865afa158015611771573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061179591906140e1565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637dc0d1d06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061181b91906140e1565b90506000846001600160a01b031663d068cdc56040518163ffffffff1660e01b8152600401602060405180830381865afa15801561185d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611881919061406a565b90506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e7919061406a565b90506000846001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611929573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194d919061406a565b60405163fc57d4df60e01b81526001600160a01b03878116600483015291925060009186169063fc57d4df90602401602060405180830381865afa158015611999573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119bd919061406a565b90506000886001600160a01b0316635c0f6bd16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119ff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a23919061406a565b6040516341976e0960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152919250600091611ae99184917f000000000000000000000000000000000000000000000000000000000000000016906341976e0990602401602060405180830381865afa158015611ab5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad9919061406a565b611ae3898c61223e565b866122ca565b60408051610100810182526001600160a01b039c8d16815299909b1660208a0152998801959095526060870193909352608086019190915260a085015260c0840152505060e08101929092525090565b611b4161389e565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b0772d0b6040518163ffffffff1660e01b8152600401600060405180830381865afa158015611ba1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611bc99190810190613fb2565b80519091506000816001600160401b03811115611be857611be8613f76565b604051908082528060200260200182016040528015611c2157816020015b611c0e6138e4565b815260200190600190039081611c065790505b50905060005b82811015611c7757611c5286858381518110611c4557611c45613f8c565b6020026020010151611ccc565b828281518110611c6457611c64613f8c565b6020908102919091010152600101611c27565b506000611c8386612330565b90506000611c908761236a565b90506000611c9d88612439565b604080518082018252958652805160608101825294855260208581019490945284015250820152949350505050565b611cd46138e4565b6000806000846001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3b91906140e1565b6040516370a0823160e01b81526001600160a01b038881166004830152919250908216906370a0823190602401602060405180830381865afa158015611d85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da9919061406a565b604051636eb1769f60e11b81526001600160a01b03888116600483015287811660248301529194509082169063dd62ed3e90604401602060405180830381865afa158015611dfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e1f919061406a565b6040516370a0823160e01b81526001600160a01b0388811660048301529193506000918716906370a0823190602401602060405180830381865afa158015611e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8f919061406a565b90506000611e9d828861223e565b60405163929fe9a160e01b81526001600160a01b038a8116600483015289811660248301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063929fe9a190604401602060405180830381865afa158015611f11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f359190614159565b6040805160c0810182526001600160a01b03808c16808352602083018b90528284018a90526060830187905292516395dd919360e01b8152908d166004820152929350916080830191906395dd919390602401602060405180830381865afa158015611fa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc9919061406a565b8152602001821515815250965050505050505092915050565b600080611fef8585612506565b9050611ffd85858584612746565b95945050505050565b6000806040518060200160405280856001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612052573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612076919061406a565b90529050600061208786868461293b565b6001600160e01b0316905061209f8686868486612b7b565b9695505050505050565b6000806120b583612ced565b6040516325b6d78360e21b81526001600160a01b0386811660048301529192506000918516906396db5e0c90602401602060405180830381865afa158015612101573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612125919061406a565b61212f9083614174565b60405163044c28db60e21b81526001600160a01b0387811660048301529192506000916ec097ce7bc90715b34b9f10000000009190871690631130a36c90602401602060405180830381865afa15801561218d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b1919061406a565b6121bb9084614187565b6121c5919061419e565b604051630189212f60e41b81526001600160a01b038881166004830152919250829187169063189212f090602401602060405180830381865afa158015612210573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612234919061406a565b61209f91906140b5565b600080826001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa15801561227f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122a3919061406a565b9050670de0b6b3a76400006122b88286614187565b6122c2919061419e565b949350505050565b600080670de0b6b3a76400006122e08486614187565b6122ea919061419e565b9050806000036122fe5760009150506122c2565b60008561230f886301e13380614187565b6123199190614187565b9050612325828261419e565b979650505050505050565b604080518082019091526060808252602082015260008061235084612efe565b604080518082019091529182526020820152949350505050565b600154606090806001600160401b0381111561238857612388613f76565b6040519080825280602002602001820160405280156123d557816020015b604080516060808201835260008083526020830152918101919091528152602001906001900390816123a65790505b50915060005b818110156103d55761241484600183815481106123fa576123fa613f8c565b6000918252602090912001546001600160a01b03166132cc565b83828151811061242657612426613f8c565b60209081029190910101526001016123db565b600054606090806001600160401b0381111561245757612457613f76565b6040519080825280602002602001820160405280156124a257816020015b60408051606081018252600080825260208083018290529282015282526000199092019101816124755790505b50915060005b818110156103d5576124e184600083815481106124c7576124c7613f8c565b6000918252602090912001546001600160a01b0316613581565b8382815181106124f3576124f3613f8c565b60209081029190910101526001016124a8565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d81c5e4586866040518363ffffffff1660e01b8152600401612559929190614083565b6040805180830381865afa158015612575573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061259991906141d7565b9150915060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663cf9cfb6187876040518363ffffffff1660e01b81526004016125ed929190614083565b602060405180830381865afa15801561260a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061262e919061406a565b905042600061264663ffffffff80841690861661363f565b90506000811180156126585750600083115b15612730576000876001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561269d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126c1919061406a565b905060006126cf838661364b565b905060008083116126ef57604051806020016040528060008152506126f9565b6126f98284613657565b9050600061271e60405180602001604052808b6001600160e01b03168152508361369c565b51995061075298505050505050505050565b50506001600160e01b0390921695945050505050565b604080516020808201835283825282519081019283905263111d2e5760e31b90925260ff861660248301526001600160a01b0385811660448401528481166064840152600092839181907f0000000000000000000000000000000000000000000000000000000000000000166388e972b860848301602060405180830381865afa1580156127d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127fc919061406a565b905280519091501580156128105750815115155b156128a3577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ed302dfd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612873573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612897919061420c565b6001600160e01b031681525b60006128af83836136c8565b6040516370a0823160e01b81526001600160a01b0388811660048301529192506000918916906370a0823190602401602060405180830381865afa1580156128fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061291f919061406a565b9050600061292d82846136f4565b9a9950505050505050505050565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634b3a0a7487876040518363ffffffff1660e01b815260040161298e929190614083565b6040805180830381865afa1580156129aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ce91906141d7565b9150915060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c376fada88886040518363ffffffff1660e01b8152600401612a22929190614083565b602060405180830381865afa158015612a3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a63919061406a565b9050426000612a7b63ffffffff80841690861661363f565b9050600081118015612a8d5750600083115b15612b6e576000612aff896001600160a01b03166347bd37186040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ad5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612af9919061406a565b8961371e565b90506000612b0d838661364b565b90506000808311612b2d5760405180602001604052806000815250612b37565b612b378284613657565b90506000612b5c60405180602001604052808b6001600160e01b03168152508361369c565b51995061076a98505050505050505050565b5092979650505050505050565b6040805160208082018352848252825190810192839052637937969d60e01b90925260ff871660248301526001600160a01b0386811660448401528581166064840152600092839181907f000000000000000000000000000000000000000000000000000000000000000016637937969d60848301602060405180830381865afa158015612c0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c31919061406a565b9052805190915015612cdf576000612c4983836136c8565b6040516395dd919360e01b81526001600160a01b038981166004830152919250600091612cc491908b16906395dd919390602401602060405180830381865afa158015612c9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cbe919061406a565b8761371e565b90506000612cd282846136f4565b9550611ffd945050505050565b506000979650505050505050565b600080826001600160a01b031663cfa992016040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d52919061406a565b612d5c9042614174565b90506000836001600160a01b031663d068cdc56040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc2919061406a565b90506000846001600160a01b0316635c0f6bd16040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e28919061406a565b90506000856001600160a01b031663e9ee2fa96040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e8e919061406a565b9050831580612e9b575082155b80612ea4575081155b15612eb25795945050505050565b6000612ebe8584614187565b9050600084612edc836ec097ce7bc90715b34b9f1000000000614187565b612ee6919061419e565b9050612ef281846140b5565b98975050505050505050565b60608060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166312edb24c6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612f61573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612f899190810190613fb2565b51905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b0772d0b6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612fec573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130149190810190613fb2565b51905060008260ff166001600160401b0381111561303457613034613f76565b60405190808252806020026020018201604052801561307957816020015b60408051808201909152600080825260208201528152602001906001900390816130525790505b5090506000826001600160401b0381111561309657613096613f76565b6040519080825280602002602001820160405280156130bf578160200160208202803683370190505b5090506000805b8560ff168160ff161015613216576000806130e18b84610792565b9150915060405180604001604052808460ff16815260200183815250868460ff168151811061311257613112613f8c565b602002602001018190525060005b8151811015613200576000805b868110156131995783838151811061314757613147613f8c565b60200260200101516001600160a01b031688828151811061316a5761316a613f8c565b60200260200101516001600160a01b0316036131895760019150613199565b613192816140c8565b905061312d565b50806131ef578282815181106131b1576131b1613f8c565b60200260200101518787815181106131cb576131cb613f8c565b6001600160a01b03909216602092830291909101909101526131ec866140c8565b95505b506131f9816140c8565b9050613120565b505050808061320e9061413a565b9150506130c6565b506000816001600160401b0381111561323157613231613f76565b60405190808252806020026020018201604052801561325a578160200160208202803683370190505b50905060005b828110156132bc5783818151811061327a5761327a613f8c565b602002602001015182828151811061329457613294613f8c565b6001600160a01b03909216602092830291909101909101526132b5816140c8565b9050613260565b5092989297509195505050505050565b604080516060808201835260008083526020830152918101919091526000826001600160a01b031663bf199e626040518163ffffffff1660e01b8152600401602060405180830381865afa158015613328573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061334c919061406a565b604051636006c17d60e11b81526001600160a01b03868116600483015291925060009185169063c00d82fa90602401602060405180830381865afa158015613398573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133bc919061406a565b90506000826001600160401b038111156133d8576133d8613f76565b60405190808252806020026020018201604052801561341d57816020015b60408051808201909152600080825260208201528152602001906001900390816133f65790505b50905060005b83811015613556576040516379f5ecb760e01b8152600481018290526000906001600160a01b038816906379f5ecb790602401602060405180830381865afa158015613473573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061349791906140e1565b60405163591d8a4b60e01b81526001600160a01b0380831660048301528a8116602483015291925060009189169063591d8a4b90604401602060405180830381865afa1580156134eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061350f919061406a565b90506040518060400160405280828152602001836001600160a01b031681525084848151811061354157613541613f8c565b60209081029190910101525050600101613423565b50604080516060810182526001600160a01b0387168152602081019390935282015291505092915050565b60408051606081018252600080825260208201819052918101829052906135a884846120a9565b90506040518060600160405280846001600160a01b03168152602001846001600160a01b0316639a59a0716040518163ffffffff1660e01b8152600401602060405180830381865afa158015613602573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061362691906140e1565b6001600160a01b03168152602001919091529392505050565b600061076a8284614174565b600061076a8284614187565b604080516020810190915260008152604051806020016040528061369361368d866ec097ce7bc90715b34b9f100000000061364b565b85613738565b90529392505050565b604080516020810190915260008152604051806020016040528061369385600001518560000151613744565b60408051602081019091526000815260405180602001604052806136938560000151856000015161363f565b60006ec097ce7bc90715b34b9f100000000061371484846000015161364b565b61076a919061419e565b600061076a61373584670de0b6b3a764000061364b565b83515b600061076a828461419e565b600061076a82846140b5565b6040518060c0016040528060006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081525090565b60405180610280016040528060006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081526020016060815260200160008152602001600081526020016000151581526020016000151581525090565b60405180610100016040528060006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060400160405280606081526020016138df6040805160a0810182526060808201818152608083018290528252602082018190529181019190915290565b905290565b6040518060c0016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000151581525090565b6001600160a01b038116811461393a57600080fd5b50565b60006020828403121561394f57600080fd5b813561076a81613925565b602080825282518282018190526000919060409081850190868401855b828110156139d157815180516001600160a01b0390811686528782015116878601528581015186860152606080820151908601526080808201519086015260a0908101519085015260c09093019290850190600101613977565b5091979650505050505050565b6000602082840312156139f057600080fd5b5035919050565b600081518084526020808501945080840160005b83811015613a2757815187529582019590820190600101613a0b565b509495945050505050565b80516001600160a01b0316825260006102806020830151602085015260408301516040850152606083015160608501526080830151608085015260a083015160a085015260c083015160c085015260e083015160e085015261010080840151818601525061012080840151818601525061014080840151818601525061016080840151613ac9828701826001600160a01b03169052565b505061018083810151908501526101a080840151908501526101c080840151818601839052613afa838701826139f7565b925050506101e08084015185830382870152613b1683826139f7565b9250505061020080840151818601525061022080840151818601525061024080840151613b468287018215159052565b50506102609283015115159390920192909252919050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015612b6e57603f19888603018452613ba1858351613a32565b94509285019290850190600101613b85565b602080825282518282018190526000919060409081850190868401855b828110156139d157815180516001600160a01b0390811686528782015116878601528581015186860152606080820151908601526080808201519086015260a0808201519086015260c0808201519086015260e090810151908501526101009093019290850190600101613bd0565b80516001600160a01b031682526020808201519083015260408082015190830152606080820151908301526080808201519083015260a0908101511515910152565b600081518084526020808501945080840160005b83811015613a275781516001600160a01b031687529582019590820190600101613c95565b600081518084526020808501808196508360051b810191508286016000805b86811015613d66578385038a52825180516001600160a01b03908116875287820151888801526040918201516060838901819052815190890181905290890192608089019286929091905b80841015613d4f578551805186528c015183168c860152948b01949381019360019390930192613d24565b5050509b88019b5095505091850191600101613cd9565b509298975050505050505050565b600081518084526020808501945080840160005b83811015613a2757815180516001600160a01b0390811689528482015116848901526040908101519088015260609096019590820190600101613d88565b60208082528251604083830181905281516060850181905260009392830191849160808701905b80841015613e1657613e00828651613c3f565b60c0820191508585019450600184019350613ded565b5087850151878203601f190183890152805160608084528151908401859052805160a0850181905292965090945086019060009060c08401905b80831015613e7c578351805160ff16835289015189830152928801926001929092019190850190613e50565b5094870151838603605f1901608085015294613e988187613c81565b95505050508484015181840386830152613eb28482613cba565b95505081840151935080850382820152505050611ffd8282613d74565b60008060408385031215613ee257600080fd5b8235613eed81613925565b91506020830135613efd81613925565b809150509250929050565b60c081016107528284613c3f565b60208152600061076a6020830184613a32565b60008060408385031215613f3c57600080fd5b8235613f4781613925565b9150602083013560ff81168114613efd57600080fd5b8281526040602082015260006122c26040830184613c81565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b8051613fad81613925565b919050565b60006020808385031215613fc557600080fd5b82516001600160401b0380821115613fdc57600080fd5b818501915085601f830112613ff057600080fd5b81518181111561400257614002613f76565b8060051b604051601f19603f8301168101818110858211171561402757614027613f76565b60405291825284820192508381018501918883111561404557600080fd5b938501935b82851015612ef25761405b85613fa2565b8452938501939285019261404a565b60006020828403121561407c57600080fd5b5051919050565b60ff9290921682526001600160a01b0316602082015260400190565b634e487b7160e01b600052601160045260246000fd5b808201808211156107525761075261409f565b6000600182016140da576140da61409f565b5060010190565b6000602082840312156140f357600080fd5b815161076a81613925565b80518015158114613fad57600080fd5b6000806040838503121561412157600080fd5b61412a836140fe565b9150602083015190509250929050565b600060ff821660ff81036141505761415061409f565b60010192915050565b60006020828403121561416b57600080fd5b61076a826140fe565b818103818111156107525761075261409f565b80820281158282048414176107525761075261409f565b6000826141bb57634e487b7160e01b600052601260045260246000fd5b500490565b80516001600160e01b0381168114613fad57600080fd5b600080604083850312156141ea57600080fd5b6141f3836141c0565b9150602083015163ffffffff81168114613efd57600080fd5b60006020828403121561421e57600080fd5b61076a826141c056fea2646970667358221220dcb56d58409917c8d39410383a2daa613bc06de36bfe3ac41486a11249f6f02564736f6c634300081100330000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000d38220cff996a73e9110aaca64e02d581b83a0cd000000000000000000000000e6505f92583103af7ed9974dec451a7af4e3a3be0000000000000000000000003daabdd029879fe3316c092364156a04fff868e400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000b52ab55f9325b4522c3bdac692d4f21b0cba05ee0000000000000000000000005896c198e445e269021b04d7c84fa46dc2cedcd80000000000000000000000001218b178e170e8cfb3ba5ada853aaf4579845347
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106101005760003560e01c8063ba2a7bcb11610097578063c6626af911610066578063c6626af91461029f578063d7094980146102b2578063daf9a852146102d2578063f7abb299146102f357600080fd5b8063ba2a7bcb1461022d578063bd9a548b14610242578063c37f68e21461025f578063c5171f421461027f57600080fd5b8063663f21d3116100d3578063663f21d3146101be5780638b701eb0146101e55780638fb3dfee146102055780639e613b591461021857600080fd5b80630676c1b7146101055780632b109a9b146101495780635af0cd90146101705780635fe3b56714610197575b600080fd5b61012c7f000000000000000000000000e6505f92583103af7ed9974dec451a7af4e3a3be81565b6040516001600160a01b0390911681526020015b60405180910390f35b61012c7f000000000000000000000000d38220cff996a73e9110aaca64e02d581b83a0cd81565b61012c7f000000000000000000000000000000000000000000000000000000000000000081565b61012c7f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c881565b61012c7f0000000000000000000000003daabdd029879fe3316c092364156a04fff868e481565b6101f86101f336600461393d565b61031a565b604051610140919061395a565b61012c6102133660046139de565b6103dc565b610220610406565b6040516101409190613b5e565b610235610545565b6040516101409190613bb3565b61024a610607565b60408051928352602083019190915201610140565b61027261026d36600461393d565b610741565b6040516101409190613dc6565b61029261028d366004613ecf565b610758565b6040516101409190613f08565b61012c6102ad3660046139de565b610771565b6102c56102c036600461393d565b610781565b6040516101409190613f16565b6102e56102e0366004613f29565b610792565b604051610140929190613f5d565b61012c7f000000000000000000000000000000000000000000000000000000000000000081565b600054606090806001600160401b0381111561033857610338613f76565b60405190808252806020026020018201604052801561037157816020015b61035e613750565b8152602001906001900390816103565790505b50915060005b818110156103d5576103b0846000838154811061039657610396613f8c565b6000918252602090912001546001600160a01b0316610a57565b8382815181106103c2576103c2613f8c565b6020908102919091010152600101610377565b5050919050565b600081815481106103ec57600080fd5b6000918252602090912001546001600160a01b0316905081565b606060007f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c86001600160a01b031663b0772d0b6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610468573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104909190810190613fb2565b80519091506000816001600160401b038111156104af576104af613f76565b6040519080825280602002602001820160405280156104e857816020015b6104d5613798565b8152602001906001900390816104cd5790505b50905060005b8281101561053d5761051884828151811061050b5761050b613f8c565b6020026020010151610c6a565b82828151811061052a5761052a613f8c565b60209081029190910101526001016104ee565b509392505050565b60008054606091816001600160401b0381111561056457610564613f76565b60405190808252806020026020018201604052801561059d57816020015b61058a613847565b8152602001906001900390816105825790505b50905060005b82811015610600576105db600082815481106105c1576105c1613f8c565b6000918252602090912001546001600160a01b0316611729565b8282815181106105ed576105ed613f8c565b60209081029190910101526001016105a3565b5092915050565b6000807f0000000000000000000000003daabdd029879fe3316c092364156a04fff868e46001600160a01b031663ca7c4dba6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610668573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068c919061406a565b6040516341976e0960e01b81526001600160a01b037f000000000000000000000000e6505f92583103af7ed9974dec451a7af4e3a3be811660048301529192507f0000000000000000000000003daabdd029879fe3316c092364156a04fff868e4909116906341976e0990602401602060405180830381865afa158015610717573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061073b919061406a565b91509091565b61074961389e565b61075282611b39565b92915050565b6107606138e4565b61076a8383611ccc565b9392505050565b600181815481106103ec57600080fd5b610789613798565b61075282610c6a565b6000606060007f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c86001600160a01b031663b0772d0b6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156107f6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261081e9190810190613fb2565b80516040516305b9783d60e01b8152919250906000906001600160a01b037f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c816906305b9783d906108759089908b90600401614083565b602060405180830381865afa158015610892573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b6919061406a565b9050600080836001600160401b038111156108d3576108d3613f76565b6040519080825280602002602001820160405280156108fc578160200160208202803683370190505b5090506000805b858110156109a757600087828151811061091f5761091f613f8c565b602002602001015190506109348b828e611fe2565b94506109418b828e612006565b61094b90866140b5565b945061095785876140b5565b9550841561099e5780848461096b816140c8565b95508151811061097d5761097d613f8c565b60200260200101906001600160a01b031690816001600160a01b0316815250505b50600101610903565b506000816001600160401b038111156109c2576109c2613f76565b6040519080825280602002602001820160405280156109eb578160200160208202803683370190505b50905060005b82811015610a4557838181518110610a0b57610a0b613f8c565b6020026020010151828281518110610a2557610a25613f8c565b6001600160a01b03909216602092830291909101909101526001016109f1565b50939a93995092975050505050505050565b610a5f613750565b6000826001600160a01b0316639a59a0716040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac391906140e1565b6040516370a0823160e01b81526001600160a01b0386811660048301529192506000918316906370a0823190602401602060405180830381865afa158015610b0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b33919061406a565b60405163044c28db60e21b81526001600160a01b038781166004830152919250600091861690631130a36c90602401602060405180830381865afa158015610b7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba3919061406a565b90506000610bb187876120a9565b604051636eb1769f60e11b81526001600160a01b038981166004830152888116602483015291925060009186169063dd62ed3e90604401602060405180830381865afa158015610c05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c29919061406a565b6040805160c0810182526001600160a01b03808b168252979097166020880152860192909252506060840192909252608083015260a0820152905092915050565b610c72613798565b604051638e8f294b60e01b81526001600160a01b03808416600483015283916000917f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c81690638e8f294b906024016040805180830381865afa158015610cdc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d00919061410e565b915050600080856001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6891906140e1565b9150816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610da8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcc919061406a565b90506000866001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e32919061406a565b90506000610e40828961223e565b905060007f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c86001600160a01b03166312edb24c6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610ea2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610eca9190810190613fb2565b5190506000816001600160401b03811115610ee757610ee7613f76565b604051908082528060200260200182016040528015610f10578160200160208202803683370190505b5090506000826001600160401b03811115610f2d57610f2d613f76565b604051908082528060200260200182016040528015610f56578160200160208202803683370190505b50905060005b838160ff1610156110d75760405163cf9cfb6160e01b81526001600160a01b037f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c8169063cf9cfb6190610fb59084908e90600401614083565b602060405180830381865afa158015610fd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff6919061406a565b838260ff168151811061100b5761100b613f8c565b60209081029190910101526040516361bb7d6d60e11b81526001600160a01b037f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c8169063c376fada906110649084908e90600401614083565b602060405180830381865afa158015611081573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a5919061406a565b828260ff16815181106110ba576110ba613f8c565b6020908102919091010152806110cf8161413a565b915050610f5c565b5060006040518061028001604052808b6001600160a01b031681526020018d6001600160a01b031663d3bd2c726040518163ffffffff1660e01b8152600401602060405180830381865afa158015611133573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611157919061406a565b81526020018d6001600160a01b031663cd91801c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561119a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111be919061406a565b81526020017f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c86001600160a01b0316637dc0d1d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015611221573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124591906140e1565b6001600160a01b031663fc57d4df8f6040518263ffffffff1660e01b815260040161127f91906001600160a01b0391909116815260200190565b602060405180830381865afa15801561129c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c0919061406a565b81526020018d6001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611303573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611327919061406a565b81526020018d6001600160a01b031663173b99046040518163ffffffff1660e01b8152600401602060405180830381865afa15801561136a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138e919061406a565b815260405163252c221960e11b81526001600160a01b038d811660048301526020909201917f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c81690634a58443290602401602060405180830381865afa1580156113fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611420919061406a565b81526020018781526020018681526020018d6001600160a01b03166347bd37186040518163ffffffff1660e01b8152600401602060405180830381865afa15801561146f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611493919061406a565b81526020018a8152602001896001600160a01b031681526020018881526020018d6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114f1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611515919061406a565b81526020018481526020018381526020018d6001600160a01b0316638f840ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611564573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611588919061406a565b81526020018d6001600160a01b0316633b1d21a26040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ef919061406a565b815260405163731f0c2b60e01b81526001600160a01b038d811660048301526020909201917f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c8169063731f0c2b90602401602060405180830381865afa15801561165d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116819190614159565b15158152604051636d154ea560e01b81526001600160a01b038d811660048301526020909201917f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c81690636d154ea590602401602060405180830381865afa1580156116f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117159190614159565b151590529c9b505050505050505050505050565b611731613847565b6000826001600160a01b0316639a59a0716040518163ffffffff1660e01b8152600401602060405180830381865afa158015611771573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061179591906140e1565b905060007f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c86001600160a01b0316637dc0d1d06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061181b91906140e1565b90506000846001600160a01b031663d068cdc56040518163ffffffff1660e01b8152600401602060405180830381865afa15801561185d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611881919061406a565b90506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e7919061406a565b90506000846001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611929573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194d919061406a565b60405163fc57d4df60e01b81526001600160a01b03878116600483015291925060009186169063fc57d4df90602401602060405180830381865afa158015611999573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119bd919061406a565b90506000886001600160a01b0316635c0f6bd16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119ff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a23919061406a565b6040516341976e0960e01b81526001600160a01b037f000000000000000000000000e6505f92583103af7ed9974dec451a7af4e3a3be81166004830152919250600091611ae99184917f0000000000000000000000003daabdd029879fe3316c092364156a04fff868e416906341976e0990602401602060405180830381865afa158015611ab5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad9919061406a565b611ae3898c61223e565b866122ca565b60408051610100810182526001600160a01b039c8d16815299909b1660208a0152998801959095526060870193909352608086019190915260a085015260c0840152505060e08101929092525090565b611b4161389e565b60007f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c86001600160a01b031663b0772d0b6040518163ffffffff1660e01b8152600401600060405180830381865afa158015611ba1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611bc99190810190613fb2565b80519091506000816001600160401b03811115611be857611be8613f76565b604051908082528060200260200182016040528015611c2157816020015b611c0e6138e4565b815260200190600190039081611c065790505b50905060005b82811015611c7757611c5286858381518110611c4557611c45613f8c565b6020026020010151611ccc565b828281518110611c6457611c64613f8c565b6020908102919091010152600101611c27565b506000611c8386612330565b90506000611c908761236a565b90506000611c9d88612439565b604080518082018252958652805160608101825294855260208581019490945284015250820152949350505050565b611cd46138e4565b6000806000846001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3b91906140e1565b6040516370a0823160e01b81526001600160a01b038881166004830152919250908216906370a0823190602401602060405180830381865afa158015611d85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da9919061406a565b604051636eb1769f60e11b81526001600160a01b03888116600483015287811660248301529194509082169063dd62ed3e90604401602060405180830381865afa158015611dfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e1f919061406a565b6040516370a0823160e01b81526001600160a01b0388811660048301529193506000918716906370a0823190602401602060405180830381865afa158015611e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8f919061406a565b90506000611e9d828861223e565b60405163929fe9a160e01b81526001600160a01b038a8116600483015289811660248301529192506000917f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c8169063929fe9a190604401602060405180830381865afa158015611f11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f359190614159565b6040805160c0810182526001600160a01b03808c16808352602083018b90528284018a90526060830187905292516395dd919360e01b8152908d166004820152929350916080830191906395dd919390602401602060405180830381865afa158015611fa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc9919061406a565b8152602001821515815250965050505050505092915050565b600080611fef8585612506565b9050611ffd85858584612746565b95945050505050565b6000806040518060200160405280856001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612052573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612076919061406a565b90529050600061208786868461293b565b6001600160e01b0316905061209f8686868486612b7b565b9695505050505050565b6000806120b583612ced565b6040516325b6d78360e21b81526001600160a01b0386811660048301529192506000918516906396db5e0c90602401602060405180830381865afa158015612101573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612125919061406a565b61212f9083614174565b60405163044c28db60e21b81526001600160a01b0387811660048301529192506000916ec097ce7bc90715b34b9f10000000009190871690631130a36c90602401602060405180830381865afa15801561218d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b1919061406a565b6121bb9084614187565b6121c5919061419e565b604051630189212f60e41b81526001600160a01b038881166004830152919250829187169063189212f090602401602060405180830381865afa158015612210573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612234919061406a565b61209f91906140b5565b600080826001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa15801561227f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122a3919061406a565b9050670de0b6b3a76400006122b88286614187565b6122c2919061419e565b949350505050565b600080670de0b6b3a76400006122e08486614187565b6122ea919061419e565b9050806000036122fe5760009150506122c2565b60008561230f886301e13380614187565b6123199190614187565b9050612325828261419e565b979650505050505050565b604080518082019091526060808252602082015260008061235084612efe565b604080518082019091529182526020820152949350505050565b600154606090806001600160401b0381111561238857612388613f76565b6040519080825280602002602001820160405280156123d557816020015b604080516060808201835260008083526020830152918101919091528152602001906001900390816123a65790505b50915060005b818110156103d55761241484600183815481106123fa576123fa613f8c565b6000918252602090912001546001600160a01b03166132cc565b83828151811061242657612426613f8c565b60209081029190910101526001016123db565b600054606090806001600160401b0381111561245757612457613f76565b6040519080825280602002602001820160405280156124a257816020015b60408051606081018252600080825260208083018290529282015282526000199092019101816124755790505b50915060005b818110156103d5576124e184600083815481106124c7576124c7613f8c565b6000918252602090912001546001600160a01b0316613581565b8382815181106124f3576124f3613f8c565b60209081029190910101526001016124a8565b60008060007f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c86001600160a01b031663d81c5e4586866040518363ffffffff1660e01b8152600401612559929190614083565b6040805180830381865afa158015612575573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061259991906141d7565b9150915060007f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c86001600160a01b031663cf9cfb6187876040518363ffffffff1660e01b81526004016125ed929190614083565b602060405180830381865afa15801561260a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061262e919061406a565b905042600061264663ffffffff80841690861661363f565b90506000811180156126585750600083115b15612730576000876001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561269d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126c1919061406a565b905060006126cf838661364b565b905060008083116126ef57604051806020016040528060008152506126f9565b6126f98284613657565b9050600061271e60405180602001604052808b6001600160e01b03168152508361369c565b51995061075298505050505050505050565b50506001600160e01b0390921695945050505050565b604080516020808201835283825282519081019283905263111d2e5760e31b90925260ff861660248301526001600160a01b0385811660448401528481166064840152600092839181907f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c8166388e972b860848301602060405180830381865afa1580156127d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127fc919061406a565b905280519091501580156128105750815115155b156128a3577f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c86001600160a01b031663ed302dfd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612873573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612897919061420c565b6001600160e01b031681525b60006128af83836136c8565b6040516370a0823160e01b81526001600160a01b0388811660048301529192506000918916906370a0823190602401602060405180830381865afa1580156128fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061291f919061406a565b9050600061292d82846136f4565b9a9950505050505050505050565b60008060007f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c86001600160a01b0316634b3a0a7487876040518363ffffffff1660e01b815260040161298e929190614083565b6040805180830381865afa1580156129aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ce91906141d7565b9150915060007f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c86001600160a01b031663c376fada88886040518363ffffffff1660e01b8152600401612a22929190614083565b602060405180830381865afa158015612a3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a63919061406a565b9050426000612a7b63ffffffff80841690861661363f565b9050600081118015612a8d5750600083115b15612b6e576000612aff896001600160a01b03166347bd37186040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ad5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612af9919061406a565b8961371e565b90506000612b0d838661364b565b90506000808311612b2d5760405180602001604052806000815250612b37565b612b378284613657565b90506000612b5c60405180602001604052808b6001600160e01b03168152508361369c565b51995061076a98505050505050505050565b5092979650505050505050565b6040805160208082018352848252825190810192839052637937969d60e01b90925260ff871660248301526001600160a01b0386811660448401528581166064840152600092839181907f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c816637937969d60848301602060405180830381865afa158015612c0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c31919061406a565b9052805190915015612cdf576000612c4983836136c8565b6040516395dd919360e01b81526001600160a01b038981166004830152919250600091612cc491908b16906395dd919390602401602060405180830381865afa158015612c9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cbe919061406a565b8761371e565b90506000612cd282846136f4565b9550611ffd945050505050565b506000979650505050505050565b600080826001600160a01b031663cfa992016040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d52919061406a565b612d5c9042614174565b90506000836001600160a01b031663d068cdc56040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc2919061406a565b90506000846001600160a01b0316635c0f6bd16040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e28919061406a565b90506000856001600160a01b031663e9ee2fa96040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e8e919061406a565b9050831580612e9b575082155b80612ea4575081155b15612eb25795945050505050565b6000612ebe8584614187565b9050600084612edc836ec097ce7bc90715b34b9f1000000000614187565b612ee6919061419e565b9050612ef281846140b5565b98975050505050505050565b60608060007f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c86001600160a01b03166312edb24c6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612f61573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612f899190810190613fb2565b51905060007f0000000000000000000000008041680fb73e1fe5f851e76233dcdfa0f2d2d7c86001600160a01b031663b0772d0b6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612fec573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130149190810190613fb2565b51905060008260ff166001600160401b0381111561303457613034613f76565b60405190808252806020026020018201604052801561307957816020015b60408051808201909152600080825260208201528152602001906001900390816130525790505b5090506000826001600160401b0381111561309657613096613f76565b6040519080825280602002602001820160405280156130bf578160200160208202803683370190505b5090506000805b8560ff168160ff161015613216576000806130e18b84610792565b9150915060405180604001604052808460ff16815260200183815250868460ff168151811061311257613112613f8c565b602002602001018190525060005b8151811015613200576000805b868110156131995783838151811061314757613147613f8c565b60200260200101516001600160a01b031688828151811061316a5761316a613f8c565b60200260200101516001600160a01b0316036131895760019150613199565b613192816140c8565b905061312d565b50806131ef578282815181106131b1576131b1613f8c565b60200260200101518787815181106131cb576131cb613f8c565b6001600160a01b03909216602092830291909101909101526131ec866140c8565b95505b506131f9816140c8565b9050613120565b505050808061320e9061413a565b9150506130c6565b506000816001600160401b0381111561323157613231613f76565b60405190808252806020026020018201604052801561325a578160200160208202803683370190505b50905060005b828110156132bc5783818151811061327a5761327a613f8c565b602002602001015182828151811061329457613294613f8c565b6001600160a01b03909216602092830291909101909101526132b5816140c8565b9050613260565b5092989297509195505050505050565b604080516060808201835260008083526020830152918101919091526000826001600160a01b031663bf199e626040518163ffffffff1660e01b8152600401602060405180830381865afa158015613328573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061334c919061406a565b604051636006c17d60e11b81526001600160a01b03868116600483015291925060009185169063c00d82fa90602401602060405180830381865afa158015613398573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133bc919061406a565b90506000826001600160401b038111156133d8576133d8613f76565b60405190808252806020026020018201604052801561341d57816020015b60408051808201909152600080825260208201528152602001906001900390816133f65790505b50905060005b83811015613556576040516379f5ecb760e01b8152600481018290526000906001600160a01b038816906379f5ecb790602401602060405180830381865afa158015613473573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061349791906140e1565b60405163591d8a4b60e01b81526001600160a01b0380831660048301528a8116602483015291925060009189169063591d8a4b90604401602060405180830381865afa1580156134eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061350f919061406a565b90506040518060400160405280828152602001836001600160a01b031681525084848151811061354157613541613f8c565b60209081029190910101525050600101613423565b50604080516060810182526001600160a01b0387168152602081019390935282015291505092915050565b60408051606081018252600080825260208201819052918101829052906135a884846120a9565b90506040518060600160405280846001600160a01b03168152602001846001600160a01b0316639a59a0716040518163ffffffff1660e01b8152600401602060405180830381865afa158015613602573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061362691906140e1565b6001600160a01b03168152602001919091529392505050565b600061076a8284614174565b600061076a8284614187565b604080516020810190915260008152604051806020016040528061369361368d866ec097ce7bc90715b34b9f100000000061364b565b85613738565b90529392505050565b604080516020810190915260008152604051806020016040528061369385600001518560000151613744565b60408051602081019091526000815260405180602001604052806136938560000151856000015161363f565b60006ec097ce7bc90715b34b9f100000000061371484846000015161364b565b61076a919061419e565b600061076a61373584670de0b6b3a764000061364b565b83515b600061076a828461419e565b600061076a82846140b5565b6040518060c0016040528060006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081525090565b60405180610280016040528060006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081526020016060815260200160008152602001600081526020016000151581526020016000151581525090565b60405180610100016040528060006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060400160405280606081526020016138df6040805160a0810182526060808201818152608083018290528252602082018190529181019190915290565b905290565b6040518060c0016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000151581525090565b6001600160a01b038116811461393a57600080fd5b50565b60006020828403121561394f57600080fd5b813561076a81613925565b602080825282518282018190526000919060409081850190868401855b828110156139d157815180516001600160a01b0390811686528782015116878601528581015186860152606080820151908601526080808201519086015260a0908101519085015260c09093019290850190600101613977565b5091979650505050505050565b6000602082840312156139f057600080fd5b5035919050565b600081518084526020808501945080840160005b83811015613a2757815187529582019590820190600101613a0b565b509495945050505050565b80516001600160a01b0316825260006102806020830151602085015260408301516040850152606083015160608501526080830151608085015260a083015160a085015260c083015160c085015260e083015160e085015261010080840151818601525061012080840151818601525061014080840151818601525061016080840151613ac9828701826001600160a01b03169052565b505061018083810151908501526101a080840151908501526101c080840151818601839052613afa838701826139f7565b925050506101e08084015185830382870152613b1683826139f7565b9250505061020080840151818601525061022080840151818601525061024080840151613b468287018215159052565b50506102609283015115159390920192909252919050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015612b6e57603f19888603018452613ba1858351613a32565b94509285019290850190600101613b85565b602080825282518282018190526000919060409081850190868401855b828110156139d157815180516001600160a01b0390811686528782015116878601528581015186860152606080820151908601526080808201519086015260a0808201519086015260c0808201519086015260e090810151908501526101009093019290850190600101613bd0565b80516001600160a01b031682526020808201519083015260408082015190830152606080820151908301526080808201519083015260a0908101511515910152565b600081518084526020808501945080840160005b83811015613a275781516001600160a01b031687529582019590820190600101613c95565b600081518084526020808501808196508360051b810191508286016000805b86811015613d66578385038a52825180516001600160a01b03908116875287820151888801526040918201516060838901819052815190890181905290890192608089019286929091905b80841015613d4f578551805186528c015183168c860152948b01949381019360019390930192613d24565b5050509b88019b5095505091850191600101613cd9565b509298975050505050505050565b600081518084526020808501945080840160005b83811015613a2757815180516001600160a01b0390811689528482015116848901526040908101519088015260609096019590820190600101613d88565b60208082528251604083830181905281516060850181905260009392830191849160808701905b80841015613e1657613e00828651613c3f565b60c0820191508585019450600184019350613ded565b5087850151878203601f190183890152805160608084528151908401859052805160a0850181905292965090945086019060009060c08401905b80831015613e7c578351805160ff16835289015189830152928801926001929092019190850190613e50565b5094870151838603605f1901608085015294613e988187613c81565b95505050508484015181840386830152613eb28482613cba565b95505081840151935080850382820152505050611ffd8282613d74565b60008060408385031215613ee257600080fd5b8235613eed81613925565b91506020830135613efd81613925565b809150509250929050565b60c081016107528284613c3f565b60208152600061076a6020830184613a32565b60008060408385031215613f3c57600080fd5b8235613f4781613925565b9150602083013560ff81168114613efd57600080fd5b8281526040602082015260006122c26040830184613c81565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b8051613fad81613925565b919050565b60006020808385031215613fc557600080fd5b82516001600160401b0380821115613fdc57600080fd5b818501915085601f830112613ff057600080fd5b81518181111561400257614002613f76565b8060051b604051601f19603f8301168101818110858211171561402757614027613f76565b60405291825284820192508381018501918883111561404557600080fd5b938501935b82851015612ef25761405b85613fa2565b8452938501939285019261404a565b60006020828403121561407c57600080fd5b5051919050565b60ff9290921682526001600160a01b0316602082015260400190565b634e487b7160e01b600052601160045260246000fd5b808201808211156107525761075261409f565b6000600182016140da576140da61409f565b5060010190565b6000602082840312156140f357600080fd5b815161076a81613925565b80518015158114613fad57600080fd5b6000806040838503121561412157600080fd5b61412a836140fe565b9150602083015190509250929050565b600060ff821660ff81036141505761415061409f565b60010192915050565b60006020828403121561416b57600080fd5b61076a826140fe565b818103818111156107525761075261409f565b80820281158282048414176107525761075261409f565b6000826141bb57634e487b7160e01b600052601260045260246000fd5b500490565b80516001600160e01b0381168114613fad57600080fd5b600080604083850312156141ea57600080fd5b6141f3836141c0565b9150602083015163ffffffff81168114613efd57600080fd5b60006020828403121561421e57600080fd5b61076a826141c056fea2646970667358221220dcb56d58409917c8d39410383a2daa613bc06de36bfe3ac41486a11249f6f02564736f6c63430008110033