Address Details
contract
0x303ED1df62Fa067659B586EbEe8De0EcE824Ab39
- Contract Name
- BiPoolManager
- Creator
- 0x56fd3f–9b8d81 at 0x53ced9–288ee9
- Balance
- 0 CELO ( )
- Locked CELO Balance
- 0.00 CELO
- Voting CELO Balance
- 0.00 CELO
- Pending Unlocked Gold
- 0.00 CELO
- Tokens
-
Fetching tokens...
- Transactions
- 1 Transactions
- Transfers
- 0 Transfers
- Gas Used
- 28,909
- Last Balance Update
- 18860345
This contract has been verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- BiPoolManager
- Optimization enabled
- true
- Compiler version
- v0.5.17+commit.d19bba13
- Optimization runs
- 10000
- Verified at
- 2023-05-02T19:04:08.052092Z
lib/mento-core/contracts/BiPoolManager.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; pragma experimental ABIEncoderV2; import { Ownable } from "openzeppelin-solidity/contracts/ownership/Ownable.sol"; import { SafeMath } from "openzeppelin-solidity/contracts/math/SafeMath.sol"; import { IERC20Metadata } from "./common/interfaces/IERC20Metadata.sol"; import { IExchangeProvider } from "./interfaces/IExchangeProvider.sol"; import { IBiPoolManager } from "./interfaces/IBiPoolManager.sol"; import { IReserve } from "./interfaces/IReserve.sol"; import { IPricingModule } from "./interfaces/IPricingModule.sol"; import { ISortedOracles } from "./interfaces/ISortedOracles.sol"; import { IBreakerBox } from "./interfaces/IBreakerBox.sol"; import { StableToken } from "./StableToken.sol"; import { Initializable } from "./common/Initializable.sol"; import { FixidityLib } from "./common/FixidityLib.sol"; /** * @title BiPoolExchangeManager * @notice An exchange manager that manages asset exchanges consisting of two assets */ contract BiPoolManager is IExchangeProvider, IBiPoolManager, Initializable, Ownable { using FixidityLib for FixidityLib.Fraction; using SafeMath for uint256; /* ==================== State Variables ==================== */ // Address of the broker contract. address public broker; // Maps an exchange id to the corresponding PoolExchange struct. // exchangeId is in the format "asset0Symbol:asset1Symbol:pricingModuleName" mapping(bytes32 => PoolExchange) public exchanges; bytes32[] public exchangeIds; uint256 private constant TRADING_MODE_BIDIRECTIONAL = 0; // Address of the Mento Reserve contract IReserve public reserve; // Address of the Mento BreakerBox contract IBreakerBox public breakerBox; // Address of the Mento SortedOracles contract ISortedOracles public sortedOracles; // Token precision multiplier used to normalize values to the // same precision when calculating vAMM bucket sizes. mapping(address => uint256) public tokenPrecisionMultipliers; /* ==================== Constructor ==================== */ /** * @notice Sets initialized == true on implementation contracts. * @param test Set to true to skip implementation initialization. */ // solhint-disable-next-line no-empty-blocks constructor(bool test) public Initializable(test) {} /** * @notice Allows the contract to be upgradable via the proxy. * @param _broker The address of the broker contract. * @param _reserve The address of the reserve contract. * @param _sortedOracles The address of the sorted oracles contract. * @param _breakerBox The address of the breaker box contract. */ function initialize( address _broker, IReserve _reserve, ISortedOracles _sortedOracles, IBreakerBox _breakerBox ) external initializer { _transferOwnership(msg.sender); setBroker(_broker); setReserve(_reserve); setSortedOracles(_sortedOracles); setBreakerBox(_breakerBox); } /* ==================== Modifiers ==================== */ modifier onlyBroker() { require(msg.sender == broker, "Caller is not the Broker"); _; } /* ==================== View Functions ==================== */ /** * @notice Get a PoolExchange from storage. * @param exchangeId the exchange id */ function getPoolExchange(bytes32 exchangeId) public view returns (PoolExchange memory exchange) { exchange = exchanges[exchangeId]; require(exchange.asset0 != address(0), "An exchange with the specified id does not exist"); } /** * @notice Get all exchange IDs. * @return exchangeIds List of the exchangeIds. */ function getExchangeIds() external view returns (bytes32[] memory) { return exchangeIds; } /** * @notice Get all exchanges (used by interfaces) * @dev We don't expect the number of exchanges to grow to * astronomical values so this is safe gas-wise as is. */ function getExchanges() public view returns (Exchange[] memory _exchanges) { _exchanges = new Exchange[](exchangeIds.length); for (uint256 i = 0; i < exchangeIds.length; i++) { _exchanges[i].exchangeId = exchangeIds[i]; _exchanges[i].assets = new address[](2); _exchanges[i].assets[0] = exchanges[exchangeIds[i]].asset0; _exchanges[i].assets[1] = exchanges[exchangeIds[i]].asset1; } } /** * @notice Calculate amountOut of tokenOut received for a given amountIn of tokenIn * @param exchangeId The id of the exchange i.e PoolExchange to use * @param tokenIn The token to be sold * @param tokenOut The token to be bought * @param amountIn The amount of tokenIn to be sold * @return amountOut The amount of tokenOut to be bought */ function getAmountOut( bytes32 exchangeId, address tokenIn, address tokenOut, uint256 amountIn ) external view returns (uint256 amountOut) { PoolExchange memory exchange = getPoolExchange(exchangeId); (amountOut, ) = _getAmountOut(exchange, tokenIn, tokenOut, amountIn); } /** * @notice Calculate amountIn of tokenIn for a given amountOut of tokenOut * @param exchangeId The id of the exchange i.e PoolExchange to use * @param tokenIn The token to be sold * @param tokenOut The token to be bought * @param amountOut The amount of tokenOut to be bought * @return amountIn The amount of tokenIn to be sold */ function getAmountIn( bytes32 exchangeId, address tokenIn, address tokenOut, uint256 amountOut ) external view returns (uint256 amountIn) { PoolExchange memory exchange = getPoolExchange(exchangeId); (amountIn, ) = _getAmountIn(exchange, tokenIn, tokenOut, amountOut); } /* ==================== Mutative Functions ==================== */ /** * @notice Sets the address of the broker contract. * @param _broker The new address of the broker contract. */ function setBroker(address _broker) public onlyOwner { require(_broker != address(0), "Broker address must be set"); broker = _broker; emit BrokerUpdated(_broker); } /** * @notice Sets the address of the reserve contract. * @param _reserve The new address of the reserve contract. */ function setReserve(IReserve _reserve) public onlyOwner { require(address(_reserve) != address(0), "Reserve address must be set"); reserve = _reserve; emit ReserveUpdated(address(_reserve)); } /** * @notice Sets the address of the BreakerBox. * @param _breakerBox The new BreakerBox address. */ function setBreakerBox(IBreakerBox _breakerBox) public onlyOwner { require(address(_breakerBox) != address(0), "BreakerBox address must be set"); breakerBox = _breakerBox; emit BreakerBoxUpdated(address(_breakerBox)); } /** * @notice Sets the address of the sortedOracles contract. * @param _sortedOracles The new address of the sorted oracles contract. */ function setSortedOracles(ISortedOracles _sortedOracles) public onlyOwner { require(address(_sortedOracles) != address(0), "SortedOracles address must be set"); sortedOracles = _sortedOracles; emit SortedOraclesUpdated(address(_sortedOracles)); } function setTokenPrecisionMultipliers(address[] calldata tokens, uint256[] calldata precisionMultipliers) external onlyOwner { require(tokens.length == precisionMultipliers.length, "tokens and precisionMultipliers must be the same length"); for (uint256 i = 0; i < tokens.length; i++) { tokenPrecisionMultipliers[tokens[i]] = precisionMultipliers[i]; } } /** * @notice Creates a new exchange using the given parameters. * @param _exchange the PoolExchange to create. * @return exchangeId The id of the newly created exchange. */ function createExchange(PoolExchange calldata _exchange) external onlyOwner returns (bytes32 exchangeId) { PoolExchange memory exchange = _exchange; require(address(exchange.pricingModule) != address(0), "pricingModule must be set"); require(exchange.asset0 != address(0), "asset0 must be set"); require(exchange.asset1 != address(0), "asset1 must be set"); require(exchange.asset0 != exchange.asset1, "exchange assets can't be identical"); exchangeId = keccak256( abi.encodePacked( IERC20Metadata(exchange.asset0).symbol(), IERC20Metadata(exchange.asset1).symbol(), exchange.pricingModule.name() ) ); require(exchanges[exchangeId].asset0 == address(0), "An exchange with the specified assets and exchange exists"); validate(exchange); (uint256 bucket0, uint256 bucket1) = getUpdatedBuckets(exchange); exchange.bucket0 = bucket0; exchange.bucket1 = bucket1; if (IERC20Metadata(exchange.asset0).decimals() > 18) { revert("asset0 decimals must be <= 18"); } if (IERC20Metadata(exchange.asset1).decimals() > 18) { revert("asset1 decimals must be <= 18"); } tokenPrecisionMultipliers[exchange.asset0] = 10**(18 - uint256(IERC20Metadata(exchange.asset0).decimals())); tokenPrecisionMultipliers[exchange.asset1] = 10**(18 - uint256(IERC20Metadata(exchange.asset1).decimals())); exchanges[exchangeId] = exchange; exchangeIds.push(exchangeId); emit ExchangeCreated(exchangeId, exchange.asset0, exchange.asset1, address(exchange.pricingModule)); } /** * @notice Destroys a exchange with the given parameters if it exists and frees up * the collateral and stable allocation it was using. * @param exchangeId the id of the exchange to destroy * @param exchangeIdIndex The index of the exchangeId in the ids array * @return destroyed A boolean indicating whether or not the exchange was successfully destroyed. */ function destroyExchange(bytes32 exchangeId, uint256 exchangeIdIndex) external onlyOwner returns (bool destroyed) { require(exchangeIdIndex < exchangeIds.length, "exchangeIdIndex not in range"); require(exchangeIds[exchangeIdIndex] == exchangeId, "exchangeId at index doesn't match"); PoolExchange memory exchange = exchanges[exchangeId]; delete exchanges[exchangeId]; exchangeIds[exchangeIdIndex] = exchangeIds[exchangeIds.length.sub(1)]; exchangeIds.pop(); destroyed = true; emit ExchangeDestroyed(exchangeId, exchange.asset0, exchange.asset1, address(exchange.pricingModule)); } /** * @notice Execute a token swap with fixed amountIn * @param exchangeId The id of exchange, i.e. PoolExchange to use * @param tokenIn The token to be sold * @param tokenOut The token to be bought * @param amountIn The amount of tokenIn to be sold * @return amountOut The amount of tokenOut to be bought */ function swapIn( bytes32 exchangeId, address tokenIn, address tokenOut, uint256 amountIn ) external onlyBroker returns (uint256 amountOut) { PoolExchange memory exchange = getPoolExchange(exchangeId); require( breakerBox.getRateFeedTradingMode(exchange.config.referenceRateFeedID) == TRADING_MODE_BIDIRECTIONAL, "Trading is suspended for this reference rate" ); bool bucketsUpdated; (amountOut, bucketsUpdated) = _getAmountOut(exchange, tokenIn, tokenOut, amountIn); executeSwap(exchangeId, exchange, tokenIn, amountIn, amountOut, bucketsUpdated); return amountOut; } /** * @notice Execute a token swap with fixed amountOut * @param exchangeId The id of exchange, i.e. PoolExchange to use * @param tokenIn The token to be sold * @param tokenOut The token to be bought * @param amountOut The amount of tokenOut to be bought * @return amountIn The amount of tokenIn to be sold */ function swapOut( bytes32 exchangeId, address tokenIn, address tokenOut, uint256 amountOut ) external onlyBroker returns (uint256 amountIn) { PoolExchange memory exchange = getPoolExchange(exchangeId); require( breakerBox.getRateFeedTradingMode(exchange.config.referenceRateFeedID) == TRADING_MODE_BIDIRECTIONAL, "Trading is suspended for this reference rate" ); bool bucketsUpdated; (amountIn, bucketsUpdated) = _getAmountIn(exchange, tokenIn, tokenOut, amountOut); executeSwap(exchangeId, exchange, tokenIn, amountIn, amountOut, bucketsUpdated); return amountIn; } /* ==================== Private Functions ==================== */ /** * @notice Execute a swap against the in memory exchange and write * the new bucket sizes to storage. * @param exchangeId The id of the exchange * @param exchange The exchange to operate on * @param tokenIn The token to be sold * @param amountIn The amount of tokenIn to be sold * @param amountOut The amount of tokenOut to be bought * @param bucketsUpdated wether the buckets updated during the swap */ function executeSwap( bytes32 exchangeId, PoolExchange memory exchange, address tokenIn, uint256 amountIn, uint256 amountOut, bool bucketsUpdated ) internal { if (bucketsUpdated) { // solhint-disable-next-line not-rely-on-time exchanges[exchangeId].lastBucketUpdate = now; emit BucketsUpdated(exchangeId, exchange.bucket0, exchange.bucket1); } if (tokenIn == exchange.asset0) { exchanges[exchangeId].bucket0 = exchange.bucket0.add(amountIn); exchanges[exchangeId].bucket1 = exchange.bucket1.sub(amountOut); } else { exchanges[exchangeId].bucket0 = exchange.bucket0.sub(amountOut); exchanges[exchangeId].bucket1 = exchange.bucket1.add(amountIn); } } /** * @notice Calculate amountOut of tokenOut received for a given amountIn of tokenIn * @param exchange The exchange to operate on * @param tokenIn The token to be sold * @param tokenOut The token to be bought * @param amountIn The amount of tokenIn to be sold * @return amountOut The amount of tokenOut to be bought * @return bucketsUpdated Wether the buckets were updated during the quote */ function _getAmountOut( PoolExchange memory exchange, address tokenIn, address tokenOut, uint256 amountIn ) internal view returns (uint256 amountOut, bool bucketsUpdated) { require( (tokenIn == exchange.asset0 && tokenOut == exchange.asset1) || (tokenIn == exchange.asset1 && tokenOut == exchange.asset0), "tokenIn and tokenOut must match exchange" ); (exchange, bucketsUpdated) = updateBucketsIfNecessary(exchange); if (tokenIn == exchange.asset0) { amountOut = exchange.pricingModule.getAmountOut( exchange.bucket0, exchange.bucket1, exchange.config.spread.unwrap(), amountIn.mul(tokenPrecisionMultipliers[exchange.asset0]) ).div(tokenPrecisionMultipliers[exchange.asset1]); } else { amountOut = exchange.pricingModule.getAmountOut( exchange.bucket1, exchange.bucket0, exchange.config.spread.unwrap(), amountIn.mul(tokenPrecisionMultipliers[exchange.asset1]) ).div(tokenPrecisionMultipliers[exchange.asset0]); } } /** * @notice Calculate amountIn of tokenIn for a given amountOut of tokenOut * @param exchange The exchange to operate on * @param tokenIn The token to be sold * @param tokenOut The token to be bought * @param amountOut The amount of tokenOut to be bought * @return amountIn The amount of tokenIn to be sold * @return bucketsUpdated Wether the buckets were updated during the quote */ function _getAmountIn( PoolExchange memory exchange, address tokenIn, address tokenOut, uint256 amountOut ) internal view returns (uint256 amountIn, bool bucketsUpdated) { require( (tokenIn == exchange.asset0 && tokenOut == exchange.asset1) || (tokenIn == exchange.asset1 && tokenOut == exchange.asset0), "tokenIn and tokenOut must match exchange" ); (exchange, bucketsUpdated) = updateBucketsIfNecessary(exchange); if (tokenIn == exchange.asset0) { amountIn = exchange.pricingModule.getAmountIn( exchange.bucket0, exchange.bucket1, exchange.config.spread.unwrap(), amountOut.mul(tokenPrecisionMultipliers[exchange.asset1]) ).div(tokenPrecisionMultipliers[exchange.asset0]); } else { amountIn = exchange.pricingModule.getAmountIn( exchange.bucket1, exchange.bucket0, exchange.config.spread.unwrap(), amountOut.mul(tokenPrecisionMultipliers[exchange.asset0]) ).div(tokenPrecisionMultipliers[exchange.asset1]); } } /** * @notice If conditions are met, update the exchange bucket sizes. * @dev This doesn't checkpoint the exchange, just updates the in-memory one * so it should be used in a context that then checkpoints the exchange. * @param exchange The exchange being updated. * @return exchangeAfter The updated exchange. */ function updateBucketsIfNecessary(PoolExchange memory exchange) internal view returns (PoolExchange memory, bool updated) { if (shouldUpdateBuckets(exchange)) { (exchange.bucket0, exchange.bucket1) = getUpdatedBuckets(exchange); updated = true; } return (exchange, updated); } /** * @notice Determine if a exchange's buckets should be updated * based on staleness of buckets and oracle rates. * @param exchange The PoolExchange. * @return shouldUpdate */ function shouldUpdateBuckets(PoolExchange memory exchange) internal view returns (bool) { (bool isReportExpired, ) = sortedOracles.isOldestReportExpired(exchange.config.referenceRateFeedID); // solhint-disable-next-line not-rely-on-time bool timePassed = now >= exchange.lastBucketUpdate.add(exchange.config.referenceRateResetFrequency); bool enoughReports = (sortedOracles.numRates(exchange.config.referenceRateFeedID) >= exchange.config.minimumReports); // solhint-disable-next-line not-rely-on-time bool medianReportRecent = sortedOracles.medianTimestamp(exchange.config.referenceRateFeedID) > now.sub(exchange.config.referenceRateResetFrequency); return timePassed && enoughReports && medianReportRecent && !isReportExpired; } /** * @notice Calculate the new bucket sizes for a exchange. * @param exchange The PoolExchange in context. * @return bucket0 The size of bucket0. * @return bucket1 The size of bucket1. */ function getUpdatedBuckets(PoolExchange memory exchange) internal view returns (uint256 bucket0, uint256 bucket1) { bucket0 = exchange.config.stablePoolResetSize; uint256 exchangeRateNumerator; uint256 exchangeRateDenominator; (exchangeRateNumerator, exchangeRateDenominator) = getOracleExchangeRate(exchange.config.referenceRateFeedID); bucket1 = exchangeRateDenominator.mul(bucket0).div(exchangeRateNumerator); } /** * @notice Get the exchange rate as numerator,denominator from sorted oracles * and protect in case of a 0-denominator. * @param target the reportTarget to read from SortedOracles * @return rateNumerator * @return rateDenominator */ function getOracleExchangeRate(address target) internal view returns (uint256, uint256) { uint256 rateNumerator; uint256 rateDenominator; (rateNumerator, rateDenominator) = sortedOracles.medianRate(target); require(rateDenominator > 0, "exchange rate denominator must be greater than 0"); return (rateNumerator, rateDenominator); } /** * @notice Valitates a PoolExchange's parameters and configuration * @dev Reverts if not valid * @param exchange The PoolExchange to validate */ function validate(PoolExchange memory exchange) private view { require(reserve.isStableAsset(exchange.asset0), "asset0 must be a stable registered with the reserve"); require( reserve.isStableAsset(exchange.asset1) || reserve.isCollateralAsset(exchange.asset1), "asset1 must be a stable or collateral" ); require(FixidityLib.lte(exchange.config.spread, FixidityLib.fixed1()), "spread must be less than or equal to 1"); require(exchange.config.referenceRateFeedID != address(0), "referenceRateFeedID must be set"); } }
/lib/mento-core/contracts/StableToken.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; import "./interfaces/IStableToken.sol"; import "./interfaces/ICeloToken.sol"; import "./common/interfaces/ICeloVersionedContract.sol"; import "./common/CalledByVm.sol"; import "./common/Initializable.sol"; import "./common/FixidityLib.sol"; import "./common/Freezable.sol"; import "./common/UsingRegistry.sol"; import "./common/UsingPrecompiles.sol"; /** * @title An ERC20 compliant token with adjustable supply. */ // solhint-disable-next-line max-line-length contract StableToken is ICeloVersionedContract, Ownable, Initializable, UsingRegistry, UsingPrecompiles, Freezable, CalledByVm, IStableToken, IERC20, ICeloToken { using FixidityLib for FixidityLib.Fraction; using SafeMath for uint256; event InflationFactorUpdated(uint256 factor, uint256 lastUpdated); event InflationParametersUpdated(uint256 rate, uint256 updatePeriod, uint256 lastUpdated); event Transfer(address indexed from, address indexed to, uint256 value); event TransferComment(string comment); bytes32 private constant GRANDA_MENTO_REGISTRY_ID = keccak256(abi.encodePacked("GrandaMento")); bytes32 private constant BROKER_REGISTRY_ID = keccak256(abi.encodePacked("Broker")); string internal name_; string internal symbol_; uint8 internal decimals_; // Stored as units. Value can be found using unitsToValue(). mapping(address => uint256) internal balances; uint256 internal totalSupply_; // Stored as values. Units can be found using valueToUnits(). mapping(address => mapping(address => uint256)) internal allowed; // STABILITY FEE PARAMETERS // The `rate` is how much the `factor` is adjusted by per `updatePeriod`. // The `factor` describes units/value of StableToken, and is greater than or equal to 1. // The `updatePeriod` governs how often the `factor` is updated. // `factorLastUpdated` indicates when the inflation factor was last updated. struct InflationState { FixidityLib.Fraction rate; FixidityLib.Fraction factor; uint256 updatePeriod; uint256 factorLastUpdated; } // solhint-disable-next-line state-visibility InflationState inflationState; // The registry ID of the exchange contract with permission to mint and burn this token. // Unique per StableToken instance. // solhint-disable-next-line state-visibility bytes32 exchangeRegistryId; /** * @notice Recomputes and updates inflation factor if more than `updatePeriod` * has passed since last update. */ modifier updateInflationFactor() { FixidityLib.Fraction memory updatedInflationFactor; uint256 lastUpdated; (updatedInflationFactor, lastUpdated) = getUpdatedInflationFactor(); if (lastUpdated != inflationState.factorLastUpdated) { inflationState.factor = updatedInflationFactor; inflationState.factorLastUpdated = lastUpdated; emit InflationFactorUpdated(inflationState.factor.unwrap(), inflationState.factorLastUpdated); } _; } /** * @notice Returns the storage, major, minor, and patch version of the contract. * @return Storage version of the contract. * @return Major version of the contract. * @return Minor version of the contract. * @return Patch version of the contract. */ function getVersionNumber() external pure returns ( uint256, uint256, uint256, uint256 ) { return (1, 2, 1, 0); } /** * @notice Sets initialized == true on implementation contracts * @param test Set to true to skip implementation initialization */ constructor(bool test) public Initializable(test) {} /** * @param _name The name of the stable token (English) * @param _symbol A short symbol identifying the token (e.g. "cUSD") * @param _decimals Tokens are divisible to this many decimal places. * @param registryAddress Address of the Registry contract. * @param inflationRate Weekly inflation rate. * @param inflationFactorUpdatePeriod How often the inflation factor is updated, in seconds. * @param initialBalanceAddresses Array of addresses with an initial balance. * @param initialBalanceValues Array of balance values corresponding to initialBalanceAddresses. * @param exchangeIdentifier String identifier of exchange in registry (for specific fiat pairs) */ function initialize( string calldata _name, string calldata _symbol, uint8 _decimals, address registryAddress, uint256 inflationRate, uint256 inflationFactorUpdatePeriod, address[] calldata initialBalanceAddresses, uint256[] calldata initialBalanceValues, string calldata exchangeIdentifier ) external initializer { require(inflationRate != 0, "Must provide a non-zero inflation rate"); require(inflationFactorUpdatePeriod > 0, "inflationFactorUpdatePeriod must be > 0"); _transferOwnership(msg.sender); totalSupply_ = 0; name_ = _name; symbol_ = _symbol; decimals_ = _decimals; inflationState.rate = FixidityLib.wrap(inflationRate); inflationState.factor = FixidityLib.fixed1(); inflationState.updatePeriod = inflationFactorUpdatePeriod; // solhint-disable-next-line not-rely-on-time inflationState.factorLastUpdated = now; require(initialBalanceAddresses.length == initialBalanceValues.length, "Array length mismatch"); for (uint256 i = 0; i < initialBalanceAddresses.length; i = i.add(1)) { _mint(initialBalanceAddresses[i], initialBalanceValues[i]); } setRegistry(registryAddress); exchangeRegistryId = keccak256(abi.encodePacked(exchangeIdentifier)); } /** * @notice Updates Inflation Parameters. * @param rate New rate. * @param updatePeriod How often inflationFactor is updated. */ function setInflationParameters(uint256 rate, uint256 updatePeriod) external onlyOwner updateInflationFactor { require(rate != 0, "Must provide a non-zero inflation rate."); require(updatePeriod > 0, "updatePeriod must be > 0"); inflationState.rate = FixidityLib.wrap(rate); inflationState.updatePeriod = updatePeriod; emit InflationParametersUpdated( rate, updatePeriod, // solhint-disable-next-line not-rely-on-time now ); } /** * @notice Increase the allowance of another user. * @param spender The address which is being approved to spend StableToken. * @param value The increment of the amount of StableToken approved to the spender. * @return True if the transaction succeeds. */ function increaseAllowance(address spender, uint256 value) external updateInflationFactor returns (bool) { require(spender != address(0), "reserved address 0x0 cannot have allowance"); uint256 oldValue = allowed[msg.sender][spender]; uint256 newValue = oldValue.add(value); allowed[msg.sender][spender] = newValue; emit Approval(msg.sender, spender, newValue); return true; } /** * @notice Decrease the allowance of another user. * @param spender The address which is being approved to spend StableToken. * @param value The decrement of the amount of StableToken approved to the spender. * @return True if the transaction succeeds. */ function decreaseAllowance(address spender, uint256 value) external updateInflationFactor returns (bool) { uint256 oldValue = allowed[msg.sender][spender]; uint256 newValue = oldValue.sub(value); allowed[msg.sender][spender] = newValue; emit Approval(msg.sender, spender, newValue); return true; } /** * @notice Approve a user to transfer StableToken on behalf of another user. * @param spender The address which is being approved to spend StableToken. * @param value The amount of StableToken approved to the spender. * @return True if the transaction succeeds. */ function approve(address spender, uint256 value) external updateInflationFactor returns (bool) { require(spender != address(0), "reserved address 0x0 cannot have allowance"); allowed[msg.sender][spender] = value; emit Approval(msg.sender, spender, value); return true; } /** * @notice Mints new StableToken and gives it to 'to'. * @param to The account for which to mint tokens. * @param value The amount of StableToken to mint. */ function mint(address to, uint256 value) external updateInflationFactor returns (bool) { require( msg.sender == registry.getAddressFor(BROKER_REGISTRY_ID) || msg.sender == registry.getAddressFor(getExchangeRegistryId()) || msg.sender == registry.getAddressFor(VALIDATORS_REGISTRY_ID) || msg.sender == registry.getAddressFor(GRANDA_MENTO_REGISTRY_ID), "Sender not authorized to mint" ); return _mint(to, value); } /** * @notice Mints new StableToken and gives it to 'to'. * @param to The account for which to mint tokens. * @param value The amount of StableToken to mint. */ function _mint(address to, uint256 value) private returns (bool) { require(to != address(0), "0 is a reserved address"); if (value == 0) { return true; } uint256 units = _valueToUnits(inflationState.factor, value); totalSupply_ = totalSupply_.add(units); balances[to] = balances[to].add(units); emit Transfer(address(0), to, value); return true; } /** * @notice Transfer token for a specified address * @param to The address to transfer to. * @param value The amount to be transferred. * @param comment The transfer comment. * @return True if the transaction succeeds. */ function transferWithComment( address to, uint256 value, string calldata comment ) external updateInflationFactor onlyWhenNotFrozen returns (bool) { bool succeeded = transfer(to, value); emit TransferComment(comment); return succeeded; } /** * @notice Burns StableToken from the balance of msg.sender. * @param value The amount of StableToken to burn. */ function burn(uint256 value) external updateInflationFactor returns (bool) { require( msg.sender == registry.getAddressFor(BROKER_REGISTRY_ID) || msg.sender == registry.getAddressFor(getExchangeRegistryId()) || msg.sender == registry.getAddressFor(GRANDA_MENTO_REGISTRY_ID), "Sender not authorized to burn" ); uint256 units = _valueToUnits(inflationState.factor, value); require(units <= balances[msg.sender], "value exceeded balance of sender"); totalSupply_ = totalSupply_.sub(units); balances[msg.sender] = balances[msg.sender].sub(units); emit Transfer(msg.sender, address(0), units); return true; } /** * @notice Transfers StableToken from one address to another on behalf of a user. * @param from The address to transfer StableToken from. * @param to The address to transfer StableToken to. * @param value The amount of StableToken to transfer. * @return True if the transaction succeeds. */ function transferFrom( address from, address to, uint256 value ) external updateInflationFactor onlyWhenNotFrozen returns (bool) { uint256 units = _valueToUnits(inflationState.factor, value); require(to != address(0), "transfer attempted to reserved address 0x0"); require(units <= balances[from], "transfer value exceeded balance of sender"); require(value <= allowed[from][msg.sender], "transfer value exceeded sender's allowance for recipient"); balances[to] = balances[to].add(units); balances[from] = balances[from].sub(units); allowed[from][msg.sender] = allowed[from][msg.sender].sub(value); emit Transfer(from, to, value); return true; } /** * @return The name of the stable token. */ function name() external view returns (string memory) { return name_; } /** * @return The symbol of the stable token. */ function symbol() external view returns (string memory) { return symbol_; } /** * @return The number of decimal places to which StableToken is divisible. */ function decimals() external view returns (uint8) { return decimals_; } /** * @notice Gets the amount of owner's StableToken allowed to be spent by spender. * @param accountOwner The owner of the StableToken. * @param spender The spender of the StableToken. * @return The amount of StableToken owner is allowing spender to spend. */ function allowance(address accountOwner, address spender) external view returns (uint256) { return allowed[accountOwner][spender]; } /** * @notice Gets the balance of the specified address using the presently stored inflation factor. * @param accountOwner The address to query the balance of. * @return The balance of the specified address. */ function balanceOf(address accountOwner) external view returns (uint256) { return unitsToValue(balances[accountOwner]); } /** * @return The total value of StableToken in existence * @dev Though totalSupply_ is stored in units, this returns value. */ function totalSupply() external view returns (uint256) { return unitsToValue(totalSupply_); } /** * @notice gets inflation parameters. * @return rate * @return factor * @return updatePeriod * @return factorLastUpdated */ function getInflationParameters() external view returns ( uint256, uint256, uint256, uint256 ) { return ( inflationState.rate.unwrap(), inflationState.factor.unwrap(), inflationState.updatePeriod, inflationState.factorLastUpdated ); } /** * @notice Returns the units for a given value given the current inflation factor. * @param value The value to convert to units. * @return The units corresponding to `value` given the current inflation factor. * @dev We don't compute the updated inflationFactor here because * we assume any function calling this will have updated the inflation factor. */ function valueToUnits(uint256 value) external view returns (uint256) { FixidityLib.Fraction memory updatedInflationFactor; (updatedInflationFactor, ) = getUpdatedInflationFactor(); return _valueToUnits(updatedInflationFactor, value); } /** * @notice Returns the exchange id in the registry of the corresponding fiat pair exchange. * @dev When this storage is uninitialized, it falls back to the default EXCHANGE_REGISTRY_ID. * exchangeRegistryId was introduced after the initial release of cUSD's StableToken, * so exchangeRegistryId will be uninitialized for that contract. If cUSD's StableToken * exchangeRegistryId were to be correctly initialized, this function could be deprecated * in favor of using exchangeRegistryId directly. * @return Registry id for the corresponding exchange. */ function getExchangeRegistryId() public view returns (bytes32) { if (exchangeRegistryId == bytes32(0)) { return EXCHANGE_REGISTRY_ID; } else { return exchangeRegistryId; } } /** * @notice Returns the value of a given number of units given the current inflation factor. * @param units The units to convert to value. * @return The value corresponding to `units` given the current inflation factor. */ function unitsToValue(uint256 units) public view returns (uint256) { FixidityLib.Fraction memory updatedInflationFactor; (updatedInflationFactor, ) = getUpdatedInflationFactor(); // We're ok using FixidityLib.divide here because updatedInflationFactor is // not going to surpass maxFixedDivisor any time soon. // Quick upper-bound estimation: if annual inflation were 5% (an order of // magnitude more than the initial proposal of 0.5%), in 500 years, the // inflation factor would be on the order of 10**10, which is still a safe // divisor. return FixidityLib.newFixed(units).divide(updatedInflationFactor).fromFixed(); } /** * @notice Returns the units for a given value given the current inflation factor. * @param inflationFactor The current inflation factor. * @param value The value to convert to units. * @return The units corresponding to `value` given the current inflation factor. * @dev We assume any function calling this will have updated the inflation factor. */ function _valueToUnits(FixidityLib.Fraction memory inflationFactor, uint256 value) private pure returns (uint256) { return inflationFactor.multiply(FixidityLib.newFixed(value)).fromFixed(); } /** * @notice Computes the up-to-date inflation factor. * @return Current inflation factor. * @return Last time when the returned inflation factor was updated. */ function getUpdatedInflationFactor() private view returns (FixidityLib.Fraction memory, uint256) { /* solhint-disable not-rely-on-time */ if (now < inflationState.factorLastUpdated.add(inflationState.updatePeriod)) { return (inflationState.factor, inflationState.factorLastUpdated); } uint256 numerator; uint256 denominator; // TODO: handle retroactive updates given decreases to updatePeriod uint256 timesToApplyInflation = now.sub(inflationState.factorLastUpdated).div(inflationState.updatePeriod); (numerator, denominator) = fractionMulExp( inflationState.factor.unwrap(), FixidityLib.fixed1().unwrap(), inflationState.rate.unwrap(), FixidityLib.fixed1().unwrap(), timesToApplyInflation, decimals_ ); // This should never happen. If something went wrong updating the // inflation factor, keep the previous factor if (numerator == 0 || denominator == 0) { return (inflationState.factor, inflationState.factorLastUpdated); } FixidityLib.Fraction memory currentInflationFactor = FixidityLib.wrap(numerator).divide( FixidityLib.wrap(denominator) ); uint256 lastUpdated = inflationState.factorLastUpdated.add( inflationState.updatePeriod.mul(now.sub(inflationState.factorLastUpdated)).div(inflationState.updatePeriod) ); return (currentInflationFactor, lastUpdated); /* solhint-enable not-rely-on-time */ } /** * @notice Transfers `value` from `msg.sender` to `to` * @param to The address to transfer to. * @param value The amount to be transferred. */ // solhint-disable-next-line no-simple-event-func-name function transfer(address to, uint256 value) public updateInflationFactor onlyWhenNotFrozen returns (bool) { return _transfer(to, value); } /** * @notice Transfers StableToken from one address to another * @param to The address to transfer StableToken to. * @param value The amount of StableToken to be transferred. */ function _transfer(address to, uint256 value) internal returns (bool) { require(to != address(0), "transfer attempted to reserved address 0x0"); uint256 units = _valueToUnits(inflationState.factor, value); require(balances[msg.sender] >= units, "transfer value exceeded balance of sender"); balances[msg.sender] = balances[msg.sender].sub(units); balances[to] = balances[to].add(units); emit Transfer(msg.sender, to, value); return true; } /** * @notice Reserve balance for making payments for gas in this StableToken currency. * @param from The account to reserve balance from * @param value The amount of balance to reserve * @dev Note that this function is called by the protocol when paying for tx fees in this * currency. After the tx is executed, gas is refunded to the sender and credited to the * various tx fee recipients via a call to `creditGasFees`. Note too that the events emitted * by `creditGasFees` reflect the *net* gas fee payments for the transaction. */ function debitGasFees(address from, uint256 value) external onlyVm onlyWhenNotFrozen updateInflationFactor { uint256 units = _valueToUnits(inflationState.factor, value); balances[from] = balances[from].sub(units); totalSupply_ = totalSupply_.sub(units); } /** * @notice Alternative function to credit balance after making payments * for gas in this StableToken currency. * @param from The account to debit balance from * @param feeRecipient Coinbase address * @param gatewayFeeRecipient Gateway address * @param communityFund Community fund address * @param tipTxFee Coinbase fee * @param baseTxFee Community fund fee * @param gatewayFee Gateway fee * @dev Note that this function is called by the protocol when paying for tx fees in this * currency. Before the tx is executed, gas is debited from the sender via a call to * `debitGasFees`. Note too that the events emitted by `creditGasFees` reflect the *net* gas fee * payments for the transaction. */ function creditGasFees( address from, address feeRecipient, address gatewayFeeRecipient, address communityFund, uint256 refund, uint256 tipTxFee, uint256 gatewayFee, uint256 baseTxFee ) external onlyVm onlyWhenNotFrozen { uint256 units = _valueToUnits(inflationState.factor, refund); balances[from] = balances[from].add(units); units = units.add(_creditGas(from, communityFund, baseTxFee)); units = units.add(_creditGas(from, feeRecipient, tipTxFee)); units = units.add(_creditGas(from, gatewayFeeRecipient, gatewayFee)); totalSupply_ = totalSupply_.add(units); } function _creditGas( address from, address to, uint256 value ) internal returns (uint256) { if (to == address(0)) { return 0; } uint256 units = _valueToUnits(inflationState.factor, value); balances[to] = balances[to].add(units); emit Transfer(from, to, value); return units; } }
/lib/mento-core/contracts/common/CalledByVm.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; contract CalledByVm { modifier onlyVm() { require(msg.sender == address(0), "Only VM can call"); _; } }
/lib/mento-core/contracts/common/FixidityLib.sol
pragma solidity ^0.5.13; /** * @title FixidityLib * @author Gadi Guy, Alberto Cuesta Canada * @notice This library provides fixed point arithmetic with protection against * overflow. * All operations are done with uint256 and the operands must have been created * with any of the newFrom* functions, which shift the comma digits() to the * right and check for limits, or with wrap() which expects a number already * in the internal representation of a fraction. * When using this library be sure to use maxNewFixed() as the upper limit for * creation of fixed point numbers. * @dev All contained functions are pure and thus marked internal to be inlined * on consuming contracts at compile time for gas efficiency. */ library FixidityLib { struct Fraction { uint256 value; } /** * @notice Number of positions that the comma is shifted to the right. */ function digits() internal pure returns (uint8) { return 24; } uint256 private constant FIXED1_UINT = 1000000000000000000000000; /** * @notice This is 1 in the fixed point units used in this library. * @dev Test fixed1() equals 10^digits() * Hardcoded to 24 digits. */ function fixed1() internal pure returns (Fraction memory) { return Fraction(FIXED1_UINT); } /** * @notice Wrap a uint256 that represents a 24-decimal fraction in a Fraction * struct. * @param x Number that already represents a 24-decimal fraction. * @return A Fraction struct with contents x. */ function wrap(uint256 x) internal pure returns (Fraction memory) { return Fraction(x); } /** * @notice Unwraps the uint256 inside of a Fraction struct. */ function unwrap(Fraction memory x) internal pure returns (uint256) { return x.value; } /** * @notice The amount of decimals lost on each multiplication operand. * @dev Test mulPrecision() equals sqrt(fixed1) */ function mulPrecision() internal pure returns (uint256) { return 1000000000000; } /** * @notice Maximum value that can be converted to fixed point. Optimize for deployment. * @dev * Test maxNewFixed() equals maxUint256() / fixed1() */ function maxNewFixed() internal pure returns (uint256) { return 115792089237316195423570985008687907853269984665640564; } /** * @notice Converts a uint256 to fixed point Fraction * @dev Test newFixed(0) returns 0 * Test newFixed(1) returns fixed1() * Test newFixed(maxNewFixed()) returns maxNewFixed() * fixed1() * Test newFixed(maxNewFixed()+1) fails */ function newFixed(uint256 x) internal pure returns (Fraction memory) { require(x <= maxNewFixed(), "can't create fixidity number larger than maxNewFixed()"); return Fraction(x * FIXED1_UINT); } /** * @notice Converts a uint256 in the fixed point representation of this * library to a non decimal. All decimal digits will be truncated. */ function fromFixed(Fraction memory x) internal pure returns (uint256) { return x.value / FIXED1_UINT; } /** * @notice Converts two uint256 representing a fraction to fixed point units, * equivalent to multiplying dividend and divisor by 10^digits(). * @param numerator numerator must be <= maxNewFixed() * @param denominator denominator must be <= maxNewFixed() and denominator can't be 0 * @dev * Test newFixedFraction(1,0) fails * Test newFixedFraction(0,1) returns 0 * Test newFixedFraction(1,1) returns fixed1() * Test newFixedFraction(1,fixed1()) returns 1 */ function newFixedFraction(uint256 numerator, uint256 denominator) internal pure returns (Fraction memory) { Fraction memory convertedNumerator = newFixed(numerator); Fraction memory convertedDenominator = newFixed(denominator); return divide(convertedNumerator, convertedDenominator); } /** * @notice Returns the integer part of a fixed point number. * @dev * Test integer(0) returns 0 * Test integer(fixed1()) returns fixed1() * Test integer(newFixed(maxNewFixed())) returns maxNewFixed()*fixed1() */ function integer(Fraction memory x) internal pure returns (Fraction memory) { return Fraction((x.value / FIXED1_UINT) * FIXED1_UINT); // Can't overflow } /** * @notice Returns the fractional part of a fixed point number. * In the case of a negative number the fractional is also negative. * @dev * Test fractional(0) returns 0 * Test fractional(fixed1()) returns 0 * Test fractional(fixed1()-1) returns 10^24-1 */ function fractional(Fraction memory x) internal pure returns (Fraction memory) { return Fraction(x.value - (x.value / FIXED1_UINT) * FIXED1_UINT); // Can't overflow } /** * @notice x+y. * @dev The maximum value that can be safely used as an addition operator is defined as * maxFixedAdd = maxUint256()-1 / 2, or * 57896044618658097711785492504343953926634992332820282019728792003956564819967. * Test add(maxFixedAdd,maxFixedAdd) equals maxFixedAdd + maxFixedAdd * Test add(maxFixedAdd+1,maxFixedAdd+1) throws */ function add(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) { uint256 z = x.value + y.value; require(z >= x.value, "add overflow detected"); return Fraction(z); } /** * @notice x-y. * @dev * Test subtract(6, 10) fails */ function subtract(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) { require(x.value >= y.value, "substraction underflow detected"); return Fraction(x.value - y.value); } /** * @notice x*y. If any of the operators is higher than the max multiplier value it * might overflow. * @dev The maximum value that can be safely used as a multiplication operator * (maxFixedMul) is calculated as sqrt(maxUint256()*fixed1()), * or 340282366920938463463374607431768211455999999999999 * Test multiply(0,0) returns 0 * Test multiply(maxFixedMul,0) returns 0 * Test multiply(0,maxFixedMul) returns 0 * Test multiply(fixed1()/mulPrecision(),fixed1()*mulPrecision()) returns fixed1() * Test multiply(maxFixedMul,maxFixedMul) is around maxUint256() * Test multiply(maxFixedMul+1,maxFixedMul+1) fails */ // solhint-disable-next-line code-complexity function multiply(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) { if (x.value == 0 || y.value == 0) return Fraction(0); if (y.value == FIXED1_UINT) return x; if (x.value == FIXED1_UINT) return y; // Separate into integer and fractional parts // x = x1 + x2, y = y1 + y2 uint256 x1 = integer(x).value / FIXED1_UINT; uint256 x2 = fractional(x).value; uint256 y1 = integer(y).value / FIXED1_UINT; uint256 y2 = fractional(y).value; // (x1 + x2) * (y1 + y2) = (x1 * y1) + (x1 * y2) + (x2 * y1) + (x2 * y2) uint256 x1y1 = x1 * y1; if (x1 != 0) require(x1y1 / x1 == y1, "overflow x1y1 detected"); // x1y1 needs to be multiplied back by fixed1 // solhint-disable-next-line var-name-mixedcase uint256 fixed_x1y1 = x1y1 * FIXED1_UINT; if (x1y1 != 0) require(fixed_x1y1 / x1y1 == FIXED1_UINT, "overflow x1y1 * fixed1 detected"); x1y1 = fixed_x1y1; uint256 x2y1 = x2 * y1; if (x2 != 0) require(x2y1 / x2 == y1, "overflow x2y1 detected"); uint256 x1y2 = x1 * y2; if (x1 != 0) require(x1y2 / x1 == y2, "overflow x1y2 detected"); x2 = x2 / mulPrecision(); y2 = y2 / mulPrecision(); uint256 x2y2 = x2 * y2; if (x2 != 0) require(x2y2 / x2 == y2, "overflow x2y2 detected"); // result = fixed1() * x1 * y1 + x1 * y2 + x2 * y1 + x2 * y2 / fixed1(); Fraction memory result = Fraction(x1y1); result = add(result, Fraction(x2y1)); // Add checks for overflow result = add(result, Fraction(x1y2)); // Add checks for overflow result = add(result, Fraction(x2y2)); // Add checks for overflow return result; } /** * @notice 1/x * @dev * Test reciprocal(0) fails * Test reciprocal(fixed1()) returns fixed1() * Test reciprocal(fixed1()*fixed1()) returns 1 // Testing how the fractional is truncated * Test reciprocal(1+fixed1()*fixed1()) returns 0 // Testing how the fractional is truncated * Test reciprocal(newFixedFraction(1, 1e24)) returns newFixed(1e24) */ function reciprocal(Fraction memory x) internal pure returns (Fraction memory) { require(x.value != 0, "can't call reciprocal(0)"); return Fraction((FIXED1_UINT * FIXED1_UINT) / x.value); // Can't overflow } /** * @notice x/y. If the dividend is higher than the max dividend value, it * might overflow. You can use multiply(x,reciprocal(y)) instead. * @dev The maximum value that can be safely used as a dividend (maxNewFixed) is defined as * divide(maxNewFixed,newFixedFraction(1,fixed1())) is around maxUint256(). * This yields the value 115792089237316195423570985008687907853269984665640564. * Test maxNewFixed equals maxUint256()/fixed1() * Test divide(maxNewFixed,1) equals maxNewFixed*(fixed1) * Test divide(maxNewFixed+1,multiply(mulPrecision(),mulPrecision())) throws * Test divide(fixed1(),0) fails * Test divide(maxNewFixed,1) = maxNewFixed*(10^digits()) * Test divide(maxNewFixed+1,1) throws */ function divide(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) { require(y.value != 0, "can't divide by 0"); // solhint-disable-next-line var-name-mixedcase uint256 X = x.value * FIXED1_UINT; require(X / FIXED1_UINT == x.value, "overflow at divide"); return Fraction(X / y.value); } /** * @notice x > y */ function gt(Fraction memory x, Fraction memory y) internal pure returns (bool) { return x.value > y.value; } /** * @notice x >= y */ function gte(Fraction memory x, Fraction memory y) internal pure returns (bool) { return x.value >= y.value; } /** * @notice x < y */ function lt(Fraction memory x, Fraction memory y) internal pure returns (bool) { return x.value < y.value; } /** * @notice x <= y */ function lte(Fraction memory x, Fraction memory y) internal pure returns (bool) { return x.value <= y.value; } /** * @notice x == y */ function equals(Fraction memory x, Fraction memory y) internal pure returns (bool) { return x.value == y.value; } /** * @notice x <= 1 */ function isProperFraction(Fraction memory x) internal pure returns (bool) { return lte(x, fixed1()); } }
/lib/mento-core/contracts/common/Freezable.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; import "./UsingRegistry.sol"; contract Freezable is UsingRegistry { // onlyWhenNotFrozen functions can only be called when `frozen` is false, otherwise they will // revert. modifier onlyWhenNotFrozen() { require(!getFreezer().isFrozen(address(this)), "can't call when contract is frozen"); _; } }
/lib/mento-core/contracts/common/Initializable.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; contract Initializable { bool public initialized; constructor(bool testingDeployment) public { if (!testingDeployment) { initialized = true; } } modifier initializer() { require(!initialized, "contract already initialized"); initialized = true; _; } }
/lib/mento-core/contracts/common/UsingPrecompiles.sol
// SPDX-License-Identifier: GPL-3.0-or-later // solhint-disable state-visibility pragma solidity ^0.5.13; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; import "./interfaces/ICeloVersionedContract.sol"; contract UsingPrecompiles { using SafeMath for uint256; address constant TRANSFER = address(0xff - 2); address constant FRACTION_MUL = address(0xff - 3); address constant PROOF_OF_POSSESSION = address(0xff - 4); address constant GET_VALIDATOR = address(0xff - 5); address constant NUMBER_VALIDATORS = address(0xff - 6); address constant EPOCH_SIZE = address(0xff - 7); address constant BLOCK_NUMBER_FROM_HEADER = address(0xff - 8); address constant HASH_HEADER = address(0xff - 9); address constant GET_PARENT_SEAL_BITMAP = address(0xff - 10); address constant GET_VERIFIED_SEAL_BITMAP = address(0xff - 11); /** * @notice calculate a * b^x for fractions a, b to `decimals` precision * @param aNumerator Numerator of first fraction * @param aDenominator Denominator of first fraction * @param bNumerator Numerator of exponentiated fraction * @param bDenominator Denominator of exponentiated fraction * @param exponent exponent to raise b to * @param _decimals precision * @return Numerator of the computed quantity (not reduced). * @return Denominator of the computed quantity (not reduced). */ function fractionMulExp( uint256 aNumerator, uint256 aDenominator, uint256 bNumerator, uint256 bDenominator, uint256 exponent, uint256 _decimals ) public view returns (uint256, uint256) { require(aDenominator != 0 && bDenominator != 0, "a denominator is zero"); uint256 returnNumerator; uint256 returnDenominator; bool success; bytes memory out; (success, out) = FRACTION_MUL.staticcall( abi.encodePacked(aNumerator, aDenominator, bNumerator, bDenominator, exponent, _decimals) ); require(success, "error calling fractionMulExp precompile"); returnNumerator = getUint256FromBytes(out, 0); returnDenominator = getUint256FromBytes(out, 32); return (returnNumerator, returnDenominator); } /** * @notice Returns the current epoch size in blocks. * @return The current epoch size in blocks. */ function getEpochSize() public view returns (uint256) { bytes memory out; bool success; (success, out) = EPOCH_SIZE.staticcall(abi.encodePacked()); require(success, "error calling getEpochSize precompile"); return getUint256FromBytes(out, 0); } /** * @notice Returns the epoch number at a block. * @param blockNumber Block number where epoch number is calculated. * @return Epoch number. */ function getEpochNumberOfBlock(uint256 blockNumber) public view returns (uint256) { return epochNumberOfBlock(blockNumber, getEpochSize()); } /** * @notice Returns the epoch number at a block. * @return Current epoch number. */ function getEpochNumber() public view returns (uint256) { return getEpochNumberOfBlock(block.number); } /** * @notice Returns the epoch number at a block. * @param blockNumber Block number where epoch number is calculated. * @param epochSize The epoch size in blocks. * @return Epoch number. */ function epochNumberOfBlock(uint256 blockNumber, uint256 epochSize) internal pure returns (uint256) { // Follows GetEpochNumber from celo-blockchain/blob/master/consensus/istanbul/utils.go uint256 epochNumber = blockNumber / epochSize; if (blockNumber % epochSize == 0) { return epochNumber; } else { return epochNumber.add(1); } } /** * @notice Gets a validator address from the current validator set. * @param index Index of requested validator in the validator set. * @return Address of validator at the requested index. */ function validatorSignerAddressFromCurrentSet(uint256 index) public view returns (address) { bytes memory out; bool success; (success, out) = GET_VALIDATOR.staticcall(abi.encodePacked(index, uint256(block.number))); require(success, "error calling validatorSignerAddressFromCurrentSet precompile"); return address(getUint256FromBytes(out, 0)); } /** * @notice Gets a validator address from the validator set at the given block number. * @param index Index of requested validator in the validator set. * @param blockNumber Block number to retrieve the validator set from. * @return Address of validator at the requested index. */ function validatorSignerAddressFromSet(uint256 index, uint256 blockNumber) public view returns (address) { bytes memory out; bool success; (success, out) = GET_VALIDATOR.staticcall(abi.encodePacked(index, blockNumber)); require(success, "error calling validatorSignerAddressFromSet precompile"); return address(getUint256FromBytes(out, 0)); } /** * @notice Gets the size of the current elected validator set. * @return Size of the current elected validator set. */ function numberValidatorsInCurrentSet() public view returns (uint256) { bytes memory out; bool success; (success, out) = NUMBER_VALIDATORS.staticcall(abi.encodePacked(uint256(block.number))); require(success, "error calling numberValidatorsInCurrentSet precompile"); return getUint256FromBytes(out, 0); } /** * @notice Gets the size of the validator set that must sign the given block number. * @param blockNumber Block number to retrieve the validator set from. * @return Size of the validator set. */ function numberValidatorsInSet(uint256 blockNumber) public view returns (uint256) { bytes memory out; bool success; (success, out) = NUMBER_VALIDATORS.staticcall(abi.encodePacked(blockNumber)); require(success, "error calling numberValidatorsInSet precompile"); return getUint256FromBytes(out, 0); } /** * @notice Checks a BLS proof of possession. * @param sender The address signed by the BLS key to generate the proof of possession. * @param blsKey The BLS public key that the validator is using for consensus, should pass proof * of possession. 48 bytes. * @param blsPop The BLS public key proof-of-possession, which consists of a signature on the * account address. 96 bytes. * @return True upon success. */ function checkProofOfPossession( address sender, bytes memory blsKey, bytes memory blsPop ) public view returns (bool) { bool success; (success, ) = PROOF_OF_POSSESSION.staticcall(abi.encodePacked(sender, blsKey, blsPop)); return success; } /** * @notice Parses block number out of header. * @param header RLP encoded header * @return Block number. */ function getBlockNumberFromHeader(bytes memory header) public view returns (uint256) { bytes memory out; bool success; (success, out) = BLOCK_NUMBER_FROM_HEADER.staticcall(abi.encodePacked(header)); require(success, "error calling getBlockNumberFromHeader precompile"); return getUint256FromBytes(out, 0); } /** * @notice Computes hash of header. * @param header RLP encoded header * @return Header hash. */ function hashHeader(bytes memory header) public view returns (bytes32) { bytes memory out; bool success; (success, out) = HASH_HEADER.staticcall(abi.encodePacked(header)); require(success, "error calling hashHeader precompile"); return getBytes32FromBytes(out, 0); } /** * @notice Gets the parent seal bitmap from the header at the given block number. * @param blockNumber Block number to retrieve. Must be within 4 epochs of the current number. * @return Bitmap parent seal with set bits at indices corresponding to signing validators. */ function getParentSealBitmap(uint256 blockNumber) public view returns (bytes32) { bytes memory out; bool success; (success, out) = GET_PARENT_SEAL_BITMAP.staticcall(abi.encodePacked(blockNumber)); require(success, "error calling getParentSealBitmap precompile"); return getBytes32FromBytes(out, 0); } /** * @notice Verifies the BLS signature on the header and returns the seal bitmap. * The validator set used for verification is retrieved based on the parent hash field of the * header. If the parent hash is not in the blockchain, verification fails. * @param header RLP encoded header * @return Bitmap parent seal with set bits at indices correspoinding to signing validators. */ function getVerifiedSealBitmapFromHeader(bytes memory header) public view returns (bytes32) { bytes memory out; bool success; (success, out) = GET_VERIFIED_SEAL_BITMAP.staticcall(abi.encodePacked(header)); require(success, "error calling getVerifiedSealBitmapFromHeader precompile"); return getBytes32FromBytes(out, 0); } /** * @notice Converts bytes to uint256. * @param bs byte[] data * @param start offset into byte data to convert * @return uint256 data */ function getUint256FromBytes(bytes memory bs, uint256 start) internal pure returns (uint256) { return uint256(getBytes32FromBytes(bs, start)); } /** * @notice Converts bytes to bytes32. * @param bs byte[] data * @param start offset into byte data to convert * @return bytes32 data */ function getBytes32FromBytes(bytes memory bs, uint256 start) internal pure returns (bytes32) { require(bs.length >= start.add(32), "slicing out of range"); bytes32 x; // solhint-disable-next-line no-inline-assembly assembly { x := mload(add(bs, add(start, 32))) } return x; } /** * @notice Returns the minimum number of required signers for a given block number. * @dev Computed in celo-blockchain as int(math.Ceil(float64(2*valSet.Size()) / 3)) */ function minQuorumSize(uint256 blockNumber) public view returns (uint256) { return numberValidatorsInSet(blockNumber).mul(2).add(2).div(3); } /** * @notice Computes byzantine quorum from current validator set size * @return Byzantine quorum of validators. */ function minQuorumSizeInCurrentSet() public view returns (uint256) { return minQuorumSize(block.number); } }
/lib/mento-core/contracts/common/UsingRegistry.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; import "./interfaces/IFreezer.sol"; import "./interfaces/IRegistry.sol"; import "../interfaces/IExchange.sol"; import "../interfaces/IReserve.sol"; import "../interfaces/ISortedOracles.sol"; import "../interfaces/IStableToken.sol"; contract UsingRegistry is Ownable { event RegistrySet(address indexed registryAddress); // solhint-disable state-visibility bytes32 constant ACCOUNTS_REGISTRY_ID = keccak256(abi.encodePacked("Accounts")); bytes32 constant ATTESTATIONS_REGISTRY_ID = keccak256(abi.encodePacked("Attestations")); bytes32 constant DOWNTIME_SLASHER_REGISTRY_ID = keccak256(abi.encodePacked("DowntimeSlasher")); bytes32 constant DOUBLE_SIGNING_SLASHER_REGISTRY_ID = keccak256(abi.encodePacked("DoubleSigningSlasher")); bytes32 constant ELECTION_REGISTRY_ID = keccak256(abi.encodePacked("Election")); bytes32 constant EXCHANGE_REGISTRY_ID = keccak256(abi.encodePacked("Exchange")); bytes32 constant FEE_CURRENCY_WHITELIST_REGISTRY_ID = keccak256(abi.encodePacked("FeeCurrencyWhitelist")); bytes32 constant FREEZER_REGISTRY_ID = keccak256(abi.encodePacked("Freezer")); bytes32 constant GOLD_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked("GoldToken")); bytes32 constant GOVERNANCE_REGISTRY_ID = keccak256(abi.encodePacked("Governance")); bytes32 constant GOVERNANCE_SLASHER_REGISTRY_ID = keccak256(abi.encodePacked("GovernanceSlasher")); bytes32 constant LOCKED_GOLD_REGISTRY_ID = keccak256(abi.encodePacked("LockedGold")); bytes32 constant RESERVE_REGISTRY_ID = keccak256(abi.encodePacked("Reserve")); bytes32 constant RANDOM_REGISTRY_ID = keccak256(abi.encodePacked("Random")); bytes32 constant SORTED_ORACLES_REGISTRY_ID = keccak256(abi.encodePacked("SortedOracles")); bytes32 constant STABLE_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked("StableToken")); bytes32 constant VALIDATORS_REGISTRY_ID = keccak256(abi.encodePacked("Validators")); // solhint-enable state-visibility IRegistry public registry; modifier onlyRegisteredContract(bytes32 identifierHash) { require(registry.getAddressForOrDie(identifierHash) == msg.sender, "only registered contract"); _; } modifier onlyRegisteredContracts(bytes32[] memory identifierHashes) { require(registry.isOneOf(identifierHashes, msg.sender), "only registered contracts"); _; } /** * @notice Updates the address pointing to a Registry contract. * @param registryAddress The address of a registry contract for routing to other contracts. */ function setRegistry(address registryAddress) public onlyOwner { require(registryAddress != address(0), "Cannot register the null address"); registry = IRegistry(registryAddress); emit RegistrySet(registryAddress); } function getExchange() internal view returns (IExchange) { return IExchange(registry.getAddressForOrDie(EXCHANGE_REGISTRY_ID)); } function getFreezer() internal view returns (IFreezer) { return IFreezer(registry.getAddressForOrDie(FREEZER_REGISTRY_ID)); } function getGoldToken() internal view returns (IERC20) { return IERC20(registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID)); } function getReserve() internal view returns (IReserve) { return IReserve(registry.getAddressForOrDie(RESERVE_REGISTRY_ID)); } function getSortedOracles() internal view returns (ISortedOracles) { return ISortedOracles(registry.getAddressForOrDie(SORTED_ORACLES_REGISTRY_ID)); } function getStableToken() internal view returns (IStableToken) { return IStableToken(registry.getAddressForOrDie(STABLE_TOKEN_REGISTRY_ID)); } }
/lib/mento-core/contracts/common/interfaces/ICeloVersionedContract.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; interface ICeloVersionedContract { /** * @notice Returns the storage, major, minor, and patch version of the contract. * @return Storage version of the contract. * @return Major version of the contract. * @return Minor version of the contract. * @return Patch version of the contract. */ function getVersionNumber() external pure returns ( uint256, uint256, uint256, uint256 ); }
/lib/mento-core/contracts/common/interfaces/IERC20Metadata.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; interface IERC20Metadata { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); /** * @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 `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
/lib/mento-core/contracts/common/interfaces/IFreezer.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; interface IFreezer { function isFrozen(address) external view returns (bool); }
/lib/mento-core/contracts/common/interfaces/IRegistry.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; interface IRegistry { function setAddressFor(string calldata, address) external; function getAddressForOrDie(bytes32) external view returns (address); function getAddressFor(bytes32) external view returns (address); function getAddressForStringOrDie(string calldata identifier) external view returns (address); function getAddressForString(string calldata identifier) external view returns (address); function isOneOf(bytes32[] calldata, address) external view returns (bool); }
/lib/mento-core/contracts/common/linkedlists/LinkedList.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; /** * @title Maintains a doubly linked list keyed by bytes32. * @dev Following the `next` pointers will lead you to the head, rather than the tail. */ library LinkedList { using SafeMath for uint256; struct Element { bytes32 previousKey; bytes32 nextKey; bool exists; } struct List { bytes32 head; bytes32 tail; uint256 numElements; mapping(bytes32 => Element) elements; } /** * @notice Inserts an element into a doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to insert. * @param previousKey The key of the element that comes before the element to insert. * @param nextKey The key of the element that comes after the element to insert. */ function insert( List storage list, bytes32 key, bytes32 previousKey, bytes32 nextKey ) internal { require(key != bytes32(0), "Key must be defined"); require(!contains(list, key), "Can't insert an existing element"); require(previousKey != key && nextKey != key, "Key cannot be the same as previousKey or nextKey"); Element storage element = list.elements[key]; element.exists = true; if (list.numElements == 0) { list.tail = key; list.head = key; } else { require(previousKey != bytes32(0) || nextKey != bytes32(0), "Either previousKey or nextKey must be defined"); element.previousKey = previousKey; element.nextKey = nextKey; if (previousKey != bytes32(0)) { require(contains(list, previousKey), "If previousKey is defined, it must exist in the list"); Element storage previousElement = list.elements[previousKey]; require(previousElement.nextKey == nextKey, "previousKey must be adjacent to nextKey"); previousElement.nextKey = key; } else { list.tail = key; } if (nextKey != bytes32(0)) { require(contains(list, nextKey), "If nextKey is defined, it must exist in the list"); Element storage nextElement = list.elements[nextKey]; require(nextElement.previousKey == previousKey, "previousKey must be adjacent to nextKey"); nextElement.previousKey = key; } else { list.head = key; } } list.numElements = list.numElements.add(1); } /** * @notice Inserts an element at the tail of the doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to insert. */ function push(List storage list, bytes32 key) internal { insert(list, key, bytes32(0), list.tail); } /** * @notice Removes an element from the doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to remove. */ function remove(List storage list, bytes32 key) internal { Element storage element = list.elements[key]; require(key != bytes32(0) && contains(list, key), "key not in list"); if (element.previousKey != bytes32(0)) { Element storage previousElement = list.elements[element.previousKey]; previousElement.nextKey = element.nextKey; } else { list.tail = element.nextKey; } if (element.nextKey != bytes32(0)) { Element storage nextElement = list.elements[element.nextKey]; nextElement.previousKey = element.previousKey; } else { list.head = element.previousKey; } delete list.elements[key]; list.numElements = list.numElements.sub(1); } /** * @notice Updates an element in the list. * @param list A storage pointer to the underlying list. * @param key The element key. * @param previousKey The key of the element that comes before the updated element. * @param nextKey The key of the element that comes after the updated element. */ function update( List storage list, bytes32 key, bytes32 previousKey, bytes32 nextKey ) internal { require(key != bytes32(0) && key != previousKey && key != nextKey && contains(list, key), "key on in list"); remove(list, key); insert(list, key, previousKey, nextKey); } /** * @notice Returns whether or not a particular key is present in the sorted list. * @param list A storage pointer to the underlying list. * @param key The element key. * @return Whether or not the key is in the sorted list. */ function contains(List storage list, bytes32 key) internal view returns (bool) { return list.elements[key].exists; } /** * @notice Returns the keys of the N elements at the head of the list. * @param list A storage pointer to the underlying list. * @param n The number of elements to return. * @return The keys of the N elements at the head of the list. * @dev Reverts if n is greater than the number of elements in the list. */ function headN(List storage list, uint256 n) internal view returns (bytes32[] memory) { require(n <= list.numElements, "not enough elements"); bytes32[] memory keys = new bytes32[](n); bytes32 key = list.head; for (uint256 i = 0; i < n; i = i.add(1)) { keys[i] = key; key = list.elements[key].previousKey; } return keys; } /** * @notice Gets all element keys from the doubly linked list. * @param list A storage pointer to the underlying list. * @return All element keys from head to tail. */ function getKeys(List storage list) internal view returns (bytes32[] memory) { return headN(list, list.numElements); } }
/lib/mento-core/contracts/common/linkedlists/SortedLinkedList.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; import "./LinkedList.sol"; /** * @title Maintains a sorted list of unsigned ints keyed by bytes32. */ library SortedLinkedList { using SafeMath for uint256; using LinkedList for LinkedList.List; struct List { LinkedList.List list; mapping(bytes32 => uint256) values; } /** * @notice Inserts an element into a doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to insert. * @param value The element value. * @param lesserKey The key of the element less than the element to insert. * @param greaterKey The key of the element greater than the element to insert. */ function insert( List storage list, bytes32 key, uint256 value, bytes32 lesserKey, bytes32 greaterKey ) internal { require(key != bytes32(0) && key != lesserKey && key != greaterKey && !contains(list, key), "invalid key"); require( (lesserKey != bytes32(0) || greaterKey != bytes32(0)) || list.list.numElements == 0, "greater and lesser key zero" ); require(contains(list, lesserKey) || lesserKey == bytes32(0), "invalid lesser key"); require(contains(list, greaterKey) || greaterKey == bytes32(0), "invalid greater key"); (lesserKey, greaterKey) = getLesserAndGreater(list, value, lesserKey, greaterKey); list.list.insert(key, lesserKey, greaterKey); list.values[key] = value; } /** * @notice Removes an element from the doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to remove. */ function remove(List storage list, bytes32 key) internal { list.list.remove(key); list.values[key] = 0; } /** * @notice Updates an element in the list. * @param list A storage pointer to the underlying list. * @param key The element key. * @param value The element value. * @param lesserKey The key of the element will be just left of `key` after the update. * @param greaterKey The key of the element will be just right of `key` after the update. * @dev Note that only one of "lesserKey" or "greaterKey" needs to be correct to reduce friction. */ function update( List storage list, bytes32 key, uint256 value, bytes32 lesserKey, bytes32 greaterKey ) internal { remove(list, key); insert(list, key, value, lesserKey, greaterKey); } /** * @notice Inserts an element at the tail of the doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to insert. */ function push(List storage list, bytes32 key) internal { insert(list, key, 0, bytes32(0), list.list.tail); } /** * @notice Removes N elements from the head of the list and returns their keys. * @param list A storage pointer to the underlying list. * @param n The number of elements to pop. * @return The keys of the popped elements. */ function popN(List storage list, uint256 n) internal returns (bytes32[] memory) { require(n <= list.list.numElements, "not enough elements"); bytes32[] memory keys = new bytes32[](n); for (uint256 i = 0; i < n; i = i.add(1)) { bytes32 key = list.list.head; keys[i] = key; remove(list, key); } return keys; } /** * @notice Returns whether or not a particular key is present in the sorted list. * @param list A storage pointer to the underlying list. * @param key The element key. * @return Whether or not the key is in the sorted list. */ function contains(List storage list, bytes32 key) internal view returns (bool) { return list.list.contains(key); } /** * @notice Returns the value for a particular key in the sorted list. * @param list A storage pointer to the underlying list. * @param key The element key. * @return The element value. */ function getValue(List storage list, bytes32 key) internal view returns (uint256) { return list.values[key]; } /** * @notice Gets all elements from the doubly linked list. * @param list A storage pointer to the underlying list. * @return Array of all keys in the list. * @return Values corresponding to keys, which will be ordered largest to smallest. */ function getElements(List storage list) internal view returns (bytes32[] memory, uint256[] memory) { bytes32[] memory keys = getKeys(list); uint256[] memory values = new uint256[](keys.length); for (uint256 i = 0; i < keys.length; i = i.add(1)) { values[i] = list.values[keys[i]]; } return (keys, values); } /** * @notice Gets all element keys from the doubly linked list. * @param list A storage pointer to the underlying list. * @return All element keys from head to tail. */ function getKeys(List storage list) internal view returns (bytes32[] memory) { return list.list.getKeys(); } /** * @notice Returns first N greatest elements of the list. * @param list A storage pointer to the underlying list. * @param n The number of elements to return. * @return The keys of the first n elements. * @dev Reverts if n is greater than the number of elements in the list. */ function headN(List storage list, uint256 n) internal view returns (bytes32[] memory) { return list.list.headN(n); } /** * @notice Returns the keys of the elements greaterKey than and less than the provided value. * @param list A storage pointer to the underlying list. * @param value The element value. * @param lesserKey The key of the element which could be just left of the new value. * @param greaterKey The key of the element which could be just right of the new value. * @return The correct lesserKey keys. * @return The correct greaterKey keys. */ function getLesserAndGreater( List storage list, uint256 value, bytes32 lesserKey, bytes32 greaterKey ) private view returns (bytes32, bytes32) { // Check for one of the following conditions and fail if none are met: // 1. The value is less than the current lowest value // 2. The value is greater than the current greatest value // 3. The value is just greater than the value for `lesserKey` // 4. The value is just less than the value for `greaterKey` if (lesserKey == bytes32(0) && isValueBetween(list, value, lesserKey, list.list.tail)) { return (lesserKey, list.list.tail); } else if (greaterKey == bytes32(0) && isValueBetween(list, value, list.list.head, greaterKey)) { return (list.list.head, greaterKey); } else if ( lesserKey != bytes32(0) && isValueBetween(list, value, lesserKey, list.list.elements[lesserKey].nextKey) ) { return (lesserKey, list.list.elements[lesserKey].nextKey); } else if ( greaterKey != bytes32(0) && isValueBetween(list, value, list.list.elements[greaterKey].previousKey, greaterKey) ) { return (list.list.elements[greaterKey].previousKey, greaterKey); } else { require(false, "get lesser and greater failure"); } } /** * @notice Returns whether or not a given element is between two other elements. * @param list A storage pointer to the underlying list. * @param value The element value. * @param lesserKey The key of the element whose value should be lesserKey. * @param greaterKey The key of the element whose value should be greaterKey. * @return True if the given element is between the two other elements. */ function isValueBetween( List storage list, uint256 value, bytes32 lesserKey, bytes32 greaterKey ) private view returns (bool) { bool isLesser = lesserKey == bytes32(0) || list.values[lesserKey] <= value; bool isGreater = greaterKey == bytes32(0) || list.values[greaterKey] >= value; return isLesser && isGreater; } }
/lib/mento-core/contracts/common/linkedlists/SortedLinkedListWithMedian.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; import "./LinkedList.sol"; import "./SortedLinkedList.sol"; /** * @title Maintains a sorted list of unsigned ints keyed by bytes32. */ library SortedLinkedListWithMedian { using SafeMath for uint256; using SortedLinkedList for SortedLinkedList.List; enum MedianAction { None, Lesser, Greater } enum MedianRelation { Undefined, Lesser, Greater, Equal } struct List { SortedLinkedList.List list; bytes32 median; mapping(bytes32 => MedianRelation) relation; } /** * @notice Inserts an element into a doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to insert. * @param value The element value. * @param lesserKey The key of the element less than the element to insert. * @param greaterKey The key of the element greater than the element to insert. */ function insert( List storage list, bytes32 key, uint256 value, bytes32 lesserKey, bytes32 greaterKey ) internal { list.list.insert(key, value, lesserKey, greaterKey); LinkedList.Element storage element = list.list.list.elements[key]; MedianAction action = MedianAction.None; if (list.list.list.numElements == 1) { list.median = key; list.relation[key] = MedianRelation.Equal; } else if (list.list.list.numElements % 2 == 1) { // When we have an odd number of elements, and the element that we inserted is less than // the previous median, we need to slide the median down one element, since we had previously // selected the greater of the two middle elements. if (element.previousKey == bytes32(0) || list.relation[element.previousKey] == MedianRelation.Lesser) { action = MedianAction.Lesser; list.relation[key] = MedianRelation.Lesser; } else { list.relation[key] = MedianRelation.Greater; } } else { // When we have an even number of elements, and the element that we inserted is greater than // the previous median, we need to slide the median up one element, since we always select // the greater of the two middle elements. if (element.nextKey == bytes32(0) || list.relation[element.nextKey] == MedianRelation.Greater) { action = MedianAction.Greater; list.relation[key] = MedianRelation.Greater; } else { list.relation[key] = MedianRelation.Lesser; } } updateMedian(list, action); } /** * @notice Removes an element from the doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to remove. */ function remove(List storage list, bytes32 key) internal { MedianAction action = MedianAction.None; if (list.list.list.numElements == 0) { list.median = bytes32(0); } else if (list.list.list.numElements % 2 == 0) { // When we have an even number of elements, we always choose the higher of the two medians. // Thus, if the element we're removing is greaterKey than or equal to the median we need to // slide the median left by one. if (list.relation[key] == MedianRelation.Greater || list.relation[key] == MedianRelation.Equal) { action = MedianAction.Lesser; } } else { // When we don't have an even number of elements, we just choose the median value. // Thus, if the element we're removing is less than or equal to the median, we need to slide // median right by one. if (list.relation[key] == MedianRelation.Lesser || list.relation[key] == MedianRelation.Equal) { action = MedianAction.Greater; } } updateMedian(list, action); list.list.remove(key); } /** * @notice Updates an element in the list. * @param list A storage pointer to the underlying list. * @param key The element key. * @param value The element value. * @param lesserKey The key of the element will be just left of `key` after the update. * @param greaterKey The key of the element will be just right of `key` after the update. * @dev Note that only one of "lesserKey" or "greaterKey" needs to be correct to reduce friction. */ function update( List storage list, bytes32 key, uint256 value, bytes32 lesserKey, bytes32 greaterKey ) internal { remove(list, key); insert(list, key, value, lesserKey, greaterKey); } /** * @notice Inserts an element at the tail of the doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to insert. */ function push(List storage list, bytes32 key) internal { insert(list, key, 0, bytes32(0), list.list.list.tail); } /** * @notice Removes N elements from the head of the list and returns their keys. * @param list A storage pointer to the underlying list. * @param n The number of elements to pop. * @return The keys of the popped elements. */ function popN(List storage list, uint256 n) internal returns (bytes32[] memory) { require(n <= list.list.list.numElements, "not enough elements"); bytes32[] memory keys = new bytes32[](n); for (uint256 i = 0; i < n; i = i.add(1)) { bytes32 key = list.list.list.head; keys[i] = key; remove(list, key); } return keys; } /** * @notice Returns whether or not a particular key is present in the sorted list. * @param list A storage pointer to the underlying list. * @param key The element key. * @return Whether or not the key is in the sorted list. */ function contains(List storage list, bytes32 key) internal view returns (bool) { return list.list.contains(key); } /** * @notice Returns the value for a particular key in the sorted list. * @param list A storage pointer to the underlying list. * @param key The element key. * @return The element value. */ function getValue(List storage list, bytes32 key) internal view returns (uint256) { return list.list.values[key]; } /** * @notice Returns the median value of the sorted list. * @param list A storage pointer to the underlying list. * @return The median value. */ function getMedianValue(List storage list) internal view returns (uint256) { return getValue(list, list.median); } /** * @notice Returns the key of the first element in the list. * @param list A storage pointer to the underlying list. * @return The key of the first element in the list. */ function getHead(List storage list) internal view returns (bytes32) { return list.list.list.head; } /** * @notice Returns the key of the median element in the list. * @param list A storage pointer to the underlying list. * @return The key of the median element in the list. */ function getMedian(List storage list) internal view returns (bytes32) { return list.median; } /** * @notice Returns the key of the last element in the list. * @param list A storage pointer to the underlying list. * @return The key of the last element in the list. */ function getTail(List storage list) internal view returns (bytes32) { return list.list.list.tail; } /** * @notice Returns the number of elements in the list. * @param list A storage pointer to the underlying list. * @return The number of elements in the list. */ function getNumElements(List storage list) internal view returns (uint256) { return list.list.list.numElements; } /** * @notice Gets all elements from the doubly linked list. * @param list A storage pointer to the underlying list. * @return Array of all keys in the list. * @return Values corresponding to keys, which will be ordered largest to smallest. * @return Array of relations to median of corresponding list elements. */ function getElements(List storage list) internal view returns ( bytes32[] memory, uint256[] memory, MedianRelation[] memory ) { bytes32[] memory keys = getKeys(list); uint256[] memory values = new uint256[](keys.length); MedianRelation[] memory relations = new MedianRelation[](keys.length); for (uint256 i = 0; i < keys.length; i = i.add(1)) { values[i] = list.list.values[keys[i]]; relations[i] = list.relation[keys[i]]; } return (keys, values, relations); } /** * @notice Gets all element keys from the doubly linked list. * @param list A storage pointer to the underlying list. * @return All element keys from head to tail. */ function getKeys(List storage list) internal view returns (bytes32[] memory) { return list.list.getKeys(); } /** * @notice Moves the median pointer right or left of its current value. * @param list A storage pointer to the underlying list. * @param action Which direction to move the median pointer. */ function updateMedian(List storage list, MedianAction action) private { LinkedList.Element storage previousMedian = list.list.list.elements[list.median]; if (action == MedianAction.Lesser) { list.relation[list.median] = MedianRelation.Greater; list.median = previousMedian.previousKey; } else if (action == MedianAction.Greater) { list.relation[list.median] = MedianRelation.Lesser; list.median = previousMedian.nextKey; } list.relation[list.median] = MedianRelation.Equal; } }
/lib/mento-core/contracts/interfaces/IBiPoolManager.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; pragma experimental ABIEncoderV2; import { IPricingModule } from "./IPricingModule.sol"; import { FixidityLib } from "../common/FixidityLib.sol"; /** * @title BiPool Manager interface * @notice The two asset pool manager is responsible for * managing the state of all two-asset virtual pools. */ interface IBiPoolManager { /** * @title PoolExchange * @notice The PoolExchange is a type of asset exchange that * that implements an AMM with two virtual buckets. */ struct PoolExchange { address asset0; address asset1; IPricingModule pricingModule; uint256 bucket0; uint256 bucket1; uint256 lastBucketUpdate; PoolConfig config; } /** * @notice Variables related to bucket updates and sizing. * @dev Broken down into a separate struct because the compiler * version doesn't support structs with too many members. * Sad reacts only. */ struct PoolConfig { FixidityLib.Fraction spread; address referenceRateFeedID; // rateFeedID of the price that this pool follows (i.e. it's reference rate) uint256 referenceRateResetFrequency; uint256 minimumReports; uint256 stablePoolResetSize; } /** * @notice Emitted when a new PoolExchange has been created. * @param exchangeId The id of the new PoolExchange * @param asset0 The address of asset0 * @param asset1 The address of asset1 * @param pricingModule the address of the pricingModule */ event ExchangeCreated( bytes32 indexed exchangeId, address indexed asset0, address indexed asset1, address pricingModule ); /** * @notice Emitted when a PoolExchange has been destroyed. * @param exchangeId The id of the PoolExchange * @param asset0 The address of asset0 * @param asset1 The address of asset1 * @param pricingModule the address of the pricingModule */ event ExchangeDestroyed( bytes32 indexed exchangeId, address indexed asset0, address indexed asset1, address pricingModule ); /** * @notice Emitted when the broker address is updated. * @param newBroker The address of the new broker. */ event BrokerUpdated(address indexed newBroker); /** * @notice Emitted when the reserve address is updated. * @param newReserve The address of the new reserve. */ event ReserveUpdated(address indexed newReserve); /** * @notice Emitted when the breakerBox address is updated. * @param newBreakerBox The address of the new breakerBox. */ event BreakerBoxUpdated(address newBreakerBox); /** * @notice Emitted when the sortedOracles address is updated. * @param newSortedOracles The address of the new sortedOracles. */ event SortedOraclesUpdated(address indexed newSortedOracles); /** * @notice Emitted when the buckets for a specified exchange are updated. * @param exchangeId The id of the exchange * @param bucket0 The new bucket0 size * @param bucket1 The new bucket1 size */ event BucketsUpdated(bytes32 indexed exchangeId, uint256 bucket0, uint256 bucket1); /** * @notice Retrieves the pool with the specified exchangeId. * @param exchangeId The id of the pool to be retrieved. * @return exchange The PoolExchange with that ID. */ function getPoolExchange(bytes32 exchangeId) external view returns (PoolExchange memory exchange); /** * @notice Get all exchange IDs. * @return exchangeIds List of the exchangeIds. */ function getExchangeIds() external view returns (bytes32[] memory exchangeIds); /** * @notice Create a PoolExchange with the provided data. * @param exchange The PoolExchange to be created. * @return exchangeId The id of the exchange. */ function createExchange(PoolExchange calldata exchange) external returns (bytes32 exchangeId); /** * @notice Delete a PoolExchange. * @param exchangeId The PoolExchange to be created. * @param exchangeIdIndex The index of the exchangeId in the exchangeIds array. * @return destroyed - true on successful delition. */ function destroyExchange(bytes32 exchangeId, uint256 exchangeIdIndex) external returns (bool destroyed); }
/lib/mento-core/contracts/interfaces/IBreakerBox.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; /** * @title Breaker Box Interface * @notice Defines the basic interface for the Breaker Box */ interface IBreakerBox { /** * @dev Used to track additional info about * the current trading mode a specific rate feed ID is in. * LastUpdatedTime helps to check cooldown. * LastUpdatedBlock helps to determine if check should be executed. */ struct TradingModeInfo { uint64 tradingMode; uint64 lastUpdatedTime; uint128 lastUpdatedBlock; } /** * @notice Emitted when a new breaker is added to the breaker box. * @param breaker The address of the new breaker. */ event BreakerAdded(address indexed breaker); /** * @notice Emitted when a breaker is removed from the breaker box. * @param breaker The address of the breaker that was removed. */ event BreakerRemoved(address indexed breaker); /** * @notice Emitted when a breaker is tripped by a rate feed. * @param breaker The address of the breaker that was tripped. * @param rateFeedID The address of the rate feed. */ event BreakerTripped(address indexed breaker, address indexed rateFeedID); /** * @notice Emitted when a new rate feed is added to the breaker box. * @param rateFeedID The address of the rate feed that was added. */ event RateFeedAdded(address indexed rateFeedID); /** * @notice Emitted when a rate feed is removed from the breaker box. * @param rateFeedID The rate feed that was removed. */ event RateFeedRemoved(address indexed rateFeedID); /** * @notice Emitted when the trading mode for a rate feed is updated * @param rateFeedID The address of the rataFeedID. * @param tradingMode The new trading mode of the rate feed. */ event TradingModeUpdated(address indexed rateFeedID, uint256 tradingMode); /** * @notice Emitted after a reset attempt is successful. * @param rateFeedID The address of the rate feed. * @param breaker The address of the breaker. */ event ResetSuccessful(address indexed rateFeedID, address indexed breaker); /** * @notice Emitted after a reset attempt fails when the * rate feed fails the breakers reset criteria. * @param rateFeedID The address of the rate feed. * @param breaker The address of the breaker. */ event ResetAttemptCriteriaFail(address indexed rateFeedID, address indexed breaker); /** * @notice Emitted after a reset attempt fails when cooldown time has not elapsed. * @param rateFeedID The address of the rate feed. * @param breaker The address of the breaker. */ event ResetAttemptNotCool(address indexed rateFeedID, address indexed breaker); /** * @notice Emitted when the sortedOracles address is updated. * @param newSortedOracles The address of the new sortedOracles. */ event SortedOraclesUpdated(address indexed newSortedOracles); /** * @notice Emitted when the breaker is enabled or disabled for a rate feed. * @param breaker The address of the breaker. * @param rateFeedID The address of the rate feed. * @param status Indicating the status. */ event BreakerStatusUpdated(address breaker, address rateFeedID, bool status); /** * @notice Retrives an ordered array of all breaker addresses. */ function getBreakers() external view returns (address[] memory); /** * @notice Checks if a breaker with the specified address has been added to the breaker box. * @param breaker The address of the breaker to check; * @return A bool indicating whether or not the breaker has been added. */ function isBreaker(address breaker) external view returns (bool); /** * @notice Checks breakers for the rateFeedID and sets correct trading mode * if any breakers are tripped or need to be reset. * @param rateFeedID The registryId of the rateFeedID to run checks for. */ function checkAndSetBreakers(address rateFeedID) external; /** * @notice Gets the trading mode for the specified rateFeedID. * @param rateFeedID The address of the rateFeedID to retrieve the trading mode for. */ function getRateFeedTradingMode(address rateFeedID) external view returns (uint256 tradingMode); }
/lib/mento-core/contracts/interfaces/ICeloToken.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; /** * @title This interface describes the non- ERC20 shared interface for all Celo Tokens, and * in the absence of interface inheritance is intended as a companion to IERC20.sol. */ interface ICeloToken { function transferWithComment( address, uint256, string calldata ) external returns (bool); function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); }
/lib/mento-core/contracts/interfaces/IExchange.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; interface IExchange { function buy( uint256, uint256, bool ) external returns (uint256); function sell( uint256, uint256, bool ) external returns (uint256); function exchange( uint256, uint256, bool ) external returns (uint256); function setUpdateFrequency(uint256) external; function getBuyTokenAmount(uint256, bool) external view returns (uint256); function getSellTokenAmount(uint256, bool) external view returns (uint256); function getBuyAndSellBuckets(bool) external view returns (uint256, uint256); }
/lib/mento-core/contracts/interfaces/IExchangeProvider.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; pragma experimental ABIEncoderV2; /** * @title ExchangeProvider interface * @notice The IExchangeProvider interface is the interface that the Broker uses * to communicate with different exchange manager implementations like the BiPoolManager */ interface IExchangeProvider { /** * @notice Exchange - a struct that's used only by UIs (frontends/CLIs) * in order to discover what asset swaps are possible within an * exchange provider. * It's up to the specific exchange provider to convert its internal * representation to this universal struct. This conversion should * only happen in view calls used for discovery. * @param exchangeId The ID of the exchange, used to initiate swaps or get quotes. * @param assets An array of addresses of ERC20 tokens that can be swapped. */ struct Exchange { bytes32 exchangeId; address[] assets; } /** * @notice Get all exchanges supported by the ExchangeProvider. * @return exchanges An array of Exchange structs. */ function getExchanges() external view returns (Exchange[] memory exchanges); /** * @notice Execute a token swap with fixed amountIn * @param exchangeId The id of the exchange to use * @param tokenIn The token to be sold * @param tokenOut The token to be bought * @param amountIn The amount of tokenIn to be sold * @return amountOut The amount of tokenOut to be bought */ function swapIn( bytes32 exchangeId, address tokenIn, address tokenOut, uint256 amountIn ) external returns (uint256 amountOut); /** * @notice Execute a token swap with fixed amountOut * @param exchangeId The id of the exchange to use * @param tokenIn The token to be sold * @param tokenOut The token to be bought * @param amountOut The amount of tokenOut to be bought * @return amountIn The amount of tokenIn to be sold */ function swapOut( bytes32 exchangeId, address tokenIn, address tokenOut, uint256 amountOut ) external returns (uint256 amountIn); /** * @notice Calculate amountOut of tokenOut received for a given amountIn of tokenIn * @param exchangeId The id of the exchange to use * @param tokenIn The token to be sold * @param tokenOut The token to be bought * @param amountIn The amount of tokenIn to be sold * @return amountOut The amount of tokenOut to be bought */ function getAmountOut( bytes32 exchangeId, address tokenIn, address tokenOut, uint256 amountIn ) external view returns (uint256 amountOut); /** * @notice Calculate amountIn of tokenIn needed for a given amountOut of tokenOut * @param exchangeId The id of the exchange to use * @param tokenIn The token to be sold * @param tokenOut The token to be bought * @param amountOut The amount of tokenOut to be bought * @return amountIn The amount of tokenIn to be sold */ function getAmountIn( bytes32 exchangeId, address tokenIn, address tokenOut, uint256 amountOut ) external view returns (uint256 amountIn); }
/lib/mento-core/contracts/interfaces/IPricingModule.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; /** * @title Interface for a Mento Pricing Module. * @notice A Mento pricing module represents an exchange relation between a pair of ERC20 assets. */ interface IPricingModule { /** * @notice Returns the output amount and new bucket sizes for a given input amount. * @param tokenInBucketSize Size of the tokenIn bucket. * @param tokenOutBucketSize Size of the tokenOut bucket. * @param spread Spread charged on exchanges. * @param amountIn Amount of tokenIn being paid in. * @return amountOut Amount of tokenOut that will be paid out. */ function getAmountOut( uint256 tokenInBucketSize, uint256 tokenOutBucketSize, uint256 spread, uint256 amountIn ) external view returns (uint256 amountOut); /** * @notice Returns the input amount necessary for a given output amount. * @param tokenInBucketSize Size of the tokenIn bucket. * @param tokenOutBucketSize Size of the tokenOut bucket. * @param spread Spread charged on exchanges. * @param amountOut Amount of tokenIn being paid out. * @return amountIn Amount of tokenOut that would have to be paid in. */ function getAmountIn( uint256 tokenInBucketSize, uint256 tokenOutBucketSize, uint256 spread, uint256 amountOut ) external view returns (uint256 amountIn); /** * @notice Retrieve the name of this pricing module. * @return exchangeName The name of the pricing module. */ function name() external view returns (string memory pricingModuleName); }
/lib/mento-core/contracts/interfaces/IReserve.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; interface IReserve { function setTobinTaxStalenessThreshold(uint256) external; function addToken(address) external returns (bool); function removeToken(address, uint256) external returns (bool); function transferGold(address payable, uint256) external returns (bool); function transferExchangeGold(address payable, uint256) external returns (bool); function transferCollateralAsset( address collateralAsset, address payable to, uint256 value ) external returns (bool); function getReserveGoldBalance() external view returns (uint256); function getUnfrozenReserveGoldBalance() external view returns (uint256); function getOrComputeTobinTax() external returns (uint256, uint256); function getTokens() external view returns (address[] memory); function getReserveRatio() external view returns (uint256); function addExchangeSpender(address) external; function removeExchangeSpender(address, uint256) external; function addSpender(address) external; function removeSpender(address) external; function isStableAsset(address) external view returns (bool); function isCollateralAsset(address) external view returns (bool); function getDailySpendingRatioForCollateralAsset(address collateralAsset) external view returns (uint256); function isExchangeSpender(address exchange) external view returns (bool); function addCollateralAsset(address asset) external returns (bool); function transferExchangeCollateralAsset( address collateralAsset, address payable to, uint256 value ) external returns (bool); }
/lib/mento-core/contracts/interfaces/ISortedOracles.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; import "../common/linkedlists/SortedLinkedListWithMedian.sol"; interface ISortedOracles { function addOracle(address, address) external; function removeOracle( address, address, uint256 ) external; function report( address, uint256, address, address ) external; function removeExpiredReports(address, uint256) external; function isOldestReportExpired(address token) external view returns (bool, address); function numRates(address) external view returns (uint256); function medianRate(address) external view returns (uint256, uint256); function numTimestamps(address) external view returns (uint256); function medianTimestamp(address) external view returns (uint256); function getOracles(address) external view returns (address[] memory); function getTimestamps(address token) external view returns ( address[] memory, uint256[] memory, SortedLinkedListWithMedian.MedianRelation[] memory ); }
/lib/mento-core/contracts/interfaces/IStableToken.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.5.13; /** * @title This interface describes the functions specific to Celo Stable Tokens, and in the * absence of interface inheritance is intended as a companion to IERC20.sol and ICeloToken.sol. */ interface IStableToken { function mint(address, uint256) external returns (bool); function burn(uint256) external returns (bool); function setInflationParameters(uint256, uint256) external; function valueToUnits(uint256) external view returns (uint256); function unitsToValue(uint256) external view returns (uint256); function getInflationParameters() external view returns ( uint256, uint256, uint256, uint256 ); function getExchangeRegistryId() external view returns (bytes32); // NOTE: duplicated with IERC20.sol, remove once interface inheritance is supported. function balanceOf(address) external view returns (uint256); }
/lib/mento-core/lib/openzeppelin-contracts/contracts/GSN/Context.sol
pragma solidity ^0.5.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN 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. */ contract Context { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. constructor () internal { } // solhint-disable-previous-line no-empty-blocks function _msgSender() internal view returns (address payable) { return msg.sender; } function _msgData() internal view returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
/lib/mento-core/lib/openzeppelin-contracts/contracts/math/SafeMath.sol
pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
/lib/mento-core/lib/openzeppelin-contracts/contracts/ownership/Ownable.sol
pragma solidity ^0.5.0; import "../GSN/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * 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. */ contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner(), "Ownable: caller is not the owner"); _; } /** * @dev Returns true if the caller is the current owner. */ function isOwner() public view returns (bool) { return _msgSender() == _owner; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = 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 onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
/lib/mento-core/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol
pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"bool","name":"test","internalType":"bool"}]},{"type":"event","name":"BreakerBoxUpdated","inputs":[{"type":"address","name":"newBreakerBox","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"BrokerUpdated","inputs":[{"type":"address","name":"newBroker","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"BucketsUpdated","inputs":[{"type":"bytes32","name":"exchangeId","internalType":"bytes32","indexed":true},{"type":"uint256","name":"bucket0","internalType":"uint256","indexed":false},{"type":"uint256","name":"bucket1","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExchangeCreated","inputs":[{"type":"bytes32","name":"exchangeId","internalType":"bytes32","indexed":true},{"type":"address","name":"asset0","internalType":"address","indexed":true},{"type":"address","name":"asset1","internalType":"address","indexed":true},{"type":"address","name":"pricingModule","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"ExchangeDestroyed","inputs":[{"type":"bytes32","name":"exchangeId","internalType":"bytes32","indexed":true},{"type":"address","name":"asset0","internalType":"address","indexed":true},{"type":"address","name":"asset1","internalType":"address","indexed":true},{"type":"address","name":"pricingModule","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ReserveUpdated","inputs":[{"type":"address","name":"newReserve","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"SortedOraclesUpdated","inputs":[{"type":"address","name":"newSortedOracles","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IBreakerBox"}],"name":"breakerBox","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"broker","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes32","name":"exchangeId","internalType":"bytes32"}],"name":"createExchange","inputs":[{"type":"tuple","name":"_exchange","internalType":"struct IBiPoolManager.PoolExchange","components":[{"type":"address","name":"asset0","internalType":"address"},{"type":"address","name":"asset1","internalType":"address"},{"type":"address","name":"pricingModule","internalType":"contract IPricingModule"},{"type":"uint256","name":"bucket0","internalType":"uint256"},{"type":"uint256","name":"bucket1","internalType":"uint256"},{"type":"uint256","name":"lastBucketUpdate","internalType":"uint256"},{"type":"tuple","name":"config","internalType":"struct IBiPoolManager.PoolConfig","components":[{"type":"tuple","name":"spread","internalType":"struct FixidityLib.Fraction","components":[{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"address","name":"referenceRateFeedID","internalType":"address"},{"type":"uint256","name":"referenceRateResetFrequency","internalType":"uint256"},{"type":"uint256","name":"minimumReports","internalType":"uint256"},{"type":"uint256","name":"stablePoolResetSize","internalType":"uint256"}]}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"destroyed","internalType":"bool"}],"name":"destroyExchange","inputs":[{"type":"bytes32","name":"exchangeId","internalType":"bytes32"},{"type":"uint256","name":"exchangeIdIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"exchangeIds","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"asset0","internalType":"address"},{"type":"address","name":"asset1","internalType":"address"},{"type":"address","name":"pricingModule","internalType":"contract IPricingModule"},{"type":"uint256","name":"bucket0","internalType":"uint256"},{"type":"uint256","name":"bucket1","internalType":"uint256"},{"type":"uint256","name":"lastBucketUpdate","internalType":"uint256"},{"type":"tuple","name":"config","internalType":"struct IBiPoolManager.PoolConfig","components":[{"type":"tuple","name":"spread","internalType":"struct FixidityLib.Fraction","components":[{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"address","name":"referenceRateFeedID","internalType":"address"},{"type":"uint256","name":"referenceRateResetFrequency","internalType":"uint256"},{"type":"uint256","name":"minimumReports","internalType":"uint256"},{"type":"uint256","name":"stablePoolResetSize","internalType":"uint256"}]}],"name":"exchanges","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amountIn","internalType":"uint256"}],"name":"getAmountIn","inputs":[{"type":"bytes32","name":"exchangeId","internalType":"bytes32"},{"type":"address","name":"tokenIn","internalType":"address"},{"type":"address","name":"tokenOut","internalType":"address"},{"type":"uint256","name":"amountOut","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amountOut","internalType":"uint256"}],"name":"getAmountOut","inputs":[{"type":"bytes32","name":"exchangeId","internalType":"bytes32"},{"type":"address","name":"tokenIn","internalType":"address"},{"type":"address","name":"tokenOut","internalType":"address"},{"type":"uint256","name":"amountIn","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32[]","name":"","internalType":"bytes32[]"}],"name":"getExchangeIds","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"_exchanges","internalType":"struct IExchangeProvider.Exchange[]","components":[{"type":"bytes32","name":"exchangeId","internalType":"bytes32"},{"type":"address[]","name":"assets","internalType":"address[]"}]}],"name":"getExchanges","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"exchange","internalType":"struct IBiPoolManager.PoolExchange","components":[{"type":"address","name":"asset0","internalType":"address"},{"type":"address","name":"asset1","internalType":"address"},{"type":"address","name":"pricingModule","internalType":"contract IPricingModule"},{"type":"uint256","name":"bucket0","internalType":"uint256"},{"type":"uint256","name":"bucket1","internalType":"uint256"},{"type":"uint256","name":"lastBucketUpdate","internalType":"uint256"},{"type":"tuple","name":"config","internalType":"struct IBiPoolManager.PoolConfig","components":[{"type":"tuple","name":"spread","internalType":"struct FixidityLib.Fraction","components":[{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"address","name":"referenceRateFeedID","internalType":"address"},{"type":"uint256","name":"referenceRateResetFrequency","internalType":"uint256"},{"type":"uint256","name":"minimumReports","internalType":"uint256"},{"type":"uint256","name":"stablePoolResetSize","internalType":"uint256"}]}]}],"name":"getPoolExchange","inputs":[{"type":"bytes32","name":"exchangeId","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","name":"initialize","inputs":[{"type":"address","name":"_broker","internalType":"address"},{"type":"address","name":"_reserve","internalType":"contract IReserve"},{"type":"address","name":"_sortedOracles","internalType":"contract ISortedOracles"},{"type":"address","name":"_breakerBox","internalType":"contract IBreakerBox"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"initialized","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isOwner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IReserve"}],"name":"reserve","inputs":[]},{"type":"function","stateMutability":"nonpayable","name":"setBreakerBox","inputs":[{"type":"address","name":"_breakerBox","internalType":"contract IBreakerBox"}]},{"type":"function","stateMutability":"nonpayable","name":"setBroker","inputs":[{"type":"address","name":"_broker","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","name":"setReserve","inputs":[{"type":"address","name":"_reserve","internalType":"contract IReserve"}]},{"type":"function","stateMutability":"nonpayable","name":"setSortedOracles","inputs":[{"type":"address","name":"_sortedOracles","internalType":"contract ISortedOracles"}]},{"type":"function","stateMutability":"nonpayable","name":"setTokenPrecisionMultipliers","inputs":[{"type":"address[]","name":"tokens","internalType":"address[]"},{"type":"uint256[]","name":"precisionMultipliers","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ISortedOracles"}],"name":"sortedOracles","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"amountOut","internalType":"uint256"}],"name":"swapIn","inputs":[{"type":"bytes32","name":"exchangeId","internalType":"bytes32"},{"type":"address","name":"tokenIn","internalType":"address"},{"type":"address","name":"tokenOut","internalType":"address"},{"type":"uint256","name":"amountIn","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"amountIn","internalType":"uint256"}],"name":"swapOut","inputs":[{"type":"bytes32","name":"exchangeId","internalType":"bytes32"},{"type":"address","name":"tokenIn","internalType":"address"},{"type":"address","name":"tokenOut","internalType":"address"},{"type":"uint256","name":"amountOut","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tokenPrecisionMultipliers","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]}]
Contract Creation Code
0x60806040523480156200001157600080fd5b5060405162003dde38038062003dde8339810160408190526200003491620000cf565b808062000049576000805460ff191660011790555b5060006200005f6001600160e01b03620000b816565b60008054610100600160a81b0319166101006001600160a01b038416908102919091178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3505062000117565b3390565b8051620000c981620000fd565b92915050565b600060208284031215620000e257600080fd5b6000620000f08484620000bc565b949350505050565b151590565b6200010881620000f8565b81146200011457600080fd5b50565b613cb780620001276000396000f3fe608060405234801561001057600080fd5b50600436106101b95760003560e01c80639cecc80a116100f9578063dc162e3611610097578063f2fde38b11610071578063f2fde38b14610389578063f414c5e41461039c578063f670dde1146103a4578063f8c8765e146103b7576101b9565b8063dc162e361461034e578063decc1c8614610363578063e46eb5b614610376576101b9565b8063bf0d0213116100d3578063bf0d0213146102fa578063cd3293de1461030d578063d3385d0514610315578063d482dda614610328576101b9565b80639cecc80a146102cc578063abff0110146102df578063b0898691146102e7576101b9565b806342bfc99c11610166578063715018a611610140578063715018a6146102945780638da5cb5b1461029c5780638f32d59b146102b157806393c7e3bc146102b9576101b9565b806342bfc99c1461025b57806345b2b4671461026e5780634afb215e14610281576101b9565b80631e2e3a6b116101975780631e2e3a6b14610206578063278488a41461021b57806338b1e9f71461023b576101b9565b8063040bbd35146101be578063132e8aa7146101d3578063158ef93e146101f1575b600080fd5b6101d16101cc366004612c1b565b6103ca565b005b6101db61048b565b6040516101e8919061393a565b60405180910390f35b6101f961049a565b6040516101e8919061391e565b61020e6104a3565b6040516101e8919061390d565b61022e610229366004612b78565b61066b565b6040516101e89190613b19565b61024e610249366004612b78565b61074e565b6040516101e8919061392c565b61024e610269366004612b96565b61076c565b61024e61027c366004612a29565b610898565b6101d161028f366004612c1b565b6108aa565b6101d1610956565b6102a46109e0565b6040516101e89190613885565b6101f96109f4565b61024e6102c7366004612b96565b610a1d565b6101d16102da366004612c1b565b610a49565b6102a4610af5565b61024e6102f5366004612c6e565b610b04565b6101d1610308366004612a29565b61122a565b6101db6112d6565b61024e610323366004612b96565b6112e5565b61033b610336366004612b78565b611407565b6040516101e89796959493929190613893565b610356611493565b6040516101e891906138fc565b6101d1610371366004612ab0565b6114eb565b6101f9610384366004612beb565b61159a565b6101d1610397366004612a29565b6118fa565b6101db61192a565b61024e6103b2366004612b96565b611939565b6101d16103c5366004612a4f565b61195a565b6103d26109f4565b6103f75760405162461bcd60e51b81526004016103ee90613a69565b60405180910390fd5b6001600160a01b03811661041d5760405162461bcd60e51b81526004016103ee90613ae9565b600580547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f21921b3b46ef2c939e85d6a14410c6e3b9ce132b66e944357ff4f789f68e00e290610480908390613885565b60405180910390a150565b6006546001600160a01b031681565b60005460ff1681565b60035460408051828152602080840282010190915260609180156104e157816020015b6104ce6126fe565b8152602001906001900390816104c65790505b50905060005b60035481101561066757600381815481106104fe57fe5b906000526020600020015482828151811061051557fe5b60209081029190910101515260408051600280825260608201909252908160200160208202803883390190505082828151811061054e57fe5b602002602001015160200181905250600260006003838154811061056e57fe5b9060005260206000200154815260200190815260200160002060000160009054906101000a90046001600160a01b03168282815181106105aa57fe5b6020026020010151602001516000815181106105c257fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060026000600383815481106105f357fe5b9060005260206000200154815260200190815260200160002060010160009054906101000a90046001600160a01b031682828151811061062f57fe5b60200260200101516020015160018151811061064757fe5b6001600160a01b03909216602092830291909101909101526001016104e7565b5090565b610673612716565b50600081815260026020818152604092839020835160e08101855281546001600160a01b03908116825260018301548116828501529382015484168186015260038201546060808301919091526004830154608080840191909152600584015460a080850191909152875160c08181018a5260068701549282019283529181526007860154881696810196909652600885015497860197909752600984015491850191909152600a9092015491830191909152928301528151166107495760405162461bcd60e51b81526004016103ee90613ab9565b919050565b6003818154811061075b57fe5b600091825260209091200154905081565b6001546000906001600160a01b031633146107995760405162461bcd60e51b81526004016103ee906139f9565b6107a1612716565b6107aa8661066b565b60055460c0820151602001516040517fc0b05da00000000000000000000000000000000000000000000000000000000081529293506000926001600160a01b039092169163c0b05da09161080091600401613885565b60206040518083038186803b15801561081857600080fd5b505afa15801561082c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108509190810190612cac565b1461086d5760405162461bcd60e51b81526004016103ee90613959565b600061087b828787876119db565b909350905061088e878388878786611c2c565b5050949350505050565b60076020526000908152604090205481565b6108b26109f4565b6108ce5760405162461bcd60e51b81526004016103ee90613a69565b6001600160a01b0381166108f45760405162461bcd60e51b81526004016103ee90613ac9565b600680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f590fd633a008765ce9e65e8081adfba311e99e11b958a5ecb5000ea3355f735390600090a250565b61095e6109f4565b61097a5760405162461bcd60e51b81526004016103ee90613a69565b600080546040516101009091046001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffff0000000000000000000000000000000000000000ff169055565b60005461010090046001600160a01b031690565b6000805461010090046001600160a01b0316610a0e611d4f565b6001600160a01b031614905090565b6000610a27612716565b610a308661066b565b9050610a3e818686866119db565b509695505050505050565b610a516109f4565b610a6d5760405162461bcd60e51b81526004016103ee90613a69565b6001600160a01b038116610a935760405162461bcd60e51b81526004016103ee90613ad9565b600480547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f0b248ab246a87e452fbedee8dc12dfc53e3f3bfdc6920999062c56dea4ab522a90600090a250565b6001546001600160a01b031681565b6000610b0e6109f4565b610b2a5760405162461bcd60e51b81526004016103ee90613a69565b610b32612716565b610b4136849003840184612c8d565b60408101519091506001600160a01b0316610b6e5760405162461bcd60e51b81526004016103ee90613a39565b80516001600160a01b0316610b955760405162461bcd60e51b81526004016103ee90613999565b60208101516001600160a01b0316610bbf5760405162461bcd60e51b81526004016103ee90613a89565b80602001516001600160a01b031681600001516001600160a01b03161415610bf95760405162461bcd60e51b81526004016103ee90613a79565b80600001516001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015610c3657600080fd5b505afa158015610c4a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c729190810190612c39565b81602001516001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015610caf57600080fd5b505afa158015610cc3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ceb9190810190612c39565b82604001516001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b158015610d2857600080fd5b505afa158015610d3c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d649190810190612c39565b604051602001610d7693929190613861565b60408051601f198184030181529181528151602092830120600081815260029093529120549092506001600160a01b031615610dc45760405162461bcd60e51b81526004016103ee906139c9565b610dcd81611d53565b600080610dd983611fc3565b915091508183606001818152505080836080018181525050601283600001516001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015610e3057600080fd5b505afa158015610e44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e689190810190612cfa565b60ff161115610e895760405162461bcd60e51b81526004016103ee906139d9565b601283602001516001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015610ec857600080fd5b505afa158015610edc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610f009190810190612cfa565b60ff161115610f215760405162461bcd60e51b81526004016103ee90613a19565b82600001516001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015610f5e57600080fd5b505afa158015610f72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610f969190810190612cfa565b60ff16601203600a0a6007600085600001516001600160a01b03166001600160a01b031681526020019081526020016000208190555082602001516001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561100957600080fd5b505afa15801561101d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110419190810190612cfa565b60ff16601203600a0a6007600085602001516001600160a01b03166001600160a01b0316815260200190815260200160002081905550826002600086815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550606082015181600301556080820151816004015560a0820151816005015560c08201518160060160008201518160000160008201518160000155505060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506040820151816002015560608201518160030155608082015181600401555050905050600384908060018154018082558091505090600182039060005260206000200160009091929091909150555082602001516001600160a01b031683600001516001600160a01b0316857fb374789237d43aed0f75b4c50a45793fd70e354bb96eecd573f35f5d509d78a1866040015160405161121a9190613885565b60405180910390a4505050919050565b6112326109f4565b61124e5760405162461bcd60e51b81526004016103ee90613a69565b6001600160a01b0381166112745760405162461bcd60e51b81526004016103ee90613b09565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f865dab7821134b6eb27cba259b40e33bbc1b898e970a535a18a83147f380a51f90600090a250565b6004546001600160a01b031681565b6001546000906001600160a01b031633146113125760405162461bcd60e51b81526004016103ee906139f9565b61131a612716565b6113238661066b565b60055460c0820151602001516040517fc0b05da00000000000000000000000000000000000000000000000000000000081529293506000926001600160a01b039092169163c0b05da09161137991600401613885565b60206040518083038186803b15801561139157600080fd5b505afa1580156113a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113c99190810190612cac565b146113e65760405162461bcd60e51b81526004016103ee90613959565b60006113f482878787612007565b909350905061088e878388868886611c2c565b6002602081815260009283526040928390208054600182015493820154600383015460048401546005850154885160c081018a52600687015460a08201908152815260078701546001600160a01b0390811698820198909852600887015499810199909952600986015460608a0152600a90950154608089015292851696958516959190941693929087565b606060038054806020026020016040519081016040528092919081815260200182805480156114e157602002820191906000526020600020905b8154815260200190600101908083116114cd575b5050505050905090565b6114f36109f4565b61150f5760405162461bcd60e51b81526004016103ee90613a69565b82811461152e5760405162461bcd60e51b81526004016103ee90613a49565b60005b838110156115935782828281811061154557fe5b905060200201356007600087878581811061155c57fe5b90506020020160206115719190810190612a29565b6001600160a01b03168152602081019190915260400160002055600101611531565b5050505050565b60006115a46109f4565b6115c05760405162461bcd60e51b81526004016103ee90613a69565b60035482106115e15760405162461bcd60e51b81526004016103ee906139a9565b82600383815481106115ef57fe5b9060005260206000200154146116175760405162461bcd60e51b81526004016103ee90613a99565b61161f612716565b600260008581526020019081526020016000206040518060e00160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016002820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600382015481526020016004820154815260200160058201548152602001600682016040518060a00160405290816000820160405180602001604052908160008201548152505081526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600282015481526020016003820154815260200160048201548152505081525050905060026000858152602001908152602001600020600080820160006101000a8154906001600160a01b0302191690556001820160006101000a8154906001600160a01b0302191690556002820160006101000a8154906001600160a01b03021916905560038201600090556004820160009055600582016000905560068201600080820160008082016000905550506001820160006101000a8154906001600160a01b030219169055600282016000905560038201600090556004820160009055505050506003611848600160038054905061217090919063ffffffff16565b8154811061185257fe5b90600052602060002001546003848154811061186a57fe5b600091825260209091200155600380548061188157fe5b600190038181906000526020600020016000905590556001915080602001516001600160a01b031681600001516001600160a01b0316857fadbbec6c203cb0248e89fe6d15ad651061a9d5203a1ab0273256e2b7decffa8984604001516040516118eb9190613885565b60405180910390a45092915050565b6119026109f4565b61191e5760405162461bcd60e51b81526004016103ee90613a69565b611927816121bb565b50565b6005546001600160a01b031681565b6000611943612716565b61194c8661066b565b9050610a3e81868686612007565b60005460ff161561197d5760405162461bcd60e51b81526004016103ee90613979565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556119b1336121bb565b6119ba8461122a565b6119c383610a49565b6119cc826108aa565b6119d5816103ca565b50505050565b60008085600001516001600160a01b0316856001600160a01b0316148015611a18575085602001516001600160a01b0316846001600160a01b0316145b80611a4f575085602001516001600160a01b0316856001600160a01b0316148015611a4f575085516001600160a01b038581169116145b611a6b5760405162461bcd60e51b81526004016103ee90613af9565b611a748661225e565b815191975091506001600160a01b0386811691161415611b9657611b8f6007600088602001516001600160a01b03166001600160a01b031681526020019081526020016000205487604001516001600160a01b03166352707d8c89606001518a60800151611ae98c60c0015160000151612293565b8c516001600160a01b0316600090815260076020526040902054611b14908b9063ffffffff61229716565b6040518563ffffffff1660e01b8152600401611b339493929190613b43565b60206040518083038186803b158015611b4b57600080fd5b505afa158015611b5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b839190810190612cac565b9063ffffffff6122d116565b9150611c23565b611c206007600088600001516001600160a01b03166001600160a01b031681526020019081526020016000205487604001516001600160a01b03166352707d8c89608001518a60600151611bf18c60c0015160000151612293565b6020808e01516001600160a01b0316600090815260079091526040902054611b14908b9063ffffffff61229716565b91505b94509492505050565b8015611c9057426002600088815260200190815260200160002060050181905550857f949f5db193cbfa01f2d443b1c656bfede15497de0d86838cea089bd60c43834286606001518760800151604051611c87929190613b28565b60405180910390a25b84516001600160a01b0385811691161415611cf8576060850151611cba908463ffffffff61231316565b6000878152600260205260409020600301556080850151611ce1908363ffffffff61217016565b600087815260026020526040902060040155611d47565b6060850151611d0d908363ffffffff61217016565b6000878152600260205260409020600301556080850151611d34908463ffffffff61231316565b6000878152600260205260409020600401555b505050505050565b3390565b6004805482516040517f4f8e6e230000000000000000000000000000000000000000000000000000000081526001600160a01b0390921692634f8e6e2392611d9c929101613885565b60206040518083038186803b158015611db457600080fd5b505afa158015611dc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611dec9190810190612b20565b611e085760405162461bcd60e51b81526004016103ee90613969565b6004805460208301516040517f4f8e6e230000000000000000000000000000000000000000000000000000000081526001600160a01b0390921692634f8e6e2392611e54929101613885565b60206040518083038186803b158015611e6c57600080fd5b505afa158015611e80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611ea49190810190612b20565b80611f4657506004805460208301516040517fcae182fe0000000000000000000000000000000000000000000000000000000081526001600160a01b039092169263cae182fe92611ef6929101613885565b60206040518083038186803b158015611f0e57600080fd5b505afa158015611f22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611f469190810190612b20565b611f625760405162461bcd60e51b81526004016103ee906139e9565b60c081015151611f7990611f74612338565b61235c565b611f955760405162461bcd60e51b81526004016103ee90613a29565b60c0810151602001516001600160a01b03166119275760405162461bcd60e51b81526004016103ee90613aa9565b6000808260c00151608001519150600080611fe58560c0015160200151612364565b9092509050611ffe82611b83838763ffffffff61229716565b92505050915091565b60008085600001516001600160a01b0316856001600160a01b0316148015612044575085602001516001600160a01b0316846001600160a01b0316145b8061207b575085602001516001600160a01b0316856001600160a01b031614801561207b575085516001600160a01b038581169116145b6120975760405162461bcd60e51b81526004016103ee90613af9565b6120a08661225e565b815191975091506001600160a01b038681169116141561211557611b8f6007600088600001516001600160a01b03166001600160a01b031681526020019081526020016000205487604001516001600160a01b031663571fd01289606001518a60800151611bf18c60c0015160000151612293565b611c206007600088602001516001600160a01b03166001600160a01b031681526020019081526020016000205487604001516001600160a01b031663571fd01289608001518a60600151611ae98c60c0015160000151612293565b60006121b283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612431565b90505b92915050565b6001600160a01b0381166121e15760405162461bcd60e51b81526004016103ee90613989565b600080546040516001600160a01b038085169361010090930416917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b03909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b612266612716565b600061227183612462565b1561228d5761227f83611fc3565b608085015260608401525060015b91929050565b5190565b6000826122a6575060006121b5565b828202828482816122b357fe5b04146121b25760405162461bcd60e51b81526004016103ee90613a59565b60006121b283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506126c7565b6000828201838110156121b25760405162461bcd60e51b81526004016103ee906139b9565b612340612773565b50604080516020810190915269d3c21bcecceda1000000815290565b519051111590565b6006546040517fef90e1b00000000000000000000000000000000000000000000000000000000081526000918291829182916001600160a01b039091169063ef90e1b0906123b6908890600401613885565b604080518083038186803b1580156123cd57600080fd5b505afa1580156123e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506124059190810190612cca565b9092509050806124275760405162461bcd60e51b81526004016103ee90613a09565b9092509050915091565b600081848411156124555760405162461bcd60e51b81526004016103ee9190613948565b50508183035b9392505050565b60065460c0820151602001516040517fffe736bf00000000000000000000000000000000000000000000000000000000815260009283926001600160a01b039091169163ffe736bf916124b791600401613885565b604080518083038186803b1580156124ce57600080fd5b505afa1580156124e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506125069190810190612b3e565b509050600061252a8460c00151604001518560a0015161231390919063ffffffff16565b60c085015160608101516006546020909201516040517fbbc66a94000000000000000000000000000000000000000000000000000000008152429490941015945060009391926001600160a01b03169163bbc66a949161258c91600401613885565b60206040518083038186803b1580156125a457600080fd5b505afa1580156125b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506125dc9190810190612cac565b1015905060006125fd8660c00151604001514261217090919063ffffffff16565b60065460c0880151602001516040517f071b48fc0000000000000000000000000000000000000000000000000000000081526001600160a01b039092169163071b48fc9161264d91600401613885565b60206040518083038186803b15801561266557600080fd5b505afa158015612679573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061269d9190810190612cac565b1190508280156126aa5750815b80156126b35750805b80156126bd575083155b9695505050505050565b600081836126e85760405162461bcd60e51b81526004016103ee9190613948565b5060008385816126f457fe5b0495945050505050565b60408051808201909152600081526060602082015290565b6040518060e0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200161276e612786565b905290565b6040518060200160405280600081525090565b6040518060a00160405280612799612773565b815260200160006001600160a01b031681526020016000815260200160008152602001600081525090565b80356121b581613c3c565b80516121b581613c3c565b60008083601f8401126127ec57600080fd5b50813567ffffffffffffffff81111561280457600080fd5b60208301915083602082028301111561281c57600080fd5b9250929050565b80516121b581613c50565b80356121b581613c59565b80356121b581613c62565b600082601f83011261285557600080fd5b815161286861286382613b9f565b613b78565b9150808252602083016020830185838301111561288457600080fd5b61288f838284613c06565b50505092915050565b6000602082840312156128aa57600080fd5b6128b46020613b78565b905060006128c2848461282e565b82525092915050565b600060a082840312156128dd57600080fd5b6128e760a0613b78565b905060006128f58484612898565b8252506020612906848483016127c4565b602083015250604061291a8482850161282e565b604083015250606061292e8482850161282e565b60608301525060806129428482850161282e565b60808301525092915050565b6000610160828403121561296157600080fd5b50919050565b6000610160828403121561297a57600080fd5b61298460e0613b78565b9050600061299284846127c4565b82525060206129a3848483016127c4565b60208301525060406129b784828501612839565b60408301525060606129cb8482850161282e565b60608301525060806129df8482850161282e565b60808301525060a06129f38482850161282e565b60a08301525060c0612a07848285016128cb565b60c08301525092915050565b80516121b581613c59565b80516121b581613c6b565b600060208284031215612a3b57600080fd5b6000612a4784846127c4565b949350505050565b60008060008060808587031215612a6557600080fd5b6000612a7187876127c4565b9450506020612a8287828801612839565b9350506040612a9387828801612839565b9250506060612aa487828801612839565b91505092959194509250565b60008060008060408587031215612ac657600080fd5b843567ffffffffffffffff811115612add57600080fd5b612ae9878288016127da565b9450945050602085013567ffffffffffffffff811115612b0857600080fd5b612b14878288016127da565b95989497509550505050565b600060208284031215612b3257600080fd5b6000612a478484612823565b60008060408385031215612b5157600080fd5b6000612b5d8585612823565b9250506020612b6e858286016127cf565b9150509250929050565b600060208284031215612b8a57600080fd5b6000612a47848461282e565b60008060008060808587031215612bac57600080fd5b6000612bb8878761282e565b9450506020612bc9878288016127c4565b9350506040612bda878288016127c4565b9250506060612aa48782880161282e565b60008060408385031215612bfe57600080fd5b6000612c0a858561282e565b9250506020612b6e8582860161282e565b600060208284031215612c2d57600080fd5b6000612a478484612839565b600060208284031215612c4b57600080fd5b815167ffffffffffffffff811115612c6257600080fd5b612a4784828501612844565b60006101608284031215612c8157600080fd5b6000612a47848461294e565b60006101608284031215612ca057600080fd5b6000612a478484612967565b600060208284031215612cbe57600080fd5b6000612a478484612a13565b60008060408385031215612cdd57600080fd5b6000612ce98585612a13565b9250506020612b6e85828601612a13565b600060208284031215612d0c57600080fd5b6000612a478484612a1e565b6000612d248383612d44565b505060200190565b6000612d248383612e71565b60006121b2838361373a565b612d4d81613bd6565b82525050565b6000612d5e82612293565b612d688185613bcd565b9350612d7383613bc7565b8060005b83811015612da1578151612d8b8882612d18565b9750612d9683613bc7565b925050600101612d77565b509495945050505050565b6000612db782612293565b612dc18185613bcd565b9350612dcc83613bc7565b8060005b83811015612da1578151612de48882612d2c565b9750612def83613bc7565b925050600101612dd0565b6000612e0582612293565b612e0f8185613bcd565b935083602082028501612e2185613bc7565b8060005b85811015612e5b5784840389528151612e3e8582612d38565b9450612e4983613bc7565b60209a909a0199925050600101612e25565b5091979650505050505050565b612d4d81613be1565b612d4d81613be6565b612d4d81613be9565b6000612e8e82612293565b612e988185613bcd565b9350612ea8818560208601613c06565b612eb181613c32565b9093019392505050565b6000612ec682612293565b612ed08185610749565b9350612ee0818560208601613c06565b9290920192915050565b6000612ef7602c83613bcd565b7f54726164696e672069732073757370656e64656420666f72207468697320726581527f666572656e636520726174650000000000000000000000000000000000000000602082015260400192915050565b6000612f56603383613bcd565b7f617373657430206d757374206265206120737461626c6520726567697374657281527f6564207769746820746865207265736572766500000000000000000000000000602082015260400192915050565b6000612fb5601c83613bcd565b7f636f6e747261637420616c726561647920696e697469616c697a656400000000815260200192915050565b6000612fee602683613bcd565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181527f6464726573730000000000000000000000000000000000000000000000000000602082015260400192915050565b600061304d601283613bcd565b7f617373657430206d757374206265207365740000000000000000000000000000815260200192915050565b6000613086601c83613bcd565b7f65786368616e67654964496e646578206e6f7420696e2072616e676500000000815260200192915050565b60006130bf601b83613bcd565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b60006130f8603983613bcd565b7f416e2065786368616e676520776974682074686520737065636966696564206181527f737365747320616e642065786368616e67652065786973747300000000000000602082015260400192915050565b6000613157601d83613bcd565b7f61737365743020646563696d616c73206d757374206265203c3d203138000000815260200192915050565b6000613190602583613bcd565b7f617373657431206d757374206265206120737461626c65206f7220636f6c6c6181527f746572616c000000000000000000000000000000000000000000000000000000602082015260400192915050565b60006131ef601883613bcd565b7f43616c6c6572206973206e6f74207468652042726f6b65720000000000000000815260200192915050565b6000613228603083613bcd565b7f65786368616e676520726174652064656e6f6d696e61746f72206d757374206281527f652067726561746572207468616e203000000000000000000000000000000000602082015260400192915050565b6000613287601d83613bcd565b7f61737365743120646563696d616c73206d757374206265203c3d203138000000815260200192915050565b60006132c0602683613bcd565b7f737072656164206d757374206265206c657373207468616e206f72206571756181527f6c20746f20310000000000000000000000000000000000000000000000000000602082015260400192915050565b600061331f601983613bcd565b7f70726963696e674d6f64756c65206d7573742062652073657400000000000000815260200192915050565b6000613358603783613bcd565b7f746f6b656e7320616e6420707265636973696f6e4d756c7469706c696572732081527f6d757374206265207468652073616d65206c656e677468000000000000000000602082015260400192915050565b60006133b7602183613bcd565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f81527f7700000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b6000613416602083613bcd565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572815260200192915050565b600061344f602283613bcd565b7f65786368616e6765206173736574732063616e2774206265206964656e74696381527f616c000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b60006134ae601283613bcd565b7f617373657431206d757374206265207365740000000000000000000000000000815260200192915050565b60006134e7602183613bcd565b7f65786368616e6765496420617420696e64657820646f65736e2774206d61746381527f6800000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b6000613546601f83613bcd565b7f7265666572656e636552617465466565644944206d7573742062652073657400815260200192915050565b600061357f603083613bcd565b7f416e2065786368616e676520776974682074686520737065636966696564206981527f6420646f6573206e6f7420657869737400000000000000000000000000000000602082015260400192915050565b60006135de602183613bcd565b7f536f727465644f7261636c65732061646472657373206d75737420626520736581527f7400000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b600061363d601b83613bcd565b7f526573657276652061646472657373206d757374206265207365740000000000815260200192915050565b6000613676601e83613bcd565b7f427265616b6572426f782061646472657373206d757374206265207365740000815260200192915050565b60006136af602883613bcd565b7f746f6b656e496e20616e6420746f6b656e4f7574206d757374206d617463682081527f65786368616e6765000000000000000000000000000000000000000000000000602082015260400192915050565b600061370e601a83613bcd565b7f42726f6b65722061646472657373206d75737420626520736574000000000000815260200192915050565b8051600090604084019061374e8582612e71565b50602083015184820360208601526137668282612d53565b95945050505050565b805160208301906119d58482612e71565b805160a0830190613791848261376f565b5060208201516137a46020850182612d44565b5060408201516137b76040850182612e71565b5060608201516137ca6060850182612e71565b5060808201516119d56080850182612e71565b80516101608301906137ef8482612d44565b5060208201516138026020850182612d44565b5060408201516138156040850182612e7a565b5060608201516138286060850182612e71565b50608082015161383b6080850182612e71565b5060a082015161384e60a0850182612e71565b5060c08201516119d560c0850182613780565b600061386d8286612ebb565b91506138798285612ebb565b91506137668284612ebb565b602081016121b58284612d44565b61016081016138a2828a612d44565b6138af6020830189612d44565b6138bc6040830188612e7a565b6138c96060830187612e71565b6138d66080830186612e71565b6138e360a0830185612e71565b6138f060c0830184613780565b98975050505050505050565b602080825281016121b28184612dac565b602080825281016121b28184612dfa565b602081016121b58284612e68565b602081016121b58284612e71565b602081016121b58284612e7a565b602080825281016121b28184612e83565b602080825281016121b581612eea565b602080825281016121b581612f49565b602080825281016121b581612fa8565b602080825281016121b581612fe1565b602080825281016121b581613040565b602080825281016121b581613079565b602080825281016121b5816130b2565b602080825281016121b5816130eb565b602080825281016121b58161314a565b602080825281016121b581613183565b602080825281016121b5816131e2565b602080825281016121b58161321b565b602080825281016121b58161327a565b602080825281016121b5816132b3565b602080825281016121b581613312565b602080825281016121b58161334b565b602080825281016121b5816133aa565b602080825281016121b581613409565b602080825281016121b581613442565b602080825281016121b5816134a1565b602080825281016121b5816134da565b602080825281016121b581613539565b602080825281016121b581613572565b602080825281016121b5816135d1565b602080825281016121b581613630565b602080825281016121b581613669565b602080825281016121b5816136a2565b602080825281016121b581613701565b61016081016121b582846137dd565b60408101613b368285612e71565b61245b6020830184612e71565b60808101613b518287612e71565b613b5e6020830186612e71565b613b6b6040830185612e71565b6137666060830184612e71565b60405181810167ffffffffffffffff81118282101715613b9757600080fd5b604052919050565b600067ffffffffffffffff821115613bb657600080fd5b506020601f91909101601f19160190565b60200190565b90815260200190565b60006121b582613bf4565b151590565b90565b60006121b582613bd6565b6001600160a01b031690565b60ff1690565b60005b83811015613c21578181015183820152602001613c09565b838111156119d55750506000910152565b601f01601f191690565b613c4581613bd6565b811461192757600080fd5b613c4581613be1565b613c4581613be6565b613c4581613be9565b613c4581613c0056fea365627a7a7231582086a42c98505c9f7c3a8a3405830852763d4c1c9559a65eb671ee864f3517827b6c6578706572696d656e74616cf564736f6c634300051100400000000000000000000000000000000000000000000000000000000000000000
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106101b95760003560e01c80639cecc80a116100f9578063dc162e3611610097578063f2fde38b11610071578063f2fde38b14610389578063f414c5e41461039c578063f670dde1146103a4578063f8c8765e146103b7576101b9565b8063dc162e361461034e578063decc1c8614610363578063e46eb5b614610376576101b9565b8063bf0d0213116100d3578063bf0d0213146102fa578063cd3293de1461030d578063d3385d0514610315578063d482dda614610328576101b9565b80639cecc80a146102cc578063abff0110146102df578063b0898691146102e7576101b9565b806342bfc99c11610166578063715018a611610140578063715018a6146102945780638da5cb5b1461029c5780638f32d59b146102b157806393c7e3bc146102b9576101b9565b806342bfc99c1461025b57806345b2b4671461026e5780634afb215e14610281576101b9565b80631e2e3a6b116101975780631e2e3a6b14610206578063278488a41461021b57806338b1e9f71461023b576101b9565b8063040bbd35146101be578063132e8aa7146101d3578063158ef93e146101f1575b600080fd5b6101d16101cc366004612c1b565b6103ca565b005b6101db61048b565b6040516101e8919061393a565b60405180910390f35b6101f961049a565b6040516101e8919061391e565b61020e6104a3565b6040516101e8919061390d565b61022e610229366004612b78565b61066b565b6040516101e89190613b19565b61024e610249366004612b78565b61074e565b6040516101e8919061392c565b61024e610269366004612b96565b61076c565b61024e61027c366004612a29565b610898565b6101d161028f366004612c1b565b6108aa565b6101d1610956565b6102a46109e0565b6040516101e89190613885565b6101f96109f4565b61024e6102c7366004612b96565b610a1d565b6101d16102da366004612c1b565b610a49565b6102a4610af5565b61024e6102f5366004612c6e565b610b04565b6101d1610308366004612a29565b61122a565b6101db6112d6565b61024e610323366004612b96565b6112e5565b61033b610336366004612b78565b611407565b6040516101e89796959493929190613893565b610356611493565b6040516101e891906138fc565b6101d1610371366004612ab0565b6114eb565b6101f9610384366004612beb565b61159a565b6101d1610397366004612a29565b6118fa565b6101db61192a565b61024e6103b2366004612b96565b611939565b6101d16103c5366004612a4f565b61195a565b6103d26109f4565b6103f75760405162461bcd60e51b81526004016103ee90613a69565b60405180910390fd5b6001600160a01b03811661041d5760405162461bcd60e51b81526004016103ee90613ae9565b600580547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f21921b3b46ef2c939e85d6a14410c6e3b9ce132b66e944357ff4f789f68e00e290610480908390613885565b60405180910390a150565b6006546001600160a01b031681565b60005460ff1681565b60035460408051828152602080840282010190915260609180156104e157816020015b6104ce6126fe565b8152602001906001900390816104c65790505b50905060005b60035481101561066757600381815481106104fe57fe5b906000526020600020015482828151811061051557fe5b60209081029190910101515260408051600280825260608201909252908160200160208202803883390190505082828151811061054e57fe5b602002602001015160200181905250600260006003838154811061056e57fe5b9060005260206000200154815260200190815260200160002060000160009054906101000a90046001600160a01b03168282815181106105aa57fe5b6020026020010151602001516000815181106105c257fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060026000600383815481106105f357fe5b9060005260206000200154815260200190815260200160002060010160009054906101000a90046001600160a01b031682828151811061062f57fe5b60200260200101516020015160018151811061064757fe5b6001600160a01b03909216602092830291909101909101526001016104e7565b5090565b610673612716565b50600081815260026020818152604092839020835160e08101855281546001600160a01b03908116825260018301548116828501529382015484168186015260038201546060808301919091526004830154608080840191909152600584015460a080850191909152875160c08181018a5260068701549282019283529181526007860154881696810196909652600885015497860197909752600984015491850191909152600a9092015491830191909152928301528151166107495760405162461bcd60e51b81526004016103ee90613ab9565b919050565b6003818154811061075b57fe5b600091825260209091200154905081565b6001546000906001600160a01b031633146107995760405162461bcd60e51b81526004016103ee906139f9565b6107a1612716565b6107aa8661066b565b60055460c0820151602001516040517fc0b05da00000000000000000000000000000000000000000000000000000000081529293506000926001600160a01b039092169163c0b05da09161080091600401613885565b60206040518083038186803b15801561081857600080fd5b505afa15801561082c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108509190810190612cac565b1461086d5760405162461bcd60e51b81526004016103ee90613959565b600061087b828787876119db565b909350905061088e878388878786611c2c565b5050949350505050565b60076020526000908152604090205481565b6108b26109f4565b6108ce5760405162461bcd60e51b81526004016103ee90613a69565b6001600160a01b0381166108f45760405162461bcd60e51b81526004016103ee90613ac9565b600680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f590fd633a008765ce9e65e8081adfba311e99e11b958a5ecb5000ea3355f735390600090a250565b61095e6109f4565b61097a5760405162461bcd60e51b81526004016103ee90613a69565b600080546040516101009091046001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffff0000000000000000000000000000000000000000ff169055565b60005461010090046001600160a01b031690565b6000805461010090046001600160a01b0316610a0e611d4f565b6001600160a01b031614905090565b6000610a27612716565b610a308661066b565b9050610a3e818686866119db565b509695505050505050565b610a516109f4565b610a6d5760405162461bcd60e51b81526004016103ee90613a69565b6001600160a01b038116610a935760405162461bcd60e51b81526004016103ee90613ad9565b600480547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f0b248ab246a87e452fbedee8dc12dfc53e3f3bfdc6920999062c56dea4ab522a90600090a250565b6001546001600160a01b031681565b6000610b0e6109f4565b610b2a5760405162461bcd60e51b81526004016103ee90613a69565b610b32612716565b610b4136849003840184612c8d565b60408101519091506001600160a01b0316610b6e5760405162461bcd60e51b81526004016103ee90613a39565b80516001600160a01b0316610b955760405162461bcd60e51b81526004016103ee90613999565b60208101516001600160a01b0316610bbf5760405162461bcd60e51b81526004016103ee90613a89565b80602001516001600160a01b031681600001516001600160a01b03161415610bf95760405162461bcd60e51b81526004016103ee90613a79565b80600001516001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015610c3657600080fd5b505afa158015610c4a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c729190810190612c39565b81602001516001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015610caf57600080fd5b505afa158015610cc3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ceb9190810190612c39565b82604001516001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b158015610d2857600080fd5b505afa158015610d3c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d649190810190612c39565b604051602001610d7693929190613861565b60408051601f198184030181529181528151602092830120600081815260029093529120549092506001600160a01b031615610dc45760405162461bcd60e51b81526004016103ee906139c9565b610dcd81611d53565b600080610dd983611fc3565b915091508183606001818152505080836080018181525050601283600001516001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015610e3057600080fd5b505afa158015610e44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e689190810190612cfa565b60ff161115610e895760405162461bcd60e51b81526004016103ee906139d9565b601283602001516001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015610ec857600080fd5b505afa158015610edc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610f009190810190612cfa565b60ff161115610f215760405162461bcd60e51b81526004016103ee90613a19565b82600001516001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015610f5e57600080fd5b505afa158015610f72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610f969190810190612cfa565b60ff16601203600a0a6007600085600001516001600160a01b03166001600160a01b031681526020019081526020016000208190555082602001516001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561100957600080fd5b505afa15801561101d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110419190810190612cfa565b60ff16601203600a0a6007600085602001516001600160a01b03166001600160a01b0316815260200190815260200160002081905550826002600086815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550606082015181600301556080820151816004015560a0820151816005015560c08201518160060160008201518160000160008201518160000155505060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506040820151816002015560608201518160030155608082015181600401555050905050600384908060018154018082558091505090600182039060005260206000200160009091929091909150555082602001516001600160a01b031683600001516001600160a01b0316857fb374789237d43aed0f75b4c50a45793fd70e354bb96eecd573f35f5d509d78a1866040015160405161121a9190613885565b60405180910390a4505050919050565b6112326109f4565b61124e5760405162461bcd60e51b81526004016103ee90613a69565b6001600160a01b0381166112745760405162461bcd60e51b81526004016103ee90613b09565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f865dab7821134b6eb27cba259b40e33bbc1b898e970a535a18a83147f380a51f90600090a250565b6004546001600160a01b031681565b6001546000906001600160a01b031633146113125760405162461bcd60e51b81526004016103ee906139f9565b61131a612716565b6113238661066b565b60055460c0820151602001516040517fc0b05da00000000000000000000000000000000000000000000000000000000081529293506000926001600160a01b039092169163c0b05da09161137991600401613885565b60206040518083038186803b15801561139157600080fd5b505afa1580156113a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113c99190810190612cac565b146113e65760405162461bcd60e51b81526004016103ee90613959565b60006113f482878787612007565b909350905061088e878388868886611c2c565b6002602081815260009283526040928390208054600182015493820154600383015460048401546005850154885160c081018a52600687015460a08201908152815260078701546001600160a01b0390811698820198909852600887015499810199909952600986015460608a0152600a90950154608089015292851696958516959190941693929087565b606060038054806020026020016040519081016040528092919081815260200182805480156114e157602002820191906000526020600020905b8154815260200190600101908083116114cd575b5050505050905090565b6114f36109f4565b61150f5760405162461bcd60e51b81526004016103ee90613a69565b82811461152e5760405162461bcd60e51b81526004016103ee90613a49565b60005b838110156115935782828281811061154557fe5b905060200201356007600087878581811061155c57fe5b90506020020160206115719190810190612a29565b6001600160a01b03168152602081019190915260400160002055600101611531565b5050505050565b60006115a46109f4565b6115c05760405162461bcd60e51b81526004016103ee90613a69565b60035482106115e15760405162461bcd60e51b81526004016103ee906139a9565b82600383815481106115ef57fe5b9060005260206000200154146116175760405162461bcd60e51b81526004016103ee90613a99565b61161f612716565b600260008581526020019081526020016000206040518060e00160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016002820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600382015481526020016004820154815260200160058201548152602001600682016040518060a00160405290816000820160405180602001604052908160008201548152505081526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600282015481526020016003820154815260200160048201548152505081525050905060026000858152602001908152602001600020600080820160006101000a8154906001600160a01b0302191690556001820160006101000a8154906001600160a01b0302191690556002820160006101000a8154906001600160a01b03021916905560038201600090556004820160009055600582016000905560068201600080820160008082016000905550506001820160006101000a8154906001600160a01b030219169055600282016000905560038201600090556004820160009055505050506003611848600160038054905061217090919063ffffffff16565b8154811061185257fe5b90600052602060002001546003848154811061186a57fe5b600091825260209091200155600380548061188157fe5b600190038181906000526020600020016000905590556001915080602001516001600160a01b031681600001516001600160a01b0316857fadbbec6c203cb0248e89fe6d15ad651061a9d5203a1ab0273256e2b7decffa8984604001516040516118eb9190613885565b60405180910390a45092915050565b6119026109f4565b61191e5760405162461bcd60e51b81526004016103ee90613a69565b611927816121bb565b50565b6005546001600160a01b031681565b6000611943612716565b61194c8661066b565b9050610a3e81868686612007565b60005460ff161561197d5760405162461bcd60e51b81526004016103ee90613979565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556119b1336121bb565b6119ba8461122a565b6119c383610a49565b6119cc826108aa565b6119d5816103ca565b50505050565b60008085600001516001600160a01b0316856001600160a01b0316148015611a18575085602001516001600160a01b0316846001600160a01b0316145b80611a4f575085602001516001600160a01b0316856001600160a01b0316148015611a4f575085516001600160a01b038581169116145b611a6b5760405162461bcd60e51b81526004016103ee90613af9565b611a748661225e565b815191975091506001600160a01b0386811691161415611b9657611b8f6007600088602001516001600160a01b03166001600160a01b031681526020019081526020016000205487604001516001600160a01b03166352707d8c89606001518a60800151611ae98c60c0015160000151612293565b8c516001600160a01b0316600090815260076020526040902054611b14908b9063ffffffff61229716565b6040518563ffffffff1660e01b8152600401611b339493929190613b43565b60206040518083038186803b158015611b4b57600080fd5b505afa158015611b5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b839190810190612cac565b9063ffffffff6122d116565b9150611c23565b611c206007600088600001516001600160a01b03166001600160a01b031681526020019081526020016000205487604001516001600160a01b03166352707d8c89608001518a60600151611bf18c60c0015160000151612293565b6020808e01516001600160a01b0316600090815260079091526040902054611b14908b9063ffffffff61229716565b91505b94509492505050565b8015611c9057426002600088815260200190815260200160002060050181905550857f949f5db193cbfa01f2d443b1c656bfede15497de0d86838cea089bd60c43834286606001518760800151604051611c87929190613b28565b60405180910390a25b84516001600160a01b0385811691161415611cf8576060850151611cba908463ffffffff61231316565b6000878152600260205260409020600301556080850151611ce1908363ffffffff61217016565b600087815260026020526040902060040155611d47565b6060850151611d0d908363ffffffff61217016565b6000878152600260205260409020600301556080850151611d34908463ffffffff61231316565b6000878152600260205260409020600401555b505050505050565b3390565b6004805482516040517f4f8e6e230000000000000000000000000000000000000000000000000000000081526001600160a01b0390921692634f8e6e2392611d9c929101613885565b60206040518083038186803b158015611db457600080fd5b505afa158015611dc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611dec9190810190612b20565b611e085760405162461bcd60e51b81526004016103ee90613969565b6004805460208301516040517f4f8e6e230000000000000000000000000000000000000000000000000000000081526001600160a01b0390921692634f8e6e2392611e54929101613885565b60206040518083038186803b158015611e6c57600080fd5b505afa158015611e80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611ea49190810190612b20565b80611f4657506004805460208301516040517fcae182fe0000000000000000000000000000000000000000000000000000000081526001600160a01b039092169263cae182fe92611ef6929101613885565b60206040518083038186803b158015611f0e57600080fd5b505afa158015611f22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611f469190810190612b20565b611f625760405162461bcd60e51b81526004016103ee906139e9565b60c081015151611f7990611f74612338565b61235c565b611f955760405162461bcd60e51b81526004016103ee90613a29565b60c0810151602001516001600160a01b03166119275760405162461bcd60e51b81526004016103ee90613aa9565b6000808260c00151608001519150600080611fe58560c0015160200151612364565b9092509050611ffe82611b83838763ffffffff61229716565b92505050915091565b60008085600001516001600160a01b0316856001600160a01b0316148015612044575085602001516001600160a01b0316846001600160a01b0316145b8061207b575085602001516001600160a01b0316856001600160a01b031614801561207b575085516001600160a01b038581169116145b6120975760405162461bcd60e51b81526004016103ee90613af9565b6120a08661225e565b815191975091506001600160a01b038681169116141561211557611b8f6007600088600001516001600160a01b03166001600160a01b031681526020019081526020016000205487604001516001600160a01b031663571fd01289606001518a60800151611bf18c60c0015160000151612293565b611c206007600088602001516001600160a01b03166001600160a01b031681526020019081526020016000205487604001516001600160a01b031663571fd01289608001518a60600151611ae98c60c0015160000151612293565b60006121b283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612431565b90505b92915050565b6001600160a01b0381166121e15760405162461bcd60e51b81526004016103ee90613989565b600080546040516001600160a01b038085169361010090930416917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b03909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b612266612716565b600061227183612462565b1561228d5761227f83611fc3565b608085015260608401525060015b91929050565b5190565b6000826122a6575060006121b5565b828202828482816122b357fe5b04146121b25760405162461bcd60e51b81526004016103ee90613a59565b60006121b283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506126c7565b6000828201838110156121b25760405162461bcd60e51b81526004016103ee906139b9565b612340612773565b50604080516020810190915269d3c21bcecceda1000000815290565b519051111590565b6006546040517fef90e1b00000000000000000000000000000000000000000000000000000000081526000918291829182916001600160a01b039091169063ef90e1b0906123b6908890600401613885565b604080518083038186803b1580156123cd57600080fd5b505afa1580156123e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506124059190810190612cca565b9092509050806124275760405162461bcd60e51b81526004016103ee90613a09565b9092509050915091565b600081848411156124555760405162461bcd60e51b81526004016103ee9190613948565b50508183035b9392505050565b60065460c0820151602001516040517fffe736bf00000000000000000000000000000000000000000000000000000000815260009283926001600160a01b039091169163ffe736bf916124b791600401613885565b604080518083038186803b1580156124ce57600080fd5b505afa1580156124e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506125069190810190612b3e565b509050600061252a8460c00151604001518560a0015161231390919063ffffffff16565b60c085015160608101516006546020909201516040517fbbc66a94000000000000000000000000000000000000000000000000000000008152429490941015945060009391926001600160a01b03169163bbc66a949161258c91600401613885565b60206040518083038186803b1580156125a457600080fd5b505afa1580156125b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506125dc9190810190612cac565b1015905060006125fd8660c00151604001514261217090919063ffffffff16565b60065460c0880151602001516040517f071b48fc0000000000000000000000000000000000000000000000000000000081526001600160a01b039092169163071b48fc9161264d91600401613885565b60206040518083038186803b15801561266557600080fd5b505afa158015612679573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061269d9190810190612cac565b1190508280156126aa5750815b80156126b35750805b80156126bd575083155b9695505050505050565b600081836126e85760405162461bcd60e51b81526004016103ee9190613948565b5060008385816126f457fe5b0495945050505050565b60408051808201909152600081526060602082015290565b6040518060e0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200161276e612786565b905290565b6040518060200160405280600081525090565b6040518060a00160405280612799612773565b815260200160006001600160a01b031681526020016000815260200160008152602001600081525090565b80356121b581613c3c565b80516121b581613c3c565b60008083601f8401126127ec57600080fd5b50813567ffffffffffffffff81111561280457600080fd5b60208301915083602082028301111561281c57600080fd5b9250929050565b80516121b581613c50565b80356121b581613c59565b80356121b581613c62565b600082601f83011261285557600080fd5b815161286861286382613b9f565b613b78565b9150808252602083016020830185838301111561288457600080fd5b61288f838284613c06565b50505092915050565b6000602082840312156128aa57600080fd5b6128b46020613b78565b905060006128c2848461282e565b82525092915050565b600060a082840312156128dd57600080fd5b6128e760a0613b78565b905060006128f58484612898565b8252506020612906848483016127c4565b602083015250604061291a8482850161282e565b604083015250606061292e8482850161282e565b60608301525060806129428482850161282e565b60808301525092915050565b6000610160828403121561296157600080fd5b50919050565b6000610160828403121561297a57600080fd5b61298460e0613b78565b9050600061299284846127c4565b82525060206129a3848483016127c4565b60208301525060406129b784828501612839565b60408301525060606129cb8482850161282e565b60608301525060806129df8482850161282e565b60808301525060a06129f38482850161282e565b60a08301525060c0612a07848285016128cb565b60c08301525092915050565b80516121b581613c59565b80516121b581613c6b565b600060208284031215612a3b57600080fd5b6000612a4784846127c4565b949350505050565b60008060008060808587031215612a6557600080fd5b6000612a7187876127c4565b9450506020612a8287828801612839565b9350506040612a9387828801612839565b9250506060612aa487828801612839565b91505092959194509250565b60008060008060408587031215612ac657600080fd5b843567ffffffffffffffff811115612add57600080fd5b612ae9878288016127da565b9450945050602085013567ffffffffffffffff811115612b0857600080fd5b612b14878288016127da565b95989497509550505050565b600060208284031215612b3257600080fd5b6000612a478484612823565b60008060408385031215612b5157600080fd5b6000612b5d8585612823565b9250506020612b6e858286016127cf565b9150509250929050565b600060208284031215612b8a57600080fd5b6000612a47848461282e565b60008060008060808587031215612bac57600080fd5b6000612bb8878761282e565b9450506020612bc9878288016127c4565b9350506040612bda878288016127c4565b9250506060612aa48782880161282e565b60008060408385031215612bfe57600080fd5b6000612c0a858561282e565b9250506020612b6e8582860161282e565b600060208284031215612c2d57600080fd5b6000612a478484612839565b600060208284031215612c4b57600080fd5b815167ffffffffffffffff811115612c6257600080fd5b612a4784828501612844565b60006101608284031215612c8157600080fd5b6000612a47848461294e565b60006101608284031215612ca057600080fd5b6000612a478484612967565b600060208284031215612cbe57600080fd5b6000612a478484612a13565b60008060408385031215612cdd57600080fd5b6000612ce98585612a13565b9250506020612b6e85828601612a13565b600060208284031215612d0c57600080fd5b6000612a478484612a1e565b6000612d248383612d44565b505060200190565b6000612d248383612e71565b60006121b2838361373a565b612d4d81613bd6565b82525050565b6000612d5e82612293565b612d688185613bcd565b9350612d7383613bc7565b8060005b83811015612da1578151612d8b8882612d18565b9750612d9683613bc7565b925050600101612d77565b509495945050505050565b6000612db782612293565b612dc18185613bcd565b9350612dcc83613bc7565b8060005b83811015612da1578151612de48882612d2c565b9750612def83613bc7565b925050600101612dd0565b6000612e0582612293565b612e0f8185613bcd565b935083602082028501612e2185613bc7565b8060005b85811015612e5b5784840389528151612e3e8582612d38565b9450612e4983613bc7565b60209a909a0199925050600101612e25565b5091979650505050505050565b612d4d81613be1565b612d4d81613be6565b612d4d81613be9565b6000612e8e82612293565b612e988185613bcd565b9350612ea8818560208601613c06565b612eb181613c32565b9093019392505050565b6000612ec682612293565b612ed08185610749565b9350612ee0818560208601613c06565b9290920192915050565b6000612ef7602c83613bcd565b7f54726164696e672069732073757370656e64656420666f72207468697320726581527f666572656e636520726174650000000000000000000000000000000000000000602082015260400192915050565b6000612f56603383613bcd565b7f617373657430206d757374206265206120737461626c6520726567697374657281527f6564207769746820746865207265736572766500000000000000000000000000602082015260400192915050565b6000612fb5601c83613bcd565b7f636f6e747261637420616c726561647920696e697469616c697a656400000000815260200192915050565b6000612fee602683613bcd565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181527f6464726573730000000000000000000000000000000000000000000000000000602082015260400192915050565b600061304d601283613bcd565b7f617373657430206d757374206265207365740000000000000000000000000000815260200192915050565b6000613086601c83613bcd565b7f65786368616e67654964496e646578206e6f7420696e2072616e676500000000815260200192915050565b60006130bf601b83613bcd565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b60006130f8603983613bcd565b7f416e2065786368616e676520776974682074686520737065636966696564206181527f737365747320616e642065786368616e67652065786973747300000000000000602082015260400192915050565b6000613157601d83613bcd565b7f61737365743020646563696d616c73206d757374206265203c3d203138000000815260200192915050565b6000613190602583613bcd565b7f617373657431206d757374206265206120737461626c65206f7220636f6c6c6181527f746572616c000000000000000000000000000000000000000000000000000000602082015260400192915050565b60006131ef601883613bcd565b7f43616c6c6572206973206e6f74207468652042726f6b65720000000000000000815260200192915050565b6000613228603083613bcd565b7f65786368616e676520726174652064656e6f6d696e61746f72206d757374206281527f652067726561746572207468616e203000000000000000000000000000000000602082015260400192915050565b6000613287601d83613bcd565b7f61737365743120646563696d616c73206d757374206265203c3d203138000000815260200192915050565b60006132c0602683613bcd565b7f737072656164206d757374206265206c657373207468616e206f72206571756181527f6c20746f20310000000000000000000000000000000000000000000000000000602082015260400192915050565b600061331f601983613bcd565b7f70726963696e674d6f64756c65206d7573742062652073657400000000000000815260200192915050565b6000613358603783613bcd565b7f746f6b656e7320616e6420707265636973696f6e4d756c7469706c696572732081527f6d757374206265207468652073616d65206c656e677468000000000000000000602082015260400192915050565b60006133b7602183613bcd565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f81527f7700000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b6000613416602083613bcd565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572815260200192915050565b600061344f602283613bcd565b7f65786368616e6765206173736574732063616e2774206265206964656e74696381527f616c000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b60006134ae601283613bcd565b7f617373657431206d757374206265207365740000000000000000000000000000815260200192915050565b60006134e7602183613bcd565b7f65786368616e6765496420617420696e64657820646f65736e2774206d61746381527f6800000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b6000613546601f83613bcd565b7f7265666572656e636552617465466565644944206d7573742062652073657400815260200192915050565b600061357f603083613bcd565b7f416e2065786368616e676520776974682074686520737065636966696564206981527f6420646f6573206e6f7420657869737400000000000000000000000000000000602082015260400192915050565b60006135de602183613bcd565b7f536f727465644f7261636c65732061646472657373206d75737420626520736581527f7400000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b600061363d601b83613bcd565b7f526573657276652061646472657373206d757374206265207365740000000000815260200192915050565b6000613676601e83613bcd565b7f427265616b6572426f782061646472657373206d757374206265207365740000815260200192915050565b60006136af602883613bcd565b7f746f6b656e496e20616e6420746f6b656e4f7574206d757374206d617463682081527f65786368616e6765000000000000000000000000000000000000000000000000602082015260400192915050565b600061370e601a83613bcd565b7f42726f6b65722061646472657373206d75737420626520736574000000000000815260200192915050565b8051600090604084019061374e8582612e71565b50602083015184820360208601526137668282612d53565b95945050505050565b805160208301906119d58482612e71565b805160a0830190613791848261376f565b5060208201516137a46020850182612d44565b5060408201516137b76040850182612e71565b5060608201516137ca6060850182612e71565b5060808201516119d56080850182612e71565b80516101608301906137ef8482612d44565b5060208201516138026020850182612d44565b5060408201516138156040850182612e7a565b5060608201516138286060850182612e71565b50608082015161383b6080850182612e71565b5060a082015161384e60a0850182612e71565b5060c08201516119d560c0850182613780565b600061386d8286612ebb565b91506138798285612ebb565b91506137668284612ebb565b602081016121b58284612d44565b61016081016138a2828a612d44565b6138af6020830189612d44565b6138bc6040830188612e7a565b6138c96060830187612e71565b6138d66080830186612e71565b6138e360a0830185612e71565b6138f060c0830184613780565b98975050505050505050565b602080825281016121b28184612dac565b602080825281016121b28184612dfa565b602081016121b58284612e68565b602081016121b58284612e71565b602081016121b58284612e7a565b602080825281016121b28184612e83565b602080825281016121b581612eea565b602080825281016121b581612f49565b602080825281016121b581612fa8565b602080825281016121b581612fe1565b602080825281016121b581613040565b602080825281016121b581613079565b602080825281016121b5816130b2565b602080825281016121b5816130eb565b602080825281016121b58161314a565b602080825281016121b581613183565b602080825281016121b5816131e2565b602080825281016121b58161321b565b602080825281016121b58161327a565b602080825281016121b5816132b3565b602080825281016121b581613312565b602080825281016121b58161334b565b602080825281016121b5816133aa565b602080825281016121b581613409565b602080825281016121b581613442565b602080825281016121b5816134a1565b602080825281016121b5816134da565b602080825281016121b581613539565b602080825281016121b581613572565b602080825281016121b5816135d1565b602080825281016121b581613630565b602080825281016121b581613669565b602080825281016121b5816136a2565b602080825281016121b581613701565b61016081016121b582846137dd565b60408101613b368285612e71565b61245b6020830184612e71565b60808101613b518287612e71565b613b5e6020830186612e71565b613b6b6040830185612e71565b6137666060830184612e71565b60405181810167ffffffffffffffff81118282101715613b9757600080fd5b604052919050565b600067ffffffffffffffff821115613bb657600080fd5b506020601f91909101601f19160190565b60200190565b90815260200190565b60006121b582613bf4565b151590565b90565b60006121b582613bd6565b6001600160a01b031690565b60ff1690565b60005b83811015613c21578181015183820152602001613c09565b838111156119d55750506000910152565b601f01601f191690565b613c4581613bd6565b811461192757600080fd5b613c4581613be1565b613c4581613be6565b613c4581613be9565b613c4581613c0056fea365627a7a7231582086a42c98505c9f7c3a8a3405830852763d4c1c9559a65eb671ee864f3517827b6c6578706572696d656e74616cf564736f6c63430005110040
External libraries
AddressLinkedList : 0x2f0f7686fffefc3c266403ad600035581deaedff
AddressSortedLinkedListWithMedian : 0x29b1b5e05217c751038861af2c77494eab10a257