Source Code
Overview
CELO Balance
CELO Value
$0.00Multichain Info
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Broker
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.18;
pragma experimental ABIEncoderV2;
import { Ownable } from "openzeppelin-contracts-next/contracts/access/Ownable.sol";
import { SafeERC20MintableBurnable } from "contracts/common/SafeERC20MintableBurnable.sol";
import { IERC20MintableBurnable as IERC20 } from "contracts/common/IERC20MintableBurnable.sol";
import { IExchangeProvider } from "../interfaces/IExchangeProvider.sol";
import { IBroker } from "../interfaces/IBroker.sol";
import { IBrokerAdmin } from "../interfaces/IBrokerAdmin.sol";
import { IReserve } from "../interfaces/IReserve.sol";
import { ITradingLimits } from "../interfaces/ITradingLimits.sol";
import { TradingLimits } from "../libraries/TradingLimits.sol";
import { Initializable } from "celo/contracts/common/Initializable.sol";
import { ReentrancyGuard } from "openzeppelin-contracts-next/contracts/security/ReentrancyGuard.sol";
interface IERC20Metadata {
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
/**
* @title Broker
* @notice The broker executes swaps and keeps track of spending limits per pair.
*/
contract Broker is IBroker, IBrokerAdmin, Initializable, Ownable, ReentrancyGuard {
using TradingLimits for ITradingLimits.State;
using TradingLimits for ITradingLimits.Config;
using SafeERC20MintableBurnable for IERC20;
/* ==================== State Variables ==================== */
/// @inheritdoc IBroker
address[] public exchangeProviders;
/// @inheritdoc IBroker
mapping(address => bool) public isExchangeProvider;
mapping(bytes32 => ITradingLimits.State) public tradingLimitsState;
mapping(bytes32 => ITradingLimits.Config) public tradingLimitsConfig;
// Deprecated address of the reserve. Kept to keep storage layout consistent with previous versions.
// slither-disable-next-line constable-states
uint256 public __deprecated0; // prev: IReserve public reserve;
uint256 private constant MAX_INT256 = uint256(type(int256).max);
mapping(address => address) public exchangeReserve;
/* ==================== Constructor ==================== */
/**
* @notice Sets initialized == true on implementation contracts.
* @param test Set to true to skip implementation initialization.
*/
constructor(bool test) Initializable(test) {}
/// @inheritdoc IBroker
function initialize(address[] calldata _exchangeProviders, address[] calldata _reserves) external initializer {
_transferOwnership(msg.sender);
for (uint256 i = 0; i < _exchangeProviders.length; i++) {
addExchangeProvider(_exchangeProviders[i], _reserves[i]);
}
}
/// @inheritdoc IBroker
function setReserves(
address[] calldata _exchangeProviders,
address[] calldata _reserves
) external override(IBroker, IBrokerAdmin) onlyOwner {
for (uint256 i = 0; i < _exchangeProviders.length; i++) {
require(isExchangeProvider[_exchangeProviders[i]], "ExchangeProvider does not exist");
require(_reserves[i] != address(0), "Reserve address can't be 0");
exchangeReserve[_exchangeProviders[i]] = _reserves[i];
emit ReserveSet(_exchangeProviders[i], _reserves[i]);
}
}
/* ==================== Mutative Functions ==================== */
/// @inheritdoc IBroker
function addExchangeProvider(
address exchangeProvider,
address reserve
) public override(IBroker, IBrokerAdmin) onlyOwner returns (uint256 index) {
require(!isExchangeProvider[exchangeProvider], "ExchangeProvider already exists in the list");
require(exchangeProvider != address(0), "ExchangeProvider address can't be 0");
require(reserve != address(0), "Reserve address can't be 0");
exchangeProviders.push(exchangeProvider);
isExchangeProvider[exchangeProvider] = true;
exchangeReserve[exchangeProvider] = reserve;
emit ExchangeProviderAdded(exchangeProvider);
emit ReserveSet(exchangeProvider, reserve);
index = exchangeProviders.length - 1;
}
/// @inheritdoc IBroker
function removeExchangeProvider(
address exchangeProvider,
uint256 index
) public override(IBroker, IBrokerAdmin) onlyOwner {
require(exchangeProviders[index] == exchangeProvider, "index doesn't match provider");
exchangeProviders[index] = exchangeProviders[exchangeProviders.length - 1];
exchangeProviders.pop();
delete isExchangeProvider[exchangeProvider];
delete exchangeReserve[exchangeProvider];
emit ExchangeProviderRemoved(exchangeProvider);
}
/// @inheritdoc IBroker
function getAmountIn(
address exchangeProvider,
bytes32 exchangeId,
address tokenIn,
address tokenOut,
uint256 amountOut
) external view returns (uint256 amountIn) {
require(isExchangeProvider[exchangeProvider], "ExchangeProvider does not exist");
address reserve = exchangeReserve[exchangeProvider];
if (IReserve(reserve).isCollateralAsset(tokenOut)) {
require(IERC20(tokenOut).balanceOf(reserve) >= amountOut, "Insufficient balance in reserve");
}
amountIn = IExchangeProvider(exchangeProvider).getAmountIn(exchangeId, tokenIn, tokenOut, amountOut);
}
/// @inheritdoc IBroker
function getAmountOut(
address exchangeProvider,
bytes32 exchangeId,
address tokenIn,
address tokenOut,
uint256 amountIn
) external view returns (uint256 amountOut) {
require(isExchangeProvider[exchangeProvider], "ExchangeProvider does not exist");
amountOut = IExchangeProvider(exchangeProvider).getAmountOut(exchangeId, tokenIn, tokenOut, amountIn);
address reserve = exchangeReserve[exchangeProvider];
if (IReserve(reserve).isCollateralAsset(tokenOut)) {
require(IERC20(tokenOut).balanceOf(reserve) >= amountOut, "Insufficient balance in reserve");
}
}
/// @inheritdoc IBroker
function swapIn(
address exchangeProvider,
bytes32 exchangeId,
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256 amountOutMin
) external nonReentrant returns (uint256 amountOut) {
require(isExchangeProvider[exchangeProvider], "ExchangeProvider does not exist");
// slither-disable-next-line reentrancy-benign
amountOut = IExchangeProvider(exchangeProvider).swapIn(exchangeId, tokenIn, tokenOut, amountIn);
require(amountOut >= amountOutMin, "amountOutMin not met");
guardTradingLimits(exchangeId, tokenIn, amountIn, tokenOut, amountOut);
address reserve = exchangeReserve[exchangeProvider];
transferIn(payable(msg.sender), tokenIn, amountIn, reserve);
transferOut(payable(msg.sender), tokenOut, amountOut, reserve);
emit Swap(exchangeProvider, exchangeId, msg.sender, tokenIn, tokenOut, amountIn, amountOut);
}
/// @inheritdoc IBroker
function swapOut(
address exchangeProvider,
bytes32 exchangeId,
address tokenIn,
address tokenOut,
uint256 amountOut,
uint256 amountInMax
) external nonReentrant returns (uint256 amountIn) {
require(isExchangeProvider[exchangeProvider], "ExchangeProvider does not exist");
// slither-disable-next-line reentrancy-benign
amountIn = IExchangeProvider(exchangeProvider).swapOut(exchangeId, tokenIn, tokenOut, amountOut);
require(amountIn <= amountInMax, "amountInMax exceeded");
guardTradingLimits(exchangeId, tokenIn, amountIn, tokenOut, amountOut);
address reserve = exchangeReserve[exchangeProvider];
transferIn(payable(msg.sender), tokenIn, amountIn, reserve);
transferOut(payable(msg.sender), tokenOut, amountOut, reserve);
emit Swap(exchangeProvider, exchangeId, msg.sender, tokenIn, tokenOut, amountIn, amountOut);
}
/// @inheritdoc IBroker
function burnStableTokens(address token, uint256 amount) public returns (bool) {
IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
IERC20(token).safeBurn(amount);
return true;
}
/// @inheritdoc IBroker
function configureTradingLimit(
bytes32 exchangeId,
address token,
ITradingLimits.Config memory config
) external onlyOwner {
config.validate();
bytes32 limitId = exchangeId ^ bytes32(uint256(uint160(token)));
tradingLimitsConfig[limitId] = config;
tradingLimitsState[limitId] = tradingLimitsState[limitId].reset(config);
emit TradingLimitConfigured(exchangeId, token, config);
}
/* ==================== Private Functions ==================== */
/**
* @notice Transfer a specified Mento asset to the given address.
* If the specified asset is a stable asset it will be minted directly to the address. If
* the asset is a collateral asset it will be transferred from the reserve to the given address.
* @param to The address receiving the asset.
* @param token The asset to transfer.
* @param amount The amount of `token` to be transferred.
* @param _reserve The address of the corresponding reserve.
*/
function transferOut(address payable to, address token, uint256 amount, address _reserve) internal {
IReserve reserve = IReserve(_reserve);
if (reserve.isStableAsset(token)) {
IERC20(token).safeMint(to, amount);
} else if (reserve.isCollateralAsset(token)) {
require(reserve.transferExchangeCollateralAsset(token, to, amount), "Transfer of the collateral asset failed");
} else {
revert("Token must be stable or collateral assert");
}
}
/**
* @notice Transfer a specified Mento asset into the reserve or the broker.
* If the specified asset is a stable asset it will be transfered to the broker
* and burned. If the asset is a collateral asset it will be transferred to the reserve.
* @param from The address to transfer the asset from.
* @param token The asset to transfer.
* @param amount The amount of `token` to be transferred.
* @param _reserve The address of the corresponding reserve.
*/
function transferIn(address payable from, address token, uint256 amount, address _reserve) internal {
IReserve reserve = IReserve(_reserve);
if (reserve.isStableAsset(token)) {
IERC20(token).safeTransferFrom(from, address(this), amount);
IERC20(token).safeBurn(amount);
} else if (reserve.isCollateralAsset(token)) {
IERC20(token).safeTransferFrom(from, address(reserve), amount);
} else {
revert("Token must be stable or collateral assert");
}
}
/**
* @notice Verify trading limits for a trade in both directions.
* @dev Reverts if the trading limits are met for outflow or inflow.
* @param exchangeId the ID of the exchange being used.
* @param _tokenIn the address of the token flowing in.
* @param amountIn the amount of token flowing in.
* @param _tokenOut the address of the token flowing out.
* @param amountOut the amount of token flowing out.
*/
function guardTradingLimits(
bytes32 exchangeId,
address _tokenIn,
uint256 amountIn,
address _tokenOut,
uint256 amountOut
) internal {
bytes32 tokenIn = bytes32(uint256(uint160(_tokenIn)));
bytes32 tokenOut = bytes32(uint256(uint160(_tokenOut)));
require(amountIn <= uint256(MAX_INT256), "amountIn too large");
require(amountOut <= uint256(MAX_INT256), "amountOut too large");
guardTradingLimit(exchangeId ^ tokenIn, int256(amountIn), _tokenIn);
guardTradingLimit(exchangeId ^ tokenOut, -1 * int256(amountOut), _tokenOut);
}
/**
* @notice Updates and verifies a trading limit if it's configured.
* @dev Will revert if the trading limit is exceeded by this trade.
* @param tradingLimitId the ID of the trading limit associated with the token
* @param deltaFlow the deltaflow of this token, negative for outflow, positive for inflow.
* @param token the address of the token, used to lookup decimals.
*/
function guardTradingLimit(bytes32 tradingLimitId, int256 deltaFlow, address token) internal {
ITradingLimits.Config memory tradingLimitConfig = tradingLimitsConfig[tradingLimitId];
if (tradingLimitConfig.flags > 0) {
ITradingLimits.State memory tradingLimitState = tradingLimitsState[tradingLimitId];
tradingLimitState = tradingLimitState.update(tradingLimitConfig, deltaFlow, IERC20Metadata(token).decimals());
tradingLimitState.verify(tradingLimitConfig);
tradingLimitsState[tradingLimitId] = tradingLimitState;
}
}
/* ==================== View Functions ==================== */
/**
* @notice Get the list of registered exchange providers.
* @dev This can be used by UI or clients to discover all pairs.
* @return exchangeProviders the addresses of all exchange providers.
*/
function getExchangeProviders() external view returns (address[] memory) {
return exchangeProviders;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/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.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract 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() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions 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 virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}pragma solidity ^0.8.0;
import { IERC20MintableBurnable as IERC20 } from "contracts/common/IERC20MintableBurnable.sol";
import { Address } from "openzeppelin-contracts-next/contracts/utils/Address.sol";
/**
* @title SafeERC20MintableBurnable
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20MintableBurnable for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20MintableBurnable {
using Address for address;
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeMint(IERC20 token, address account, uint256 amount) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.mint.selector, account, amount));
}
function safeBurn(IERC20 token, uint256 amount) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.burn.selector, amount));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}pragma solidity ^0.8.0;
import "openzeppelin-contracts-next/contracts/token/ERC20/IERC20.sol";
/**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see {ERC20Detailed}.
*/
interface IERC20MintableBurnable is IERC20 {
function mint(address account, uint256 amount) external;
function burn(uint256 amount) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >0.5.13 <0.9;
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 pool 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);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >0.5.13 <0.9;
pragma experimental ABIEncoderV2;
import { ITradingLimits } from "./ITradingLimits.sol";
/*
* @title Broker Interface for trader functions
* @notice The broker is responsible for executing swaps and keeping track of trading limits.
*/
interface IBroker {
/**
* @notice Emitted when a swap occurs.
* @param exchangeProvider The exchange provider used.
* @param exchangeId The id of the exchange used.
* @param trader The user that initiated the swap.
* @param tokenIn The address of the token that was sold.
* @param tokenOut The address of the token that was bought.
* @param amountIn The amount of token sold.
* @param amountOut The amount of token bought.
*/
event Swap(
address exchangeProvider,
bytes32 indexed exchangeId,
address indexed trader,
address indexed tokenIn,
address tokenOut,
uint256 amountIn,
uint256 amountOut
);
/**
* @notice Emitted when a new trading limit is configured.
* @param exchangeId the exchangeId to target.
* @param token the token to target.
* @param config the new trading limits config.
*/
event TradingLimitConfigured(bytes32 exchangeId, address token, ITradingLimits.Config config);
/**
* @notice Allows the contract to be upgradable via the proxy.
* @param _exchangeProviders The addresses of the ExchangeProvider contracts.
* @param _reserves The address of the Reserve contract.
*/
function initialize(address[] calldata _exchangeProviders, address[] calldata _reserves) external;
/**
* @notice Set the reserves for the exchange providers.
* @param _exchangeProviders The addresses of the ExchangeProvider contracts.
* @param _reserves The addresses of the Reserve contracts.
*/
function setReserves(address[] calldata _exchangeProviders, address[] calldata _reserves) external;
/**
* @notice Add an exchange provider to the list of providers.
* @param exchangeProvider The address of the exchange provider to add.
* @param reserve The address of the reserve used by the exchange provider.
* @return index The index of the newly added specified exchange provider.
*/
function addExchangeProvider(address exchangeProvider, address reserve) external returns (uint256 index);
/**
* @notice Remove an exchange provider from the list of providers.
* @param exchangeProvider The address of the exchange provider to remove.
* @param index The index of the exchange provider being removed.
*/
function removeExchangeProvider(address exchangeProvider, uint256 index) external;
/**
* @notice Calculate amountIn of tokenIn needed for a given amountOut of tokenOut.
* @param exchangeProvider the address of the exchange provider for the pair.
* @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(
address exchangeProvider,
bytes32 exchangeId,
address tokenIn,
address tokenOut,
uint256 amountOut
) external view returns (uint256 amountIn);
/**
* @notice Calculate amountOut of tokenOut received for a given amountIn of tokenIn.
* @param exchangeProvider the address of the exchange provider for the pair.
* @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(
address exchangeProvider,
bytes32 exchangeId,
address tokenIn,
address tokenOut,
uint256 amountIn
) external view returns (uint256 amountOut);
/**
* @notice Execute a token swap with fixed amountIn.
* @param exchangeProvider the address of the exchange provider for the pair.
* @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.
* @param amountOutMin Minimum amountOut to be received - controls slippage.
* @return amountOut The amount of tokenOut to be bought.
*/
function swapIn(
address exchangeProvider,
bytes32 exchangeId,
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256 amountOutMin
) external returns (uint256 amountOut);
/**
* @notice Execute a token swap with fixed amountOut.
* @param exchangeProvider the address of the exchange provider for the pair.
* @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.
* @param amountInMax Maximum amount of tokenIn that can be traded.
* @return amountIn The amount of tokenIn to be sold.
*/
function swapOut(
address exchangeProvider,
bytes32 exchangeId,
address tokenIn,
address tokenOut,
uint256 amountOut,
uint256 amountInMax
) external returns (uint256 amountIn);
/**
* @notice Permissionless way to burn stables from msg.sender directly.
* @param token The token getting burned.
* @param amount The amount of the token getting burned.
* @return True if transaction succeeds.
*/
function burnStableTokens(address token, uint256 amount) external returns (bool);
/**
* @notice Configure trading limits for an (exchangeId, token) tuple.
* @dev Will revert if the configuration is not valid according to the TradingLimits library.
* Resets existing state according to the TradingLimits library logic.
* Can only be called by owner.
* @param exchangeId the exchangeId to target.
* @param token the token to target.
* @param config the new trading limits config.
*/
function configureTradingLimit(bytes32 exchangeId, address token, ITradingLimits.Config calldata config) external;
/**
* @notice Get the list of registered exchange providers.
* @dev This can be used by UI or clients to discover all pairs.
* @return exchangeProviders the addresses of all exchange providers.
*/
function getExchangeProviders() external view returns (address[] memory);
/**
* @notice Get the address of the exchange provider at a given index.
* @dev Auto-generated getter for the exchangeProviders array.
* @param index The index of the exchange provider.
* @return exchangeProvider The address of the exchange provider.
*/
function exchangeProviders(uint256 index) external view returns (address exchangeProvider);
/**
* @notice Check if a given address is an exchange provider.
* @dev Auto-generated getter for the isExchangeProvider mapping.
* @param exchangeProvider The address to check.
* @return isExchangeProvider True if the address is an exchange provider, false otherwise.
*/
function isExchangeProvider(address exchangeProvider) external view returns (bool);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.5.13 <0.8.19;
/*
* @title Broker Admin Interface
* @notice Contains admin functions to configure the broker that
* should be only callable by the owner.
*/
interface IBrokerAdmin {
/**
* @notice Emitted when an ExchangeProvider is added.
* @param exchangeProvider The address of the ExchangeProvider.
*/
event ExchangeProviderAdded(address indexed exchangeProvider);
/**
* @notice Emitted when an ExchangeProvider is removed.
* @param exchangeProvider The address of the ExchangeProvider.
*/
event ExchangeProviderRemoved(address indexed exchangeProvider);
/**
* @notice Emitted when the reserve is updated.
* @param newAddress The new address.
* @param prevAddress The previous address.
*/
event ReserveSet(address indexed newAddress, address indexed prevAddress);
/**
* @notice Remove an ExchangeProvider at a specified index.
* @param exchangeProvider The address of the ExchangeProvider to remove.
* @param index The index in the exchange providers array.
*/
function removeExchangeProvider(address exchangeProvider, uint256 index) external;
/**
* @notice Add an ExchangeProvider.
* @param exchangeProvider The address of the ExchangeProvider to add.
* @return index The index where the ExchangeProvider was inserted.
*/
function addExchangeProvider(address exchangeProvider, address reserve) external returns (uint256 index);
/**
* @notice Set the reserves for the exchange providers.
* @param _exchangeProviders The addresses of the ExchangeProvider contracts.
* @param _reserves The addresses of the Reserve contracts.
*/
function setReserves(address[] calldata _exchangeProviders, address[] calldata _reserves) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >0.5.13 <0.9;
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);
function initialize(
address registryAddress,
uint256 _tobinTaxStalenessThreshold,
uint256 _spendingRatioForCelo,
uint256 _frozenGold,
uint256 _frozenDays,
bytes32[] calldata _assetAllocationSymbols,
uint256[] calldata _assetAllocationWeights,
uint256 _tobinTax,
uint256 _tobinTaxReserveRatio,
address[] calldata _collateralAssets,
uint256[] calldata _collateralAssetDailySpendingRatios
) external;
/// @notice IOwnable:
function transferOwnership(address newOwner) external;
function renounceOwnership() external;
function owner() external view returns (address);
/// @notice Getters:
function registry() external view returns (address);
function tobinTaxStalenessThreshold() external view returns (uint256);
function tobinTax() external view returns (uint256);
function tobinTaxReserveRatio() external view returns (uint256);
function getDailySpendingRatio() external view returns (uint256);
function checkIsCollateralAsset(address collateralAsset) external view returns (bool);
function isToken(address) external view returns (bool);
function getOtherReserveAddresses() external view returns (address[] memory);
function getAssetAllocationSymbols() external view returns (bytes32[] memory);
function getAssetAllocationWeights() external view returns (uint256[] memory);
function collateralAssetSpendingLimit(address) external view returns (uint256);
function getExchangeSpenders() external view returns (address[] memory);
function getUnfrozenBalance() external view returns (uint256);
function isOtherReserveAddress(address otherReserveAddress) external view returns (bool);
function isSpender(address spender) external view returns (bool);
/// @notice Setters:
function setRegistry(address) external;
function setTobinTax(uint256) external;
function setTobinTaxReserveRatio(uint256) external;
function setDailySpendingRatio(uint256 spendingRatio) external;
function setDailySpendingRatioForCollateralAssets(
address[] calldata _collateralAssets,
uint256[] calldata collateralAssetDailySpendingRatios
) external;
function setFrozenGold(uint256 frozenGold, uint256 frozenDays) external;
function setAssetAllocations(bytes32[] calldata symbols, uint256[] calldata weights) external;
function removeCollateralAsset(address collateralAsset, uint256 index) external returns (bool);
function addOtherReserveAddress(address otherReserveAddress) external returns (bool);
function removeOtherReserveAddress(address otherReserveAddress, uint256 index) external returns (bool);
function collateralAssets(uint256 index) external view returns (address);
function collateralAssetLastSpendingDay(address collateralAsset) external view returns (uint256);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >0.5.13 <0.9;
interface ITradingLimits {
/**
* @dev The State struct contains the current state of a trading limit config.
* @param lastUpdated0 The timestamp of the last reset of netflow0.
* @param lastUpdated1 The timestamp of the last reset of netflow1.
* @param netflow0 The current netflow of the asset for limit0.
* @param netflow1 The current netflow of the asset for limit1.
* @param netflowGlobal The current netflow of the asset for limitGlobal.
*/
struct State {
uint32 lastUpdated0;
uint32 lastUpdated1;
int48 netflow0;
int48 netflow1;
int48 netflowGlobal;
}
/**
* @dev The Config struct contains the configuration of trading limits.
* @param timestep0 The time window in seconds for limit0.
* @param timestep1 The time window in seconds for limit1.
* @param limit0 The limit0 for the asset.
* @param limit1 The limit1 for the asset.
* @param limitGlobal The global limit for the asset.
* @param flags A bitfield of flags to enable/disable the individual limits.
*/
struct Config {
uint32 timestep0;
uint32 timestep1;
int48 limit0;
int48 limit1;
int48 limitGlobal;
uint8 flags;
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.18;
pragma experimental ABIEncoderV2;
import { ITradingLimits } from "contracts/interfaces/ITradingLimits.sol";
/**
* @title TradingLimits
* @author Mento Team
* @notice This library provides data structs and utility functions for
* defining and verifying trading limits on the netflow of an asset.
* There are three limits that can be enabled:
* - L0: A timewindow based limit, verifies that:
* -1 * limit0 <= netflow0 <= limit0,
* for a netflow0 that resets every timespan0 seconds.
* - L1: A timewindow based limit, verifies that:
* -1 * limit1 <= netflow1 <= limit1,
* for a netflow1 that resets every timespan1 second.
* - LG: A global (or lifetime) limit that ensures that:
* -1 * limitGlobal <= netflowGlobal <= limitGlobal,
* for a netflowGlobal that doesn't reset until the
* limit is disabled.
* @dev All contained functions are pure or view and marked internal to
* be inlined on consuming contracts at compile time for gas efficiency.
* Both State and Config structs are designed to be packed in one
* storage slot each.
* In order to pack both the state and config into one slot each,
* some assumptions are made:
* 1. limit{0,1,Global} and netflow{0,1,Global} are recorded with
* ZERO decimals precision to fit in an int48.
* Any subunit delta in netflow will be rounded up to one unit.
* 2. netflow{0,1,Global} have to fit in int48, thus have to fit in the range:
* -140_737_488_355_328 to 140_737_488_355_328, which can cover most
* tokens of interest, but will break down for tokens which trade
* in large unit values.
* 3. timespan{0,1} and lastUpdated{0,1} have to fit in int32 therefore
* the timestamps will overflow sometime in the year 2102.
*
* The library ensures that netflow0 and netflow1 are reset during
* the update phase, but does not control how the full State gets
* updated if the Config changes, this is left to the library consumer.
*/
library TradingLimits {
uint8 private constant L0 = 1; // 0b001 Limit0
uint8 private constant L1 = 2; // 0b010 Limit1
uint8 private constant LG = 4; // 0b100 LimitGlobal
int48 private constant MAX_INT48 = type(int48).max;
int48 private constant MIN_INT48 = type(int48).min;
/**
* @notice Validate a trading limit configuration.
* @dev Reverts if the configuration is malformed.
* @param self the Config struct to check.
*/
function validate(ITradingLimits.Config memory self) internal pure {
require(self.flags & L1 == 0 || self.flags & L0 != 0, "L1 without L0 not allowed");
require(self.flags & L0 == 0 || self.timestep0 > 0, "timestep0 can't be zero if active");
require(self.flags & L1 == 0 || self.timestep1 > 0, "timestep1 can't be zero if active");
require(self.flags & L0 == 0 || self.limit0 > 0, "limit0 can't be zero if active");
require(self.flags & L1 == 0 || self.limit1 > 0, "limit1 can't be zero if active");
require(self.flags & LG == 0 || self.limitGlobal > 0, "limitGlobal can't be zero if active");
require(self.flags & (L0 | L1) != 3 || self.limit0 < self.limit1, "limit1 must be greater than limit0");
require(self.flags & (L1 | LG) != 6 || self.limit1 < self.limitGlobal, "limitGlobal must be greater than limit1");
require(self.flags & (L0 | LG) != 5 || self.limit0 < self.limitGlobal, "limitGlobal must be greater than limit0");
}
/**
* @notice Verify a trading limit State with a provided Config.
* @dev Reverts if the limits are exceeded.
* @param self the trading limit State to check.
* @param config the trading limit Config to check against.
*/
function verify(ITradingLimits.State memory self, ITradingLimits.Config memory config) internal pure {
if ((config.flags & L0) > 0 && (-1 * config.limit0 > self.netflow0 || self.netflow0 > config.limit0)) {
revert("L0 Exceeded");
}
if ((config.flags & L1) > 0 && (-1 * config.limit1 > self.netflow1 || self.netflow1 > config.limit1)) {
revert("L1 Exceeded");
}
if (
(config.flags & LG) > 0 &&
(-1 * config.limitGlobal > self.netflowGlobal || self.netflowGlobal > config.limitGlobal)
) {
revert("LG Exceeded");
}
}
/**
* @notice Reset an existing state with a new config.
* It keps netflows of enabled limits and resets when disabled.
* It resets all timestamp checkpoints to reset time-window limits
* on next swap.
* @param self the trading limit state to reset.
* @param config the updated config to reset against.
* @return the reset state.
*/
function reset(
ITradingLimits.State memory self,
ITradingLimits.Config memory config
) internal pure returns (ITradingLimits.State memory) {
// Ensure the next swap will reset the trading limits windows.
self.lastUpdated0 = 0;
self.lastUpdated1 = 0;
if (config.flags & L0 == 0) {
self.netflow0 = 0;
}
if (config.flags & L1 == 0) {
self.netflow1 = 0;
}
if (config.flags & LG == 0) {
self.netflowGlobal = 0;
}
return self;
}
/**
* @notice Updates a trading limit State in the context of a Config with the deltaFlow provided.
* @dev Reverts if the values provided cause overflows.
* @param self the trading limit State to update.
* @param config the trading limit Config for the provided State.
* @param _deltaFlow the delta flow to add to the netflow.
* @param decimals the number of decimals the _deltaFlow is denominated in.
* @return State the updated state.
*/
function update(
ITradingLimits.State memory self,
ITradingLimits.Config memory config,
int256 _deltaFlow,
uint8 decimals
) internal view returns (ITradingLimits.State memory) {
if (_deltaFlow == 0) {
return self;
}
int256 _deltaFlowUnits = _deltaFlow / int256((10 ** uint256(decimals)));
require(_deltaFlowUnits <= MAX_INT48, "dFlow too large");
require(_deltaFlowUnits >= MIN_INT48, "dFlow too small");
int48 deltaFlowUnits = int48(_deltaFlowUnits);
if (deltaFlowUnits == 0) {
deltaFlowUnits = _deltaFlow > 0 ? int48(1) : int48(-1);
}
if (config.flags & L0 > 0) {
if (block.timestamp > self.lastUpdated0 + config.timestep0) {
self.netflow0 = 0;
self.lastUpdated0 = uint32(block.timestamp);
}
self.netflow0 = safeINT48Add(self.netflow0, deltaFlowUnits);
if (config.flags & L1 > 0) {
if (block.timestamp > self.lastUpdated1 + config.timestep1) {
self.netflow1 = 0;
self.lastUpdated1 = uint32(block.timestamp);
}
self.netflow1 = safeINT48Add(self.netflow1, deltaFlowUnits);
}
}
if (config.flags & LG > 0) {
self.netflowGlobal = safeINT48Add(self.netflowGlobal, deltaFlowUnits);
}
return self;
}
/**
* @notice Safe add two int48s.
* @dev Reverts if addition causes over/underflow.
* @param a number to add.
* @param b number to add.
* @return int48 result of addition.
*/
function safeINT48Add(int48 a, int48 b) internal pure returns (int48) {
int256 c = int256(a) + int256(b);
require(c >= MIN_INT48 && c <= MAX_INT48, "int48 addition overflow");
return int48(c);
}
}// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.5.13 <0.9.0;
contract Initializable {
bool public initialized;
constructor(bool testingDeployment) public {
if (!testingDeployment) {
initialized = true;
}
}
modifier initializer() {
require(!initialized, "contract already initialized");
initialized = true;
_;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}{
"remappings": [
"openzeppelin-solidity/=lib/openzeppelin-contracts/",
"openzeppelin-contracts/=lib/openzeppelin-contracts-next/",
"openzeppelin-contracts-next/=lib/openzeppelin-contracts-next/",
"test/=test/",
"forge-std/=lib/forge-std/src/",
"safe-contracts/=lib/safe-contracts/",
"prb/math/=lib/prb-math/src/",
"celo/=node_modules/@celo/",
"contracts/=contracts/",
"@chainlink/contracts/=lib/foundry-chainlink-toolkit/lib/chainlink-brownie-contracts/contracts/src/",
"@openzeppelin/=lib/foundry-chainlink-toolkit/lib/openzeppelin-contracts/",
"@prb/test/=lib/prb-math/lib/prb-test/src/",
"chainlink-brownie-contracts/=lib/foundry-chainlink-toolkit/lib/chainlink-brownie-contracts/contracts/src/v0.6/vendor/@arbitrum/nitro-contracts/src/",
"ds-test/=lib/prb-math/lib/forge-std/lib/ds-test/src/",
"foundry-chainlink-toolkit/=lib/foundry-chainlink-toolkit/",
"mento-std/=lib/mento-std/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"prb-math/=lib/prb-math/src/",
"prb-test/=lib/prb-math/lib/prb-test/src/",
"src/=lib/prb-math/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": false
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"bool","name":"test","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"exchangeProvider","type":"address"}],"name":"ExchangeProviderAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"exchangeProvider","type":"address"}],"name":"ExchangeProviderRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newAddress","type":"address"},{"indexed":true,"internalType":"address","name":"prevAddress","type":"address"}],"name":"ReserveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"exchangeProvider","type":"address"},{"indexed":true,"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"uint32","name":"timestep0","type":"uint32"},{"internalType":"uint32","name":"timestep1","type":"uint32"},{"internalType":"int48","name":"limit0","type":"int48"},{"internalType":"int48","name":"limit1","type":"int48"},{"internalType":"int48","name":"limitGlobal","type":"int48"},{"internalType":"uint8","name":"flags","type":"uint8"}],"indexed":false,"internalType":"struct ITradingLimits.Config","name":"config","type":"tuple"}],"name":"TradingLimitConfigured","type":"event"},{"inputs":[],"name":"__deprecated0","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"exchangeProvider","type":"address"},{"internalType":"address","name":"reserve","type":"address"}],"name":"addExchangeProvider","outputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnStableTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"uint32","name":"timestep0","type":"uint32"},{"internalType":"uint32","name":"timestep1","type":"uint32"},{"internalType":"int48","name":"limit0","type":"int48"},{"internalType":"int48","name":"limit1","type":"int48"},{"internalType":"int48","name":"limitGlobal","type":"int48"},{"internalType":"uint8","name":"flags","type":"uint8"}],"internalType":"struct ITradingLimits.Config","name":"config","type":"tuple"}],"name":"configureTradingLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"exchangeProviders","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"exchangeReserve","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"exchangeProvider","type":"address"},{"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"getAmountIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"exchangeProvider","type":"address"},{"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExchangeProviders","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_exchangeProviders","type":"address[]"},{"internalType":"address[]","name":"_reserves","type":"address[]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isExchangeProvider","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"exchangeProvider","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"removeExchangeProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_exchangeProviders","type":"address[]"},{"internalType":"address[]","name":"_reserves","type":"address[]"}],"name":"setReserves","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"exchangeProvider","type":"address"},{"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"swapIn","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"exchangeProvider","type":"address"},{"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"}],"name":"swapOut","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tradingLimitsConfig","outputs":[{"internalType":"uint32","name":"timestep0","type":"uint32"},{"internalType":"uint32","name":"timestep1","type":"uint32"},{"internalType":"int48","name":"limit0","type":"int48"},{"internalType":"int48","name":"limit1","type":"int48"},{"internalType":"int48","name":"limitGlobal","type":"int48"},{"internalType":"uint8","name":"flags","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tradingLimitsState","outputs":[{"internalType":"uint32","name":"lastUpdated0","type":"uint32"},{"internalType":"uint32","name":"lastUpdated1","type":"uint32"},{"internalType":"int48","name":"netflow0","type":"int48"},{"internalType":"int48","name":"netflow1","type":"int48"},{"internalType":"int48","name":"netflowGlobal","type":"int48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60806040523480156200001157600080fd5b5060405162003157380380620031578339810160408190526200003491620000b9565b808062000049576000805460ff191660011790555b50620000553362000060565b5060018055620000e4565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b600060208284031215620000cc57600080fd5b81518015158114620000dd57600080fd5b9392505050565b61306380620000f46000396000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c806387071a2d116100b8578063d163b1351161007c578063d163b13514610326578063d1d786b114610339578063ddbbe8501461035c578063ddeb9dd21461036f578063f01ecd1714610382578063f2fde38b1461041057600080fd5b806387071a2d146102965780638da5cb5b146102d7578063a20f2305146102ed578063a9b5aab314610300578063c4454fdc1461031357600080fd5b80635a2248b2116100ff5780635a2248b2146101bc578063715018a6146101c557806373cf25f8146101cd578063770d0a34146101e0578063821a816c146101f357600080fd5b806304710d531461013c57806304e4564014610151578063131cab2a14610177578063158ef93e1461019a5780632cac2568146101a7575b600080fd5b61014f61014a36600461299c565b610423565b005b61016461015f3660046129c6565b6105bb565b6040519081526020015b60405180910390f35b61018a61018536600461299c565b6107b0565b604051901515815260200161016e565b60005461018a9060ff1681565b6101af6107e4565b60405161016e9190612a1b565b61016460065481565b61014f610846565b61014f6101db366004612ab4565b61085a565b6101646101ee366004612b20565b610939565b610254610201366004612b53565b60056020819052600091825260409091205463ffffffff80821692640100000000830490911691600160401b8104820b91600160701b8204810b91600160a01b810490910b90600160d01b900460ff1686565b6040805163ffffffff9788168152969095166020870152600593840b9486019490945290820b6060850152900b608083015260ff1660a082015260c00161016e565b6102bf6102a4366004612b6c565b6007602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161016e565b60005461010090046001600160a01b03166102bf565b6101646102fb3660046129c6565b610b74565b61014f61030e366004612bc7565b610d6a565b6102bf610321366004612b53565b6110ad565b610164610334366004612ca7565b6110d7565b61018a610347366004612b6c565b60036020526000908152604090205460ff1681565b61016461036a366004612ca7565b611287565b61014f61037d366004612ab4565b61141f565b6103d8610390366004612b53565b60046020526000908152604090205463ffffffff80821691640100000000810490911690600160401b8104600590810b91600160701b8104820b91600160a01b909104900b85565b6040805163ffffffff9687168152959094166020860152600592830b93850193909352810b60608401520b608082015260a00161016e565b61014f61041e366004612b6c565b611636565b61042b6116af565b816001600160a01b03166002828154811061044857610448612d06565b6000918252602090912001546001600160a01b0316146104af5760405162461bcd60e51b815260206004820152601c60248201527f696e64657820646f65736e2774206d617463682070726f76696465720000000060448201526064015b60405180910390fd5b600280546104bf90600190612d32565b815481106104cf576104cf612d06565b600091825260209091200154600280546001600160a01b0390921691839081106104fb576104fb612d06565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600280548061053a5761053a612d45565b60008281526020808220830160001990810180546001600160a01b031990811690915593019093556001600160a01b038516808252600384526040808320805460ff1916905560079094528382208054909316909255915190917f29e92ab2e30f4f74283034c28c451b6faac986b554f1808101eb6418bdba19d491a25050565b6001600160a01b03851660009081526003602052604081205460ff166105f35760405162461bcd60e51b81526004016104a690612d5b565b6001600160a01b0386811660009081526007602052604090819020549051636570c17f60e11b81528583166004820152911690819063cae182fe90602401602060405180830381865afa15801561064e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106729190612d92565b15610732576040516370a0823160e01b81526001600160a01b0382811660048301528491908616906370a0823190602401602060405180830381865afa1580156106c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e49190612db4565b10156107325760405162461bcd60e51b815260206004820152601f60248201527f496e73756666696369656e742062616c616e636520696e20726573657276650060448201526064016104a6565b60405163f670dde160e01b81526001600160a01b0388169063f670dde190610764908990899089908990600401612dcd565b602060405180830381865afa158015610781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a59190612db4565b979650505050505050565b60006107c76001600160a01b03841633308561170f565b6107da6001600160a01b03841683611780565b5060015b92915050565b6060600280548060200260200160405190810160405280929190818152602001828054801561083c57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161081e575b5050505050905090565b61084e6116af565b61085860006117a3565b565b60005460ff16156108ad5760405162461bcd60e51b815260206004820152601c60248201527f636f6e747261637420616c726561647920696e697469616c697a65640000000060448201526064016104a6565b6000805460ff191660011790556108c3336117a3565b60005b838110156109325761091f8585838181106108e3576108e3612d06565b90506020020160208101906108f89190612b6c565b84848481811061090a5761090a612d06565b90506020020160208101906101ee9190612b6c565b508061092a81612df2565b9150506108c6565b5050505050565b60006109436116af565b6001600160a01b03831660009081526003602052604090205460ff16156109c05760405162461bcd60e51b815260206004820152602b60248201527f45786368616e676550726f766964657220616c7265616479206578697374732060448201526a1a5b881d1a19481b1a5cdd60aa1b60648201526084016104a6565b6001600160a01b038316610a225760405162461bcd60e51b815260206004820152602360248201527f45786368616e676550726f766964657220616464726573732063616e2774206260448201526206520360ec1b60648201526084016104a6565b6001600160a01b038216610a785760405162461bcd60e51b815260206004820152601a60248201527f5265736572766520616464726573732063616e2774206265203000000000000060448201526064016104a6565b6002805460018082019092557f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0180546001600160a01b03199081166001600160a01b038781169182179093556000818152600360209081526040808320805460ff19169097179096556007905284812080549093169387169390931790915591517f2ee2cb0721ec60b86190cae5c48e25064b69b35abad32452a4ec99d232033de29190a2816001600160a01b0316836001600160a01b03167fb69e1c416d8be92ac92c8e97e77c4626fba5e6ab50161099f659ea3303479e5060405160405180910390a3600254610b6d90600190612d32565b9392505050565b6001600160a01b03851660009081526003602052604081205460ff16610bac5760405162461bcd60e51b81526004016104a690612d5b565b6040516324f1f8ef60e21b81526001600160a01b038716906393c7e3bc90610bde908890889088908890600401612dcd565b602060405180830381865afa158015610bfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1f9190612db4565b6001600160a01b0387811660009081526007602052604090819020549051636570c17f60e11b815286831660048201529293501690819063cae182fe90602401602060405180830381865afa158015610c7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca09190612d92565b15610d60576040516370a0823160e01b81526001600160a01b0382811660048301528391908616906370a0823190602401602060405180830381865afa158015610cee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d129190612db4565b1015610d605760405162461bcd60e51b815260206004820152601f60248201527f496e73756666696369656e742062616c616e636520696e20726573657276650060448201526064016104a6565b5095945050505050565b610d726116af565b610d7b816117fc565b6000826001600160a01b031660001b84189050816005600083815260200190815260200160002060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548165ffffffffffff021916908360050b65ffffffffffff160217905550606082015181600001600e6101000a81548165ffffffffffff021916908360050b65ffffffffffff16021790555060808201518160000160146101000a81548165ffffffffffff021916908360050b65ffffffffffff16021790555060a082015181600001601a6101000a81548160ff021916908360ff160217905550905050610f7182600460008481526020019081526020016000206040518060a00160405290816000820160009054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160049054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160089054906101000a900460050b60050b60050b815260200160008201600e9054906101000a900460050b60050b60050b81526020016000820160149054906101000a900460050b60050b60050b81525050611c0290919063ffffffff16565b6000828152600460209081526040918290208351815485840151868601516060808901516080998a015163ffffffff96871667ffffffffffffffff199096169590951764010000000094871694909402939093176bffffffffffffffffffffffff60401b1916600160401b65ffffffffffff9384160265ffffffffffff60701b191617600160701b938316939093029290921765ffffffffffff60a01b1916600160a01b91909316029190911790925583518981526001600160a01b03891681850152875182168186015292870151168282015291850151600590810b8285015291850151820b60a0808301919091529285015190910b60c08201529083015160ff1660e08201527f1a082a1efaf1549c18917ddcb1f759680c29371609e24f4b946e93acf4ce5ad2906101000160405180910390a150505050565b600281815481106110bd57600080fd5b6000918252602090912001546001600160a01b0316905081565b60006110e1611c84565b6001600160a01b03871660009081526003602052604090205460ff166111195760405162461bcd60e51b81526004016104a690612d5b565b60405163d3385d0560e01b81526001600160a01b0388169063d3385d059061114b908990899089908990600401612dcd565b6020604051808303816000875af115801561116a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118e9190612db4565b9050818111156111d75760405162461bcd60e51b8152602060048201526014602482015273185b5bdd5b9d125b93585e08195e18d95959195960621b60448201526064016104a6565b6111e48686838787611cdd565b6001600160a01b038088166000908152600760205260409020541661120b33878484611db2565b61121733868684611f2f565b604080516001600160a01b038a8116825287811660208301529181018490526060810186905290871690339089907fe7b046415cac9de47940c3087e06db13a0e058ccf53ac5f0edd49ebb4c2c3a6f906080015b60405180910390a45061127d60018055565b9695505050505050565b6000611291611c84565b6001600160a01b03871660009081526003602052604090205460ff166112c95760405162461bcd60e51b81526004016104a690612d5b565b6040516310aff26760e21b81526001600160a01b038816906342bfc99c906112fb908990899089908990600401612dcd565b6020604051808303816000875af115801561131a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133e9190612db4565b9050818110156113875760405162461bcd60e51b8152602060048201526014602482015273185b5bdd5b9d13dd5d135a5b881b9bdd081b595d60621b60448201526064016104a6565b6113948686858785611cdd565b6001600160a01b03808816600090815260076020526040902054166113bb33878684611db2565b6113c733868484611f2f565b604080516001600160a01b038a8116825287811660208301529181018690526060810184905290871690339089907fe7b046415cac9de47940c3087e06db13a0e058ccf53ac5f0edd49ebb4c2c3a6f9060800161126b565b6114276116af565b60005b83811015610932576003600086868481811061144857611448612d06565b905060200201602081019061145d9190612b6c565b6001600160a01b0316815260208101919091526040016000205460ff166114965760405162461bcd60e51b81526004016104a690612d5b565b60008383838181106114aa576114aa612d06565b90506020020160208101906114bf9190612b6c565b6001600160a01b0316036115155760405162461bcd60e51b815260206004820152601a60248201527f5265736572766520616464726573732063616e2774206265203000000000000060448201526064016104a6565b82828281811061152757611527612d06565b905060200201602081019061153c9190612b6c565b6007600087878581811061155257611552612d06565b90506020020160208101906115679190612b6c565b6001600160a01b039081168252602082019290925260400160002080546001600160a01b031916929091169190911790558282828181106115aa576115aa612d06565b90506020020160208101906115bf9190612b6c565b6001600160a01b03168585838181106115da576115da612d06565b90506020020160208101906115ef9190612b6c565b6001600160a01b03167fb69e1c416d8be92ac92c8e97e77c4626fba5e6ab50161099f659ea3303479e5060405160405180910390a38061162e81612df2565b91505061142a565b61163e6116af565b6001600160a01b0381166116a35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016104a6565b6116ac816117a3565b50565b6000546001600160a01b036101009091041633146108585760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104a6565b6040516001600160a01b038085166024830152831660448201526064810182905261177a9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526120fb565b50505050565b61179f826342966c6860e01b8360405160240161174391815260200190565b5050565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b60a08101516002161580611816575060a081015160011615155b6118625760405162461bcd60e51b815260206004820152601960248201527f4c3120776974686f7574204c30206e6f7420616c6c6f7765640000000000000060448201526064016104a6565b60a0810151600116158061187c5750805163ffffffff1615155b6118d25760405162461bcd60e51b815260206004820152602160248201527f74696d6573746570302063616e2774206265207a65726f2069662061637469766044820152606560f81b60648201526084016104a6565b60a081015160021615806118f057506000816020015163ffffffff16115b6119465760405162461bcd60e51b815260206004820152602160248201527f74696d6573746570312063616e2774206265207a65726f2069662061637469766044820152606560f81b60648201526084016104a6565b60a0810151600116158061196157506000816040015160050b135b6119ad5760405162461bcd60e51b815260206004820152601e60248201527f6c696d6974302063616e2774206265207a65726f20696620616374697665000060448201526064016104a6565b60a081015160021615806119c857506000816060015160050b135b611a145760405162461bcd60e51b815260206004820152601e60248201527f6c696d6974312063616e2774206265207a65726f20696620616374697665000060448201526064016104a6565b60a08101516004161580611a2f57506000816080015160050b135b611a875760405162461bcd60e51b815260206004820152602360248201527f6c696d6974476c6f62616c2063616e2774206265207a65726f2069662061637460448201526269766560e81b60648201526084016104a6565b60a08101516003908116141580611aab5750806060015160050b816040015160050b125b611b025760405162461bcd60e51b815260206004820152602260248201527f6c696d697431206d7573742062652067726561746572207468616e206c696d69604482015261074360f41b60648201526084016104a6565b60a08101516006908116141580611b265750806080015160050b816060015160050b125b611b825760405162461bcd60e51b815260206004820152602760248201527f6c696d6974476c6f62616c206d7573742062652067726561746572207468616e604482015266206c696d69743160c81b60648201526084016104a6565b60a08101516005908116141580611ba65750806080015160050b816040015160050b125b6116ac5760405162461bcd60e51b815260206004820152602760248201527f6c696d6974476c6f62616c206d7573742062652067726561746572207468616e6044820152660206c696d6974360cc1b60648201526084016104a6565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915260008084526020840181905260a08301516001169003611c4f57600060408401525b60a0820151600216600003611c6657600060608401525b60a0820151600416600003611c7d57600060808401525b5090919050565b600260015403611cd65760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016104a6565b6002600155565b6001600160a01b038085169083166001600160ff1b03851115611d375760405162461bcd60e51b8152602060048201526012602482015271616d6f756e74496e20746f6f206c6172676560701b60448201526064016104a6565b6001600160ff1b03831115611d845760405162461bcd60e51b8152602060048201526013602482015272616d6f756e744f757420746f6f206c6172676560681b60448201526064016104a6565b611d9182881886886121d2565b611da9878218611da385600019612e0b565b866121d2565b50505050505050565b604051634f8e6e2360e01b81526001600160a01b038481166004830152829190821690634f8e6e2390602401602060405180830381865afa158015611dfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e1f9190612d92565b15611e5157611e396001600160a01b03851686308661170f565b611e4c6001600160a01b03851684611780565b610932565b604051636570c17f60e11b81526001600160a01b03858116600483015282169063cae182fe90602401602060405180830381865afa158015611e97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebb9190612d92565b15611ed557611e4c6001600160a01b03851686838661170f565b60405162461bcd60e51b815260206004820152602960248201527f546f6b656e206d75737420626520737461626c65206f7220636f6c6c61746572604482015268185b08185cdcd95c9d60ba1b60648201526084016104a6565b604051634f8e6e2360e01b81526001600160a01b038481166004830152829190821690634f8e6e2390602401602060405180830381865afa158015611f78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9c9190612d92565b15611fb557611e4c6001600160a01b03851686856123e4565b604051636570c17f60e11b81526001600160a01b03858116600483015282169063cae182fe90602401602060405180830381865afa158015611ffb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201f9190612d92565b15611ed557604051631af8e0ff60e21b81526001600160a01b038581166004830152868116602483015260448201859052821690636be383fc906064016020604051808303816000875af115801561207b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209f9190612d92565b611e4c5760405162461bcd60e51b815260206004820152602760248201527f5472616e73666572206f662074686520636f6c6c61746572616c2061737365746044820152660819985a5b195960ca1b60648201526084016104a6565b6000612150826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166124149092919063ffffffff16565b8051909150156121cd578080602001905181019061216e9190612d92565b6121cd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016104a6565b505050565b600083815260056020818152604092839020835160c081018552905463ffffffff808216835264010000000082041692820192909252600160401b8204830b93810193909352600160701b8104820b6060840152600160a01b810490910b6080830152600160d01b900460ff1660a082018190521561177a57600084815260046020818152604092839020835160a081018552905463ffffffff808216835264010000000082041682840152600160401b8104600590810b83870152600160701b8204810b6060840152600160a01b909104900b6080820152835163313ce56760e01b81529351909361232093869389936001600160a01b038a169363313ce567938181019392918290030181865afa1580156122f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123179190612e3b565b8492919061242b565b905061232c818361260c565b600094855260046020908152604095869020825181549284015197840151606085015160809095015163ffffffff92831667ffffffffffffffff19909516949094176401000000009290991691909102979097176bffffffffffffffffffffffff60401b1916600160401b65ffffffffffff9889160265ffffffffffff60701b191617600160701b938816939093029290921765ffffffffffff60a01b1916600160a01b969091169590950294909417909355505050565b6040516001600160a01b0383166024820152604481018290526121cd9084906340c10f1960e01b90606401611743565b60606124238484600085612792565b949350505050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915282600003612465575083612423565b600061247560ff8416600a612f3c565b61247f9085612f48565b9050657fffffffffff8113156124c95760405162461bcd60e51b815260206004820152600f60248201526e64466c6f7720746f6f206c6172676560881b60448201526064016104a6565b657fffffffffff198112156125125760405162461bcd60e51b815260206004820152600f60248201526e19119b1bddc81d1bdbc81cdb585b1b608a1b60448201526064016104a6565b80600581900b600003612535576000851361252f57600019612532565b60015b90505b60a0860151600116156125dd57855187516125509190612f84565b63ffffffff1642111561256e576000604088015263ffffffff421687525b61257c876040015182612862565b60050b604088015260a0860151600216156125dd57856020015187602001516125a59190612f84565b63ffffffff164211156125c6576000606088015263ffffffff421660208801525b6125d4876060015182612862565b60050b60608801525b60a086015160041615612601576125f8876080015182612862565b60050b60808801525b509495945050505050565b60a0810151600116158015906126535750816040015160050b81604001516000196126379190612fa8565b60050b13806126535750806040015160050b826040015160050b135b1561268e5760405162461bcd60e51b815260206004820152600b60248201526a130c08115e18d95959195960aa1b60448201526064016104a6565b60a0810151600216158015906126d55750816060015160050b81606001516000196126b99190612fa8565b60050b13806126d55750806060015160050b826060015160050b135b156127105760405162461bcd60e51b815260206004820152600b60248201526a130c48115e18d95959195960aa1b60448201526064016104a6565b60a0810151600416158015906127575750816080015160050b816080015160001961273b9190612fa8565b60050b13806127575750806080015160050b826080015160050b135b1561179f5760405162461bcd60e51b815260206004820152600b60248201526a1311c8115e18d95959195960aa1b60448201526064016104a6565b6060824710156127f35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016104a6565b600080866001600160a01b0316858760405161280f9190612fec565b60006040518083038185875af1925050503d806000811461284c576040519150601f19603f3d011682016040523d82523d6000602084013e612851565b606091505b50915091506107a5878383876128e2565b6000808260050b8460050b6128779190613008565b9050657fffffffffff1981128015906128965750657fffffffffff8113155b610b6d5760405162461bcd60e51b815260206004820152601760248201527f696e743438206164646974696f6e206f766572666c6f7700000000000000000060448201526064016104a6565b6060831561295157825160000361294a576001600160a01b0385163b61294a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016104a6565b5081612423565b61242383838151156129665781518083602001fd5b8060405162461bcd60e51b81526004016104a69190613030565b80356001600160a01b038116811461299757600080fd5b919050565b600080604083850312156129af57600080fd5b6129b883612980565b946020939093013593505050565b600080600080600060a086880312156129de57600080fd5b6129e786612980565b9450602086013593506129fc60408701612980565b9250612a0a60608701612980565b949793965091946080013592915050565b6020808252825182820181905260009190848201906040850190845b81811015612a5c5783516001600160a01b031683529284019291840191600101612a37565b50909695505050505050565b60008083601f840112612a7a57600080fd5b50813567ffffffffffffffff811115612a9257600080fd5b6020830191508360208260051b8501011115612aad57600080fd5b9250929050565b60008060008060408587031215612aca57600080fd5b843567ffffffffffffffff80821115612ae257600080fd5b612aee88838901612a68565b90965094506020870135915080821115612b0757600080fd5b50612b1487828801612a68565b95989497509550505050565b60008060408385031215612b3357600080fd5b612b3c83612980565b9150612b4a60208401612980565b90509250929050565b600060208284031215612b6557600080fd5b5035919050565b600060208284031215612b7e57600080fd5b610b6d82612980565b803563ffffffff8116811461299757600080fd5b8035600581900b811461299757600080fd5b60ff811681146116ac57600080fd5b803561299781612bad565b6000806000838503610100811215612bde57600080fd5b84359350612bee60208601612980565b925060c0603f1982011215612c0257600080fd5b5060405160c0810181811067ffffffffffffffff82111715612c3457634e487b7160e01b600052604160045260246000fd5b8060405250612c4560408601612b87565b8152612c5360608601612b87565b6020820152612c6460808601612b9b565b6040820152612c7560a08601612b9b565b6060820152612c8660c08601612b9b565b6080820152612c9760e08601612bbc565b60a0820152809150509250925092565b60008060008060008060c08789031215612cc057600080fd5b612cc987612980565b955060208701359450612cde60408801612980565b9350612cec60608801612980565b92506080870135915060a087013590509295509295509295565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b818103818111156107de576107de612d1c565b634e487b7160e01b600052603160045260246000fd5b6020808252601f908201527f45786368616e676550726f766964657220646f6573206e6f7420657869737400604082015260600190565b600060208284031215612da457600080fd5b81518015158114610b6d57600080fd5b600060208284031215612dc657600080fd5b5051919050565b9384526001600160a01b03928316602085015291166040830152606082015260800190565b600060018201612e0457612e04612d1c565b5060010190565b80820260008212600160ff1b84141615612e2757612e27612d1c565b81810583148215176107de576107de612d1c565b600060208284031215612e4d57600080fd5b8151610b6d81612bad565b600181815b80851115612e93578160001904821115612e7957612e79612d1c565b80851615612e8657918102915b93841c9390800290612e5d565b509250929050565b600082612eaa575060016107de565b81612eb7575060006107de565b8160018114612ecd5760028114612ed757612ef3565b60019150506107de565b60ff841115612ee857612ee8612d1c565b50506001821b6107de565b5060208310610133831016604e8410600b8410161715612f16575081810a6107de565b612f208383612e58565b8060001904821115612f3457612f34612d1c565b029392505050565b6000610b6d8383612e9b565b600082612f6557634e487b7160e01b600052601260045260246000fd5b600160ff1b821460001984141615612f7f57612f7f612d1c565b500590565b63ffffffff818116838216019080821115612fa157612fa1612d1c565b5092915050565b60008260050b8260050b028060050b9150808214612fa157612fa1612d1c565b60005b83811015612fe3578181015183820152602001612fcb565b50506000910152565b60008251612ffe818460208701612fc8565b9190910192915050565b808201828112600083128015821682158216171561302857613028612d1c565b505092915050565b602081526000825180602084015261304f816040850160208701612fc8565b601f01601f19169190910160400192915050560000000000000000000000000000000000000000000000000000000000000001
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101375760003560e01c806387071a2d116100b8578063d163b1351161007c578063d163b13514610326578063d1d786b114610339578063ddbbe8501461035c578063ddeb9dd21461036f578063f01ecd1714610382578063f2fde38b1461041057600080fd5b806387071a2d146102965780638da5cb5b146102d7578063a20f2305146102ed578063a9b5aab314610300578063c4454fdc1461031357600080fd5b80635a2248b2116100ff5780635a2248b2146101bc578063715018a6146101c557806373cf25f8146101cd578063770d0a34146101e0578063821a816c146101f357600080fd5b806304710d531461013c57806304e4564014610151578063131cab2a14610177578063158ef93e1461019a5780632cac2568146101a7575b600080fd5b61014f61014a36600461299c565b610423565b005b61016461015f3660046129c6565b6105bb565b6040519081526020015b60405180910390f35b61018a61018536600461299c565b6107b0565b604051901515815260200161016e565b60005461018a9060ff1681565b6101af6107e4565b60405161016e9190612a1b565b61016460065481565b61014f610846565b61014f6101db366004612ab4565b61085a565b6101646101ee366004612b20565b610939565b610254610201366004612b53565b60056020819052600091825260409091205463ffffffff80821692640100000000830490911691600160401b8104820b91600160701b8204810b91600160a01b810490910b90600160d01b900460ff1686565b6040805163ffffffff9788168152969095166020870152600593840b9486019490945290820b6060850152900b608083015260ff1660a082015260c00161016e565b6102bf6102a4366004612b6c565b6007602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161016e565b60005461010090046001600160a01b03166102bf565b6101646102fb3660046129c6565b610b74565b61014f61030e366004612bc7565b610d6a565b6102bf610321366004612b53565b6110ad565b610164610334366004612ca7565b6110d7565b61018a610347366004612b6c565b60036020526000908152604090205460ff1681565b61016461036a366004612ca7565b611287565b61014f61037d366004612ab4565b61141f565b6103d8610390366004612b53565b60046020526000908152604090205463ffffffff80821691640100000000810490911690600160401b8104600590810b91600160701b8104820b91600160a01b909104900b85565b6040805163ffffffff9687168152959094166020860152600592830b93850193909352810b60608401520b608082015260a00161016e565b61014f61041e366004612b6c565b611636565b61042b6116af565b816001600160a01b03166002828154811061044857610448612d06565b6000918252602090912001546001600160a01b0316146104af5760405162461bcd60e51b815260206004820152601c60248201527f696e64657820646f65736e2774206d617463682070726f76696465720000000060448201526064015b60405180910390fd5b600280546104bf90600190612d32565b815481106104cf576104cf612d06565b600091825260209091200154600280546001600160a01b0390921691839081106104fb576104fb612d06565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600280548061053a5761053a612d45565b60008281526020808220830160001990810180546001600160a01b031990811690915593019093556001600160a01b038516808252600384526040808320805460ff1916905560079094528382208054909316909255915190917f29e92ab2e30f4f74283034c28c451b6faac986b554f1808101eb6418bdba19d491a25050565b6001600160a01b03851660009081526003602052604081205460ff166105f35760405162461bcd60e51b81526004016104a690612d5b565b6001600160a01b0386811660009081526007602052604090819020549051636570c17f60e11b81528583166004820152911690819063cae182fe90602401602060405180830381865afa15801561064e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106729190612d92565b15610732576040516370a0823160e01b81526001600160a01b0382811660048301528491908616906370a0823190602401602060405180830381865afa1580156106c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e49190612db4565b10156107325760405162461bcd60e51b815260206004820152601f60248201527f496e73756666696369656e742062616c616e636520696e20726573657276650060448201526064016104a6565b60405163f670dde160e01b81526001600160a01b0388169063f670dde190610764908990899089908990600401612dcd565b602060405180830381865afa158015610781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a59190612db4565b979650505050505050565b60006107c76001600160a01b03841633308561170f565b6107da6001600160a01b03841683611780565b5060015b92915050565b6060600280548060200260200160405190810160405280929190818152602001828054801561083c57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161081e575b5050505050905090565b61084e6116af565b61085860006117a3565b565b60005460ff16156108ad5760405162461bcd60e51b815260206004820152601c60248201527f636f6e747261637420616c726561647920696e697469616c697a65640000000060448201526064016104a6565b6000805460ff191660011790556108c3336117a3565b60005b838110156109325761091f8585838181106108e3576108e3612d06565b90506020020160208101906108f89190612b6c565b84848481811061090a5761090a612d06565b90506020020160208101906101ee9190612b6c565b508061092a81612df2565b9150506108c6565b5050505050565b60006109436116af565b6001600160a01b03831660009081526003602052604090205460ff16156109c05760405162461bcd60e51b815260206004820152602b60248201527f45786368616e676550726f766964657220616c7265616479206578697374732060448201526a1a5b881d1a19481b1a5cdd60aa1b60648201526084016104a6565b6001600160a01b038316610a225760405162461bcd60e51b815260206004820152602360248201527f45786368616e676550726f766964657220616464726573732063616e2774206260448201526206520360ec1b60648201526084016104a6565b6001600160a01b038216610a785760405162461bcd60e51b815260206004820152601a60248201527f5265736572766520616464726573732063616e2774206265203000000000000060448201526064016104a6565b6002805460018082019092557f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0180546001600160a01b03199081166001600160a01b038781169182179093556000818152600360209081526040808320805460ff19169097179096556007905284812080549093169387169390931790915591517f2ee2cb0721ec60b86190cae5c48e25064b69b35abad32452a4ec99d232033de29190a2816001600160a01b0316836001600160a01b03167fb69e1c416d8be92ac92c8e97e77c4626fba5e6ab50161099f659ea3303479e5060405160405180910390a3600254610b6d90600190612d32565b9392505050565b6001600160a01b03851660009081526003602052604081205460ff16610bac5760405162461bcd60e51b81526004016104a690612d5b565b6040516324f1f8ef60e21b81526001600160a01b038716906393c7e3bc90610bde908890889088908890600401612dcd565b602060405180830381865afa158015610bfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1f9190612db4565b6001600160a01b0387811660009081526007602052604090819020549051636570c17f60e11b815286831660048201529293501690819063cae182fe90602401602060405180830381865afa158015610c7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca09190612d92565b15610d60576040516370a0823160e01b81526001600160a01b0382811660048301528391908616906370a0823190602401602060405180830381865afa158015610cee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d129190612db4565b1015610d605760405162461bcd60e51b815260206004820152601f60248201527f496e73756666696369656e742062616c616e636520696e20726573657276650060448201526064016104a6565b5095945050505050565b610d726116af565b610d7b816117fc565b6000826001600160a01b031660001b84189050816005600083815260200190815260200160002060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548165ffffffffffff021916908360050b65ffffffffffff160217905550606082015181600001600e6101000a81548165ffffffffffff021916908360050b65ffffffffffff16021790555060808201518160000160146101000a81548165ffffffffffff021916908360050b65ffffffffffff16021790555060a082015181600001601a6101000a81548160ff021916908360ff160217905550905050610f7182600460008481526020019081526020016000206040518060a00160405290816000820160009054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160049054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160089054906101000a900460050b60050b60050b815260200160008201600e9054906101000a900460050b60050b60050b81526020016000820160149054906101000a900460050b60050b60050b81525050611c0290919063ffffffff16565b6000828152600460209081526040918290208351815485840151868601516060808901516080998a015163ffffffff96871667ffffffffffffffff199096169590951764010000000094871694909402939093176bffffffffffffffffffffffff60401b1916600160401b65ffffffffffff9384160265ffffffffffff60701b191617600160701b938316939093029290921765ffffffffffff60a01b1916600160a01b91909316029190911790925583518981526001600160a01b03891681850152875182168186015292870151168282015291850151600590810b8285015291850151820b60a0808301919091529285015190910b60c08201529083015160ff1660e08201527f1a082a1efaf1549c18917ddcb1f759680c29371609e24f4b946e93acf4ce5ad2906101000160405180910390a150505050565b600281815481106110bd57600080fd5b6000918252602090912001546001600160a01b0316905081565b60006110e1611c84565b6001600160a01b03871660009081526003602052604090205460ff166111195760405162461bcd60e51b81526004016104a690612d5b565b60405163d3385d0560e01b81526001600160a01b0388169063d3385d059061114b908990899089908990600401612dcd565b6020604051808303816000875af115801561116a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118e9190612db4565b9050818111156111d75760405162461bcd60e51b8152602060048201526014602482015273185b5bdd5b9d125b93585e08195e18d95959195960621b60448201526064016104a6565b6111e48686838787611cdd565b6001600160a01b038088166000908152600760205260409020541661120b33878484611db2565b61121733868684611f2f565b604080516001600160a01b038a8116825287811660208301529181018490526060810186905290871690339089907fe7b046415cac9de47940c3087e06db13a0e058ccf53ac5f0edd49ebb4c2c3a6f906080015b60405180910390a45061127d60018055565b9695505050505050565b6000611291611c84565b6001600160a01b03871660009081526003602052604090205460ff166112c95760405162461bcd60e51b81526004016104a690612d5b565b6040516310aff26760e21b81526001600160a01b038816906342bfc99c906112fb908990899089908990600401612dcd565b6020604051808303816000875af115801561131a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133e9190612db4565b9050818110156113875760405162461bcd60e51b8152602060048201526014602482015273185b5bdd5b9d13dd5d135a5b881b9bdd081b595d60621b60448201526064016104a6565b6113948686858785611cdd565b6001600160a01b03808816600090815260076020526040902054166113bb33878684611db2565b6113c733868484611f2f565b604080516001600160a01b038a8116825287811660208301529181018690526060810184905290871690339089907fe7b046415cac9de47940c3087e06db13a0e058ccf53ac5f0edd49ebb4c2c3a6f9060800161126b565b6114276116af565b60005b83811015610932576003600086868481811061144857611448612d06565b905060200201602081019061145d9190612b6c565b6001600160a01b0316815260208101919091526040016000205460ff166114965760405162461bcd60e51b81526004016104a690612d5b565b60008383838181106114aa576114aa612d06565b90506020020160208101906114bf9190612b6c565b6001600160a01b0316036115155760405162461bcd60e51b815260206004820152601a60248201527f5265736572766520616464726573732063616e2774206265203000000000000060448201526064016104a6565b82828281811061152757611527612d06565b905060200201602081019061153c9190612b6c565b6007600087878581811061155257611552612d06565b90506020020160208101906115679190612b6c565b6001600160a01b039081168252602082019290925260400160002080546001600160a01b031916929091169190911790558282828181106115aa576115aa612d06565b90506020020160208101906115bf9190612b6c565b6001600160a01b03168585838181106115da576115da612d06565b90506020020160208101906115ef9190612b6c565b6001600160a01b03167fb69e1c416d8be92ac92c8e97e77c4626fba5e6ab50161099f659ea3303479e5060405160405180910390a38061162e81612df2565b91505061142a565b61163e6116af565b6001600160a01b0381166116a35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016104a6565b6116ac816117a3565b50565b6000546001600160a01b036101009091041633146108585760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104a6565b6040516001600160a01b038085166024830152831660448201526064810182905261177a9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526120fb565b50505050565b61179f826342966c6860e01b8360405160240161174391815260200190565b5050565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b60a08101516002161580611816575060a081015160011615155b6118625760405162461bcd60e51b815260206004820152601960248201527f4c3120776974686f7574204c30206e6f7420616c6c6f7765640000000000000060448201526064016104a6565b60a0810151600116158061187c5750805163ffffffff1615155b6118d25760405162461bcd60e51b815260206004820152602160248201527f74696d6573746570302063616e2774206265207a65726f2069662061637469766044820152606560f81b60648201526084016104a6565b60a081015160021615806118f057506000816020015163ffffffff16115b6119465760405162461bcd60e51b815260206004820152602160248201527f74696d6573746570312063616e2774206265207a65726f2069662061637469766044820152606560f81b60648201526084016104a6565b60a0810151600116158061196157506000816040015160050b135b6119ad5760405162461bcd60e51b815260206004820152601e60248201527f6c696d6974302063616e2774206265207a65726f20696620616374697665000060448201526064016104a6565b60a081015160021615806119c857506000816060015160050b135b611a145760405162461bcd60e51b815260206004820152601e60248201527f6c696d6974312063616e2774206265207a65726f20696620616374697665000060448201526064016104a6565b60a08101516004161580611a2f57506000816080015160050b135b611a875760405162461bcd60e51b815260206004820152602360248201527f6c696d6974476c6f62616c2063616e2774206265207a65726f2069662061637460448201526269766560e81b60648201526084016104a6565b60a08101516003908116141580611aab5750806060015160050b816040015160050b125b611b025760405162461bcd60e51b815260206004820152602260248201527f6c696d697431206d7573742062652067726561746572207468616e206c696d69604482015261074360f41b60648201526084016104a6565b60a08101516006908116141580611b265750806080015160050b816060015160050b125b611b825760405162461bcd60e51b815260206004820152602760248201527f6c696d6974476c6f62616c206d7573742062652067726561746572207468616e604482015266206c696d69743160c81b60648201526084016104a6565b60a08101516005908116141580611ba65750806080015160050b816040015160050b125b6116ac5760405162461bcd60e51b815260206004820152602760248201527f6c696d6974476c6f62616c206d7573742062652067726561746572207468616e6044820152660206c696d6974360cc1b60648201526084016104a6565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915260008084526020840181905260a08301516001169003611c4f57600060408401525b60a0820151600216600003611c6657600060608401525b60a0820151600416600003611c7d57600060808401525b5090919050565b600260015403611cd65760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016104a6565b6002600155565b6001600160a01b038085169083166001600160ff1b03851115611d375760405162461bcd60e51b8152602060048201526012602482015271616d6f756e74496e20746f6f206c6172676560701b60448201526064016104a6565b6001600160ff1b03831115611d845760405162461bcd60e51b8152602060048201526013602482015272616d6f756e744f757420746f6f206c6172676560681b60448201526064016104a6565b611d9182881886886121d2565b611da9878218611da385600019612e0b565b866121d2565b50505050505050565b604051634f8e6e2360e01b81526001600160a01b038481166004830152829190821690634f8e6e2390602401602060405180830381865afa158015611dfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e1f9190612d92565b15611e5157611e396001600160a01b03851686308661170f565b611e4c6001600160a01b03851684611780565b610932565b604051636570c17f60e11b81526001600160a01b03858116600483015282169063cae182fe90602401602060405180830381865afa158015611e97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebb9190612d92565b15611ed557611e4c6001600160a01b03851686838661170f565b60405162461bcd60e51b815260206004820152602960248201527f546f6b656e206d75737420626520737461626c65206f7220636f6c6c61746572604482015268185b08185cdcd95c9d60ba1b60648201526084016104a6565b604051634f8e6e2360e01b81526001600160a01b038481166004830152829190821690634f8e6e2390602401602060405180830381865afa158015611f78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9c9190612d92565b15611fb557611e4c6001600160a01b03851686856123e4565b604051636570c17f60e11b81526001600160a01b03858116600483015282169063cae182fe90602401602060405180830381865afa158015611ffb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201f9190612d92565b15611ed557604051631af8e0ff60e21b81526001600160a01b038581166004830152868116602483015260448201859052821690636be383fc906064016020604051808303816000875af115801561207b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209f9190612d92565b611e4c5760405162461bcd60e51b815260206004820152602760248201527f5472616e73666572206f662074686520636f6c6c61746572616c2061737365746044820152660819985a5b195960ca1b60648201526084016104a6565b6000612150826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166124149092919063ffffffff16565b8051909150156121cd578080602001905181019061216e9190612d92565b6121cd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016104a6565b505050565b600083815260056020818152604092839020835160c081018552905463ffffffff808216835264010000000082041692820192909252600160401b8204830b93810193909352600160701b8104820b6060840152600160a01b810490910b6080830152600160d01b900460ff1660a082018190521561177a57600084815260046020818152604092839020835160a081018552905463ffffffff808216835264010000000082041682840152600160401b8104600590810b83870152600160701b8204810b6060840152600160a01b909104900b6080820152835163313ce56760e01b81529351909361232093869389936001600160a01b038a169363313ce567938181019392918290030181865afa1580156122f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123179190612e3b565b8492919061242b565b905061232c818361260c565b600094855260046020908152604095869020825181549284015197840151606085015160809095015163ffffffff92831667ffffffffffffffff19909516949094176401000000009290991691909102979097176bffffffffffffffffffffffff60401b1916600160401b65ffffffffffff9889160265ffffffffffff60701b191617600160701b938816939093029290921765ffffffffffff60a01b1916600160a01b969091169590950294909417909355505050565b6040516001600160a01b0383166024820152604481018290526121cd9084906340c10f1960e01b90606401611743565b60606124238484600085612792565b949350505050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915282600003612465575083612423565b600061247560ff8416600a612f3c565b61247f9085612f48565b9050657fffffffffff8113156124c95760405162461bcd60e51b815260206004820152600f60248201526e64466c6f7720746f6f206c6172676560881b60448201526064016104a6565b657fffffffffff198112156125125760405162461bcd60e51b815260206004820152600f60248201526e19119b1bddc81d1bdbc81cdb585b1b608a1b60448201526064016104a6565b80600581900b600003612535576000851361252f57600019612532565b60015b90505b60a0860151600116156125dd57855187516125509190612f84565b63ffffffff1642111561256e576000604088015263ffffffff421687525b61257c876040015182612862565b60050b604088015260a0860151600216156125dd57856020015187602001516125a59190612f84565b63ffffffff164211156125c6576000606088015263ffffffff421660208801525b6125d4876060015182612862565b60050b60608801525b60a086015160041615612601576125f8876080015182612862565b60050b60808801525b509495945050505050565b60a0810151600116158015906126535750816040015160050b81604001516000196126379190612fa8565b60050b13806126535750806040015160050b826040015160050b135b1561268e5760405162461bcd60e51b815260206004820152600b60248201526a130c08115e18d95959195960aa1b60448201526064016104a6565b60a0810151600216158015906126d55750816060015160050b81606001516000196126b99190612fa8565b60050b13806126d55750806060015160050b826060015160050b135b156127105760405162461bcd60e51b815260206004820152600b60248201526a130c48115e18d95959195960aa1b60448201526064016104a6565b60a0810151600416158015906127575750816080015160050b816080015160001961273b9190612fa8565b60050b13806127575750806080015160050b826080015160050b135b1561179f5760405162461bcd60e51b815260206004820152600b60248201526a1311c8115e18d95959195960aa1b60448201526064016104a6565b6060824710156127f35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016104a6565b600080866001600160a01b0316858760405161280f9190612fec565b60006040518083038185875af1925050503d806000811461284c576040519150601f19603f3d011682016040523d82523d6000602084013e612851565b606091505b50915091506107a5878383876128e2565b6000808260050b8460050b6128779190613008565b9050657fffffffffff1981128015906128965750657fffffffffff8113155b610b6d5760405162461bcd60e51b815260206004820152601760248201527f696e743438206164646974696f6e206f766572666c6f7700000000000000000060448201526064016104a6565b6060831561295157825160000361294a576001600160a01b0385163b61294a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016104a6565b5081612423565b61242383838151156129665781518083602001fd5b8060405162461bcd60e51b81526004016104a69190613030565b80356001600160a01b038116811461299757600080fd5b919050565b600080604083850312156129af57600080fd5b6129b883612980565b946020939093013593505050565b600080600080600060a086880312156129de57600080fd5b6129e786612980565b9450602086013593506129fc60408701612980565b9250612a0a60608701612980565b949793965091946080013592915050565b6020808252825182820181905260009190848201906040850190845b81811015612a5c5783516001600160a01b031683529284019291840191600101612a37565b50909695505050505050565b60008083601f840112612a7a57600080fd5b50813567ffffffffffffffff811115612a9257600080fd5b6020830191508360208260051b8501011115612aad57600080fd5b9250929050565b60008060008060408587031215612aca57600080fd5b843567ffffffffffffffff80821115612ae257600080fd5b612aee88838901612a68565b90965094506020870135915080821115612b0757600080fd5b50612b1487828801612a68565b95989497509550505050565b60008060408385031215612b3357600080fd5b612b3c83612980565b9150612b4a60208401612980565b90509250929050565b600060208284031215612b6557600080fd5b5035919050565b600060208284031215612b7e57600080fd5b610b6d82612980565b803563ffffffff8116811461299757600080fd5b8035600581900b811461299757600080fd5b60ff811681146116ac57600080fd5b803561299781612bad565b6000806000838503610100811215612bde57600080fd5b84359350612bee60208601612980565b925060c0603f1982011215612c0257600080fd5b5060405160c0810181811067ffffffffffffffff82111715612c3457634e487b7160e01b600052604160045260246000fd5b8060405250612c4560408601612b87565b8152612c5360608601612b87565b6020820152612c6460808601612b9b565b6040820152612c7560a08601612b9b565b6060820152612c8660c08601612b9b565b6080820152612c9760e08601612bbc565b60a0820152809150509250925092565b60008060008060008060c08789031215612cc057600080fd5b612cc987612980565b955060208701359450612cde60408801612980565b9350612cec60608801612980565b92506080870135915060a087013590509295509295509295565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b818103818111156107de576107de612d1c565b634e487b7160e01b600052603160045260246000fd5b6020808252601f908201527f45786368616e676550726f766964657220646f6573206e6f7420657869737400604082015260600190565b600060208284031215612da457600080fd5b81518015158114610b6d57600080fd5b600060208284031215612dc657600080fd5b5051919050565b9384526001600160a01b03928316602085015291166040830152606082015260800190565b600060018201612e0457612e04612d1c565b5060010190565b80820260008212600160ff1b84141615612e2757612e27612d1c565b81810583148215176107de576107de612d1c565b600060208284031215612e4d57600080fd5b8151610b6d81612bad565b600181815b80851115612e93578160001904821115612e7957612e79612d1c565b80851615612e8657918102915b93841c9390800290612e5d565b509250929050565b600082612eaa575060016107de565b81612eb7575060006107de565b8160018114612ecd5760028114612ed757612ef3565b60019150506107de565b60ff841115612ee857612ee8612d1c565b50506001821b6107de565b5060208310610133831016604e8410600b8410161715612f16575081810a6107de565b612f208383612e58565b8060001904821115612f3457612f34612d1c565b029392505050565b6000610b6d8383612e9b565b600082612f6557634e487b7160e01b600052601260045260246000fd5b600160ff1b821460001984141615612f7f57612f7f612d1c565b500590565b63ffffffff818116838216019080821115612fa157612fa1612d1c565b5092915050565b60008260050b8260050b028060050b9150808214612fa157612fa1612d1c565b60005b83811015612fe3578181015183820152602001612fcb565b50506000910152565b60008251612ffe818460208701612fc8565b9190910192915050565b808201828112600083128015821682158216171561302857613028612d1c565b505092915050565b602081526000825180602084015261304f816040850160208701612fc8565b601f01601f1916919091016040019291505056
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000001
-----Decoded View---------------
Arg [0] : test (bool): True
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000001
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.