Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x61016060 | 19612151 | 692 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19612151 | 692 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19612151 | 692 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19612151 | 692 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19612151 | 692 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19612151 | 692 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19612151 | 692 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19612151 | 692 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19612151 | 692 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19612151 | 692 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19612151 | 692 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19612151 | 692 days ago | Contract Creation | 0 ETH | |||
| 0x61016060 | 19577960 | 697 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19577960 | 697 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19577960 | 697 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19577960 | 697 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19577960 | 697 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19577960 | 697 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19577960 | 697 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19577960 | 697 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19577960 | 697 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19577960 | 697 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19577960 | 697 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 19577960 | 697 days ago | Contract Creation | 0 ETH | |||
| 0x61016060 | 19441526 | 716 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
DeployerP1
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts/proxy/Clones.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "../interfaces/IAsset.sol";
import "../interfaces/IAssetRegistry.sol";
import "../interfaces/IBackingManager.sol";
import "../interfaces/IBasketHandler.sol";
import "../interfaces/IBroker.sol";
import "../interfaces/IDeployer.sol";
import "../interfaces/IDistributor.sol";
import "../interfaces/IFurnace.sol";
import "../interfaces/IRevenueTrader.sol";
import "../interfaces/IRToken.sol";
import "../interfaces/IStRSR.sol";
import "../mixins/Versioned.sol";
import "../plugins/assets/Asset.sol";
import "../plugins/assets/RTokenAsset.sol";
import "./Main.sol";
import "../libraries/String.sol";
/**
* @title DeployerP1
* @notice The factory contract that deploys the entire P1 system.
*/
contract DeployerP1 is IDeployer, Versioned {
using Clones for address;
string public constant ENS = "reserveprotocol.eth";
IERC20Metadata public immutable rsr;
IGnosis public immutable gnosis;
IAsset public immutable rsrAsset;
// Implementation contracts for Upgradeability
Implementations public implementations;
// checks: every address in the input is nonzero
// effects: post, all contract-state values are set
constructor(
IERC20Metadata rsr_,
IGnosis gnosis_,
IAsset rsrAsset_,
Implementations memory implementations_
) {
require(
address(rsr_) != address(0) &&
address(gnosis_) != address(0) &&
address(rsrAsset_) != address(0) &&
address(implementations_.main) != address(0) &&
address(implementations_.trading.gnosisTrade) != address(0) &&
address(implementations_.trading.dutchTrade) != address(0) &&
address(implementations_.components.assetRegistry) != address(0) &&
address(implementations_.components.backingManager) != address(0) &&
address(implementations_.components.basketHandler) != address(0) &&
address(implementations_.components.broker) != address(0) &&
address(implementations_.components.distributor) != address(0) &&
address(implementations_.components.furnace) != address(0) &&
address(implementations_.components.rsrTrader) != address(0) &&
address(implementations_.components.rTokenTrader) != address(0) &&
address(implementations_.components.rToken) != address(0) &&
address(implementations_.components.stRSR) != address(0),
"invalid address"
);
rsr = rsr_;
gnosis = gnosis_;
rsrAsset = rsrAsset_;
implementations = implementations_;
}
/// Deploys an instance of the entire system, oriented around some mandate.
///
/// The mandate describes what goals its governors should try to achieve. By succinctly
/// explaining the RToken’s purpose and what the RToken is intended to do, it provides common
/// ground for the governors to decide upon priorities and how to weigh tradeoffs.
///
/// Example Mandates:
///
/// - Capital preservation first. Spending power preservation second. Permissionless
/// access third.
/// - Capital preservation above all else. All revenues fund the over-collateralization pool.
/// - Risk-neutral pursuit of profit for token holders.
/// Maximize (gross revenue - payments for over-collateralization and governance).
/// - This RToken holds only FooCoin, to provide a trade for hedging against its
/// possible collapse.
///
/// The mandate may also be a URI to a longer body of text
/// @param name The name of the RToken to deploy
/// @param symbol The symbol of the RToken to deploy
/// @param mandate An IPFS link or direct string; describes what the RToken _should be_
/// @param owner The address that should own the entire system, hopefully a governance contract
/// @param params Deployment params
/// @return The address of the newly deployed RToken.
// effects:
// Deploy a proxy for Main and every component of Main
// Call init() on Main and every component of Main, using `params` for needed parameters
// While doing this, init assetRegistry with this.rsrAsset and a new rTokenAsset
// Set up Auth so that `owner` holds the OWNER role and no one else has any
function deploy(
string memory name,
string memory symbol,
string calldata mandate,
address owner,
DeploymentParams memory params
) external returns (address) {
require(owner != address(0) && owner != address(this), "invalid owner");
// Main - Proxy
MainP1 main = MainP1(
address(new ERC1967Proxy(address(implementations.main), new bytes(0)))
);
// Components - Proxies
IRToken rToken = IRToken(
address(new ERC1967Proxy(address(implementations.components.rToken), new bytes(0)))
);
Components memory components = Components({
stRSR: IStRSR(
address(new ERC1967Proxy(address(implementations.components.stRSR), new bytes(0)))
),
rToken: rToken,
assetRegistry: IAssetRegistry(
address(
new ERC1967Proxy(
address(implementations.components.assetRegistry),
new bytes(0)
)
)
),
basketHandler: IBasketHandler(
address(
new ERC1967Proxy(
address(implementations.components.basketHandler),
new bytes(0)
)
)
),
backingManager: IBackingManager(
address(
new ERC1967Proxy(
address(implementations.components.backingManager),
new bytes(0)
)
)
),
distributor: IDistributor(
address(
new ERC1967Proxy(address(implementations.components.distributor), new bytes(0))
)
),
rsrTrader: IRevenueTrader(
address(
new ERC1967Proxy(address(implementations.components.rsrTrader), new bytes(0))
)
),
rTokenTrader: IRevenueTrader(
address(
new ERC1967Proxy(address(implementations.components.rTokenTrader), new bytes(0))
)
),
furnace: IFurnace(
address(new ERC1967Proxy(address(implementations.components.furnace), new bytes(0)))
),
broker: IBroker(
address(new ERC1967Proxy(address(implementations.components.broker), new bytes(0)))
)
});
// Init Main
main.init(components, rsr, params.shortFreeze, params.longFreeze);
// Init Backing Manager
components.backingManager.init(
main,
params.tradingDelay,
params.backingBuffer,
params.maxTradeSlippage,
params.minTradeVolume
);
// Init Basket Handler
components.basketHandler.init(main, params.warmupPeriod);
// Init Revenue Traders
components.rsrTrader.init(main, rsr, params.maxTradeSlippage, params.minTradeVolume);
components.rTokenTrader.init(
main,
IERC20(address(rToken)),
params.maxTradeSlippage,
params.minTradeVolume
);
// Init Distributor
components.distributor.init(main, params.dist);
// Init Furnace
components.furnace.init(main, params.rewardRatio);
components.broker.init(
main,
gnosis,
implementations.trading.gnosisTrade,
params.batchAuctionLength,
implementations.trading.dutchTrade,
params.dutchAuctionLength
);
// Init StRSR
{
string memory stRSRSymbol = string(abi.encodePacked(StringLib.toLower(symbol), "RSR"));
string memory stRSRName = string(abi.encodePacked(stRSRSymbol, " Token"));
main.stRSR().init(
main,
stRSRName,
stRSRSymbol,
params.unstakingDelay,
params.rewardRatio,
params.withdrawalLeak
);
}
// Init RToken
components.rToken.init(
main,
name,
symbol,
mandate,
params.issuanceThrottle,
params.redemptionThrottle
);
// Deploy RToken/RSR Assets
IAsset[] memory assets = new IAsset[](2);
assets[0] = new RTokenAsset(components.rToken, params.rTokenMaxTradeVolume);
assets[1] = rsrAsset;
// Init Asset Registry
components.assetRegistry.init(main, assets);
// Transfer Ownership
main.grantRole(OWNER, owner);
main.renounceRole(OWNER, address(this));
emit RTokenCreated(main, components.rToken, components.stRSR, owner, version());
return (address(components.rToken));
}
/// Deploys a new RTokenAsset instance. Not needed during normal deployment flow
/// @param maxTradeVolume {UoA} The maximum trade volume for the RTokenAsset
/// @return rTokenAsset The address of the newly deployed RTokenAsset
function deployRTokenAsset(IRToken rToken, uint192 maxTradeVolume)
external
returns (IAsset rTokenAsset)
{
rTokenAsset = new RTokenAsset(rToken, maxTradeVolume);
emit RTokenAssetCreated(rToken, rTokenAsset);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControlUpgradeable.sol";
import "../utils/ContextUpgradeable.sol";
import "../utils/StringsUpgradeable.sol";
import "../utils/introspection/ERC165Upgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
StringsUpgradeable.toHexString(uint160(account), 20),
" is missing role ",
StringsUpgradeable.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControlUpgradeable {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions 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);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822ProxiableUpgradeable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeaconUpgradeable {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeaconUpgradeable.sol";
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/StorageSlotUpgradeable.sol";
import "../utils/Initializable.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*
* @custom:oz-upgrades-unsafe-allow delegatecall
*/
abstract contract ERC1967UpgradeUpgradeable is Initializable {
function __ERC1967Upgrade_init() internal onlyInitializing {
}
function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
}
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
_functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Emitted when the beacon is upgraded.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(
address newBeacon,
bytes memory data,
bool forceCall
) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
_functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
}
}
/**
* @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) private returns (bytes memory) {
require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.delegatecall(data);
return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
* initialization step. This is essential to configure modules that are added through upgrades and that require
* initialization.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.0;
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*
* _Available since v4.1._
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
address private immutable __self = address(this);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
require(address(this) != __self, "Function must be called through delegatecall");
require(_getImplementation() == __self, "Function must be called through active proxy");
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
_;
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate that the this implementation remains valid after an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
return _IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*/
function upgradeTo(address newImplementation) external virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data, true);
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeTo} and {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal override onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20PermitUpgradeable {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20MetadataUpgradeable is IERC20Upgradeable {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [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 functionCall(target, data, "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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(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) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason 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 {
// 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 v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165Upgradeable.sol";
import "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165Upgradeable).interfaceId;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
*/
library StorageSlotUpgradeable {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library StringsUpgradeable {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/Clones.sol)
pragma solidity ^0.8.0;
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*
* _Available since v3.4._
*/
library Clones {
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
instance := create(0, ptr, 0x37)
}
require(instance != address(0), "ERC1167: create failed");
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
instance := create2(0, ptr, 0x37, salt)
}
require(instance != address(0), "ERC1167: create2 failed");
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
mstore(add(ptr, 0x38), shl(0x60, deployer))
mstore(add(ptr, 0x4c), salt)
mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
predicted := keccak256(add(ptr, 0x37), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(address implementation, bytes32 salt)
internal
view
returns (address predicted)
{
return predictDeterministicAddress(implementation, salt, address(this));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)
pragma solidity ^0.8.0;
import "../Proxy.sol";
import "./ERC1967Upgrade.sol";
/**
* @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
* implementation address that can be changed. This address is stored in storage in the location specified by
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
* implementation behind the proxy.
*/
contract ERC1967Proxy is Proxy, ERC1967Upgrade {
/**
* @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
*
* If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
* function call, and allows initializing the storage of the proxy like a Solidity constructor.
*/
constructor(address _logic, bytes memory _data) payable {
_upgradeToAndCall(_logic, _data, false);
}
/**
* @dev Returns the current implementation address.
*/
function _implementation() internal view virtual override returns (address impl) {
return ERC1967Upgrade._getImplementation();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*
* @custom:oz-upgrades-unsafe-allow delegatecall
*/
abstract contract ERC1967Upgrade {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Emitted when the beacon is upgraded.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(
address newBeacon,
bytes memory data,
bool forceCall
) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)
pragma solidity ^0.8.0;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
* and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_beforeFallback();
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback() external payable virtual {
_fallback();
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
* is empty.
*/
receive() external payable virtual {
_fallback();
}
/**
* @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
* call, or as part of the Solidity `fallback` or `receive` functions.
*
* If overridden should call `super._beforeFallback()`.
*/
function _beforeFallback() internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.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 functionCall(target, data, "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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(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) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(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) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason 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 {
// 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.7.0) (utils/StorageSlot.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "../libraries/Fixed.sol";
import "./IMain.sol";
import "./IRewardable.sol";
// Not used directly in the IAsset interface, but used by many consumers to save stack space
struct Price {
uint192 low; // {UoA/tok}
uint192 high; // {UoA/tok}
}
/**
* @title IAsset
* @notice Supertype. Any token that interacts with our system must be wrapped in an asset,
* whether it is used as RToken backing or not. Any token that can report a price in the UoA
* is eligible to be an asset.
*/
interface IAsset is IRewardable {
/// Refresh saved price
/// The Reserve protocol calls this at least once per transaction, before relying on
/// the Asset's other functions.
/// @dev Called immediately after deployment, before use
function refresh() external;
/// Should not revert
/// @return low {UoA/tok} The lower end of the price estimate
/// @return high {UoA/tok} The upper end of the price estimate
function price() external view returns (uint192 low, uint192 high);
/// Should not revert
/// lotLow should be nonzero when the asset might be worth selling
/// @return lotLow {UoA/tok} The lower end of the lot price estimate
/// @return lotHigh {UoA/tok} The upper end of the lot price estimate
function lotPrice() external view returns (uint192 lotLow, uint192 lotHigh);
/// @return {tok} The balance of the ERC20 in whole tokens
function bal(address account) external view returns (uint192);
/// @return The ERC20 contract of the token with decimals() available
function erc20() external view returns (IERC20Metadata);
/// @return The number of decimals in the ERC20; just for gas optimization
function erc20Decimals() external view returns (uint8);
/// @return If the asset is an instance of ICollateral or not
function isCollateral() external view returns (bool);
/// @return {UoA} The max trade volume, in UoA
function maxTradeVolume() external view returns (uint192);
/// @return {s} The timestamp of the last refresh() that saved prices
function lastSave() external view returns (uint48);
}
// Used only in Testing. Strictly speaking an Asset does not need to adhere to this interface
interface TestIAsset is IAsset {
/// @return The address of the chainlink feed
function chainlinkFeed() external view returns (AggregatorV3Interface);
/// {1} The max % deviation allowed by the oracle
function oracleError() external view returns (uint192);
/// @return {s} Seconds that an oracle value is considered valid
function oracleTimeout() external view returns (uint48);
/// @return {s} Seconds that the lotPrice should decay over, after stale price
function priceTimeout() external view returns (uint48);
}
/// CollateralStatus must obey a linear ordering. That is:
/// - being DISABLED is worse than being IFFY, or SOUND
/// - being IFFY is worse than being SOUND.
enum CollateralStatus {
SOUND,
IFFY, // When a peg is not holding or a chainlink feed is stale
DISABLED // When the collateral has completely defaulted
}
/// Upgrade-safe maximum operator for CollateralStatus
library CollateralStatusComparator {
/// @return Whether a is worse than b
function worseThan(CollateralStatus a, CollateralStatus b) internal pure returns (bool) {
return uint256(a) > uint256(b);
}
}
/**
* @title ICollateral
* @notice A subtype of Asset that consists of the tokens eligible to back the RToken.
*/
interface ICollateral is IAsset {
/// Emitted whenever the collateral status is changed
/// @param newStatus The old CollateralStatus
/// @param newStatus The updated CollateralStatus
event CollateralStatusChanged(
CollateralStatus indexed oldStatus,
CollateralStatus indexed newStatus
);
/// @dev refresh()
/// Refresh exchange rates and update default status.
/// VERY IMPORTANT: In any valid implemntation, status() MUST become DISABLED in refresh() if
/// refPerTok() has ever decreased since last call.
/// @return The canonical name of this collateral's target unit.
function targetName() external view returns (bytes32);
/// @return The status of this collateral asset. (Is it defaulting? Might it soon?)
function status() external view returns (CollateralStatus);
// ==== Exchange Rates ====
/// @return {ref/tok} Quantity of whole reference units per whole collateral tokens
function refPerTok() external view returns (uint192);
/// @return {target/ref} Quantity of whole target units per whole reference unit in the peg
function targetPerRef() external view returns (uint192);
}
// Used only in Testing. Strictly speaking a Collateral does not need to adhere to this interface
interface TestICollateral is TestIAsset, ICollateral {
/// @return The epoch timestamp when the collateral will default from IFFY to DISABLED
function whenDefault() external view returns (uint256);
/// @return The amount of time a collateral must be in IFFY status until being DISABLED
function delayUntilDefault() external view returns (uint48);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IAsset.sol";
import "./IComponent.sol";
/// A serialization of the AssetRegistry to be passed around in the P1 impl for gas optimization
struct Registry {
IERC20[] erc20s;
IAsset[] assets;
}
/**
* @title IAssetRegistry
* @notice The AssetRegistry is in charge of maintaining the ERC20 tokens eligible
* to be handled by the rest of the system. If an asset is in the registry, this means:
* 1. Its ERC20 contract has been vetted
* 2. The asset is the only asset for that ERC20
* 3. The asset can be priced in the UoA, usually via an oracle
*/
interface IAssetRegistry is IComponent {
/// Emitted when an asset is added to the registry
/// @param erc20 The ERC20 contract for the asset
/// @param asset The asset contract added to the registry
event AssetRegistered(IERC20 indexed erc20, IAsset indexed asset);
/// Emitted when an asset is removed from the registry
/// @param erc20 The ERC20 contract for the asset
/// @param asset The asset contract removed from the registry
event AssetUnregistered(IERC20 indexed erc20, IAsset indexed asset);
// Initialization
function init(IMain main_, IAsset[] memory assets_) external;
/// Fully refresh all asset state
/// @custom:interaction
function refresh() external;
/// Register `asset`
/// If either the erc20 address or the asset was already registered, fail
/// @return true if the erc20 address was not already registered.
/// @custom:governance
function register(IAsset asset) external returns (bool);
/// Register `asset` if and only if its erc20 address is already registered.
/// If the erc20 address was not registered, revert.
/// @return swapped If the asset was swapped for a previously-registered asset
/// @custom:governance
function swapRegistered(IAsset asset) external returns (bool swapped);
/// Unregister an asset, requiring that it is already registered
/// @custom:governance
function unregister(IAsset asset) external;
/// @return {s} The timestamp of the last refresh
function lastRefresh() external view returns (uint48);
/// @return The corresponding asset for ERC20, or reverts if not registered
function toAsset(IERC20 erc20) external view returns (IAsset);
/// @return The corresponding collateral, or reverts if unregistered or not collateral
function toColl(IERC20 erc20) external view returns (ICollateral);
/// @return If the ERC20 is registered
function isRegistered(IERC20 erc20) external view returns (bool);
/// @return A list of all registered ERC20s
function erc20s() external view returns (IERC20[] memory);
/// @return reg The list of registered ERC20s and Assets, in the same order
function getRegistry() external view returns (Registry memory reg);
/// @return The number of registered ERC20s
function size() external view returns (uint256);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IBroker.sol";
import "./IComponent.sol";
import "./ITrading.sol";
/**
* @title IBackingManager
* @notice The BackingManager handles changes in the ERC20 balances that back an RToken.
* - It computes which trades to perform, if any, and initiates these trades with the Broker.
* - rebalance()
* - If already collateralized, excess assets are transferred to RevenueTraders.
* - forwardRevenue(IERC20[] calldata erc20s)
*/
interface IBackingManager is IComponent, ITrading {
/// Emitted when the trading delay is changed
/// @param oldVal The old trading delay
/// @param newVal The new trading delay
event TradingDelaySet(uint48 oldVal, uint48 newVal);
/// Emitted when the backing buffer is changed
/// @param oldVal The old backing buffer
/// @param newVal The new backing buffer
event BackingBufferSet(uint192 oldVal, uint192 newVal);
// Initialization
function init(
IMain main_,
uint48 tradingDelay_,
uint192 backingBuffer_,
uint192 maxTradeSlippage_,
uint192 minTradeVolume_
) external;
// Give RToken max allowance over a registered token
/// @custom:refresher
/// @custom:interaction
function grantRTokenAllowance(IERC20) external;
/// Apply the overall backing policy using the specified TradeKind, taking a haircut if unable
/// @param kind TradeKind.DUTCH_AUCTION or TradeKind.BATCH_AUCTION
/// @custom:interaction RCEI
function rebalance(TradeKind kind) external;
/// Forward revenue to RevenueTraders; reverts if not fully collateralized
/// @param erc20s The tokens to forward
/// @custom:interaction RCEI
function forwardRevenue(IERC20[] calldata erc20s) external;
}
interface TestIBackingManager is IBackingManager, TestITrading {
function tradingDelay() external view returns (uint48);
function backingBuffer() external view returns (uint192);
function setTradingDelay(uint48 val) external;
function setBackingBuffer(uint192 val) external;
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../libraries/Fixed.sol";
import "./IAsset.sol";
import "./IComponent.sol";
struct BasketRange {
uint192 bottom; // {BU}
uint192 top; // {BU}
}
/**
* @title IBasketHandler
* @notice The BasketHandler aims to maintain a reference basket of constant target unit amounts.
* When a collateral token defaults, a new reference basket of equal target units is set.
* When _all_ collateral tokens default for a target unit, only then is the basket allowed to fall
* in terms of target unit amounts. The basket is considered defaulted in this case.
*/
interface IBasketHandler is IComponent {
/// Emitted when the prime basket is set
/// @param erc20s The collateral tokens for the prime basket
/// @param targetAmts {target/BU} A list of quantities of target unit per basket unit
/// @param targetNames Each collateral token's targetName
event PrimeBasketSet(IERC20[] erc20s, uint192[] targetAmts, bytes32[] targetNames);
/// Emitted when the reference basket is set
/// @param nonce {basketNonce} The basket nonce
/// @param erc20s The list of collateral tokens in the reference basket
/// @param refAmts {ref/BU} The reference amounts of the basket collateral tokens
/// @param disabled True when the list of erc20s + refAmts may not be correct
event BasketSet(uint256 indexed nonce, IERC20[] erc20s, uint192[] refAmts, bool disabled);
/// Emitted when a backup config is set for a target unit
/// @param targetName The name of the target unit as a bytes32
/// @param max The max number to use from `erc20s`
/// @param erc20s The set of backup collateral tokens
event BackupConfigSet(bytes32 indexed targetName, uint256 max, IERC20[] erc20s);
/// Emitted when the warmup period is changed
/// @param oldVal The old warmup period
/// @param newVal The new warmup period
event WarmupPeriodSet(uint48 oldVal, uint48 newVal);
/// Emitted when the status of a basket has changed
/// @param oldStatus The previous basket status
/// @param newStatus The new basket status
event BasketStatusChanged(CollateralStatus oldStatus, CollateralStatus newStatus);
// Initialization
function init(IMain main_, uint48 warmupPeriod_) external;
/// Set the prime basket
/// @param erc20s The collateral tokens for the new prime basket
/// @param targetAmts The target amounts (in) {target/BU} for the new prime basket
/// required range: 1e9 values; absolute range irrelevant.
/// @custom:governance
function setPrimeBasket(IERC20[] memory erc20s, uint192[] memory targetAmts) external;
/// Set the backup configuration for a given target
/// @param targetName The name of the target as a bytes32
/// @param max The maximum number of collateral tokens to use from this target
/// Required range: 1-255
/// @param erc20s A list of ordered backup collateral tokens
/// @custom:governance
function setBackupConfig(
bytes32 targetName,
uint256 max,
IERC20[] calldata erc20s
) external;
/// Default the basket in order to schedule a basket refresh
/// @custom:protected
function disableBasket() external;
/// Governance-controlled setter to cause a basket switch explicitly
/// @custom:governance
/// @custom:interaction
function refreshBasket() external;
/// Track the basket status changes
/// @custom:refresher
function trackStatus() external;
/// @return If the BackingManager has sufficient collateral to redeem the entire RToken supply
function fullyCollateralized() external view returns (bool);
/// @return status The worst CollateralStatus of all collateral in the basket
function status() external view returns (CollateralStatus status);
/// @return If the basket is ready to issue and trade
function isReady() external view returns (bool);
/// @param erc20 The ERC20 token contract for the asset
/// @return {tok/BU} The whole token quantity of token in the reference basket
/// Returns 0 if erc20 is not registered or not in the basket
/// Returns FIX_MAX (in lieu of +infinity) if Collateral.refPerTok() is 0.
/// Otherwise, returns (token's basket.refAmts / token's Collateral.refPerTok())
function quantity(IERC20 erc20) external view returns (uint192);
/// Like quantity(), but unsafe because it DOES NOT CONFIRM THAT THE ASSET IS CORRECT
/// @param erc20 The ERC20 token contract for the asset
/// @param asset The registered asset plugin contract for the erc20
/// @return {tok/BU} The whole token quantity of token in the reference basket
/// Returns 0 if erc20 is not registered or not in the basket
/// Returns FIX_MAX (in lieu of +infinity) if Collateral.refPerTok() is 0.
/// Otherwise, returns (token's basket.refAmts / token's Collateral.refPerTok())
function quantityUnsafe(IERC20 erc20, IAsset asset) external view returns (uint192);
/// @param amount {BU}
/// @return erc20s The addresses of the ERC20 tokens in the reference basket
/// @return quantities {qTok} The quantity of each ERC20 token to issue `amount` baskets
function quote(uint192 amount, RoundingMode rounding)
external
view
returns (address[] memory erc20s, uint256[] memory quantities);
/// Return the redemption value of `amount` BUs for a linear combination of historical baskets
/// @param basketNonces An array of basket nonces to do redemption from
/// @param portions {1} An array of Fix quantities that must add up to FIX_ONE
/// @param amount {BU}
/// @return erc20s The backing collateral erc20s
/// @return quantities {qTok} ERC20 token quantities equal to `amount` BUs
function quoteCustomRedemption(
uint48[] memory basketNonces,
uint192[] memory portions,
uint192 amount
) external view returns (address[] memory erc20s, uint256[] memory quantities);
/// @return top {BU} The number of partial basket units: e.g max(coll.map((c) => c.balAsBUs())
/// bottom {BU} The number of whole basket units held by the account
function basketsHeldBy(address account) external view returns (BasketRange memory);
/// Should not revert
/// @return low {UoA/BU} The lower end of the price estimate
/// @return high {UoA/BU} The upper end of the price estimate
function price() external view returns (uint192 low, uint192 high);
/// Should not revert
/// lotLow should be nonzero if a BU could be worth selling
/// @return lotLow {UoA/tok} The lower end of the lot price estimate
/// @return lotHigh {UoA/tok} The upper end of the lot price estimate
function lotPrice() external view returns (uint192 lotLow, uint192 lotHigh);
/// @return timestamp The timestamp at which the basket was last set
function timestamp() external view returns (uint48);
/// @return The current basket nonce, regardless of status
function nonce() external view returns (uint48);
}
interface TestIBasketHandler is IBasketHandler {
function warmupPeriod() external view returns (uint48);
function setWarmupPeriod(uint48 val) external;
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "./IAsset.sol";
import "./IComponent.sol";
import "./IGnosis.sol";
import "./ITrade.sol";
enum TradeKind {
DUTCH_AUCTION,
BATCH_AUCTION
}
/// Cache of all (lot) prices for a pair to prevent re-lookup
struct TradePrices {
uint192 sellLow; // {UoA/sellTok} can be 0
uint192 sellHigh; // {UoA/sellTok} should not be 0
uint192 buyLow; // {UoA/buyTok} should not be 0
uint192 buyHigh; // {UoA/buyTok} should not be 0 or FIX_MAX
}
/// The data format that describes a request for trade with the Broker
struct TradeRequest {
IAsset sell;
IAsset buy;
uint256 sellAmount; // {qSellTok}
uint256 minBuyAmount; // {qBuyTok}
}
/**
* @title IBroker
* @notice The Broker deploys oneshot Trade contracts for Traders and monitors
* the continued proper functioning of trading platforms.
*/
interface IBroker is IComponent {
event GnosisSet(IGnosis oldVal, IGnosis newVal);
event BatchTradeImplementationSet(ITrade oldVal, ITrade newVal);
event DutchTradeImplementationSet(ITrade oldVal, ITrade newVal);
event BatchAuctionLengthSet(uint48 oldVal, uint48 newVal);
event DutchAuctionLengthSet(uint48 oldVal, uint48 newVal);
event BatchTradeDisabledSet(bool prevVal, bool newVal);
event DutchTradeDisabledSet(IERC20Metadata indexed erc20, bool prevVal, bool newVal);
// Initialization
function init(
IMain main_,
IGnosis gnosis_,
ITrade batchTradeImplemention_,
uint48 batchAuctionLength_,
ITrade dutchTradeImplemention_,
uint48 dutchAuctionLength_
) external;
/// Request a trade from the broker
/// @dev Requires setting an allowance in advance
/// @custom:interaction
function openTrade(
TradeKind kind,
TradeRequest memory req,
TradePrices memory prices
) external returns (ITrade);
/// Only callable by one of the trading contracts the broker deploys
function reportViolation() external;
function batchTradeDisabled() external view returns (bool);
function dutchTradeDisabled(IERC20Metadata erc20) external view returns (bool);
}
interface TestIBroker is IBroker {
function gnosis() external view returns (IGnosis);
function batchTradeImplementation() external view returns (ITrade);
function dutchTradeImplementation() external view returns (ITrade);
function batchAuctionLength() external view returns (uint48);
function dutchAuctionLength() external view returns (uint48);
function setGnosis(IGnosis newGnosis) external;
function setBatchTradeImplementation(ITrade newTradeImplementation) external;
function setBatchAuctionLength(uint48 newAuctionLength) external;
function setDutchTradeImplementation(ITrade newTradeImplementation) external;
function setDutchAuctionLength(uint48 newAuctionLength) external;
function enableBatchTrade() external;
function enableDutchTrade(IERC20Metadata erc20) external;
// only present on pre-3.0.0 Brokers; used by EasyAuction regression test
function disabled() external view returns (bool);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "./IMain.sol";
import "./IVersioned.sol";
/**
* @title IComponent
* @notice A Component is the central building block of all our system contracts. Components
* contain important state that must be migrated during upgrades, and they delegate
* their ownership to Main's owner.
*/
interface IComponent is IVersioned {
function main() external view returns (IMain);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "../libraries/Throttle.sol";
import "./IAsset.sol";
import "./IDistributor.sol";
import "./IGnosis.sol";
import "./IMain.sol";
import "./IRToken.sol";
import "./IStRSR.sol";
import "./ITrade.sol";
import "./IVersioned.sol";
/**
* @title DeploymentParams
* @notice The set of protocol params needed to configure a new system deployment.
* meaning that after deployment there is freedom to allow parametrizations to deviate.
*/
struct DeploymentParams {
// === Revenue sharing ===
RevenueShare dist; // revenue sharing splits between RToken and RSR
//
// === Trade sizing ===
uint192 minTradeVolume; // {UoA}
uint192 rTokenMaxTradeVolume; // {UoA}
//
// === Freezing ===
uint48 shortFreeze; // {s} how long an initial freeze lasts
uint48 longFreeze; // {s} how long each freeze extension lasts
//
// === Rewards (Furnace + StRSR) ===
uint192 rewardRatio; // the fraction of available revenues that are paid out each block period
//
// === StRSR ===
uint48 unstakingDelay; // {s} the "thawing time" of staked RSR before withdrawal
uint192 withdrawalLeak; // {1} fraction of RSR that can be withdrawn without refresh
//
// === BasketHandler ===
uint48 warmupPeriod; // {s} how long to wait until issuance/trading after regaining SOUND
//
// === BackingManager ===
uint48 tradingDelay; // {s} how long to wait until starting auctions after switching basket
uint48 batchAuctionLength; // {s} the length of a Gnosis EasyAuction
uint48 dutchAuctionLength; // {s} the length of a falling-price dutch auction
uint192 backingBuffer; // {1} how much extra backing collateral to keep
uint192 maxTradeSlippage; // {1} max slippage acceptable in a trade
//
// === RToken Supply Throttles ===
ThrottleLib.Params issuanceThrottle; // see ThrottleLib
ThrottleLib.Params redemptionThrottle;
}
/**
* @title Implementations
* @notice The set of implementation contracts to be used for proxies in the Deployer
*/
struct Implementations {
IMain main;
Components components;
TradePlugins trading;
}
struct TradePlugins {
ITrade gnosisTrade;
ITrade dutchTrade;
}
/**
* @title IDeployer
* @notice Factory contract for an RToken system instance
*/
interface IDeployer is IVersioned {
/// Emitted when a new RToken and accompanying system is deployed
/// @param main The address of `Main`
/// @param rToken The address of the RToken ERC20
/// @param stRSR The address of the StRSR ERC20 staking pool/token
/// @param owner The owner of the newly deployed system
/// @param version The semantic versioning version string (see: https://semver.org)
event RTokenCreated(
IMain indexed main,
IRToken indexed rToken,
IStRSR stRSR,
address indexed owner,
string version
);
/// Emitted when a new RTokenAsset is deployed during `deployRTokenAsset`
/// @param rToken The address of the RToken ERC20
/// @param rTokenAsset The address of the RTokenAsset
event RTokenAssetCreated(IRToken indexed rToken, IAsset rTokenAsset);
//
/// Deploys an instance of the entire system
/// @param name The name of the RToken to deploy
/// @param symbol The symbol of the RToken to deploy
/// @param mandate An IPFS link or direct string; describes what the RToken _should be_
/// @param owner The address that should own the entire system, hopefully a governance contract
/// @param params Deployment params
/// @return The address of the newly deployed Main instance.
function deploy(
string calldata name,
string calldata symbol,
string calldata mandate,
address owner,
DeploymentParams calldata params
) external returns (address);
/// Deploys a new RTokenAsset instance. Not needed during normal deployment flow
/// @param maxTradeVolume {UoA} The maximum trade volume for the RTokenAsset
function deployRTokenAsset(IRToken rToken, uint192 maxTradeVolume) external returns (IAsset);
}
interface TestIDeployer is IDeployer {
/// A top-level ENS domain that should always point to the latest Deployer instance
// solhint-disable-next-line func-name-mixedcase
function ENS() external view returns (string memory);
function rsr() external view returns (IERC20Metadata);
function gnosis() external view returns (IGnosis);
function rsrAsset() external view returns (IAsset);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IComponent.sol";
uint256 constant MAX_DISTRIBUTION = 1e4; // 10,000
uint8 constant MAX_DESTINATIONS = 100; // maximum number of RevenueShare destinations
struct RevenueShare {
uint16 rTokenDist; // {revShare} A value between [0, 10,000]
uint16 rsrDist; // {revShare} A value between [0, 10,000]
}
/// Assumes no more than 100 independent distributions.
struct RevenueTotals {
uint24 rTokenTotal; // {revShare}
uint24 rsrTotal; // {revShare}
}
/**
* @title IDistributor
* @notice The Distributor Component maintains a revenue distribution table that dictates
* how to divide revenue across the Furnace, StRSR, and any other destinations.
*/
interface IDistributor is IComponent {
/// Emitted when a distribution is set
/// @param dest The address set to receive the distribution
/// @param rTokenDist The distribution of RToken that should go to `dest`
/// @param rsrDist The distribution of RSR that should go to `dest`
event DistributionSet(address indexed dest, uint16 rTokenDist, uint16 rsrDist);
/// Emitted when revenue is distributed
/// @param erc20 The token being distributed, either RSR or the RToken itself
/// @param source The address providing the revenue
/// @param amount The amount of the revenue
event RevenueDistributed(IERC20 indexed erc20, address indexed source, uint256 amount);
// Initialization
function init(IMain main_, RevenueShare memory dist) external;
/// @custom:governance
function setDistribution(address dest, RevenueShare memory share) external;
/// Distribute the `erc20` token across all revenue destinations
/// Only callable by RevenueTraders
/// @custom:protected
function distribute(IERC20 erc20, uint256 amount) external;
/// @return revTotals The total of all destinations
function totals() external view returns (RevenueTotals memory revTotals);
}
interface TestIDistributor is IDistributor {
// solhint-disable-next-line func-name-mixedcase
function FURNACE() external view returns (address);
// solhint-disable-next-line func-name-mixedcase
function ST_RSR() external view returns (address);
/// @return rTokenDist The RToken distribution for the address
/// @return rsrDist The RSR distribution for the address
function distribution(address) external view returns (uint16 rTokenDist, uint16 rsrDist);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "../libraries/Fixed.sol";
import "./IComponent.sol";
/**
* @title IFurnace
* @notice A helper contract to burn RTokens slowly and permisionlessly.
*/
interface IFurnace is IComponent {
// Initialization
function init(IMain main_, uint192 ratio_) external;
/// Emitted when the melting ratio is changed
/// @param oldRatio The old ratio
/// @param newRatio The new ratio
event RatioSet(uint192 oldRatio, uint192 newRatio);
function ratio() external view returns (uint192);
/// Needed value range: [0, 1], granularity 1e-9
/// @custom:governance
function setRatio(uint192) external;
/// Performs any RToken melting that has vested since the last payout.
/// @custom:refresher
function melt() external;
}
interface TestIFurnace is IFurnace {
function lastPayout() external view returns (uint256);
function lastPayoutBal() external view returns (uint256);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
struct GnosisAuctionData {
IERC20 auctioningToken;
IERC20 biddingToken;
uint256 orderCancellationEndDate;
uint256 auctionEndDate;
bytes32 initialAuctionOrder;
uint256 minimumBiddingAmountPerOrder;
uint256 interimSumBidAmount;
bytes32 interimOrder;
bytes32 clearingPriceOrder;
uint96 volumeClearingPriceOrder;
bool minFundingThresholdNotReached;
bool isAtomicClosureAllowed;
uint256 feeNumerator;
uint256 minFundingThreshold;
}
/// The relevant portion of the interface of the live Gnosis EasyAuction contract
/// https://github.com/gnosis/ido-contracts/blob/main/contracts/EasyAuction.sol
interface IGnosis {
function initiateAuction(
IERC20 auctioningToken,
IERC20 biddingToken,
uint256 orderCancellationEndDate,
uint256 auctionEndDate,
uint96 auctionedSellAmount,
uint96 minBuyAmount,
uint256 minimumBiddingAmountPerOrder,
uint256 minFundingThreshold,
bool isAtomicClosureAllowed,
address accessManagerContract,
bytes memory accessManagerContractData
) external returns (uint256 auctionId);
function auctionData(uint256 auctionId) external view returns (GnosisAuctionData memory);
/// @param auctionId The external auction id
/// @dev See here for decoding: https://git.io/JMang
/// @return encodedOrder The order, encoded in a bytes 32
function settleAuction(uint256 auctionId) external returns (bytes32 encodedOrder);
/// @return The numerator over a 1000-valued denominator
function feeNumerator() external returns (uint256);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IAssetRegistry.sol";
import "./IBasketHandler.sol";
import "./IBackingManager.sol";
import "./IBroker.sol";
import "./IGnosis.sol";
import "./IFurnace.sol";
import "./IDistributor.sol";
import "./IRToken.sol";
import "./IRevenueTrader.sol";
import "./IStRSR.sol";
import "./ITrading.sol";
import "./IVersioned.sol";
// === Auth roles ===
bytes32 constant OWNER = bytes32(bytes("OWNER"));
bytes32 constant SHORT_FREEZER = bytes32(bytes("SHORT_FREEZER"));
bytes32 constant LONG_FREEZER = bytes32(bytes("LONG_FREEZER"));
bytes32 constant PAUSER = bytes32(bytes("PAUSER"));
/**
* Main is a central hub that maintains a list of Component contracts.
*
* Components:
* - perform a specific function
* - defer auth to Main
* - usually (but not always) contain sizeable state that require a proxy
*/
struct Components {
// Definitely need proxy
IRToken rToken;
IStRSR stRSR;
IAssetRegistry assetRegistry;
IBasketHandler basketHandler;
IBackingManager backingManager;
IDistributor distributor;
IFurnace furnace;
IBroker broker;
IRevenueTrader rsrTrader;
IRevenueTrader rTokenTrader;
}
interface IAuth is IAccessControlUpgradeable {
/// Emitted when `unfreezeAt` is changed
/// @param oldVal The old value of `unfreezeAt`
/// @param newVal The new value of `unfreezeAt`
event UnfreezeAtSet(uint48 oldVal, uint48 newVal);
/// Emitted when the short freeze duration governance param is changed
/// @param oldDuration The old short freeze duration
/// @param newDuration The new short freeze duration
event ShortFreezeDurationSet(uint48 oldDuration, uint48 newDuration);
/// Emitted when the long freeze duration governance param is changed
/// @param oldDuration The old long freeze duration
/// @param newDuration The new long freeze duration
event LongFreezeDurationSet(uint48 oldDuration, uint48 newDuration);
/// Emitted when the system is paused or unpaused for trading
/// @param oldVal The old value of `tradingPaused`
/// @param newVal The new value of `tradingPaused`
event TradingPausedSet(bool oldVal, bool newVal);
/// Emitted when the system is paused or unpaused for issuance
/// @param oldVal The old value of `issuancePaused`
/// @param newVal The new value of `issuancePaused`
event IssuancePausedSet(bool oldVal, bool newVal);
/**
* Trading Paused: Disable everything except for OWNER actions, RToken.issue, RToken.redeem,
* StRSR.stake, and StRSR.payoutRewards
* Issuance Paused: Disable RToken.issue
* Frozen: Disable everything except for OWNER actions + StRSR.stake (for governance)
*/
function tradingPausedOrFrozen() external view returns (bool);
function issuancePausedOrFrozen() external view returns (bool);
function frozen() external view returns (bool);
function shortFreeze() external view returns (uint48);
function longFreeze() external view returns (uint48);
// ====
// onlyRole(OWNER)
function freezeForever() external;
// onlyRole(SHORT_FREEZER)
function freezeShort() external;
// onlyRole(LONG_FREEZER)
function freezeLong() external;
// onlyRole(OWNER)
function unfreeze() external;
function pauseTrading() external;
function unpauseTrading() external;
function pauseIssuance() external;
function unpauseIssuance() external;
}
interface IComponentRegistry {
// === Component setters/getters ===
event RTokenSet(IRToken indexed oldVal, IRToken indexed newVal);
function rToken() external view returns (IRToken);
event StRSRSet(IStRSR oldVal, IStRSR newVal);
function stRSR() external view returns (IStRSR);
event AssetRegistrySet(IAssetRegistry oldVal, IAssetRegistry newVal);
function assetRegistry() external view returns (IAssetRegistry);
event BasketHandlerSet(IBasketHandler oldVal, IBasketHandler newVal);
function basketHandler() external view returns (IBasketHandler);
event BackingManagerSet(IBackingManager oldVal, IBackingManager newVal);
function backingManager() external view returns (IBackingManager);
event DistributorSet(IDistributor oldVal, IDistributor newVal);
function distributor() external view returns (IDistributor);
event RSRTraderSet(IRevenueTrader oldVal, IRevenueTrader newVal);
function rsrTrader() external view returns (IRevenueTrader);
event RTokenTraderSet(IRevenueTrader oldVal, IRevenueTrader newVal);
function rTokenTrader() external view returns (IRevenueTrader);
event FurnaceSet(IFurnace oldVal, IFurnace newVal);
function furnace() external view returns (IFurnace);
event BrokerSet(IBroker oldVal, IBroker newVal);
function broker() external view returns (IBroker);
}
/**
* @title IMain
* @notice The central hub for the entire system. Maintains components and an owner singleton role
*/
interface IMain is IVersioned, IAuth, IComponentRegistry {
function poke() external; // not used in p1
// === Initialization ===
event MainInitialized();
function init(
Components memory components,
IERC20 rsr_,
uint48 shortFreeze_,
uint48 longFreeze_
) external;
function rsr() external view returns (IERC20);
}
interface TestIMain is IMain {
/// @custom:governance
function setShortFreeze(uint48) external;
/// @custom:governance
function setLongFreeze(uint48) external;
function shortFreeze() external view returns (uint48);
function longFreeze() external view returns (uint48);
function longFreezes(address account) external view returns (uint256);
function tradingPaused() external view returns (bool);
function issuancePaused() external view returns (bool);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "./IBroker.sol";
import "./IComponent.sol";
import "./ITrading.sol";
/**
* @title IRevenueTrader
* @notice The RevenueTrader is an extension of the trading mixin that trades all
* assets at its address for a single target asset. There are two runtime instances
* of the RevenueTrader, 1 for RToken and 1 for RSR.
*/
interface IRevenueTrader is IComponent, ITrading {
// Initialization
function init(
IMain main_,
IERC20 tokenToBuy_,
uint192 maxTradeSlippage_,
uint192 minTradeVolume_
) external;
/// Distribute tokenToBuy to its destinations
/// @dev Special-case of manageTokens()
/// @custom:interaction
function distributeTokenToBuy() external;
/// Return registered ERC20s to the BackingManager if distribution for tokenToBuy is 0
/// @custom:interaction
function returnTokens(IERC20[] memory erc20s) external;
/// Process some number of tokens
/// If the tokenToBuy is included in erc20s, RevenueTrader will distribute it at end of the tx
/// @param erc20s The ERC20s to manage; can be tokenToBuy or anything registered
/// @param kinds The kinds of auctions to launch: DUTCH_AUCTION | BATCH_AUCTION
/// @custom:interaction
function manageTokens(IERC20[] memory erc20s, TradeKind[] memory kinds) external;
function tokenToBuy() external view returns (IERC20);
}
// solhint-disable-next-line no-empty-blocks
interface TestIRevenueTrader is IRevenueTrader, TestITrading {
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IComponent.sol";
import "./IMain.sol";
/**
* @title IRewardable
* @notice A simple interface mixin to support claiming of rewards.
*/
interface IRewardable {
/// Emitted whenever a reward token balance is claimed
event RewardsClaimed(IERC20 indexed erc20, uint256 amount);
/// Claim rewards earned by holding a balance of the ERC20 token
/// Must emit `RewardsClaimed` for each token rewards are claimed for
/// @custom:interaction
function claimRewards() external;
}
/**
* @title IRewardableComponent
* @notice A simple interface mixin to support claiming of rewards.
*/
interface IRewardableComponent is IRewardable {
/// Claim rewards for a single ERC20
/// Must emit `RewardsClaimed` for each token rewards are claimed for
/// @custom:interaction
function claimRewardsSingle(IERC20 erc20) external;
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
// solhint-disable-next-line max-line-length
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";
import "../libraries/Fixed.sol";
import "../libraries/Throttle.sol";
import "./IAsset.sol";
import "./IComponent.sol";
import "./IMain.sol";
import "./IRewardable.sol";
/**
* @title IRToken
* @notice An RToken is an ERC20 that is permissionlessly issuable/redeemable and tracks an
* exchange rate against a single unit: baskets, or {BU} in our type notation.
*/
interface IRToken is IComponent, IERC20MetadataUpgradeable, IERC20PermitUpgradeable {
/// Emitted when an issuance of RToken occurs, whether it occurs via slow minting or not
/// @param issuer The address holding collateral tokens
/// @param recipient The address of the recipient of the RTokens
/// @param amount The quantity of RToken being issued
/// @param baskets The corresponding number of baskets
event Issuance(
address indexed issuer,
address indexed recipient,
uint256 amount,
uint192 baskets
);
/// Emitted when a redemption of RToken occurs
/// @param redeemer The address holding RToken
/// @param recipient The address of the account receiving the backing collateral tokens
/// @param amount The quantity of RToken being redeemed
/// @param baskets The corresponding number of baskets
/// @param amount {qRTok} The amount of RTokens canceled
event Redemption(
address indexed redeemer,
address indexed recipient,
uint256 amount,
uint192 baskets
);
/// Emitted when the number of baskets needed changes
/// @param oldBasketsNeeded Previous number of baskets units needed
/// @param newBasketsNeeded New number of basket units needed
event BasketsNeededChanged(uint192 oldBasketsNeeded, uint192 newBasketsNeeded);
/// Emitted when RToken is melted, i.e the RToken supply is decreased but basketsNeeded is not
/// @param amount {qRTok}
event Melted(uint256 amount);
/// Emitted when issuance SupplyThrottle params are set
event IssuanceThrottleSet(ThrottleLib.Params oldVal, ThrottleLib.Params newVal);
/// Emitted when redemption SupplyThrottle params are set
event RedemptionThrottleSet(ThrottleLib.Params oldVal, ThrottleLib.Params newVal);
// Initialization
function init(
IMain main_,
string memory name_,
string memory symbol_,
string memory mandate_,
ThrottleLib.Params calldata issuanceThrottleParams,
ThrottleLib.Params calldata redemptionThrottleParams
) external;
/// Issue an RToken with basket collateral
/// @param amount {qRTok} The quantity of RToken to issue
/// @custom:interaction
function issue(uint256 amount) external;
/// Issue an RToken with basket collateral, to a particular recipient
/// @param recipient The address to receive the issued RTokens
/// @param amount {qRTok} The quantity of RToken to issue
/// @custom:interaction
function issueTo(address recipient, uint256 amount) external;
/// Redeem RToken for basket collateral
/// @dev Use redeemCustom for non-current baskets
/// @param amount {qRTok} The quantity {qRToken} of RToken to redeem
/// @custom:interaction
function redeem(uint256 amount) external;
/// Redeem RToken for basket collateral to a particular recipient
/// @dev Use redeemCustom for non-current baskets
/// @param recipient The address to receive the backing collateral tokens
/// @param amount {qRTok} The quantity {qRToken} of RToken to redeem
/// @custom:interaction
function redeemTo(address recipient, uint256 amount) external;
/// Redeem RToken for a linear combination of historical baskets, to a particular recipient
/// @dev Allows partial redemptions up to the minAmounts
/// @param recipient The address to receive the backing collateral tokens
/// @param amount {qRTok} The quantity {qRToken} of RToken to redeem
/// @param basketNonces An array of basket nonces to do redemption from
/// @param portions {1} An array of Fix quantities that must add up to FIX_ONE
/// @param expectedERC20sOut An array of ERC20s expected out
/// @param minAmounts {qTok} The minimum ERC20 quantities the caller should receive
/// @custom:interaction
function redeemCustom(
address recipient,
uint256 amount,
uint48[] memory basketNonces,
uint192[] memory portions,
address[] memory expectedERC20sOut,
uint256[] memory minAmounts
) external;
/// Mint an amount of RToken equivalent to baskets BUs, scaling basketsNeeded up
/// Callable only by BackingManager
/// @param baskets {BU} The number of baskets to mint RToken for
/// @custom:protected
function mint(uint192 baskets) external;
/// Melt a quantity of RToken from the caller's account
/// @param amount {qRTok} The amount to be melted
/// @custom:protected
function melt(uint256 amount) external;
/// Burn an amount of RToken from caller's account and scale basketsNeeded down
/// Callable only by BackingManager
/// @custom:protected
function dissolve(uint256 amount) external;
/// Set the number of baskets needed directly, callable only by the BackingManager
/// @param basketsNeeded {BU} The number of baskets to target
/// needed range: pretty interesting
/// @custom:protected
function setBasketsNeeded(uint192 basketsNeeded) external;
/// @return {BU} How many baskets are being targeted
function basketsNeeded() external view returns (uint192);
/// @return {qRTok} The maximum issuance that can be performed in the current block
function issuanceAvailable() external view returns (uint256);
/// @return {qRTok} The maximum redemption that can be performed in the current block
function redemptionAvailable() external view returns (uint256);
}
interface TestIRToken is IRToken {
function setIssuanceThrottleParams(ThrottleLib.Params calldata) external;
function setRedemptionThrottleParams(ThrottleLib.Params calldata) external;
function issuanceThrottleParams() external view returns (ThrottleLib.Params memory);
function redemptionThrottleParams() external view returns (ThrottleLib.Params memory);
function increaseAllowance(address, uint256) external returns (bool);
function decreaseAllowance(address, uint256) external returns (bool);
function monetizeDonations(IERC20) external;
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
// RToken Oracle Interface
interface IRTokenOracle {
struct CachedOracleData {
uint192 cachedPrice; // {UoA/tok}
uint256 cachedAtTime; // {s}
uint48 cachedAtNonce; // {basketNonce}
uint48 cachedTradesOpen;
uint256 cachedTradesNonce; // {tradeNonce}
}
// @returns rTokenPrice {D18} {UoA/rTok} The price of the RToken, in UoA
function latestPrice() external returns (uint192 rTokenPrice, uint256 updatedAt);
// Force recalculate the price of the RToken
function forceUpdatePrice() external;
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
// solhint-disable-next-line max-line-length
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";
import "../libraries/Fixed.sol";
import "./IComponent.sol";
import "./IMain.sol";
/**
* @title IStRSR
* @notice An ERC20 token representing shares of the RSR over-collateralization pool.
*
* StRSR permits the BackingManager to take RSR in times of need. In return, the BackingManager
* benefits the StRSR pool with RSR rewards purchased with a portion of its revenue.
*
* In the absence of collateral default or losses due to slippage, StRSR should have a
* monotonically increasing exchange rate with respect to RSR, meaning that over time
* StRSR is redeemable for more RSR. It is non-rebasing.
*/
interface IStRSR is IERC20MetadataUpgradeable, IERC20PermitUpgradeable, IComponent {
/// Emitted when RSR is staked
/// @param era The era at time of staking
/// @param staker The address of the staker
/// @param rsrAmount {qRSR} How much RSR was staked
/// @param stRSRAmount {qStRSR} How much stRSR was minted by this staking
event Staked(
uint256 indexed era,
address indexed staker,
uint256 rsrAmount,
uint256 stRSRAmount
);
/// Emitted when an unstaking is started
/// @param draftId The id of the draft.
/// @param draftEra The era of the draft.
/// @param staker The address of the unstaker
/// The triple (staker, draftEra, draftId) is a unique ID
/// @param rsrAmount {qRSR} How much RSR this unstaking will be worth, absent seizures
/// @param stRSRAmount {qStRSR} How much stRSR was burned by this unstaking
event UnstakingStarted(
uint256 indexed draftId,
uint256 indexed draftEra,
address indexed staker,
uint256 rsrAmount,
uint256 stRSRAmount,
uint256 availableAt
);
/// Emitted when RSR is unstaked
/// @param firstId The beginning of the range of draft IDs withdrawn in this transaction
/// @param endId The end of range of draft IDs withdrawn in this transaction
/// (ID i was withdrawn if firstId <= i < endId)
/// @param draftEra The era of the draft.
/// The triple (staker, draftEra, id) is a unique ID among drafts
/// @param staker The address of the unstaker
/// @param rsrAmount {qRSR} How much RSR this unstaking was worth
event UnstakingCompleted(
uint256 indexed firstId,
uint256 indexed endId,
uint256 draftEra,
address indexed staker,
uint256 rsrAmount
);
/// Emitted when RSR unstaking is cancelled
/// @param firstId The beginning of the range of draft IDs withdrawn in this transaction
/// @param endId The end of range of draft IDs withdrawn in this transaction
/// (ID i was withdrawn if firstId <= i < endId)
/// @param draftEra The era of the draft.
/// The triple (staker, draftEra, id) is a unique ID among drafts
/// @param staker The address of the unstaker
/// @param rsrAmount {qRSR} How much RSR this unstaking was worth
event UnstakingCancelled(
uint256 indexed firstId,
uint256 indexed endId,
uint256 draftEra,
address indexed staker,
uint256 rsrAmount
);
/// Emitted whenever the exchange rate changes
event ExchangeRateSet(uint192 oldVal, uint192 newVal);
/// Emitted whenever RSR are paids out
event RewardsPaid(uint256 rsrAmt);
/// Emitted if all the RSR in the staking pool is seized and all balances are reset to zero.
event AllBalancesReset(uint256 indexed newEra);
/// Emitted if all the RSR in the unstakin pool is seized, and all ongoing unstaking is voided.
event AllUnstakingReset(uint256 indexed newEra);
event UnstakingDelaySet(uint48 oldVal, uint48 newVal);
event RewardRatioSet(uint192 oldVal, uint192 newVal);
event WithdrawalLeakSet(uint192 oldVal, uint192 newVal);
// Initialization
function init(
IMain main_,
string memory name_,
string memory symbol_,
uint48 unstakingDelay_,
uint192 rewardRatio_,
uint192 withdrawalLeak_
) external;
/// Gather and payout rewards from rsrTrader
/// @custom:interaction
function payoutRewards() external;
/// Stakes an RSR `amount` on the corresponding RToken to earn yield and over-collateralized
/// the system
/// @param amount {qRSR}
/// @custom:interaction
function stake(uint256 amount) external;
/// Begins a delayed unstaking for `amount` stRSR
/// @param amount {qStRSR}
/// @custom:interaction
function unstake(uint256 amount) external;
/// Complete delayed unstaking for the account, up to (but not including!) `endId`
/// @custom:interaction
function withdraw(address account, uint256 endId) external;
/// Cancel unstaking for the account, up to (but not including!) `endId`
/// @custom:interaction
function cancelUnstake(uint256 endId) external;
/// Seize RSR, only callable by main.backingManager()
/// @custom:protected
function seizeRSR(uint256 amount) external;
/// Reset all stakes and advance era
/// @custom:governance
function resetStakes() external;
/// Return the maximum valid value of endId such that withdraw(endId) should immediately work
function endIdForWithdraw(address account) external view returns (uint256 endId);
/// @return {qRSR/qStRSR} The exchange rate between RSR and StRSR
function exchangeRate() external view returns (uint192);
}
interface TestIStRSR is IStRSR {
function rewardRatio() external view returns (uint192);
function setRewardRatio(uint192) external;
function unstakingDelay() external view returns (uint48);
function setUnstakingDelay(uint48) external;
function withdrawalLeak() external view returns (uint192);
function setWithdrawalLeak(uint192) external;
function increaseAllowance(address, uint256) external returns (bool);
function decreaseAllowance(address, uint256) external returns (bool);
/// @return {qStRSR/qRSR} The exchange rate between StRSR and RSR
function exchangeRate() external view returns (uint192);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "./IBroker.sol";
enum TradeStatus {
NOT_STARTED, // before init()
OPEN, // after init() and before settle()
CLOSED, // after settle()
// === Intermediate-tx state ===
PENDING // during init() or settle() (reentrancy protection)
}
/**
* Simple generalized trading interface for all Trade contracts to obey
*
* Usage: if (canSettle()) settle()
*/
interface ITrade {
/// Complete the trade and transfer tokens back to the origin trader
/// @return soldAmt {qSellTok} The quantity of tokens sold
/// @return boughtAmt {qBuyTok} The quantity of tokens bought
function settle() external returns (uint256 soldAmt, uint256 boughtAmt);
function sell() external view returns (IERC20Metadata);
function buy() external view returns (IERC20Metadata);
/// @return The timestamp at which the trade is projected to become settle-able
function endTime() external view returns (uint48);
/// @return True if the trade can be settled
/// @dev Should be guaranteed to be true eventually as an invariant
function canSettle() external view returns (bool);
/// @return TradeKind.DUTCH_AUCTION or TradeKind.BATCH_AUCTION
// solhint-disable-next-line func-name-mixedcase
function KIND() external view returns (TradeKind);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../libraries/Fixed.sol";
import "./IAsset.sol";
import "./IComponent.sol";
import "./ITrade.sol";
import "./IRewardable.sol";
/**
* @title ITrading
* @notice Common events and refresher function for all Trading contracts
*/
interface ITrading is IComponent, IRewardableComponent {
event MaxTradeSlippageSet(uint192 oldVal, uint192 newVal);
event MinTradeVolumeSet(uint192 oldVal, uint192 newVal);
/// Emitted when a trade is started
/// @param trade The one-time-use trade contract that was just deployed
/// @param sell The token to sell
/// @param buy The token to buy
/// @param sellAmount {qSellTok} The quantity of the selling token
/// @param minBuyAmount {qBuyTok} The minimum quantity of the buying token to accept
event TradeStarted(
ITrade indexed trade,
IERC20 indexed sell,
IERC20 indexed buy,
uint256 sellAmount,
uint256 minBuyAmount
);
/// Emitted after a trade ends
/// @param trade The one-time-use trade contract
/// @param sell The token to sell
/// @param buy The token to buy
/// @param sellAmount {qSellTok} The quantity of the token sold
/// @param buyAmount {qBuyTok} The quantity of the token bought
event TradeSettled(
ITrade indexed trade,
IERC20 indexed sell,
IERC20 indexed buy,
uint256 sellAmount,
uint256 buyAmount
);
/// Settle a single trade, expected to be used with multicall for efficient mass settlement
/// @param sell The sell token in the trade
/// @return The trade settled
/// @custom:refresher
function settleTrade(IERC20 sell) external returns (ITrade);
/// @return {%} The maximum trade slippage acceptable
function maxTradeSlippage() external view returns (uint192);
/// @return {UoA} The minimum trade volume in UoA, applies to all assets
function minTradeVolume() external view returns (uint192);
/// @return The ongoing trade for a sell token, or the zero address
function trades(IERC20 sell) external view returns (ITrade);
/// @return The number of ongoing trades open
function tradesOpen() external view returns (uint48);
/// @return The number of total trades ever opened
function tradesNonce() external view returns (uint256);
}
interface TestITrading is ITrading {
/// @custom:governance
function setMaxTradeSlippage(uint192 val) external;
/// @custom:governance
function setMinTradeVolume(uint192 val) external;
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
interface IVersioned {
function version() external view returns (string memory);
}// SPDX-License-Identifier: BlueOak-1.0.0 // solhint-disable func-name-mixedcase func-visibility pragma solidity ^0.8.19; /// @title FixedPoint, a fixed-point arithmetic library defining the custom type uint192 /// @author Matt Elder <[email protected]> and the Reserve Team <https://reserve.org> /** The logical type `uint192 ` is a 192 bit value, representing an 18-decimal Fixed-point fractional value. This is what's described in the Solidity documentation as "fixed192x18" -- a value represented by 192 bits, that makes 18 digits available to the right of the decimal point. The range of values that uint192 can represent is about [-1.7e20, 1.7e20]. Unless a function explicitly says otherwise, it will fail on overflow. To be clear, the following should hold: toFix(0) == 0 toFix(1) == 1e18 */ // Analysis notes: // Every function should revert iff its result is out of bounds. // Unless otherwise noted, when a rounding mode is given, that mode is applied to // a single division that may happen as the last step in the computation. // Unless otherwise noted, when a rounding mode is *not* given but is needed, it's FLOOR. // For each, we comment: // - @return is the value expressed in "value space", where uint192(1e18) "is" 1.0 // - as-ints: is the value expressed in "implementation space", where uint192(1e18) "is" 1e18 // The "@return" expression is suitable for actually using the library // The "as-ints" expression is suitable for testing // A uint value passed to this library was out of bounds for uint192 operations error UIntOutOfBounds(); bytes32 constant UIntOutofBoundsHash = keccak256(abi.encodeWithSignature("UIntOutOfBounds()")); // Used by P1 implementation for easier casting uint256 constant FIX_ONE_256 = 1e18; uint8 constant FIX_DECIMALS = 18; // If a particular uint192 is represented by the uint192 n, then the uint192 represents the // value n/FIX_SCALE. uint64 constant FIX_SCALE = 1e18; // FIX_SCALE Squared: uint128 constant FIX_SCALE_SQ = 1e36; // The largest integer that can be converted to uint192 . // This is a bit bigger than 3.1e39 uint192 constant FIX_MAX_INT = type(uint192).max / FIX_SCALE; uint192 constant FIX_ZERO = 0; // The uint192 representation of zero. uint192 constant FIX_ONE = FIX_SCALE; // The uint192 representation of one. uint192 constant FIX_MAX = type(uint192).max; // The largest uint192. (Not an integer!) uint192 constant FIX_MIN = 0; // The smallest uint192. /// An enum that describes a rounding approach for converting to ints enum RoundingMode { FLOOR, // Round towards zero ROUND, // Round to the nearest int CEIL // Round away from zero } RoundingMode constant FLOOR = RoundingMode.FLOOR; RoundingMode constant ROUND = RoundingMode.ROUND; RoundingMode constant CEIL = RoundingMode.CEIL; /* @dev Solidity 0.8.x only allows you to change one of type or size per type conversion. Thus, all the tedious-looking double conversions like uint256(uint256 (foo)) See: https://docs.soliditylang.org/en/v0.8.17/080-breaking-changes.html#new-restrictions */ /// Explicitly convert a uint256 to a uint192. Revert if the input is out of bounds. function _safeWrap(uint256 x) pure returns (uint192) { if (FIX_MAX < x) revert UIntOutOfBounds(); return uint192(x); } /// Convert a uint to its Fix representation. /// @return x // as-ints: x * 1e18 function toFix(uint256 x) pure returns (uint192) { return _safeWrap(x * FIX_SCALE); } /// Convert a uint to its fixed-point representation, and left-shift its value `shiftLeft` /// decimal digits. /// @return x * 10**shiftLeft // as-ints: x * 10**(shiftLeft + 18) function shiftl_toFix(uint256 x, int8 shiftLeft) pure returns (uint192) { return shiftl_toFix(x, shiftLeft, FLOOR); } /// @return x * 10**shiftLeft // as-ints: x * 10**(shiftLeft + 18) function shiftl_toFix( uint256 x, int8 shiftLeft, RoundingMode rounding ) pure returns (uint192) { // conditions for avoiding overflow if (x == 0) return 0; if (shiftLeft <= -96) return (rounding == CEIL ? 1 : 0); // 0 < uint.max / 10**77 < 0.5 if (40 <= shiftLeft) revert UIntOutOfBounds(); // 10**56 < FIX_MAX < 10**57 shiftLeft += 18; uint256 coeff = 10**abs(shiftLeft); uint256 shifted = (shiftLeft >= 0) ? x * coeff : _divrnd(x, coeff, rounding); return _safeWrap(shifted); } /// Divide a uint by a uint192, yielding a uint192 /// This may also fail if the result is MIN_uint192! not fixing this for optimization's sake. /// @return x / y // as-ints: x * 1e36 / y function divFix(uint256 x, uint192 y) pure returns (uint192) { // If we didn't have to worry about overflow, we'd just do `return x * 1e36 / _y` // If it's safe to do this operation the easy way, do it: if (x < uint256(type(uint256).max / FIX_SCALE_SQ)) { return _safeWrap(uint256(x * FIX_SCALE_SQ) / y); } else { return _safeWrap(mulDiv256(x, FIX_SCALE_SQ, y)); } } /// Divide a uint by a uint, yielding a uint192 /// @return x / y // as-ints: x * 1e18 / y function divuu(uint256 x, uint256 y) pure returns (uint192) { return _safeWrap(mulDiv256(FIX_SCALE, x, y)); } /// @return min(x,y) // as-ints: min(x,y) function fixMin(uint192 x, uint192 y) pure returns (uint192) { return x < y ? x : y; } /// @return max(x,y) // as-ints: max(x,y) function fixMax(uint192 x, uint192 y) pure returns (uint192) { return x > y ? x : y; } /// @return absoluteValue(x,y) // as-ints: absoluteValue(x,y) function abs(int256 x) pure returns (uint256) { return x < 0 ? uint256(-x) : uint256(x); } /// Divide two uints, returning a uint, using rounding mode `rounding`. /// @return numerator / divisor // as-ints: numerator / divisor function _divrnd( uint256 numerator, uint256 divisor, RoundingMode rounding ) pure returns (uint256) { uint256 result = numerator / divisor; if (rounding == FLOOR) return result; if (rounding == ROUND) { if (numerator % divisor > (divisor - 1) / 2) { result++; } } else { if (numerator % divisor > 0) { result++; } } return result; } library FixLib { /// Again, all arithmetic functions fail if and only if the result is out of bounds. /// Convert this fixed-point value to a uint. Round towards zero if needed. /// @return x // as-ints: x / 1e18 function toUint(uint192 x) internal pure returns (uint136) { return toUint(x, FLOOR); } /// Convert this uint192 to a uint /// @return x // as-ints: x / 1e18 with rounding function toUint(uint192 x, RoundingMode rounding) internal pure returns (uint136) { return uint136(_divrnd(uint256(x), FIX_SCALE, rounding)); } /// Return the uint192 shifted to the left by `decimal` digits /// (Similar to a bitshift but in base 10) /// @return x * 10**decimals // as-ints: x * 10**decimals function shiftl(uint192 x, int8 decimals) internal pure returns (uint192) { return shiftl(x, decimals, FLOOR); } /// Return the uint192 shifted to the left by `decimal` digits /// (Similar to a bitshift but in base 10) /// @return x * 10**decimals // as-ints: x * 10**decimals function shiftl( uint192 x, int8 decimals, RoundingMode rounding ) internal pure returns (uint192) { // Handle overflow cases if (x == 0) return 0; if (decimals <= -59) return (rounding == CEIL ? 1 : 0); // 59, because 1e58 > 2**192 if (58 <= decimals) revert UIntOutOfBounds(); // 58, because x * 1e58 > 2 ** 192 if x != 0 uint256 coeff = uint256(10**abs(decimals)); return _safeWrap(decimals >= 0 ? x * coeff : _divrnd(x, coeff, rounding)); } /// Add a uint192 to this uint192 /// @return x + y // as-ints: x + y function plus(uint192 x, uint192 y) internal pure returns (uint192) { return x + y; } /// Add a uint to this uint192 /// @return x + y // as-ints: x + y*1e18 function plusu(uint192 x, uint256 y) internal pure returns (uint192) { return _safeWrap(x + y * FIX_SCALE); } /// Subtract a uint192 from this uint192 /// @return x - y // as-ints: x - y function minus(uint192 x, uint192 y) internal pure returns (uint192) { return x - y; } /// Subtract a uint from this uint192 /// @return x - y // as-ints: x - y*1e18 function minusu(uint192 x, uint256 y) internal pure returns (uint192) { return _safeWrap(uint256(x) - uint256(y * FIX_SCALE)); } /// Multiply this uint192 by a uint192 /// Round truncated values to the nearest available value. 5e-19 rounds away from zero. /// @return x * y // as-ints: x * y/1e18 [division using ROUND, not FLOOR] function mul(uint192 x, uint192 y) internal pure returns (uint192) { return mul(x, y, ROUND); } /// Multiply this uint192 by a uint192 /// @return x * y // as-ints: x * y/1e18 function mul( uint192 x, uint192 y, RoundingMode rounding ) internal pure returns (uint192) { return _safeWrap(_divrnd(uint256(x) * uint256(y), FIX_SCALE, rounding)); } /// Multiply this uint192 by a uint /// @return x * y // as-ints: x * y function mulu(uint192 x, uint256 y) internal pure returns (uint192) { return _safeWrap(x * y); } /// Divide this uint192 by a uint192 /// @return x / y // as-ints: x * 1e18 / y function div(uint192 x, uint192 y) internal pure returns (uint192) { return div(x, y, FLOOR); } /// Divide this uint192 by a uint192 /// @return x / y // as-ints: x * 1e18 / y function div( uint192 x, uint192 y, RoundingMode rounding ) internal pure returns (uint192) { // Multiply-in FIX_SCALE before dividing by y to preserve precision. return _safeWrap(_divrnd(uint256(x) * FIX_SCALE, y, rounding)); } /// Divide this uint192 by a uint /// @return x / y // as-ints: x / y function divu(uint192 x, uint256 y) internal pure returns (uint192) { return divu(x, y, FLOOR); } /// Divide this uint192 by a uint /// @return x / y // as-ints: x / y function divu( uint192 x, uint256 y, RoundingMode rounding ) internal pure returns (uint192) { return _safeWrap(_divrnd(x, y, rounding)); } uint64 constant FIX_HALF = uint64(FIX_SCALE) / 2; /// Raise this uint192 to a nonnegative integer power. Requires that x_ <= FIX_ONE /// Gas cost is O(lg(y)), precision is +- 1e-18. /// @return x_ ** y // as-ints: x_ ** y / 1e18**(y-1) <- technically correct for y = 0. :D function powu(uint192 x_, uint48 y) internal pure returns (uint192) { require(x_ <= FIX_ONE); if (y == 1) return x_; if (x_ == FIX_ONE || y == 0) return FIX_ONE; uint256 x = uint256(x_) * FIX_SCALE; // x is D36 uint256 result = FIX_SCALE_SQ; // result is D36 while (true) { if (y & 1 == 1) result = (result * x + FIX_SCALE_SQ / 2) / FIX_SCALE_SQ; if (y <= 1) break; y = (y >> 1); x = (x * x + FIX_SCALE_SQ / 2) / FIX_SCALE_SQ; } return _safeWrap(result / FIX_SCALE); } /// Comparison operators... function lt(uint192 x, uint192 y) internal pure returns (bool) { return x < y; } function lte(uint192 x, uint192 y) internal pure returns (bool) { return x <= y; } function gt(uint192 x, uint192 y) internal pure returns (bool) { return x > y; } function gte(uint192 x, uint192 y) internal pure returns (bool) { return x >= y; } function eq(uint192 x, uint192 y) internal pure returns (bool) { return x == y; } function neq(uint192 x, uint192 y) internal pure returns (bool) { return x != y; } /// Return whether or not this uint192 is less than epsilon away from y. /// @return |x - y| < epsilon // as-ints: |x - y| < epsilon function near( uint192 x, uint192 y, uint192 epsilon ) internal pure returns (bool) { uint192 diff = x <= y ? y - x : x - y; return diff < epsilon; } // ================ Chained Operations ================ // The operation foo_bar() always means: // Do foo() followed by bar(), and overflow only if the _end_ result doesn't fit in an uint192 /// Shift this uint192 left by `decimals` digits, and convert to a uint /// @return x * 10**decimals // as-ints: x * 10**(decimals - 18) function shiftl_toUint(uint192 x, int8 decimals) internal pure returns (uint256) { return shiftl_toUint(x, decimals, FLOOR); } /// Shift this uint192 left by `decimals` digits, and convert to a uint. /// @return x * 10**decimals // as-ints: x * 10**(decimals - 18) function shiftl_toUint( uint192 x, int8 decimals, RoundingMode rounding ) internal pure returns (uint256) { // Handle overflow cases if (x == 0) return 0; // always computable, no matter what decimals is if (decimals <= -42) return (rounding == CEIL ? 1 : 0); if (96 <= decimals) revert UIntOutOfBounds(); decimals -= 18; // shift so that toUint happens at the same time. uint256 coeff = uint256(10**abs(decimals)); return decimals >= 0 ? uint256(x * coeff) : uint256(_divrnd(x, coeff, rounding)); } /// Multiply this uint192 by a uint, and output the result as a uint /// @return x * y // as-ints: x * y / 1e18 function mulu_toUint(uint192 x, uint256 y) internal pure returns (uint256) { return mulDiv256(uint256(x), y, FIX_SCALE); } /// Multiply this uint192 by a uint, and output the result as a uint /// @return x * y // as-ints: x * y / 1e18 function mulu_toUint( uint192 x, uint256 y, RoundingMode rounding ) internal pure returns (uint256) { return mulDiv256(uint256(x), y, FIX_SCALE, rounding); } /// Multiply this uint192 by a uint192 and output the result as a uint /// @return x * y // as-ints: x * y / 1e36 function mul_toUint(uint192 x, uint192 y) internal pure returns (uint256) { return mulDiv256(uint256(x), uint256(y), FIX_SCALE_SQ); } /// Multiply this uint192 by a uint192 and output the result as a uint /// @return x * y // as-ints: x * y / 1e36 function mul_toUint( uint192 x, uint192 y, RoundingMode rounding ) internal pure returns (uint256) { return mulDiv256(uint256(x), uint256(y), FIX_SCALE_SQ, rounding); } /// Compute x * y / z avoiding intermediate overflow /// @dev Only use if you need to avoid overflow; costlier than x * y / z /// @return x * y / z // as-ints: x * y / z function muluDivu( uint192 x, uint256 y, uint256 z ) internal pure returns (uint192) { return muluDivu(x, y, z, FLOOR); } /// Compute x * y / z, avoiding intermediate overflow /// @dev Only use if you need to avoid overflow; costlier than x * y / z /// @return x * y / z // as-ints: x * y / z function muluDivu( uint192 x, uint256 y, uint256 z, RoundingMode rounding ) internal pure returns (uint192) { return _safeWrap(mulDiv256(x, y, z, rounding)); } /// Compute x * y / z on Fixes, avoiding intermediate overflow /// @dev Only use if you need to avoid overflow; costlier than x * y / z /// @return x * y / z // as-ints: x * y / z function mulDiv( uint192 x, uint192 y, uint192 z ) internal pure returns (uint192) { return mulDiv(x, y, z, FLOOR); } /// Compute x * y / z on Fixes, avoiding intermediate overflow /// @dev Only use if you need to avoid overflow; costlier than x * y / z /// @return x * y / z // as-ints: x * y / z function mulDiv( uint192 x, uint192 y, uint192 z, RoundingMode rounding ) internal pure returns (uint192) { return _safeWrap(mulDiv256(x, y, z, rounding)); } // === safe*() === /// Multiply two fixes, rounding up to FIX_MAX and down to 0 /// @param a First param to multiply /// @param b Second param to multiply function safeMul( uint192 a, uint192 b, RoundingMode rounding ) internal pure returns (uint192) { // untestable: // a will never = 0 here because of the check in _price() if (a == 0 || b == 0) return 0; // untestable: // a = FIX_MAX iff b = 0 if (a == FIX_MAX || b == FIX_MAX) return FIX_MAX; // return FIX_MAX instead of throwing overflow errors. unchecked { // p and mul *are* Fix values, so have 18 decimals (D18) uint256 rawDelta = uint256(b) * a; // {D36} = {D18} * {D18} // if we overflowed, then return FIX_MAX if (rawDelta / b != a) return FIX_MAX; uint256 shiftDelta = rawDelta; // add in rounding if (rounding == RoundingMode.ROUND) shiftDelta += (FIX_ONE / 2); else if (rounding == RoundingMode.CEIL) shiftDelta += FIX_ONE - 1; // untestable (here there be dragons): // (below explanation is for the ROUND case, but it extends to the FLOOR/CEIL too) // A) shiftDelta = rawDelta + (FIX_ONE / 2) // shiftDelta overflows if: // B) shiftDelta = MAX_UINT256 - FIX_ONE/2 + 1 // rawDelta + (FIX_ONE/2) = MAX_UINT256 - FIX_ONE/2 + 1 // b * a = MAX_UINT256 - FIX_ONE + 1 // therefore shiftDelta overflows if: // C) b = (MAX_UINT256 - FIX_ONE + 1) / a // MAX_UINT256 ~= 1e77 , FIX_MAX ~= 6e57 (6e20 difference in magnitude) // a <= 1e21 (MAX_TARGET_AMT) // a must be between 1e19 & 1e20 in order for b in (C) to be uint192, // but a would have to be < 1e18 in order for (A) to overflow if (shiftDelta < rawDelta) return FIX_MAX; // return FIX_MAX if return result would truncate if (shiftDelta / FIX_ONE > FIX_MAX) return FIX_MAX; // return _div(rawDelta, FIX_ONE, rounding) return uint192(shiftDelta / FIX_ONE); // {D18} = {D36} / {D18} } } /// Divide two fixes, rounding up to FIX_MAX and down to 0 /// @param a Numerator /// @param b Denominator function safeDiv( uint192 a, uint192 b, RoundingMode rounding ) internal pure returns (uint192) { if (a == 0) return 0; if (b == 0) return FIX_MAX; uint256 raw = _divrnd(FIX_ONE_256 * a, uint256(b), rounding); if (raw >= FIX_MAX) return FIX_MAX; return uint192(raw); // don't need _safeWrap } /// Multiplies two fixes and divide by a third /// @param a First to multiply /// @param b Second to multiply /// @param c Denominator function safeMulDiv( uint192 a, uint192 b, uint192 c, RoundingMode rounding ) internal pure returns (uint192 result) { if (a == 0 || b == 0) return 0; if (a == FIX_MAX || b == FIX_MAX || c == 0) return FIX_MAX; uint256 result_256; unchecked { (uint256 hi, uint256 lo) = fullMul(a, b); if (hi >= c) return FIX_MAX; uint256 mm = mulmod(a, b, c); if (mm > lo) hi -= 1; lo -= mm; uint256 pow2 = c & (0 - c); uint256 c_256 = uint256(c); // Warning: Should not access c below this line c_256 /= pow2; lo /= pow2; lo += hi * ((0 - pow2) / pow2 + 1); uint256 r = 1; r *= 2 - c_256 * r; r *= 2 - c_256 * r; r *= 2 - c_256 * r; r *= 2 - c_256 * r; r *= 2 - c_256 * r; r *= 2 - c_256 * r; r *= 2 - c_256 * r; r *= 2 - c_256 * r; result_256 = lo * r; // Apply rounding if (rounding == CEIL) { if (mm > 0) result_256 += 1; } else if (rounding == ROUND) { if (mm > ((c_256 - 1) / 2)) result_256 += 1; } } if (result_256 >= FIX_MAX) return FIX_MAX; return uint192(result_256); } } // ================ a couple pure-uint helpers================ // as-ints comments are omitted here, because they're the same as @return statements, because // these are all pure uint functions /// Return (x*y/z), avoiding intermediate overflow. // Adapted from sources: // https://medium.com/coinmonks/4db014e080b1, https://medium.com/wicketh/afa55870a65 // and quite a few of the other excellent "Mathemagic" posts from https://medium.com/wicketh /// @dev Only use if you need to avoid overflow; costlier than x * y / z /// @return result x * y / z function mulDiv256( uint256 x, uint256 y, uint256 z ) pure returns (uint256 result) { unchecked { (uint256 hi, uint256 lo) = fullMul(x, y); if (hi >= z) revert UIntOutOfBounds(); uint256 mm = mulmod(x, y, z); if (mm > lo) hi -= 1; lo -= mm; uint256 pow2 = z & (0 - z); z /= pow2; lo /= pow2; lo += hi * ((0 - pow2) / pow2 + 1); uint256 r = 1; r *= 2 - z * r; r *= 2 - z * r; r *= 2 - z * r; r *= 2 - z * r; r *= 2 - z * r; r *= 2 - z * r; r *= 2 - z * r; r *= 2 - z * r; result = lo * r; } } /// Return (x*y/z), avoiding intermediate overflow. /// @dev Only use if you need to avoid overflow; costlier than x * y / z /// @return x * y / z function mulDiv256( uint256 x, uint256 y, uint256 z, RoundingMode rounding ) pure returns (uint256) { uint256 result = mulDiv256(x, y, z); if (rounding == FLOOR) return result; uint256 mm = mulmod(x, y, z); if (rounding == CEIL) { if (mm > 0) result += 1; } else { if (mm > ((z - 1) / 2)) result += 1; // z should be z-1 } return result; } /// Return (x*y) as a "virtual uint512" (lo, hi), representing (hi*2**256 + lo) /// Adapted from sources: /// https://medium.com/wicketh/27650fec525d, https://medium.com/coinmonks/4db014e080b1 /// @dev Intended to be internal to this library /// @return hi (hi, lo) satisfies hi*(2**256) + lo == x * y /// @return lo (paired with `hi`) function fullMul(uint256 x, uint256 y) pure returns (uint256 hi, uint256 lo) { unchecked { uint256 mm = mulmod(x, y, uint256(0) - uint256(1)); lo = x * y; hi = mm - lo; if (mm < lo) hi -= 1; } }
// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
// From https://gist.github.com/ottodevs/c43d0a8b4b891ac2da675f825b1d1dbf
library StringLib {
/// Convert any basic uppercase chars (A-Z) in str to lowercase
/// @dev This is safe for general Unicode strings in UTF-8, because every byte representing a
/// multibyte codepoint has its high bit set to 1, and this only modifies bytes with a high bit
/// set to 0. As a result, this function will _not_ transform any multi-byte capital letters,
/// like Ö, À, or Æ, to lowercase. That's much harder, and this is sufficient for our purposes.
function toLower(string memory str) internal pure returns (string memory) {
bytes memory bStr = bytes(str);
bytes memory bLower = new bytes(bStr.length);
for (uint256 i = 0; i < bStr.length; i++) {
// Uppercase character...
if ((uint8(bStr[i]) >= 65) && (uint8(bStr[i]) <= 90)) {
// So we add 32 to make it lowercase
bLower[i] = bytes1(uint8(bStr[i]) + 32);
} else {
bLower[i] = bStr[i];
}
}
return string(bLower);
}
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "./Fixed.sol";
uint48 constant ONE_HOUR = 3600; // {seconds/hour}
/**
* @title ThrottleLib
* A library that implements a usage throttle that can be used to ensure net issuance
* or net redemption for an RToken never exceeds some bounds per unit time (hour).
*
* It is expected for the RToken to use this library with two instances, one for issuance
* and one for redemption. Issuance causes the available redemption amount to increase, and
* visa versa.
*/
library ThrottleLib {
using FixLib for uint192;
struct Params {
uint256 amtRate; // {qRTok/hour} a quantity of RToken hourly; cannot be 0
uint192 pctRate; // {1/hour} a fraction of RToken hourly; can be 0
}
struct Throttle {
// === Gov params ===
Params params;
// === Cache ===
uint48 lastTimestamp; // {seconds}
uint256 lastAvailable; // {qRTok}
}
/// Reverts if usage amount exceeds available amount
/// @param supply {qRTok} Total RToken supply beforehand
/// @param amount {qRTok} Amount of RToken to use. Should be negative for the issuance
/// throttle during redemption and for the redemption throttle during issuance.
function useAvailable(
Throttle storage throttle,
uint256 supply,
int256 amount
) internal {
// untestable: amtRate will always be greater > 0 due to previous validations
if (throttle.params.amtRate == 0 && throttle.params.pctRate == 0) return;
// Calculate hourly limit
uint256 limit = hourlyLimit(throttle, supply); // {qRTok}
// Calculate available amount before supply change
uint256 available = currentlyAvailable(throttle, limit);
// Update throttle.timestamp if available amount changed or at limit
if (available != throttle.lastAvailable || available == limit) {
throttle.lastTimestamp = uint48(block.timestamp);
}
// Update throttle.lastAvailable
if (amount > 0) {
require(uint256(amount) <= available, "supply change throttled");
available -= uint256(amount);
// untestable: the final else statement, amount will never be 0
} else if (amount < 0) {
available += uint256(-amount);
}
throttle.lastAvailable = available;
}
/// @param limit {qRTok/hour} The hourly limit
/// @return available {qRTok} Amount currently available for consumption
function currentlyAvailable(Throttle storage throttle, uint256 limit)
internal
view
returns (uint256 available)
{
uint48 delta = uint48(block.timestamp) - throttle.lastTimestamp; // {seconds}
available = throttle.lastAvailable + (limit * delta) / ONE_HOUR;
if (available > limit) available = limit;
}
/// @return limit {qRTok} The hourly limit
function hourlyLimit(Throttle storage throttle, uint256 supply)
internal
view
returns (uint256 limit)
{
Params storage params = throttle.params;
// Calculate hourly limit as: max(params.amtRate, supply.mul(params.pctRate))
limit = (supply * params.pctRate) / FIX_ONE_256; // {qRTok}
if (params.amtRate > limit) limit = params.amtRate;
}
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "../interfaces/IMain.sol";
uint256 constant LONG_FREEZE_CHARGES = 6; // 6 uses
uint48 constant MAX_UNFREEZE_AT = type(uint48).max;
uint48 constant MAX_SHORT_FREEZE = 2592000; // 1 month
uint48 constant MAX_LONG_FREEZE = 31536000; // 1 year
/**
* @title Auth
* @notice Provides fine-grained access controls and exports frozen/paused states to Components.
*/
abstract contract Auth is AccessControlUpgradeable, IAuth {
/**
* System-wide states (does not impact ERC20 functions)
* - Frozen: only allow OWNER actions and staking.
* - Trading Paused: only allow OWNER actions, issuance, redemption, staking,
* and rewards payout.
* - Issuance Paused: disallow issuance
*
* Typically freezing thaws on its own in a predetermined number of blocks.
* However, OWNER can freeze forever and unfreeze.
*/
/// The rest of the contract uses the shorthand; these declarations are here for getters
bytes32 public constant OWNER_ROLE = OWNER;
bytes32 public constant SHORT_FREEZER_ROLE = SHORT_FREEZER;
bytes32 public constant LONG_FREEZER_ROLE = LONG_FREEZER;
bytes32 public constant PAUSER_ROLE = PAUSER;
// === Freezing ===
mapping(address => uint256) public longFreezes;
uint48 public unfreezeAt; // {s} uint48.max to pause indefinitely
uint48 public shortFreeze; // {s} length of an initial freeze
uint48 public longFreeze; // {s} length of a freeze extension
// === Pausing ===
/// @custom:oz-renamed-from paused
bool public tradingPaused;
bool public issuancePaused;
/* ==== Invariants ====
0 <= longFreeze[a] <= LONG_FREEZE_CHARGES for all addrs a
set{a has LONG_FREEZER} == set{a : longFreeze[a] == 0}
*/
// checks:
// - __Auth_init has not previously been called
// - 0 < shortFreeze_ <= MAX_SHORT_FREEZE
// - 0 < longFreeze_ <= MAX_LONG_FREEZE
// effects:
// - caller has only the OWNER role
// - OWNER is the admin role for all roles
// - shortFreeze' == shortFreeze_
// - longFreeze' == longFreeze_
// questions: (what do I know about the values of paused and unfreezeAt?)
// untestable:
// `else` branch of `onlyInitializing` (ie. revert) is currently untestable.
// This function is only called inside other `init` functions, each of which is wrapped
// in an `initializer` modifier, which would fail first.
// solhint-disable-next-line func-name-mixedcase
function __Auth_init(uint48 shortFreeze_, uint48 longFreeze_) internal onlyInitializing {
__AccessControl_init();
// Role setup
_setRoleAdmin(OWNER, OWNER);
_setRoleAdmin(SHORT_FREEZER, OWNER);
_setRoleAdmin(LONG_FREEZER, OWNER);
_setRoleAdmin(PAUSER, OWNER);
_grantRole(OWNER, _msgSender());
setShortFreeze(shortFreeze_);
setLongFreeze(longFreeze_);
}
// checks: caller is an admin for role, account is not 0
// effects:
// - account has the `role` role
// - if role is LONG_FREEZER, then longFreezes'[account] == LONG_FREEZE_CHARGES
function grantRole(bytes32 role, address account)
public
override(AccessControlUpgradeable, IAccessControlUpgradeable)
onlyRole(getRoleAdmin(role))
{
require(account != address(0), "cannot grant role to address 0");
if (role == LONG_FREEZER) longFreezes[account] = LONG_FREEZE_CHARGES;
_grantRole(role, account);
}
// ==== System-wide views ====
// returns: bool(main is frozen) == now < unfreezeAt
function frozen() public view returns (bool) {
return block.timestamp < unfreezeAt;
}
/// @dev This -or- condition is a performance optimization for the consuming Component
// returns: bool(main is frozen or tradingPaused) == tradingPaused || (now < unfreezeAt)
function tradingPausedOrFrozen() public view returns (bool) {
return tradingPaused || block.timestamp < unfreezeAt;
}
/// @dev This -or- condition is a performance optimization for the consuming Component
// returns: bool(main is frozen or issuancePaused) == issuancePaused || (now < unfreezeAt)
function issuancePausedOrFrozen() public view returns (bool) {
return issuancePaused || block.timestamp < unfreezeAt;
}
// === Freezing ===
/// Enter a freeze for the `shortFreeze` duration
// checks:
// - caller has the SHORT_FREEZER role
// - now + shortFreeze >= unfreezeAt (that is, this call should increase unfreezeAt)
// effects:
// - unfreezeAt' = now + shortFreeze
// - after, caller does not have the SHORT_FREEZER role
function freezeShort() external onlyRole(SHORT_FREEZER) {
// Revoke short freezer role after one use
_revokeRole(SHORT_FREEZER, _msgSender());
freezeUntil(uint48(block.timestamp) + shortFreeze);
}
/// Enter a freeze by the `longFreeze` duration
// checks:
// - caller has the LONG_FREEZER role
// - longFreezes[caller] > 0
// - now + longFreeze >= unfreezeAt (that is, this call should increase unfreezeAt)
// effects:
// - unfreezeAt' = now + longFreeze
// - longFreezes'[caller] = longFreezes[caller] - 1
// - if longFreezes'[caller] == 0 then caller loses the LONG_FREEZER role
function freezeLong() external onlyRole(LONG_FREEZER) {
longFreezes[_msgSender()] -= 1; // reverts on underflow
// Revoke on 0 charges as a cleanup step
if (longFreezes[_msgSender()] == 0) _revokeRole(LONG_FREEZER, _msgSender());
freezeUntil(uint48(block.timestamp) + longFreeze);
}
/// Enter a permanent freeze
// checks:
// - caller has the OWNER role
// - unfreezeAt != type(uint48).max
// effects: unfreezeAt' = type(uint48).max
function freezeForever() external onlyRole(OWNER) {
freezeUntil(MAX_UNFREEZE_AT);
}
/// End all freezes
// checks:
// - unfreezeAt > now (i.e, frozen() == true before the call)
// - caller has the OWNER role
// effects: unfreezeAt' = now (i.e, frozen() == false after the call)
function unfreeze() external onlyRole(OWNER) {
emit UnfreezeAtSet(unfreezeAt, uint48(block.timestamp));
unfreezeAt = uint48(block.timestamp);
}
// === Pausing ===
// checks: caller has PAUSER
// effects: tradingPaused' = true
function pauseTrading() external onlyRole(PAUSER) {
emit TradingPausedSet(tradingPaused, true);
tradingPaused = true;
}
// checks: caller has PAUSER
// effects: tradingPaused' = false
function unpauseTrading() external onlyRole(PAUSER) {
emit TradingPausedSet(tradingPaused, false);
tradingPaused = false;
}
// checks: caller has PAUSER
// effects: issuancePaused' = true
function pauseIssuance() external onlyRole(PAUSER) {
emit IssuancePausedSet(issuancePaused, true);
issuancePaused = true;
}
// checks: caller has PAUSER
// effects: issuancePaused' = false
function unpauseIssuance() external onlyRole(PAUSER) {
emit IssuancePausedSet(issuancePaused, false);
issuancePaused = false;
}
// === Gov params ===
/// @custom:governance
function setShortFreeze(uint48 shortFreeze_) public onlyRole(OWNER) {
require(shortFreeze_ > 0 && shortFreeze_ <= MAX_SHORT_FREEZE, "short freeze out of range");
emit ShortFreezeDurationSet(shortFreeze, shortFreeze_);
shortFreeze = shortFreeze_;
}
/// @custom:governance
function setLongFreeze(uint48 longFreeze_) public onlyRole(OWNER) {
require(longFreeze_ > 0 && longFreeze_ <= MAX_LONG_FREEZE, "long freeze out of range");
emit LongFreezeDurationSet(longFreeze, longFreeze_);
longFreeze = longFreeze_;
}
// === Private Helper ===
// checks: newUnfreezeAt > unfreezeAt
// effects: unfreezeAt' = newUnfreezeAt
function freezeUntil(uint48 newUnfreezeAt) private {
require(newUnfreezeAt > unfreezeAt, "frozen");
emit UnfreezeAtSet(unfreezeAt, newUnfreezeAt);
unfreezeAt = newUnfreezeAt;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[48] private __gap;
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IMain.sol";
import "./Auth.sol";
/**
* @title ComponentRegistry
*/
abstract contract ComponentRegistry is Initializable, Auth, IComponentRegistry {
// untestable:
// `else` branch of `onlyInitializing` (ie. revert) is currently untestable.
// This function is only called inside other `init` functions, each of which is wrapped
// in an `initializer` modifier, which would fail first.
// solhint-disable-next-line func-name-mixedcase
function __ComponentRegistry_init(Components memory components_) internal onlyInitializing {
_setBackingManager(components_.backingManager);
_setBasketHandler(components_.basketHandler);
_setRSRTrader(components_.rsrTrader);
_setRTokenTrader(components_.rTokenTrader);
_setAssetRegistry(components_.assetRegistry);
_setDistributor(components_.distributor);
_setFurnace(components_.furnace);
_setBroker(components_.broker);
_setStRSR(components_.stRSR);
_setRToken(components_.rToken);
}
// === Components ===
IRToken public rToken;
function _setRToken(IRToken val) private {
require(address(val) != address(0), "invalid RToken address");
emit RTokenSet(rToken, val);
rToken = val;
}
IStRSR public stRSR;
function _setStRSR(IStRSR val) private {
require(address(val) != address(0), "invalid StRSR address");
emit StRSRSet(stRSR, val);
stRSR = val;
}
IAssetRegistry public assetRegistry;
function _setAssetRegistry(IAssetRegistry val) private {
require(address(val) != address(0), "invalid AssetRegistry address");
emit AssetRegistrySet(assetRegistry, val);
assetRegistry = val;
}
IBasketHandler public basketHandler;
function _setBasketHandler(IBasketHandler val) private {
require(address(val) != address(0), "invalid BasketHandler address");
emit BasketHandlerSet(basketHandler, val);
basketHandler = val;
}
IBackingManager public backingManager;
function _setBackingManager(IBackingManager val) private {
require(address(val) != address(0), "invalid BackingManager address");
emit BackingManagerSet(backingManager, val);
backingManager = val;
}
IDistributor public distributor;
function _setDistributor(IDistributor val) private {
require(address(val) != address(0), "invalid Distributor address");
emit DistributorSet(distributor, val);
distributor = val;
}
IRevenueTrader public rsrTrader;
function _setRSRTrader(IRevenueTrader val) private {
require(address(val) != address(0), "invalid RSRTrader address");
emit RSRTraderSet(rsrTrader, val);
rsrTrader = val;
}
IRevenueTrader public rTokenTrader;
function _setRTokenTrader(IRevenueTrader val) private {
require(address(val) != address(0), "invalid RTokenTrader address");
emit RTokenTraderSet(rTokenTrader, val);
rTokenTrader = val;
}
IFurnace public furnace;
function _setFurnace(IFurnace val) private {
require(address(val) != address(0), "invalid Furnace address");
emit FurnaceSet(furnace, val);
furnace = val;
}
IBroker public broker;
function _setBroker(IBroker val) private {
require(address(val) != address(0), "invalid Broker address");
emit BrokerSet(broker, val);
broker = val;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[40] private __gap;
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "../interfaces/IVersioned.sol";
// This value should be updated on each release
string constant VERSION = "3.0.1";
/**
* @title Versioned
* @notice A mix-in to track semantic versioning uniformly across contracts.
*/
abstract contract Versioned is IVersioned {
function version() public pure virtual override returns (string memory) {
return VERSION;
}
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IMain.sol";
import "../mixins/ComponentRegistry.sol";
import "../mixins/Auth.sol";
import "../mixins/Versioned.sol";
/**
* @title Main
* @notice The center of the system around which Components orbit.
*/
// solhint-disable max-states-count
contract MainP1 is Versioned, Initializable, Auth, ComponentRegistry, UUPSUpgradeable, IMain {
IERC20 public rsr;
/// @custom:oz-upgrades-unsafe-allow constructor
// solhint-disable-next-line no-empty-blocks
constructor() initializer {}
/// Initializer
function init(
Components memory components,
IERC20 rsr_,
uint48 shortFreeze_,
uint48 longFreeze_
) public virtual initializer {
require(address(rsr_) != address(0), "invalid RSR address");
__Auth_init(shortFreeze_, longFreeze_);
__ComponentRegistry_init(components);
__UUPSUpgradeable_init();
rsr = rsr_;
emit MainInitialized();
}
/// @custom:refresher
/// @custom:interaction CEI
/// @dev Not intended to be used in production, only for equivalence with P0
function poke() external {
// == Refresher ==
assetRegistry.refresh();
// == CE block ==
if (!frozen()) furnace.melt();
stRSR.payoutRewards();
}
function hasRole(bytes32 role, address account)
public
view
override(IAccessControlUpgradeable, AccessControlUpgradeable)
returns (bool)
{
return super.hasRole(role, account);
}
// === Upgradeability ===
// solhint-disable-next-line no-empty-blocks
function _authorizeUpgrade(address newImplementation) internal override onlyRole(OWNER) {}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../../interfaces/IAsset.sol";
import "../../interfaces/IAssetRegistry.sol";
import "../../interfaces/IBackingManager.sol";
import "../../libraries/Fixed.sol";
import "./TradeLib.sol";
/// Struct purposes:
/// 1. Configure trading
/// 2. Stay under stack limit with fewer vars
/// 3. Cache information such as component addresses to save on gas
struct TradingContext {
BasketRange basketsHeld; // {BU}
// basketsHeld.top is the number of partial baskets units held
// basketsHeld.bottom is the number of full basket units held
// Components
IBackingManager bm;
IBasketHandler bh;
IAssetRegistry ar;
IStRSR stRSR;
IERC20 rsr;
IRToken rToken;
// Gov Vars
uint192 minTradeVolume; // {UoA}
uint192 maxTradeSlippage; // {1}
// Cached values
uint192[] quantities; // {tok/BU} basket quantities
}
/**
* @title RecollateralizationLibP1
* @notice An informal extension of BackingManager that implements the rebalancing logic
* Users:
* - BackingManager
* - RTokenAsset (uses `basketRange()`)
*
* Interface:
* 1. prepareRecollateralizationTrade() (external)
* 2. basketRange() (internal)
*/
library RecollateralizationLibP1 {
using FixLib for uint192;
using TradeLib for TradeInfo;
using TradeLib for IBackingManager;
/// Select and prepare a trade that moves us closer to capitalization, using the
/// basket range to avoid overeager/duplicate trading.
/// The basket range is the full range of projected outcomes for the rebalancing process.
// This is the "main loop" for recollateralization trading:
// actions:
// let range = basketRange(...)
// let trade = nextTradePair(...)
// if trade.sell is not a defaulted collateral, prepareTradeToCoverDeficit(...)
// otherwise, prepareTradeSell(...) taking the minBuyAmount as the dependent variable
function prepareRecollateralizationTrade(IBackingManager bm, BasketRange memory basketsHeld)
external
view
returns (
bool doTrade,
TradeRequest memory req,
TradePrices memory prices
)
{
IMain main = bm.main();
// === Prepare TradingContext cache ===
TradingContext memory ctx;
ctx.basketsHeld = basketsHeld;
ctx.bm = bm;
ctx.bh = main.basketHandler();
ctx.ar = main.assetRegistry();
ctx.stRSR = main.stRSR();
ctx.rsr = main.rsr();
ctx.rToken = main.rToken();
ctx.minTradeVolume = bm.minTradeVolume();
ctx.maxTradeSlippage = bm.maxTradeSlippage();
// Calculate quantities
Registry memory reg = ctx.ar.getRegistry();
ctx.quantities = new uint192[](reg.erc20s.length);
for (uint256 i = 0; i < reg.erc20s.length; ++i) {
ctx.quantities[i] = ctx.bh.quantityUnsafe(reg.erc20s[i], reg.assets[i]);
}
// ============================
// Compute a target basket range for trading - {BU}
BasketRange memory range = basketRange(ctx, reg);
// Select a pair to trade next, if one exists
TradeInfo memory trade = nextTradePair(ctx, reg, range);
// Don't trade if no pair is selected
if (address(trade.sell) == address(0) || address(trade.buy) == address(0)) {
return (false, req, prices);
}
// If we are selling a fully unpriced asset or UNSOUND collateral, do not cover deficit
// untestable:
// sellLow will not be zero, those assets are skipped in nextTradePair
if (
trade.prices.sellLow == 0 ||
(trade.sell.isCollateral() &&
ICollateral(address(trade.sell)).status() != CollateralStatus.SOUND)
) {
// Emergency case
// Set minBuyAmount as a function of sellAmount
(doTrade, req) = trade.prepareTradeSell(ctx.minTradeVolume, ctx.maxTradeSlippage);
} else {
// Normal case
// Set sellAmount as a function of minBuyAmount
(doTrade, req) = trade.prepareTradeToCoverDeficit(
ctx.minTradeVolume,
ctx.maxTradeSlippage
);
}
// At this point doTrade _must_ be true, otherwise nextTradePair assumptions are broken
assert(doTrade);
return (doTrade, req, trade.prices);
}
// Compute the target basket range
// Algorithm intuition: Trade conservatively. Quantify uncertainty based on the proportion of
// token balances requiring trading vs not requiring trading. Seek to decrease uncertainty
// the largest amount possible with each trade.
//
// How do we know this algorithm converges?
// Assumption: constant oracle prices; monotonically increasing refPerTok()
// Any volume traded narrows the BU band. Why:
// - We might increase `basketsHeld.bottom` from run-to-run, but will never decrease it
// - We might decrease the UoA amount of excess balances beyond `basketsHeld.bottom` from
// run-to-run, but will never increase it
// - We might decrease the UoA amount of missing balances up-to `basketsHeld.top` from
// run-to-run, but will never increase it
//
// Preconditions:
// - ctx is correctly populated, with current basketsHeld.bottom + basketsHeld.top
// - reg contains erc20 + asset + quantities arrays in same order and without duplicates
// Trading Strategy:
// - We will not aim to hold more than rToken.basketsNeeded() BUs
// - No double trades: if we buy B in one trade, we won't sell B in another trade
// Caveat: Unless the asset we're selling is IFFY/DISABLED
// - The best price we might get for a trade is at the high sell price and low buy price
// - The worst price we might get for a trade is at the low sell price and
// the high buy price, multiplied by ( 1 - maxTradeSlippage )
// - In the worst-case an additional dust balance can be lost, up to minTradeVolume
// - Given all that, we're aiming to hold as many BUs as possible using the assets we own.
//
// More concretely:
// - range.top = min(rToken.basketsNeeded, basketsHeld.top - least baskets missing
// + most baskets surplus)
// - range.bottom = min(rToken.basketsNeeded, basketsHeld.bottom + least baskets purchaseable)
// where "least baskets purchaseable" involves trading at the worst price,
// incurring the full maxTradeSlippage, and taking up to a minTradeVolume loss due to dust.
function basketRange(TradingContext memory ctx, Registry memory reg)
internal
view
returns (BasketRange memory range)
{
(uint192 buPriceLow, uint192 buPriceHigh) = ctx.bh.lotPrice(); // {UoA/BU}
uint192 basketsNeeded = ctx.rToken.basketsNeeded(); // {BU}
// Cap ctx.basketsHeld.top
if (ctx.basketsHeld.top > basketsNeeded) {
ctx.basketsHeld.top = basketsNeeded;
}
// === (1/3) Calculate contributions from surplus/deficits ===
// for range.top, anchor to min(ctx.basketsHeld.top, basketsNeeded)
// for range.bottom, anchor to min(ctx.basketsHeld.bottom, basketsNeeded)
// a signed delta to be applied to range.top
int256 deltaTop; // D18{BU} even though this is int256, it is D18
// not required for range.bottom
// to minimize total operations, range.bottom is calculated from a summed UoA
uint192 uoaBottom; // {UoA} pessimistic UoA estimate of balances above basketsHeld.bottom
// (no space on the stack to cache erc20s.length)
for (uint256 i = 0; i < reg.erc20s.length; ++i) {
// Exclude RToken balances to avoid double counting value
if (reg.erc20s[i] == IERC20(address(ctx.rToken))) continue;
uint192 bal = reg.assets[i].bal(address(ctx.bm)); // {tok}
// For RSR, include the staking balance
if (reg.erc20s[i] == ctx.rsr) {
bal = bal.plus(reg.assets[i].bal(address(ctx.stRSR)));
}
if (ctx.quantities[i] == 0) {
// Skip over dust-balance assets not in the basket
(uint192 lotLow, ) = reg.assets[i].lotPrice(); // {UoA/tok}
// Intentionally include value of IFFY/DISABLED collateral
if (!TradeLib.isEnoughToSell(reg.assets[i], bal, lotLow, ctx.minTradeVolume)) {
continue;
}
}
(uint192 low, uint192 high) = reg.assets[i].price(); // {UoA/tok}
// price() is better than lotPrice() here: it's important to not underestimate how
// much value could be in a token that is unpriced by using a decaying high lotPrice.
// price() will return [0, FIX_MAX] in this case, which is preferable.
// throughout these sections +/- is same as Fix.plus/Fix.minus and </> is Fix.gt/.lt
// deltaTop: optimistic case
// if in deficit relative to ctx.basketsHeld.top: deduct missing baskets
// if in surplus relative to ctx.basketsHeld.top: add-in surplus baskets
{
// {tok} = {tok/BU} * {BU}
uint192 anchor = ctx.quantities[i].mul(ctx.basketsHeld.top, CEIL);
if (anchor > bal) {
// deficit: deduct optimistic estimate of baskets missing
// {BU} = {UoA/tok} * {tok} / {UoA/BU}
deltaTop -= int256(uint256(low.mulDiv(anchor - bal, buPriceHigh, FLOOR)));
// does not need underflow protection: using low price of asset
} else {
// surplus: add-in optimistic estimate of baskets purchaseable
// {BU} = {UoA/tok} * {tok} / {UoA/BU}
deltaTop += int256(uint256(high.safeMulDiv(bal - anchor, buPriceLow, CEIL)));
}
}
// range.bottom: pessimistic case
// add-in surplus baskets relative to ctx.basketsHeld.bottom
{
// {tok} = {tok/BU} * {BU}
uint192 anchor = ctx.quantities[i].mul(ctx.basketsHeld.bottom, FLOOR);
// (1) Sum token value at low price
// {UoA} = {UoA/tok} * {tok}
uint192 val = low.mul(bal - anchor, FLOOR);
// (2) Lose minTradeVolume to dust (why: auctions can return tokens)
// Q: Why is this precisely where we should take out minTradeVolume?
// A: Our use of isEnoughToSell always uses the low price (lotLow, technically),
// so min trade volumes are always assesed based on low prices. At this point
// in the calculation we have already calculated the UoA amount corresponding to
// the excess token balance based on its low price, so we are already set up
// to straightforwardly deduct the minTradeVolume before trying to buy BUs.
uoaBottom += (val < ctx.minTradeVolume) ? 0 : val - ctx.minTradeVolume;
}
}
// ==== (2/3) Add-in ctx.*BasketsHeld safely ====
// range.top
if (deltaTop < 0) {
range.top = ctx.basketsHeld.top - _safeWrap(uint256(-deltaTop));
// reverting on underflow is appropriate here
} else {
// guard against overflow; > is same as Fix.gt
if (uint256(deltaTop) + ctx.basketsHeld.top > FIX_MAX) range.top = FIX_MAX;
else range.top = ctx.basketsHeld.top + _safeWrap(uint256(deltaTop));
}
// range.bottom
// (3) Buy BUs at their high price with the remaining value
// (4) Assume maximum slippage in trade
// {BU} = {UoA} * {1} / {UoA/BU}
range.bottom =
ctx.basketsHeld.bottom +
uoaBottom.mulDiv(FIX_ONE.minus(ctx.maxTradeSlippage), buPriceHigh, FLOOR);
// reverting on overflow is appropriate here
// ==== (3/3) Enforce (range.bottom <= range.top <= basketsNeeded) ====
if (range.top > basketsNeeded) range.top = basketsNeeded;
if (range.bottom > range.top) range.bottom = range.top;
}
// ===========================================================================================
// === Private ===
// Used in memory in `nextTradePair` to duck the stack limit
struct MaxSurplusDeficit {
CollateralStatus surplusStatus; // starts SOUND
uint192 surplus; // {UoA}
uint192 deficit; // {UoA}
}
// Choose next sell/buy pair to trade, with reference to the basket range
// Skip over trading surplus dust amounts
/// @return trade
/// sell: Surplus collateral OR address(0)
/// deficit Deficit collateral OR address(0)
/// sellAmount {sellTok} Surplus amount (whole tokens)
/// buyAmount {buyTok} Deficit amount (whole tokens)
/// prices.sellLow {UoA/sellTok} The worst-case price of the sell token on secondary markets
/// prices.sellHigh {UoA/sellTok} The best-case price of the sell token on secondary markets
/// prices.buyLow {UoA/buyTok} The best-case price of the buy token on secondary markets
/// prices.buyHigh {UoA/buyTok} The worst-case price of the buy token on secondary markets
///
// Defining "sell" and "buy":
// If bal(e) > (quantity(e) * range.top), then e is in surplus by the difference
// If bal(e) < (quantity(e) * range.bottom), then e is in deficit by the difference
//
// First, ignoring RSR:
// `trade.sell` is the token from erc20s with the greatest surplus value (in UoA),
// and sellAmount is the quantity of that token that it's in surplus (in qTok).
// if `trade.sell` == 0, then no token is in surplus by at least minTradeSize,
// and `trade.sellAmount` and `trade.sellLow` / `trade.sellHigh are unset.
//
// `trade.buy` is the token from erc20s with the greatest deficit value (in UoA),
// and buyAmount is the quantity of that token that it's in deficit (in qTok).
// if `trade.buy` == 0, then no token is in deficit at all,
// and `trade.buyAmount` and `trade.buyLow` / `trade.buyHigh` are unset.
//
// Then, just if we have a buy asset and no sell asset, consider selling available RSR.
//
// Prefer selling assets in this order: DISABLED -> SOUND -> IFFY.
// Sell IFFY last because it may recover value in the future.
// All collateral in the basket have already been guaranteed to be SOUND by upstream checks.
function nextTradePair(
TradingContext memory ctx,
Registry memory reg,
BasketRange memory range
) private view returns (TradeInfo memory trade) {
MaxSurplusDeficit memory maxes;
maxes.surplusStatus = CollateralStatus.IFFY; // least-desirable sell status
// Iterate over non-RSR/non-RToken assets
// (no space on the stack to cache erc20s.length)
for (uint256 i = 0; i < reg.erc20s.length; ++i) {
if (reg.erc20s[i] == ctx.rsr || address(reg.erc20s[i]) == address(ctx.rToken)) continue;
uint192 bal = reg.assets[i].bal(address(ctx.bm)); // {tok}
// {tok} = {BU} * {tok/BU}
// needed(Top): token balance needed for range.top baskets: quantity(e) * range.top
uint192 needed = range.top.mul(ctx.quantities[i], CEIL); // {tok}
if (bal.gt(needed)) {
(uint192 lotLow, uint192 lotHigh) = reg.assets[i].lotPrice(); // {UoA/sellTok}
if (lotHigh == 0) continue; // skip over worthless assets
// {UoA} = {sellTok} * {UoA/sellTok}
uint192 delta = bal.minus(needed).mul(lotLow, FLOOR);
// status = asset.status() if asset.isCollateral() else SOUND
CollateralStatus status; // starts SOUND
if (reg.assets[i].isCollateral()) {
status = ICollateral(address(reg.assets[i])).status();
}
// Select the most-in-surplus "best" asset still enough to sell,
// as defined by a (status, surplusAmt) ordering
if (
isBetterSurplus(maxes, status, delta) &&
TradeLib.isEnoughToSell(
reg.assets[i],
bal.minus(needed),
lotLow,
ctx.minTradeVolume
)
) {
trade.sell = reg.assets[i];
trade.sellAmount = bal.minus(needed);
trade.prices.sellLow = lotLow;
trade.prices.sellHigh = lotHigh;
maxes.surplusStatus = status;
maxes.surplus = delta;
}
} else {
// needed(Bottom): token balance needed at bottom of the basket range
needed = range.bottom.mul(ctx.quantities[i], CEIL); // {buyTok};
if (bal.lt(needed)) {
uint192 amtShort = needed.minus(bal); // {buyTok}
(uint192 lotLow, uint192 lotHigh) = reg.assets[i].lotPrice(); // {UoA/buyTok}
// {UoA} = {buyTok} * {UoA/buyTok}
uint192 delta = amtShort.mul(lotHigh, CEIL);
// The best asset to buy is whichever asset has the largest deficit
if (delta.gt(maxes.deficit)) {
trade.buy = reg.assets[i];
trade.buyAmount = amtShort;
trade.prices.buyLow = lotLow;
trade.prices.buyHigh = lotHigh;
maxes.deficit = delta;
}
}
}
}
// Use RSR if needed
if (address(trade.sell) == address(0) && address(trade.buy) != address(0)) {
IAsset rsrAsset = ctx.ar.toAsset(ctx.rsr);
uint192 rsrAvailable = rsrAsset.bal(address(ctx.bm)).plus(
rsrAsset.bal(address(ctx.stRSR))
);
(uint192 lotLow, uint192 lotHigh) = rsrAsset.lotPrice(); // {UoA/RSR}
if (
lotHigh > 0 &&
TradeLib.isEnoughToSell(rsrAsset, rsrAvailable, lotLow, ctx.minTradeVolume)
) {
trade.sell = rsrAsset;
trade.sellAmount = rsrAvailable;
trade.prices.sellLow = lotLow;
trade.prices.sellHigh = lotHigh;
}
}
}
/// @param curr The current MaxSurplusDeficit containing the best surplus so far
/// @param other The collateral status of the asset in consideration
/// @param surplusAmt {UoA} The amount by which the asset in consideration is in surplus
function isBetterSurplus(
MaxSurplusDeficit memory curr,
CollateralStatus other,
uint192 surplusAmt
) private pure returns (bool) {
// NOTE: If the CollateralStatus enum changes then this has to change!
if (curr.surplusStatus == CollateralStatus.DISABLED) {
return other == CollateralStatus.DISABLED && surplusAmt.gt(curr.surplus);
} else if (curr.surplusStatus == CollateralStatus.SOUND) {
return
other == CollateralStatus.DISABLED ||
(other == CollateralStatus.SOUND && surplusAmt.gt(curr.surplus));
} else {
// curr is IFFY
return other != CollateralStatus.IFFY || surplusAmt.gt(curr.surplus);
}
}
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../../interfaces/IAsset.sol";
import "../../interfaces/IAssetRegistry.sol";
import "../../interfaces/ITrading.sol";
import "../../libraries/Fixed.sol";
import "./RecollateralizationLib.sol";
struct TradeInfo {
IAsset sell;
IAsset buy;
uint192 sellAmount; // {sellTok}
uint192 buyAmount; // {buyTok}
TradePrices prices;
}
/**
* @title TradeLib
* @notice An internal lib for preparing individual trades on particular asset pairs
* Users:
* - RecollateralizationLib
* - RevenueTrader
*/
library TradeLib {
using FixLib for uint192;
/// Prepare a trade to sell `trade.sellAmount` that guarantees a reasonable closing price,
/// without explicitly aiming at a particular buy amount.
/// @param trade:
/// sell != 0, sellAmount >= 0 {sellTok}, prices.sellLow >= 0 {UoA/sellTok}
/// buy != 0, buyAmount (unused) {buyTok}, prices.buyHigh > 0 {UoA/buyTok}
/// @return notDust True when the trade is larger than the dust amount
/// @return req The prepared trade request to send to the Broker
//
// If notDust is true, then the returned trade request satisfies:
// req.sell == trade.sell and req.buy == trade.buy,
// req.minBuyAmount * trade.prices.buyHigh ~=
// trade.sellAmount * trade.prices.sellLow * (1-maxTradeSlippage),
// req.sellAmount == min(trade.sell.maxTradeSize(), trade.sellAmount)
// 1 < req.sellAmount
//
// If notDust is false, no trade exists that satisfies those constraints.
function prepareTradeSell(
TradeInfo memory trade,
uint192 minTradeVolume,
uint192 maxTradeSlippage
) internal view returns (bool notDust, TradeRequest memory req) {
// checked for in RevenueTrader / CollateralizatlionLib
assert(
trade.prices.buyHigh > 0 &&
trade.prices.buyHigh < FIX_MAX &&
trade.prices.sellLow < FIX_MAX
);
notDust = isEnoughToSell(
trade.sell,
trade.sellAmount,
trade.prices.sellLow,
minTradeVolume
);
// Cap sell amount
uint192 maxSell = maxTradeSize(trade.sell, trade.buy, trade.prices.sellHigh); // {sellTok}
uint192 s = trade.sellAmount > maxSell ? maxSell : trade.sellAmount; // {sellTok}
// Calculate equivalent buyAmount within [0, FIX_MAX]
// {buyTok} = {sellTok} * {1} * {UoA/sellTok} / {UoA/buyTok}
uint192 b = s.mul(FIX_ONE.minus(maxTradeSlippage)).safeMulDiv(
trade.prices.sellLow,
trade.prices.buyHigh,
CEIL
);
// {*tok} => {q*Tok}
req.sellAmount = s.shiftl_toUint(int8(trade.sell.erc20Decimals()), FLOOR);
req.minBuyAmount = b.shiftl_toUint(int8(trade.buy.erc20Decimals()), CEIL);
req.sell = trade.sell;
req.buy = trade.buy;
return (notDust, req);
}
/// Assuming we have `trade.sellAmount` sell tokens available, prepare a trade to cover as
/// much of our deficit of `trade.buyAmount` buy tokens as possible, given expected trade
/// slippage and maxTradeVolume().
/// @param trade:
/// sell != 0
/// buy != 0
/// sellAmount (unused) {sellTok}
/// buyAmount >= 0 {buyTok}
/// prices.sellLow > 0 {UoA/sellTok}
/// prices.buyHigh > 0 {UoA/buyTok}
/// @return notDust Whether the prepared trade is large enough to be worth trading
/// @return req The prepared trade request to send to the Broker
//
// Returns prepareTradeSell(trade, rules), where
// req.sellAmount = min(trade.sellAmount,
// trade.buyAmount * (buyHigh / sellLow) / (1-maxTradeSlippage))
// i.e, the minimum of trade.sellAmount and (a sale amount that, at current prices and
// maximum slippage, will yield at least the requested trade.buyAmount)
//
// Which means we should get that, if notDust is true, then:
// req.sell = sell and req.buy = buy
//
// 1 <= req.minBuyAmount <= max(trade.buyAmount, buy.minTradeSize()))
// 1 < req.sellAmount <= min(trade.sellAmount, sell.maxTradeSize())
// req.minBuyAmount ~= trade.sellAmount * sellLow / buyHigh * (1-maxTradeSlippage)
//
// req.sellAmount (and req.minBuyAmount) are maximal satisfying all these conditions
function prepareTradeToCoverDeficit(
TradeInfo memory trade,
uint192 minTradeVolume,
uint192 maxTradeSlippage
) internal view returns (bool notDust, TradeRequest memory req) {
assert(
trade.prices.sellLow > 0 &&
trade.prices.sellLow < FIX_MAX &&
trade.prices.buyHigh > 0 &&
trade.prices.buyHigh < FIX_MAX
);
// Don't buy dust.
trade.buyAmount = fixMax(
trade.buyAmount,
minTradeSize(minTradeVolume, trade.prices.buyHigh)
);
// {sellTok} = {buyTok} * {UoA/buyTok} / {UoA/sellTok}
uint192 exactSellAmount = trade.buyAmount.mulDiv(
trade.prices.buyHigh,
trade.prices.sellLow,
CEIL
);
// exactSellAmount: Amount to sell to buy `deficitAmount` if there's no slippage
// slippedSellAmount: Amount needed to sell to buy `deficitAmount`, counting slippage
uint192 slippedSellAmount = exactSellAmount.div(FIX_ONE.minus(maxTradeSlippage), CEIL);
trade.sellAmount = fixMin(slippedSellAmount, trade.sellAmount); // {sellTok}
return prepareTradeSell(trade, minTradeVolume, maxTradeSlippage);
}
/// @param asset The asset in consideration
/// @param amt {tok} The number of whole tokens we plan to sell
/// @param price {UoA/tok} The price to use for sizing
/// @param minTradeVolume {UoA} The min trade volume, passed in for gas optimization
/// @return If amt is sufficiently large to be worth selling into our trading platforms
function isEnoughToSell(
IAsset asset,
uint192 amt,
uint192 price,
uint192 minTradeVolume
) internal view returns (bool) {
return
amt.gte(minTradeSize(minTradeVolume, price)) &&
// Trading platforms often don't allow token quanta trades for rounding reasons
// {qTok} = {tok} / {tok/qTok}
amt.shiftl_toUint(int8(asset.erc20Decimals())) > 1;
}
// === Private ===
/// Calculates the minTradeSize for an asset based on the given minTradeVolume and price
/// @param minTradeVolume {UoA} The min trade volume, passed in for gas optimization
/// @return {tok} The min trade size for the asset in whole tokens
function minTradeSize(uint192 minTradeVolume, uint192 price) private pure returns (uint192) {
// {tok} = {UoA} / {UoA/tok}
uint192 size = price == 0 ? FIX_MAX : minTradeVolume.div(price, CEIL);
return size > 0 ? size : 1;
}
/// Calculates the maximum trade size for a trade pair of tokens
/// @return {tok} The max trade size for the trade overall
function maxTradeSize(
IAsset sell,
IAsset buy,
uint192 price
) private view returns (uint192) {
// D18{tok} = D18{UoA} / D18{UoA/tok}
uint192 size = fixMin(sell.maxTradeVolume(), buy.maxTradeVolume()).safeDiv(price, FLOOR);
return size > 0 ? size : 1;
}
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "../../interfaces/IAsset.sol";
import "./OracleLib.sol";
import "./VersionedAsset.sol";
contract Asset is IAsset, VersionedAsset {
using FixLib for uint192;
using OracleLib for AggregatorV3Interface;
AggregatorV3Interface public immutable chainlinkFeed; // {UoA/tok}
IERC20Metadata public immutable erc20;
uint8 public immutable erc20Decimals;
uint192 public immutable override maxTradeVolume; // {UoA}
uint48 public immutable oracleTimeout; // {s}
uint192 public immutable oracleError; // {1}
// === Lot price ===
uint48 public immutable priceTimeout; // {s} The period over which `savedHighPrice` decays to 0
uint192 public savedLowPrice; // {UoA/tok} The low price of the token during the last update
uint192 public savedHighPrice; // {UoA/tok} The high price of the token during the last update
uint48 public lastSave; // {s} The timestamp when prices were last saved
/// @param priceTimeout_ {s} The number of seconds over which savedHighPrice decays to 0
/// @param chainlinkFeed_ Feed units: {UoA/tok}
/// @param oracleError_ {1} The % the oracle feed can be off by
/// @param maxTradeVolume_ {UoA} The max trade volume, in UoA
/// @param oracleTimeout_ {s} The number of seconds until a oracle value becomes invalid
/// @dev oracleTimeout_ is also used as the timeout value in lotPrice(), should be highest of
/// all assets' oracleTimeout in a collateral if there are multiple oracles
constructor(
uint48 priceTimeout_,
AggregatorV3Interface chainlinkFeed_,
uint192 oracleError_,
IERC20Metadata erc20_,
uint192 maxTradeVolume_,
uint48 oracleTimeout_
) {
require(priceTimeout_ > 0, "price timeout zero");
require(address(chainlinkFeed_) != address(0), "missing chainlink feed");
require(oracleError_ > 0 && oracleError_ < FIX_ONE, "oracle error out of range");
require(address(erc20_) != address(0), "missing erc20");
require(maxTradeVolume_ > 0, "invalid max trade volume");
require(oracleTimeout_ > 0, "oracleTimeout zero");
priceTimeout = priceTimeout_;
chainlinkFeed = chainlinkFeed_;
oracleError = oracleError_;
erc20 = erc20_;
erc20Decimals = erc20.decimals();
maxTradeVolume = maxTradeVolume_;
oracleTimeout = oracleTimeout_;
}
/// Can revert, used by other contract functions in order to catch errors
/// Should not return FIX_MAX for low
/// Should only return FIX_MAX for high if low is 0
/// @dev The third (unused) variable is only here for compatibility with Collateral
/// @return low {UoA/tok} The low price estimate
/// @return high {UoA/tok} The high price estimate
function tryPrice()
external
view
virtual
returns (
uint192 low,
uint192 high,
uint192
)
{
uint192 p = chainlinkFeed.price(oracleTimeout); // {UoA/tok}
uint192 err = p.mul(oracleError, CEIL);
// assert(low <= high); obviously true just by inspection
return (p - err, p + err, 0);
}
/// Should not revert
/// Refresh saved prices
function refresh() public virtual override {
try this.tryPrice() returns (uint192 low, uint192 high, uint192) {
// {UoA/tok}, {UoA/tok}
// (0, 0) is a valid price; (0, FIX_MAX) is unpriced
// Save prices if priced
if (high < FIX_MAX) {
savedLowPrice = low;
savedHighPrice = high;
lastSave = uint48(block.timestamp);
} else {
// must be unpriced
assert(low == 0);
}
} catch (bytes memory errData) {
// see: docs/solidity-style.md#Catching-Empty-Data
if (errData.length == 0) revert(); // solhint-disable-line reason-string
}
}
/// Should not revert
/// @dev Should be general enough to not need to be overridden
/// @return {UoA/tok} The lower end of the price estimate
/// @return {UoA/tok} The upper end of the price estimate
function price() public view virtual returns (uint192, uint192) {
try this.tryPrice() returns (uint192 low, uint192 high, uint192) {
assert(low <= high);
return (low, high);
} catch (bytes memory errData) {
// see: docs/solidity-style.md#Catching-Empty-Data
if (errData.length == 0) revert(); // solhint-disable-line reason-string
return (0, FIX_MAX);
}
}
/// Should not revert
/// lotLow should be nonzero when the asset might be worth selling
/// @dev Should be general enough to not need to be overridden
/// @return lotLow {UoA/tok} The lower end of the lot price estimate
/// @return lotHigh {UoA/tok} The upper end of the lot price estimate
function lotPrice() external view virtual returns (uint192 lotLow, uint192 lotHigh) {
try this.tryPrice() returns (uint192 low, uint192 high, uint192) {
// if the price feed is still functioning, use that
lotLow = low;
lotHigh = high;
} catch (bytes memory errData) {
// see: docs/solidity-style.md#Catching-Empty-Data
if (errData.length == 0) revert(); // solhint-disable-line reason-string
// if the price feed is broken, use a decayed historical value
uint48 delta = uint48(block.timestamp) - lastSave; // {s}
if (delta <= oracleTimeout) {
lotLow = savedLowPrice;
lotHigh = savedHighPrice;
} else if (delta >= oracleTimeout + priceTimeout) {
return (0, 0); // no price after full timeout
} else {
// oracleTimeout <= delta <= oracleTimeout + priceTimeout
// {1} = {s} / {s}
uint192 lotMultiplier = divuu(oracleTimeout + priceTimeout - delta, priceTimeout);
// {UoA/tok} = {UoA/tok} * {1}
lotLow = savedLowPrice.mul(lotMultiplier);
lotHigh = savedHighPrice.mul(lotMultiplier);
}
}
assert(lotLow <= lotHigh);
}
/// @return {tok} The balance of the ERC20 in whole tokens
function bal(address account) external view virtual returns (uint192) {
return shiftl_toFix(erc20.balanceOf(account), -int8(erc20Decimals));
}
/// @return If the asset is an instance of ICollateral or not
function isCollateral() external pure virtual returns (bool) {
return false;
}
// solhint-disable no-empty-blocks
/// Claim rewards earned by holding a balance of the ERC20 token
/// DEPRECATED: claimRewards() will be removed from all assets and collateral plugins
function claimRewards() external virtual {}
// solhint-enable no-empty-blocks
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "../../libraries/Fixed.sol";
error StalePrice();
error ZeroPrice();
interface EACAggregatorProxy {
function aggregator() external view returns (address);
}
/// Used by asset plugins to price their collateral
library OracleLib {
/// @dev Use for nested calls that should revert when there is a problem
/// @param timeout The number of seconds after which oracle values should be considered stale
/// @return {UoA/tok}
function price(AggregatorV3Interface chainlinkFeed, uint48 timeout)
internal
view
returns (uint192)
{
try chainlinkFeed.latestRoundData() returns (
uint80 roundId,
int256 p,
uint256,
uint256 updateTime,
uint80 answeredInRound
) {
if (updateTime == 0 || answeredInRound < roundId) {
revert StalePrice();
}
// Downcast is safe: uint256(-) reverts on underflow; block.timestamp assumed < 2^48
uint48 secondsSince = uint48(block.timestamp - updateTime);
if (secondsSince > timeout) revert StalePrice();
if (p == 0) revert ZeroPrice();
// {UoA/tok}
return shiftl_toFix(uint256(p), -int8(chainlinkFeed.decimals()));
} catch (bytes memory errData) {
// Check if the aggregator was not set: if so, the chainlink feed has been deprecated
// and a _specific_ error needs to be raised in order to avoid looking like OOG
if (errData.length == 0) {
if (EACAggregatorProxy(address(chainlinkFeed)).aggregator() == address(0)) {
revert StalePrice();
}
// solhint-disable-next-line reason-string
revert();
}
// Otherwise, preserve the error bytes
// solhint-disable-next-line no-inline-assembly
assembly {
revert(add(32, errData), mload(errData))
}
}
}
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "../../p1/mixins/RecollateralizationLib.sol";
import "../../interfaces/IMain.sol";
import "../../interfaces/IRToken.sol";
import "../../interfaces/IRTokenOracle.sol";
import "./Asset.sol";
import "./VersionedAsset.sol";
uint256 constant ORACLE_TIMEOUT = 15 minutes;
/// Once an RToken gets large enough to get a price feed, replacing this asset with
/// a simpler one will do wonders for gas usage
/// @dev This RTokenAsset is ONLY compatible with Protocol ^3.0.0
contract RTokenAsset is IAsset, VersionedAsset, IRTokenOracle {
using FixLib for uint192;
using OracleLib for AggregatorV3Interface;
// Component addresses are not mutable in protocol, so it's safe to cache these
IMain public immutable main;
IBasketHandler public immutable basketHandler;
IAssetRegistry public immutable assetRegistry;
IBackingManager public immutable backingManager;
IERC20Metadata public immutable erc20;
uint8 public immutable erc20Decimals;
uint192 public immutable maxTradeVolume; // {UoA}
// Oracle State
CachedOracleData public cachedOracleData;
/// @param maxTradeVolume_ {UoA} The max trade volume, in UoA
constructor(IRToken erc20_, uint192 maxTradeVolume_) {
require(address(erc20_) != address(0), "missing erc20");
require(maxTradeVolume_ > 0, "invalid max trade volume");
main = erc20_.main();
basketHandler = main.basketHandler();
assetRegistry = main.assetRegistry();
backingManager = main.backingManager();
erc20 = IERC20Metadata(address(erc20_));
erc20Decimals = erc20_.decimals();
maxTradeVolume = maxTradeVolume_;
}
/// Can revert, used by other contract functions in order to catch errors
/// @dev This method for calculating the price can provide a 2x larger range than the average
/// oracleError of the RToken's backing collateral. This only occurs when there is
/// less RSR overcollateralization in % terms than the average (weighted) oracleError.
/// This arises from the use of oracleErrors inside of `basketRange()` and inside
/// `basketHandler.price()`. When `range.bottom == range.top` then there is no compounding.
/// @return low {UoA/tok} The low price estimate
/// @return high {UoA/tok} The high price estimate
function tryPrice(bool useLotPrice) external view virtual returns (uint192 low, uint192 high) {
(uint192 lowBUPrice, uint192 highBUPrice) = useLotPrice
? basketHandler.lotPrice()
: basketHandler.price(); // {UoA/BU}
require(lowBUPrice != 0 && highBUPrice != FIX_MAX, "invalid price");
assert(lowBUPrice <= highBUPrice); // not obviously true just by inspection
// Here we take advantage of the fact that we know RToken has 18 decimals
// to convert between uint256 an uint192. Fits due to assumed max totalSupply.
uint192 supply = _safeWrap(IRToken(address(erc20)).totalSupply());
if (supply == 0) return (lowBUPrice, highBUPrice);
// The RToken's price is not symmetric like other assets!
// range.bottom is lower because of the slippage from the shortfall
BasketRange memory range = basketRange(); // {BU}
// {UoA/tok} = {BU} * {UoA/BU} / {tok}
low = range.bottom.mulDiv(lowBUPrice, supply, FLOOR);
high = range.top.mulDiv(highBUPrice, supply, CEIL);
assert(low <= high); // not obviously true
}
// solhint-disable no-empty-blocks
function refresh() public virtual override {
// No need to save lastPrice; can piggyback off the backing collateral's lotPrice()
cachedOracleData.cachedAtTime = 0; // force oracle refresh
}
// solhint-enable no-empty-blocks
/// Should not revert
/// @dev See `tryPrice` caveat about possible compounding error in calculating price
/// @return {UoA/tok} The lower end of the price estimate
/// @return {UoA/tok} The upper end of the price estimate
function price() public view virtual returns (uint192, uint192) {
try this.tryPrice(false) returns (uint192 low, uint192 high) {
return (low, high);
} catch (bytes memory errData) {
// see: docs/solidity-style.md#Catching-Empty-Data
if (errData.length == 0) revert(); // solhint-disable-line reason-string
return (0, FIX_MAX);
}
}
/// Should not revert
/// lotLow should be nonzero when the asset might be worth selling
/// @dev See `tryPrice` caveat about possible compounding error in calculating price
/// @return lotLow {UoA/tok} The lower end of the lot price estimate
/// @return lotHigh {UoA/tok} The upper end of the lot price estimate
function lotPrice() external view returns (uint192 lotLow, uint192 lotHigh) {
try this.tryPrice(true) returns (uint192 low, uint192 high) {
lotLow = low;
lotHigh = high;
} catch (bytes memory errData) {
// see: docs/solidity-style.md#Catching-Empty-Data
if (errData.length == 0) revert(); // solhint-disable-line reason-string
return (0, 0);
}
}
/// @return {tok} The balance of the ERC20 in whole tokens
function bal(address account) external view returns (uint192) {
// The RToken has 18 decimals, so there's no reason to waste gas here doing a shiftl_toFix
// return shiftl_toFix(erc20.balanceOf(account), -int8(erc20Decimals));
return _safeWrap(erc20.balanceOf(account));
}
/// @return {s} The timestamp of the last refresh; always 0 since prices are never saved
function lastSave() external pure returns (uint48) {
return 0;
}
/// @return If the asset is an instance of ICollateral or not
function isCollateral() external pure virtual returns (bool) {
return false;
}
// solhint-disable no-empty-blocks
/// Claim rewards earned by holding a balance of the ERC20 token
/// DEPRECATED: claimRewards() will be removed from all assets and collateral plugins
function claimRewards() external virtual {}
// solhint-enable no-empty-blocks
function forceUpdatePrice() external {
_updateCachedPrice();
}
function latestPrice() external returns (uint192 rTokenPrice, uint256 updatedAt) {
// Situations that require an update, from most common to least common.
if (
cachedOracleData.cachedAtTime + ORACLE_TIMEOUT <= block.timestamp || // Cache Timeout
cachedOracleData.cachedAtNonce != basketHandler.nonce() || // Basket nonce was updated
cachedOracleData.cachedTradesNonce != backingManager.tradesNonce() || // New trades
cachedOracleData.cachedTradesOpen != backingManager.tradesOpen() // ..or settled
) {
_updateCachedPrice();
}
return (cachedOracleData.cachedPrice, cachedOracleData.cachedAtTime);
}
// ==== Private ====
// Update Oracle Data
function _updateCachedPrice() internal {
(uint192 low, uint192 high) = price();
require(low != 0 && high != FIX_MAX, "invalid price");
cachedOracleData = CachedOracleData(
(low + high) / 2,
block.timestamp,
basketHandler.nonce(),
backingManager.tradesOpen(),
backingManager.tradesNonce()
);
}
/// Computationally expensive basketRange calculation; used in price() & lotPrice()
function basketRange() private view returns (BasketRange memory range) {
BasketRange memory basketsHeld = basketHandler.basketsHeldBy(address(backingManager));
uint192 basketsNeeded = IRToken(address(erc20)).basketsNeeded(); // {BU}
// if (basketHandler.fullyCollateralized())
if (basketsHeld.bottom >= basketsNeeded) {
range.bottom = basketsNeeded;
range.top = basketsNeeded;
} else {
// Note: Extremely this is extremely wasteful in terms of gas. This only exists so
// there is _some_ asset to represent the RToken itself when it is deployed, in
// the absence of an external price feed. Any RToken that gets reasonably big
// should switch over to an asset with a price feed.
TradingContext memory ctx;
ctx.basketsHeld = basketsHeld;
ctx.bm = backingManager;
ctx.bh = basketHandler;
ctx.ar = assetRegistry;
ctx.stRSR = main.stRSR();
ctx.rsr = main.rsr();
ctx.rToken = main.rToken();
ctx.minTradeVolume = backingManager.minTradeVolume();
ctx.maxTradeSlippage = backingManager.maxTradeSlippage();
// Calculate quantities
Registry memory reg = ctx.ar.getRegistry();
ctx.quantities = new uint192[](reg.erc20s.length);
for (uint256 i = 0; i < reg.erc20s.length; ++i) {
ctx.quantities[i] = ctx.bh.quantityUnsafe(reg.erc20s[i], reg.assets[i]);
}
// will exclude UoA value from RToken balances at BackingManager
range = RecollateralizationLibP1.basketRange(ctx, reg);
}
}
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;
import "../../interfaces/IVersioned.sol";
// This value should be updated on each release
string constant ASSET_VERSION = "3.0.1";
/**
* @title VersionedAsset
* @notice A mix-in to track semantic versioning uniformly across asset plugin contracts.
*/
abstract contract VersionedAsset is IVersioned {
function version() public pure virtual override returns (string memory) {
return ASSET_VERSION;
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IERC20Metadata","name":"rsr_","type":"address"},{"internalType":"contract IGnosis","name":"gnosis_","type":"address"},{"internalType":"contract IAsset","name":"rsrAsset_","type":"address"},{"components":[{"internalType":"contract IMain","name":"main","type":"address"},{"components":[{"internalType":"contract IRToken","name":"rToken","type":"address"},{"internalType":"contract IStRSR","name":"stRSR","type":"address"},{"internalType":"contract IAssetRegistry","name":"assetRegistry","type":"address"},{"internalType":"contract IBasketHandler","name":"basketHandler","type":"address"},{"internalType":"contract IBackingManager","name":"backingManager","type":"address"},{"internalType":"contract IDistributor","name":"distributor","type":"address"},{"internalType":"contract IFurnace","name":"furnace","type":"address"},{"internalType":"contract IBroker","name":"broker","type":"address"},{"internalType":"contract IRevenueTrader","name":"rsrTrader","type":"address"},{"internalType":"contract IRevenueTrader","name":"rTokenTrader","type":"address"}],"internalType":"struct Components","name":"components","type":"tuple"},{"components":[{"internalType":"contract ITrade","name":"gnosisTrade","type":"address"},{"internalType":"contract ITrade","name":"dutchTrade","type":"address"}],"internalType":"struct TradePlugins","name":"trading","type":"tuple"}],"internalType":"struct Implementations","name":"implementations_","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IRToken","name":"rToken","type":"address"},{"indexed":false,"internalType":"contract IAsset","name":"rTokenAsset","type":"address"}],"name":"RTokenAssetCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IMain","name":"main","type":"address"},{"indexed":true,"internalType":"contract IRToken","name":"rToken","type":"address"},{"indexed":false,"internalType":"contract IStRSR","name":"stRSR","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"string","name":"version","type":"string"}],"name":"RTokenCreated","type":"event"},{"inputs":[],"name":"ENS","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"mandate","type":"string"},{"internalType":"address","name":"owner","type":"address"},{"components":[{"components":[{"internalType":"uint16","name":"rTokenDist","type":"uint16"},{"internalType":"uint16","name":"rsrDist","type":"uint16"}],"internalType":"struct RevenueShare","name":"dist","type":"tuple"},{"internalType":"uint192","name":"minTradeVolume","type":"uint192"},{"internalType":"uint192","name":"rTokenMaxTradeVolume","type":"uint192"},{"internalType":"uint48","name":"shortFreeze","type":"uint48"},{"internalType":"uint48","name":"longFreeze","type":"uint48"},{"internalType":"uint192","name":"rewardRatio","type":"uint192"},{"internalType":"uint48","name":"unstakingDelay","type":"uint48"},{"internalType":"uint192","name":"withdrawalLeak","type":"uint192"},{"internalType":"uint48","name":"warmupPeriod","type":"uint48"},{"internalType":"uint48","name":"tradingDelay","type":"uint48"},{"internalType":"uint48","name":"batchAuctionLength","type":"uint48"},{"internalType":"uint48","name":"dutchAuctionLength","type":"uint48"},{"internalType":"uint192","name":"backingBuffer","type":"uint192"},{"internalType":"uint192","name":"maxTradeSlippage","type":"uint192"},{"components":[{"internalType":"uint256","name":"amtRate","type":"uint256"},{"internalType":"uint192","name":"pctRate","type":"uint192"}],"internalType":"struct ThrottleLib.Params","name":"issuanceThrottle","type":"tuple"},{"components":[{"internalType":"uint256","name":"amtRate","type":"uint256"},{"internalType":"uint192","name":"pctRate","type":"uint192"}],"internalType":"struct ThrottleLib.Params","name":"redemptionThrottle","type":"tuple"}],"internalType":"struct DeploymentParams","name":"params","type":"tuple"}],"name":"deploy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IRToken","name":"rToken","type":"address"},{"internalType":"uint192","name":"maxTradeVolume","type":"uint192"}],"name":"deployRTokenAsset","outputs":[{"internalType":"contract IAsset","name":"rTokenAsset","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"gnosis","outputs":[{"internalType":"contract IGnosis","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementations","outputs":[{"internalType":"contract IMain","name":"main","type":"address"},{"components":[{"internalType":"contract IRToken","name":"rToken","type":"address"},{"internalType":"contract IStRSR","name":"stRSR","type":"address"},{"internalType":"contract IAssetRegistry","name":"assetRegistry","type":"address"},{"internalType":"contract IBasketHandler","name":"basketHandler","type":"address"},{"internalType":"contract IBackingManager","name":"backingManager","type":"address"},{"internalType":"contract IDistributor","name":"distributor","type":"address"},{"internalType":"contract IFurnace","name":"furnace","type":"address"},{"internalType":"contract IBroker","name":"broker","type":"address"},{"internalType":"contract IRevenueTrader","name":"rsrTrader","type":"address"},{"internalType":"contract IRevenueTrader","name":"rTokenTrader","type":"address"}],"internalType":"struct Components","name":"components","type":"tuple"},{"components":[{"internalType":"contract ITrade","name":"gnosisTrade","type":"address"},{"internalType":"contract ITrade","name":"dutchTrade","type":"address"}],"internalType":"struct TradePlugins","name":"trading","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rsr","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rsrAsset","outputs":[{"internalType":"contract IAsset","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"}]Contract Creation Code
60e06040523480156200001157600080fd5b506040516200552138038062005521833981016040819052620000349162000459565b6001600160a01b038416158015906200005557506001600160a01b03831615155b80156200006a57506001600160a01b03821615155b801562000080575080516001600160a01b031615155b80156200009a57506040810151516001600160a01b031615155b8015620000b757506040810151602001516001600160a01b031615155b8015620000d457506020810151604001516001600160a01b031615155b8015620000f157506020810151608001516001600160a01b031615155b80156200010e57506020810151606001516001600160a01b031615155b80156200012b5750602081015160e001516001600160a01b031615155b8015620001485750602081015160a001516001600160a01b031615155b8015620001655750602081015160c001516001600160a01b031615155b8015620001835750602081015161010001516001600160a01b031615155b8015620001a15750602081015161012001516001600160a01b031615155b8015620001bb57506020810151516001600160a01b031615155b8015620001d7575060208082015101516001600160a01b031615155b6200021a5760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b604482015260640160405180910390fd5b6001600160a01b03938416608090815292841660a090815291841660c09081528151600080546001600160a01b03199081169288169290921790556020808401518051600180548516918a1691909117905580820151600280548516918a16919091179055604080820151600380548616918b169190911790556060820151600480548616918b1691909117905596810151600580548516918a16919091179055948501516006805484169189169190911790559184015160078054831691881691909117905560e084015160088054831691881691909117905561010084015160098054831691881691909117905561012090930151600a805485169187169190911790559201518051600b8054841691861691909117905590910151600c80549092169216919091179055620005e1565b6001600160a01b03811681146200036357600080fd5b50565b604051606081016001600160401b03811182821017156200039757634e487b7160e01b600052604160045260246000fd5b60405290565b60405161014081016001600160401b03811182821017156200039757634e487b7160e01b600052604160045260246000fd5b8051620003dc816200034d565b919050565b600060408284031215620003f457600080fd5b604080519081016001600160401b03811182821017156200042557634e487b7160e01b600052604160045260246000fd5b806040525080915082516200043a816200034d565b815260208301516200044c816200034d565b6020919091015292915050565b6000806000808486036102008112156200047257600080fd5b85516200047f816200034d565b602087015190955062000492816200034d565b6040870151909450620004a5816200034d565b92506101a0605f198201811315620004bc57600080fd5b620004c662000366565b6060880151620004d6816200034d565b8152610140607f198401811315620004ed57600080fd5b620004f76200039d565b93506200050760808a01620003cf565b84526200051760a08a01620003cf565b60208501526200052a60c08a01620003cf565b60408501526200053d60e08a01620003cf565b606085015261010062000552818b01620003cf565b608086015261012062000567818c01620003cf565b60a087015262000579838c01620003cf565b60c08701526200058d6101608c01620003cf565b60e0870152620005a16101808c01620003cf565b82870152620005b2858c01620003cf565b81870152505050826020820152620005cf896101c08a01620003e1565b60408201529598949750929550505050565b60805160a05160c051614ef46200062d6000396000818161020d0152610dd10152600081816101130152610ade01526000818161024c0152818161071201526108e90152614ef46000f3fe60806040523480156200001157600080fd5b5060043610620000925760003560e01c806354fd4d50116200006257806354fd4d5014620001e5578063929832ef1462000207578063c8784ab1146200022f578063c99dc3dd146200024657600080fd5b806204b64714620000975780631d2e2cc414620000cb578063238c8aad146200010d57806330e9012c1462000135575b600080fd5b620000ae620000a8366004620015a3565b6200026e565b6040516001600160a01b0390911681526020015b60405180910390f35b620000fe604051806040016040528060138152602001720e4cae6cae4eccae0e4dee8dec6ded85ccae8d606b1b81525081565b604051620000c29190620016e4565b620000ae7f000000000000000000000000000000000000000000000000000000000000000081565b60005460408051610140810182526001546001600160a01b03908116825260025481166020808401919091526003548216838501526004548216606084015260055482166080840152600654821660a0840152600754821660c0840152600854821660e08401526009548216610100840152600a5482166101208401528351808501909452600b5482168452600c54821690840152620001d493169183565b604051620000c293929190620017f7565b604080518082019091526005815264332e302e3160d81b6020820152620000fe565b620000ae7f000000000000000000000000000000000000000000000000000000000000000081565b620000ae6200024036600462001839565b6200103a565b620000ae7f000000000000000000000000000000000000000000000000000000000000000081565b60006001600160a01b038316158015906200029257506001600160a01b0383163014155b620002d35760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b21037bbb732b960991b604482015260640160405180910390fd5b6000805460408051838152602081019091526001600160a01b0390911690604051620002ff9062001243565b6200030c92919062001873565b604051809103906000f08015801562000329573d6000803e3d6000fd5b5060015460408051600080825260208201928390529394506001600160a01b039092169190620003599062001243565b6200036692919062001873565b604051809103906000f08015801562000383573d6000803e3d6000fd5b5060408051610140810182526001600160a01b0383811682526002548351600080825260208281019096529596509293840192911690604051620003c79062001243565b620003d492919062001873565b604051809103906000f080158015620003f1573d6000803e3d6000fd5b506001600160a01b0390811682526003546040805160008152602080820192839052909401939190921691620004279062001243565b6200043492919062001873565b604051809103906000f08015801562000451573d6000803e3d6000fd5b506001600160a01b0390811682526004546040805160008152602080820192839052909401939190921691620004879062001243565b6200049492919062001873565b604051809103906000f080158015620004b1573d6000803e3d6000fd5b506001600160a01b0390811682526005546040805160008152602080820192839052909401939190921691620004e79062001243565b620004f492919062001873565b604051809103906000f08015801562000511573d6000803e3d6000fd5b506001600160a01b0390811682526006546040805160008152602080820192839052909401939190921691620005479062001243565b6200055492919062001873565b604051809103906000f08015801562000571573d6000803e3d6000fd5b506001600160a01b0390811682526007546040805160008152602080820192839052909401939190921691620005a79062001243565b620005b492919062001873565b604051809103906000f080158015620005d1573d6000803e3d6000fd5b506001600160a01b0390811682526008546040805160008152602080820192839052909401939190921691620006079062001243565b6200061492919062001873565b604051809103906000f08015801562000631573d6000803e3d6000fd5b506001600160a01b0390811682526009546040805160008152602080820192839052909401939190921691620006679062001243565b6200067492919062001873565b604051809103906000f08015801562000691573d6000803e3d6000fd5b506001600160a01b039081168252600a546040805160008152602080820192839052909401939190921691620006c79062001243565b620006d492919062001873565b604051809103906000f080158015620006f1573d6000803e3d6000fd5b506001600160a01b03168152509050826001600160a01b031663992e1d6a827f0000000000000000000000000000000000000000000000000000000000000000886060015189608001516040518563ffffffff1660e01b81526004016200075c9493929190620018a1565b600060405180830381600087803b1580156200077757600080fd5b505af11580156200078c573d6000803e3d6000fd5b50505060808201516101208701516101808801516101a089015160208a015160405163bcaeb7b960e01b81526001600160a01b038a8116600483015265ffffffffffff90951660248201526001600160c01b03938416604482015291831660648301529190911660848201529116915063bcaeb7b99060a401600060405180830381600087803b1580156200082057600080fd5b505af115801562000835573d6000803e3d6000fd5b505050506060810151610100860151604051638a145ca360e01b81526001600160a01b03868116600483015265ffffffffffff9092166024820152911690638a145ca390604401600060405180830381600087803b1580156200089757600080fd5b505af1158015620008ac573d6000803e3d6000fd5b5050506101008201516101a087015160208801516040516322c9f15d60e21b81526001600160a01b039093169350638b27c57492620009129288927f000000000000000000000000000000000000000000000000000000000000000092600401620018e2565b600060405180830381600087803b1580156200092d57600080fd5b505af115801562000942573d6000803e3d6000fd5b5050506101208201516101a087015160208801516040516322c9f15d60e21b81526001600160a01b039093169350638b27c57492620009889288928892600401620018e2565b600060405180830381600087803b158015620009a357600080fd5b505af1158015620009b8573d6000803e3d6000fd5b5050505060a0810151855160405163133cdbb560e31b81526001600160a01b038681166004830152825161ffff908116602484015260209093015190921660448201529116906399e6dda890606401600060405180830381600087803b15801562000a2257600080fd5b505af115801562000a37573d6000803e3d6000fd5b50505060c082015160a0870151604051630f3058d560e31b81526001600160a01b039092169250637982c6a89162000a7491879160040162001916565b600060405180830381600087803b15801562000a8f57600080fd5b505af115801562000aa4573d6000803e3d6000fd5b5050505060e0810151600b54610140870151600c54610160890151604051631471f8e360e01b81526001600160a01b0389811660048301527f000000000000000000000000000000000000000000000000000000000000000081166024830152948516604482015265ffffffffffff938416606482015291841660848301529190911660a4820152911690631471f8e39060c401600060405180830381600087803b15801562000b5357600080fd5b505af115801562000b68573d6000803e3d6000fd5b50505050600062000b798a620010c1565b60405160200162000b8b919062001938565b604051602081830303815290604052905060008160405160200162000bb1919062001961565b6040516020818303038152906040529050846001600160a01b0316634780a5e56040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000c01573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c2791906200198d565b6001600160a01b031663c6b5bba68683858b60c001518c60a001518d60e001516040518763ffffffff1660e01b815260040162000c6a96959493929190620019ad565b600060405180830381600087803b15801562000c8557600080fd5b505af115801562000c9a573d6000803e3d6000fd5b50505050505080600001516001600160a01b031663f17d835c848c8c8c8c8b6101c001518c6101e001516040518863ffffffff1660e01b815260040162000ce8979695949392919062001a18565b600060405180830381600087803b15801562000d0357600080fd5b505af115801562000d18573d6000803e3d6000fd5b50600092506002915062000d299050565b60405190808252806020026020018201604052801562000d53578160200160208202803683370190505b5090508160000151866040015160405162000d6e9062001251565b62000d7b92919062001916565b604051809103906000f08015801562000d98573d6000803e3d6000fd5b508160008151811062000daf5762000daf62001ac9565b60200260200101906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000000000000000000000000000000000000000000008160018151811062000e065762000e0662001ac9565b6001600160a01b0392831660209182029290920101526040808401519051631e2d1e7560e11b8152911690633c5a3cea9062000e49908790859060040162001adf565b600060405180830381600087803b15801562000e6457600080fd5b505af115801562000e79573d6000803e3d6000fd5b50505050836001600160a01b0316632f2ff15d6040518060400160405280600581526020016427aba722a960d91b81525062000eb59062001b3d565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b038a166024820152604401600060405180830381600087803b15801562000efe57600080fd5b505af115801562000f13573d6000803e3d6000fd5b50505050836001600160a01b03166336568abe6040518060400160405280600581526020016427aba722a960d91b81525062000f4f9062001b3d565b6040516001600160e01b031960e084901b1681526004810191909152306024820152604401600060405180830381600087803b15801562000f8f57600080fd5b505af115801562000fa4573d6000803e3d6000fd5b50505050866001600160a01b031682600001516001600160a01b0316856001600160a01b03167f27a62b7d4a7ee7a705ae91fe5a3ad74f32fc3d14e82eb82c3730630601ce9ae6856020015162001013604080518082019091526005815264332e302e3160d81b602082015290565b6040516200102392919062001873565b60405180910390a450519998505050505050505050565b600082826040516200104c9062001251565b6200105992919062001916565b604051809103906000f08015801562001076573d6000803e3d6000fd5b506040516001600160a01b038083168252919250908416907fe408b90fcc4886a187a319dfb76714920da19f65ba0ce1c597d371c983f4c8e69060200160405180910390a292915050565b606060008290506000815167ffffffffffffffff811115620010e757620010e76200125f565b6040519080825280601f01601f19166020018201604052801562001112576020820181803683370190505b50905060005b82518110156200123b57604183828151811062001139576200113962001ac9565b016020015160f81c108015906200116d5750605a83828151811062001162576200116262001ac9565b016020015160f81c11155b15620011d95782818151811062001188576200118862001ac9565b602001015160f81c60f81b60f81c6020620011a4919062001b7b565b60f81b828281518110620011bc57620011bc62001ac9565b60200101906001600160f81b031916908160001a90535062001226565b828181518110620011ee57620011ee62001ac9565b602001015160f81c60f81b8282815181106200120e576200120e62001ac9565b60200101906001600160f81b031916908160001a9053505b80620012328162001b9d565b91505062001118565b509392505050565b6104d48062001bba83390190565b612e31806200208e83390190565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156200129b576200129b6200125f565b60405290565b604051610200810167ffffffffffffffff811182821017156200129b576200129b6200125f565b600082601f830112620012da57600080fd5b813567ffffffffffffffff80821115620012f857620012f86200125f565b604051601f8301601f19908116603f011681019082821181831017156200132357620013236200125f565b816040528381528660208588010111156200133d57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6001600160a01b03811681146200137357600080fd5b50565b803562001383816200135d565b919050565b803561ffff811681146200138357600080fd5b600060408284031215620013ae57600080fd5b620013b862001275565b9050620013c58262001388565b8152620013d56020830162001388565b602082015292915050565b80356001600160c01b03811681146200138357600080fd5b803565ffffffffffff811681146200138357600080fd5b6000604082840312156200142257600080fd5b6200142c62001275565b905081358152620013d560208301620013e0565b600061026082840312156200145457600080fd5b6200145e620012a1565b90506200146c83836200139b565b81526200147c60408301620013e0565b60208201526200148f60608301620013e0565b6040820152620014a260808301620013f8565b6060820152620014b560a08301620013f8565b6080820152620014c860c08301620013e0565b60a0820152620014db60e08301620013f8565b60c0820152610100620014f0818401620013e0565b60e083015261012062001505818501620013f8565b8284015261014091506200151b828501620013f8565b908301526101606200152f848201620013f8565b82840152610180915062001545828501620013f8565b908301526101a062001559848201620013e0565b828401526101c091506200156f828501620013e0565b908301526101e062001584858583016200140f565b82840152620015988561022086016200140f565b908301525092915050565b6000806000806000806102e08789031215620015be57600080fd5b863567ffffffffffffffff80821115620015d757600080fd5b620015e58a838b01620012c8565b97506020890135915080821115620015fc57600080fd5b6200160a8a838b01620012c8565b965060408901359150808211156200162157600080fd5b818901915089601f8301126200163657600080fd5b8135818111156200164657600080fd5b8a60208285010111156200165957600080fd5b602083019650809550505050620016736060880162001376565b915062001684886080890162001440565b90509295509295509295565b60005b83811015620016ad57818101518382015260200162001693565b50506000910152565b60008151808452620016d081602086016020860162001690565b601f01601f19169290920160200192915050565b602081526000620016f96020830184620016b6565b9392505050565b80516001600160a01b0316825260208101516200172860208401826001600160a01b03169052565b5060408101516200174460408401826001600160a01b03169052565b5060608101516200176060608401826001600160a01b03169052565b5060808101516200177c60808401826001600160a01b03169052565b5060a08101516200179860a08401826001600160a01b03169052565b5060c0810151620017b460c08401826001600160a01b03169052565b5060e0810151620017d060e08401826001600160a01b03169052565b50610100818101516001600160a01b03908116918401919091526101209182015116910152565b6001600160a01b0384811682526101a082019062001819602084018662001700565b808451166101608401528060208501511661018084015250949350505050565b600080604083850312156200184d57600080fd5b82356200185a816200135d565b91506200186a60208401620013e0565b90509250929050565b6001600160a01b03831681526040602082018190526000906200189990830184620016b6565b949350505050565b6101a08101620018b2828762001700565b6001600160a01b039490941661014082015265ffffffffffff928316610160820152911661018090910152919050565b6001600160a01b0394851681529290931660208301526001600160c01b039081166040830152909116606082015260800190565b6001600160a01b039290921682526001600160c01b0316602082015260400190565b600082516200194c81846020870162001690565b622929a960e91b920191825250600301919050565b600082516200197581846020870162001690565b65102a37b5b2b760d11b920191825250600601919050565b600060208284031215620019a057600080fd5b8151620016f9816200135d565b6001600160a01b038716815260c060208201819052600090620019d390830188620016b6565b8281036040840152620019e78188620016b6565b65ffffffffffff96909616606084015250506001600160c01b039283166080820152911660a0909101529392505050565b6001600160a01b03881681526101006020820181905260009062001a3f8382018a620016b6565b9050828103604084015262001a558189620016b6565b90508281036060840152858152858760208301376000602087830101526020601f19601f88011682010191505062001aa36080830185805182526020908101516001600160c01b0316910152565b825160c083015260208301516001600160c01b031660e083015298975050505050505050565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b038381168252604060208084018290528451918401829052600092858201929091906060860190855b8181101562001b2f57855185168352948301949183019160010162001b0f565b509098975050505050505050565b8051602080830151919081101562001b5f576000198160200360031b1b821691505b50919050565b634e487b7160e01b600052601160045260246000fd5b60ff818116838216019081111562001b975762001b9762001b65565b92915050565b60006001820162001bb25762001bb262001b65565b506001019056fe60806040526040516104d43803806104d4833981016040819052610022916102d1565b61002e82826000610035565b50506103ee565b61003e83610061565b60008251118061004b5750805b1561005c5761005a83836100a1565b505b505050565b61006a816100cd565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606100c683836040518060600160405280602781526020016104ad60279139610180565b9392505050565b6001600160a01b0381163b61013f5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60606001600160a01b0384163b6101e85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610136565b600080856001600160a01b031685604051610203919061039f565b600060405180830381855af49150503d806000811461023e576040519150601f19603f3d011682016040523d82523d6000602084013e610243565b606091505b50909250905061025482828661025e565b9695505050505050565b6060831561026d5750816100c6565b82511561027d5782518084602001fd5b8160405162461bcd60e51b815260040161013691906103bb565b634e487b7160e01b600052604160045260246000fd5b60005b838110156102c85781810151838201526020016102b0565b50506000910152565b600080604083850312156102e457600080fd5b82516001600160a01b03811681146102fb57600080fd5b60208401519092506001600160401b038082111561031857600080fd5b818501915085601f83011261032c57600080fd5b81518181111561033e5761033e610297565b604051601f8201601f19908116603f0116810190838211818310171561036657610366610297565b8160405282815288602084870101111561037f57600080fd5b6103908360208301602088016102ad565b80955050505050509250929050565b600082516103b18184602087016102ad565b9190910192915050565b60208152600082518060208401526103da8160408501602087016102ad565b601f01601f19169190910160400192915050565b60b1806103fc6000396000f3fe608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea2646970667358221220d696190f1462e196c18783d2bcdbe9f7498512203fe6ebde6d2044021dbc255d64736f6c63430008130033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65646101606040523480156200001257600080fd5b5060405162002e3138038062002e3183398101604081905262000035916200035d565b6001600160a01b038216620000815760405162461bcd60e51b815260206004820152600d60248201526c06d697373696e6720657263323609c1b60448201526064015b60405180910390fd5b6000816001600160c01b031611620000dc5760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206d617820747261646520766f6c756d650000000000000000604482015260640162000078565b816001600160a01b031663dffeadd06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200011b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001419190620003a7565b6001600160a01b0316608081905260408051632f2439b160e01b81529051632f2439b1916004808201926020929091908290030181865afa1580156200018b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b19190620003a7565b6001600160a01b031660a0816001600160a01b0316815250506080516001600160a01b031663979d7e866040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200020b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002319190620003a7565b6001600160a01b031660c0816001600160a01b0316815250506080516001600160a01b031663dc8af5f66040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200028b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002b19190620003a7565b6001600160a01b0390811660e05282166101008190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa15801562000303573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003299190620003ce565b60ff16610120526001600160c01b03166101405250620003f3565b6001600160a01b03811681146200035a57600080fd5b50565b600080604083850312156200037157600080fd5b82516200037e8162000344565b60208401519092506001600160c01b03811681146200039c57600080fd5b809150509250929050565b600060208284031215620003ba57600080fd5b8151620003c78162000344565b9392505050565b600060208284031215620003e157600080fd5b815160ff81168114620003c757600080fd5b60805160a05160c05160e051610100516101205161014051612950620004e1600039600061025e015260006101ac01526000818161023701528181610558015281816107440152610b4c0152600081816102ea015281816109040152818161099201528181610aaf01528181610c5601528181610eaf01528181610f570152818161132501526113b40152600081816102940152610ca901526000818161016b015281816103c2015281816104480152818161086a01528181610ada01528181610c82015261129601526000818161031101528181610ce301528181610d710152610e1001526129506000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c806396f80ae9116100ad578063dc8af5f611610071578063dc8af5f6146102e5578063dffeadd01461030c578063efd3614c14610333578063f0f615f8146103a3578063f8ac93e8146103ab57600080fd5b806396f80ae914610280578063979d7e861461028f578063a035b1fe146102b6578063a3e6ba94146102be578063c59b3d631461028057600080fd5b80633cb5d379116100f45780633cb5d379146101a757806354fd4d50146101e05780635580f72a14610207578063785e9e861461023257806395acc4ae1461025957600080fd5b80632428adc014610126578063271181ec1461015e5780632f2439b114610166578063372500ab146101a5575b600080fd5b610139610134366004612291565b6103b5565b604080516001600160c01b039384168152929091166020830152015b60405180910390f35b61013961066b565b61018d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610155565b005b6101ce7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff9091168152602001610155565b6040805180820182526005815264332e302e3160d81b6020820152905161015591906122b3565b61021a610215366004612319565b61071e565b6040516001600160c01b039091168152602001610155565b61018d7f000000000000000000000000000000000000000000000000000000000000000081565b61021a7f000000000000000000000000000000000000000000000000000000000000000081565b60405160008152602001610155565b61018d7f000000000000000000000000000000000000000000000000000000000000000081565b610139610791565b6102c6610849565b604080516001600160c01b039093168352602083019190915201610155565b61018d7f000000000000000000000000000000000000000000000000000000000000000081565b61018d7f000000000000000000000000000000000000000000000000000000000000000081565b600054600154600254600354610366936001600160c01b0316929165ffffffffffff80821692600160301b909204169085565b604080516001600160c01b039096168652602086019490945265ffffffffffff92831693850193909352166060830152608082015260a001610155565b6101a5610a4e565b6101a56000600155565b60008060008084610446577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a035b1fe6040518163ffffffff1660e01b81526004016040805180830381865afa15801561041d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104419190612352565b6104c7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663271181ec6040518163ffffffff1660e01b81526004016040805180830381865afa1580156104a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c79190612352565b91509150816001600160c01b03166000141580156104ee57506001600160c01b0381811614155b61052f5760405162461bcd60e51b815260206004820152600d60248201526c696e76616c696420707269636560981b60448201526064015b60405180910390fd5b806001600160c01b0316826001600160c01b0316111561055157610551612385565b60006105dd7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d8919061239b565b610a56565b9050806001600160c01b03166000036105fb57509094909350915050565b6000610605610a84565b8051909150610620906001600160c01b0316858460006111b8565b602082015190965061063e906001600160c01b0316848460026111b8565b9450846001600160c01b0316866001600160c01b0316111561066257610662612385565b50505050915091565b6040516290a2b760e61b81526001600482015260009081903090632428adc0906024016040805180830381865afa9250505080156106c6575060408051601f3d908101601f191682019092526106c391810190612352565b60015b610713573d8080156106f4576040519150601f19603f3d011682016040523d82523d6000602084013e6106f9565b606091505b50805160000361070857600080fd5b506000928392509050565b90925090509091565b565b6040516370a0823160e01b81526001600160a01b03828116600483015260009161078b917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156105b4573d6000803e3d6000fd5b92915050565b6040516290a2b760e61b81526000600482018190529081903090632428adc0906024016040805180830381865afa9250505080156107ec575060408051601f3d908101601f191682019092526107e991810190612352565b60015b610840573d80801561081a576040519150601f19603f3d011682016040523d82523d6000602084013e61081f565b606091505b50805160000361082e57600080fd5b506000926001600160c01b0392509050565b90939092509050565b6000804261038460006001015461086091906123ca565b1115806108fc57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663affed0e06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ea91906123dd565b60025465ffffffffffff908116911614155b8061098a57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638767e6386040518163ffffffff1660e01b8152600401602060405180830381865afa158015610960573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610984919061239b565b60035414155b80610a2b57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c76aeb126040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1291906123dd565b600254600160301b900465ffffffffffff908116911614155b15610a3857610a386111ef565b50506000546001546001600160c01b0390911691565b61071c6111ef565b60006001600160c01b03821115610a805760405163f44398f560e01b815260040160405180910390fd5b5090565b6040805180820190915260008082526020820152604051635523caaf60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063aa47955e906024016040805180830381865afa158015610b22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b469190612475565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637121c2736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ba8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bcc91906124b2565b9050806001600160c01b031682600001516001600160c01b031610610c00576001600160c01b031680835260208301525090565b60408051610180810182526000610140820181905261016082018190526080820181905260a0820181905260c0820181905260e08201819052610100820152606061012082018190528482526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166020808501919091527f00000000000000000000000000000000000000000000000000000000000000008216848601527f00000000000000000000000000000000000000000000000000000000000000008216928401929092528351634780a5e560e01b8152935192937f000000000000000000000000000000000000000000000000000000000000000090911692634780a5e5926004808401939192918290030181865afa158015610d2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5291906124cd565b81608001906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c99dc3dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df191906124cd565b8160a001906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166340c65f726040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9091906124cd565b8160c001906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637cbf6db26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2f91906124b2565b6001600160c01b031660e08201526040805163036cf50b60e21b815290516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691630db3d42c9160048083019260209291908290030181865afa158015610fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc691906124b2565b6001600160c01b0316610100820152606081015160408051635ab1bd5360e01b815290516000926001600160a01b031691635ab1bd5391600480830192869291908290030181865afa158015611020573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526110489190810190612582565b80515190915067ffffffffffffffff81111561106657611066612405565b60405190808252806020026020018201604052801561108f578160200160208202803683370190505b5061012083015260005b8151518110156111a45782604001516001600160a01b031663d3252db5836000015183815181106110cc576110cc612670565b6020026020010151846020015184815181106110ea576110ea612670565b60200260200101516040518363ffffffff1660e01b81526004016111249291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa158015611141573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116591906124b2565b836101200151828151811061117c5761117c612670565b6001600160c01b039092166020928302919091019091015261119d81612686565b9050611099565b506111af82826114a7565b94505050505090565b60006111e46105d8866001600160c01b0316866001600160c01b0316866001600160c01b031686611ba8565b90505b949350505050565b6000806111fa610791565b91509150816001600160c01b031660001415801561122157506001600160c01b0381811614155b61125d5760405162461bcd60e51b815260206004820152600d60248201526c696e76616c696420707269636560981b6044820152606401610526565b6040518060a0016040528060028385611276919061269f565b61128091906126dc565b6001600160c01b031681526020014281526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663affed0e06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112f2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061131691906123dd565b65ffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c76aeb126040518163ffffffff1660e01b8152600401602060405180830381865afa158015611381573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113a591906123dd565b65ffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638767e6386040518163ffffffff1660e01b8152600401602060405180830381865afa158015611410573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611434919061239b565b90528051600080546001600160c01b039092166001600160c01b03199092169190911790556020810151600155604081015160028054606084015165ffffffffffff908116600160301b026bffffffffffffffffffffffff19909216931692909217919091179055608001516003555050565b604080518082019091526000808252602082015260008084604001516001600160a01b031663271181ec6040518163ffffffff1660e01b81526004016040805180830381865afa1580156114ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115239190612352565b9150915060008560c001516001600160a01b0316637121c2736040518163ffffffff1660e01b8152600401602060405180830381865afa15801561156b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158f91906124b2565b9050806001600160c01b03168660000151602001516001600160c01b031611156115c65785516001600160c01b0382166020909101525b60008060005b875151811015611a6c578860c001516001600160a01b0316886000015182815181106115fa576115fa612670565b60200260200101516001600160a01b03160315611a5c5760008860200151828151811061162957611629612670565b602090810291909101810151908b0151604051632ac07b9560e11b81526001600160a01b039182166004820152911690635580f72a90602401602060405180830381865afa15801561167f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a391906124b2565b90508960a001516001600160a01b0316896000015183815181106116c9576116c9612670565b60200260200101516001600160a01b03160361178557611782896020015183815181106116f8576116f8612670565b602090810291909101015160808c0151604051632ac07b9560e11b81526001600160a01b039182166004820152911690635580f72a90602401602060405180830381865afa15801561174e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177291906124b2565b6001600160c01b03831690611c55565b90505b896101200151828151811061179c5761179c612670565b60200260200101516001600160c01b0316600003611871576000896020015183815181106117cc576117cc612670565b60200260200101516001600160a01b031663271181ec6040518163ffffffff1660e01b81526004016040805180830381865afa158015611810573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118349190612352565b5090506118648a60200151848151811061185057611850612670565b602002602001015183838e60e00151611c68565b61186f575050611a5c565b505b6000808a60200151848151811061188a5761188a612670565b60200260200101516001600160a01b031663a035b1fe6040518163ffffffff1660e01b81526004016040805180830381865afa1580156118ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f29190612352565b91509150600061193d8d600001516020015160028f6101200151888151811061191d5761191d612670565b60200260200101516001600160c01b0316611d129092919063ffffffff16565b9050836001600160c01b0316816001600160c01b03161115611993576119796119668583612702565b6001600160c01b038516908b60006111b8565b61198c906001600160c01b031688612722565b96506119c9565b6119b36119a08286612702565b6001600160c01b038416908c6002611d3f565b6119c6906001600160c01b031688612742565b96505b5060006119f18d600001516000015160008f6101200151888151811061191d5761191d612670565b90506000611a14611a028387612702565b6001600160c01b038616906000611d12565b90508d60e001516001600160c01b0316816001600160c01b031610611a475760e08e0151611a429082612702565b611a4a565b60005b611a54908861269f565b965050505050505b611a6581612686565b90506115cc565b506000821215611aa557611a826105d88361276a565b885160200151611a929190612702565b6001600160c01b03166020870152611b00565b8751602001516001600160c01b0390611ac0908216846123ca565b1115611ad8576001600160c01b036020870152611b00565b611ae182610a56565b885160200151611af1919061269f565b6001600160c01b031660208701525b610100880151611b3090611b1d90670de0b6b3a764000090611f44565b6001600160c01b038316908660006111b8565b885151611b3d919061269f565b6001600160c01b039081168752602087015184821691161115611b6a576001600160c01b03831660208701525b85602001516001600160c01b031686600001516001600160c01b03161115611b9d5760208601516001600160c01b031686525b505050505092915050565b600080611bb6868686611f50565b90506000836002811115611bcc57611bcc612786565b03611bd85790506111e7565b60008480611be857611be86126c6565b86880990506002846002811115611c0157611c01612786565b03611c1f578015611c1a57611c176001836123ca565b91505b611c4b565b6002611c2c60018761279c565b611c3691906127af565b811115611c4b57611c486001836123ca565b91505b5095945050505050565b6000611c61828461269f565b9392505050565b6000611c8a611c778385612033565b6001600160c01b03908116908616101590565b80156111e457506001611d08866001600160a01b0316633cb5d3796040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cd4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf891906127c3565b6001600160c01b03871690612082565b1195945050505050565b60006111e76105d8611d306001600160c01b038087169088166127e6565b670de0b6b3a764000085612090565b60006001600160c01b0385161580611d5e57506001600160c01b038416155b15611d6b575060006111e7565b6001600160c01b038581161480611d8a57506001600160c01b03848116145b80611d9c57506001600160c01b038316155b15611daf57506001600160c01b036111e7565b6000806000611dd0886001600160c01b0316886001600160c01b0316612138565b91509150856001600160c01b03168210611df6576001600160c01b0393505050506111e7565b6000866001600160c01b031680611e0f57611e0f6126c6565b886001600160c01b03168a6001600160c01b031609905081811115611e35576001830392505b90819003906001600160c01b03600088900388168116908816818181611e5d57611e5d6126c6565b049050818481611e6f57611e6f6126c6565b049350818260000381611e8457611e846126c6565b046001018502939093016002848103808602820302808602820302808602820302808602820302808602820302808602820302808602820302828102975091949190896002811115611ed857611ed8612786565b03611eef578315611eea576001870196505b611f1e565b6001896002811115611f0357611f03612786565b03611f1e576002600019830104841115611f1e576001870196505b5050505050506001600160c01b03801681106111e4576001600160c01b039150506111e7565b6000611c618284612702565b6000806000611f5f8686612138565b91509150838210611f835760405163f44398f560e01b815260040160405180910390fd5b60008480611f9357611f936126c6565b868809905081811115611fa7576001830392505b908190039060008590038516808681611fc257611fc26126c6565b049550808381611fd457611fd46126c6565b049250808160000381611fe957611fe96126c6565b046001019390930291909101600285810380870282030280870282030280870282030280870282030280870282030280870282030295860290039094029390930295945050505050565b6000806001600160c01b0383161561205f5761205a6001600160c01b038516846002612165565b612068565b6001600160c01b035b90506000816001600160c01b031611611c615760016111e7565b6000611c6183836000612198565b60008061209d84866127af565b905060008360028111156120b3576120b3612786565b036120bf579050611c61565b60018360028111156120d3576120d3612786565b036121125760026120e560018661279c565b6120ef91906127af565b6120f985876127fd565b111561210d578061210981612686565b9150505b6111e7565b600061211e85876127fd565b11156111e7578061212e81612686565b9695505050505050565b600080806000198486099050838502915081810392508181101561215d576001830392505b509250929050565b60006111e76105d8612188670de0b6b3a76400006001600160c01b0388166127e6565b856001600160c01b031685612090565b6000836001600160c01b03166000036121b357506000611c61565b6029198360000b136121ec5760028260028111156121d3576121d3612786565b146121df5760006121e2565b60015b60ff169050611c61565b8260000b6060136122105760405163f44398f560e01b815260040160405180910390fd5b61221b601284612811565b9250600061222b8460000b612279565b61223690600a61290e565b905060008460000b121561225d57612258856001600160c01b03168285612090565b612270565b612270816001600160c01b0387166127e6565b95945050505050565b6000808212612288578161078b565b61078b8261276a565b6000602082840312156122a357600080fd5b81358015158114611c6157600080fd5b600060208083528351808285015260005b818110156122e0578581018301518582016040015282016122c4565b506000604082860101526040601f19601f8301168501019250505092915050565b6001600160a01b038116811461231657600080fd5b50565b60006020828403121561232b57600080fd5b8135611c6181612301565b80516001600160c01b038116811461234d57600080fd5b919050565b6000806040838503121561236557600080fd5b61236e83612336565b915061237c60208401612336565b90509250929050565b634e487b7160e01b600052600160045260246000fd5b6000602082840312156123ad57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561078b5761078b6123b4565b6000602082840312156123ef57600080fd5b815165ffffffffffff81168114611c6157600080fd5b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561243e5761243e612405565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561246d5761246d612405565b604052919050565b60006040828403121561248757600080fd5b61248f61241b565b61249883612336565b81526124a660208401612336565b60208201529392505050565b6000602082840312156124c457600080fd5b611c6182612336565b6000602082840312156124df57600080fd5b8151611c6181612301565b600067ffffffffffffffff82111561250457612504612405565b5060051b60200190565b600082601f83011261251f57600080fd5b8151602061253461252f836124ea565b612444565b82815260059290921b8401810191818101908684111561255357600080fd5b8286015b8481101561257757805161256a81612301565b8352918301918301612557565b509695505050505050565b6000602080838503121561259557600080fd5b825167ffffffffffffffff808211156125ad57600080fd5b90840190604082870312156125c157600080fd5b6125c961241b565b8251828111156125d857600080fd5b8301601f810188136125e957600080fd5b80516125f761252f826124ea565b81815260059190911b8201860190868101908a83111561261657600080fd5b928701925b8284101561263d57835161262e81612301565b8252928701929087019061261b565b8452505050828401518281111561265357600080fd5b61265f8882860161250e565b948201949094529695505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201612698576126986123b4565b5060010190565b6001600160c01b038181168382160190808211156126bf576126bf6123b4565b5092915050565b634e487b7160e01b600052601260045260246000fd5b60006001600160c01b03838116806126f6576126f66126c6565b92169190910492915050565b6001600160c01b038281168282160390808211156126bf576126bf6123b4565b81810360008312801583831316838312821617156126bf576126bf6123b4565b8082018281126000831280158216821582161715612762576127626123b4565b505092915050565b6000600160ff1b820161277f5761277f6123b4565b5060000390565b634e487b7160e01b600052602160045260246000fd5b8181038181111561078b5761078b6123b4565b6000826127be576127be6126c6565b500490565b6000602082840312156127d557600080fd5b815160ff81168114611c6157600080fd5b808202811582820484141761078b5761078b6123b4565b60008261280c5761280c6126c6565b500690565b600082810b9082900b03607f198112607f8213171561078b5761078b6123b4565b600181815b8085111561215d578160001904821115612853576128536123b4565b8085161561286057918102915b93841c9390800290612837565b60008261287c5750600161078b565b816128895750600061078b565b816001811461289f57600281146128a9576128c5565b600191505061078b565b60ff8411156128ba576128ba6123b4565b50506001821b61078b565b5060208310610133831016604e8410600b84101617156128e8575081810a61078b565b6128f28383612832565b8060001904821115612906576129066123b4565b029392505050565b6000611c61838361286d56fea26469706673582212208418e8ccb96aa03f3752c57af4f4ecfef50b99efce14a3d52849c2a2f10a0acb64736f6c63430008130033a26469706673582212206e3e2fbe8b8f51fe4b833b1c730ed1837ef5a9c4f1545f1abcebabbbc1cc2ebb64736f6c63430008130033000000000000000000000000320623b8e4ff03373931769a31fc52a4e78b5d700000000000000000000000000b7ffc1f4ad541a4ed16b40d8c37f0929158d1010000000000000000000000007edd40933dfda0ecee1ad3e61a5044962284e1a6000000000000000000000000f5366f67ff66a3cefcb18809a762d5b5931febf8000000000000000000000000b6f01aa21defa4a4de33bed16bcc06cfd23b6a6f000000000000000000000000c98eafc9f249d90e3e35e729e3679dd75a899c10000000000000000000000000773cf50adcf1730964d4a9b664baed4b9ffc24500000000000000000000000005ccca36cbb66a4e4033b08b4f6d7bac96ba55cdc000000000000000000000000bbc532a80dd141449330c1232c953da6801aed010000000000000000000000000e8439a17ba5cbb2d9823c03a02566b9dd5d96ac00000000000000000000000099580fc649c02347ebc7750524caae5cacf9d34c0000000000000000000000009a5f8a9bb91a868b7501139eedb20dc129d28f040000000000000000000000005e3e13d3d2a0adfe16f8ef5e7a2992a88e9e65af0000000000000000000000005e3e13d3d2a0adfe16f8ef5e7a2992a88e9e65af0000000000000000000000004e9b97957a0d1f4c25e42ccc69e4d2665433fea30000000000000000000000002387c22727acb91519b80a15aef393ad40dfdb2f
Deployed Bytecode
0x60806040523480156200001157600080fd5b5060043610620000925760003560e01c806354fd4d50116200006257806354fd4d5014620001e5578063929832ef1462000207578063c8784ab1146200022f578063c99dc3dd146200024657600080fd5b806204b64714620000975780631d2e2cc414620000cb578063238c8aad146200010d57806330e9012c1462000135575b600080fd5b620000ae620000a8366004620015a3565b6200026e565b6040516001600160a01b0390911681526020015b60405180910390f35b620000fe604051806040016040528060138152602001720e4cae6cae4eccae0e4dee8dec6ded85ccae8d606b1b81525081565b604051620000c29190620016e4565b620000ae7f0000000000000000000000000b7ffc1f4ad541a4ed16b40d8c37f0929158d10181565b60005460408051610140810182526001546001600160a01b03908116825260025481166020808401919091526003548216838501526004548216606084015260055482166080840152600654821660a0840152600754821660c0840152600854821660e08401526009548216610100840152600a5482166101208401528351808501909452600b5482168452600c54821690840152620001d493169183565b604051620000c293929190620017f7565b604080518082019091526005815264332e302e3160d81b6020820152620000fe565b620000ae7f0000000000000000000000007edd40933dfda0ecee1ad3e61a5044962284e1a681565b620000ae6200024036600462001839565b6200103a565b620000ae7f000000000000000000000000320623b8e4ff03373931769a31fc52a4e78b5d7081565b60006001600160a01b038316158015906200029257506001600160a01b0383163014155b620002d35760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b21037bbb732b960991b604482015260640160405180910390fd5b6000805460408051838152602081019091526001600160a01b0390911690604051620002ff9062001243565b6200030c92919062001873565b604051809103906000f08015801562000329573d6000803e3d6000fd5b5060015460408051600080825260208201928390529394506001600160a01b039092169190620003599062001243565b6200036692919062001873565b604051809103906000f08015801562000383573d6000803e3d6000fd5b5060408051610140810182526001600160a01b0383811682526002548351600080825260208281019096529596509293840192911690604051620003c79062001243565b620003d492919062001873565b604051809103906000f080158015620003f1573d6000803e3d6000fd5b506001600160a01b0390811682526003546040805160008152602080820192839052909401939190921691620004279062001243565b6200043492919062001873565b604051809103906000f08015801562000451573d6000803e3d6000fd5b506001600160a01b0390811682526004546040805160008152602080820192839052909401939190921691620004879062001243565b6200049492919062001873565b604051809103906000f080158015620004b1573d6000803e3d6000fd5b506001600160a01b0390811682526005546040805160008152602080820192839052909401939190921691620004e79062001243565b620004f492919062001873565b604051809103906000f08015801562000511573d6000803e3d6000fd5b506001600160a01b0390811682526006546040805160008152602080820192839052909401939190921691620005479062001243565b6200055492919062001873565b604051809103906000f08015801562000571573d6000803e3d6000fd5b506001600160a01b0390811682526007546040805160008152602080820192839052909401939190921691620005a79062001243565b620005b492919062001873565b604051809103906000f080158015620005d1573d6000803e3d6000fd5b506001600160a01b0390811682526008546040805160008152602080820192839052909401939190921691620006079062001243565b6200061492919062001873565b604051809103906000f08015801562000631573d6000803e3d6000fd5b506001600160a01b0390811682526009546040805160008152602080820192839052909401939190921691620006679062001243565b6200067492919062001873565b604051809103906000f08015801562000691573d6000803e3d6000fd5b506001600160a01b039081168252600a546040805160008152602080820192839052909401939190921691620006c79062001243565b620006d492919062001873565b604051809103906000f080158015620006f1573d6000803e3d6000fd5b506001600160a01b03168152509050826001600160a01b031663992e1d6a827f000000000000000000000000320623b8e4ff03373931769a31fc52a4e78b5d70886060015189608001516040518563ffffffff1660e01b81526004016200075c9493929190620018a1565b600060405180830381600087803b1580156200077757600080fd5b505af11580156200078c573d6000803e3d6000fd5b50505060808201516101208701516101808801516101a089015160208a015160405163bcaeb7b960e01b81526001600160a01b038a8116600483015265ffffffffffff90951660248201526001600160c01b03938416604482015291831660648301529190911660848201529116915063bcaeb7b99060a401600060405180830381600087803b1580156200082057600080fd5b505af115801562000835573d6000803e3d6000fd5b505050506060810151610100860151604051638a145ca360e01b81526001600160a01b03868116600483015265ffffffffffff9092166024820152911690638a145ca390604401600060405180830381600087803b1580156200089757600080fd5b505af1158015620008ac573d6000803e3d6000fd5b5050506101008201516101a087015160208801516040516322c9f15d60e21b81526001600160a01b039093169350638b27c57492620009129288927f000000000000000000000000320623b8e4ff03373931769a31fc52a4e78b5d7092600401620018e2565b600060405180830381600087803b1580156200092d57600080fd5b505af115801562000942573d6000803e3d6000fd5b5050506101208201516101a087015160208801516040516322c9f15d60e21b81526001600160a01b039093169350638b27c57492620009889288928892600401620018e2565b600060405180830381600087803b158015620009a357600080fd5b505af1158015620009b8573d6000803e3d6000fd5b5050505060a0810151855160405163133cdbb560e31b81526001600160a01b038681166004830152825161ffff908116602484015260209093015190921660448201529116906399e6dda890606401600060405180830381600087803b15801562000a2257600080fd5b505af115801562000a37573d6000803e3d6000fd5b50505060c082015160a0870151604051630f3058d560e31b81526001600160a01b039092169250637982c6a89162000a7491879160040162001916565b600060405180830381600087803b15801562000a8f57600080fd5b505af115801562000aa4573d6000803e3d6000fd5b5050505060e0810151600b54610140870151600c54610160890151604051631471f8e360e01b81526001600160a01b0389811660048301527f0000000000000000000000000b7ffc1f4ad541a4ed16b40d8c37f0929158d10181166024830152948516604482015265ffffffffffff938416606482015291841660848301529190911660a4820152911690631471f8e39060c401600060405180830381600087803b15801562000b5357600080fd5b505af115801562000b68573d6000803e3d6000fd5b50505050600062000b798a620010c1565b60405160200162000b8b919062001938565b604051602081830303815290604052905060008160405160200162000bb1919062001961565b6040516020818303038152906040529050846001600160a01b0316634780a5e56040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000c01573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c2791906200198d565b6001600160a01b031663c6b5bba68683858b60c001518c60a001518d60e001516040518763ffffffff1660e01b815260040162000c6a96959493929190620019ad565b600060405180830381600087803b15801562000c8557600080fd5b505af115801562000c9a573d6000803e3d6000fd5b50505050505080600001516001600160a01b031663f17d835c848c8c8c8c8b6101c001518c6101e001516040518863ffffffff1660e01b815260040162000ce8979695949392919062001a18565b600060405180830381600087803b15801562000d0357600080fd5b505af115801562000d18573d6000803e3d6000fd5b50600092506002915062000d299050565b60405190808252806020026020018201604052801562000d53578160200160208202803683370190505b5090508160000151866040015160405162000d6e9062001251565b62000d7b92919062001916565b604051809103906000f08015801562000d98573d6000803e3d6000fd5b508160008151811062000daf5762000daf62001ac9565b60200260200101906001600160a01b031690816001600160a01b0316815250507f0000000000000000000000007edd40933dfda0ecee1ad3e61a5044962284e1a68160018151811062000e065762000e0662001ac9565b6001600160a01b0392831660209182029290920101526040808401519051631e2d1e7560e11b8152911690633c5a3cea9062000e49908790859060040162001adf565b600060405180830381600087803b15801562000e6457600080fd5b505af115801562000e79573d6000803e3d6000fd5b50505050836001600160a01b0316632f2ff15d6040518060400160405280600581526020016427aba722a960d91b81525062000eb59062001b3d565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b038a166024820152604401600060405180830381600087803b15801562000efe57600080fd5b505af115801562000f13573d6000803e3d6000fd5b50505050836001600160a01b03166336568abe6040518060400160405280600581526020016427aba722a960d91b81525062000f4f9062001b3d565b6040516001600160e01b031960e084901b1681526004810191909152306024820152604401600060405180830381600087803b15801562000f8f57600080fd5b505af115801562000fa4573d6000803e3d6000fd5b50505050866001600160a01b031682600001516001600160a01b0316856001600160a01b03167f27a62b7d4a7ee7a705ae91fe5a3ad74f32fc3d14e82eb82c3730630601ce9ae6856020015162001013604080518082019091526005815264332e302e3160d81b602082015290565b6040516200102392919062001873565b60405180910390a450519998505050505050505050565b600082826040516200104c9062001251565b6200105992919062001916565b604051809103906000f08015801562001076573d6000803e3d6000fd5b506040516001600160a01b038083168252919250908416907fe408b90fcc4886a187a319dfb76714920da19f65ba0ce1c597d371c983f4c8e69060200160405180910390a292915050565b606060008290506000815167ffffffffffffffff811115620010e757620010e76200125f565b6040519080825280601f01601f19166020018201604052801562001112576020820181803683370190505b50905060005b82518110156200123b57604183828151811062001139576200113962001ac9565b016020015160f81c108015906200116d5750605a83828151811062001162576200116262001ac9565b016020015160f81c11155b15620011d95782818151811062001188576200118862001ac9565b602001015160f81c60f81b60f81c6020620011a4919062001b7b565b60f81b828281518110620011bc57620011bc62001ac9565b60200101906001600160f81b031916908160001a90535062001226565b828181518110620011ee57620011ee62001ac9565b602001015160f81c60f81b8282815181106200120e576200120e62001ac9565b60200101906001600160f81b031916908160001a9053505b80620012328162001b9d565b91505062001118565b509392505050565b6104d48062001bba83390190565b612e31806200208e83390190565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156200129b576200129b6200125f565b60405290565b604051610200810167ffffffffffffffff811182821017156200129b576200129b6200125f565b600082601f830112620012da57600080fd5b813567ffffffffffffffff80821115620012f857620012f86200125f565b604051601f8301601f19908116603f011681019082821181831017156200132357620013236200125f565b816040528381528660208588010111156200133d57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6001600160a01b03811681146200137357600080fd5b50565b803562001383816200135d565b919050565b803561ffff811681146200138357600080fd5b600060408284031215620013ae57600080fd5b620013b862001275565b9050620013c58262001388565b8152620013d56020830162001388565b602082015292915050565b80356001600160c01b03811681146200138357600080fd5b803565ffffffffffff811681146200138357600080fd5b6000604082840312156200142257600080fd5b6200142c62001275565b905081358152620013d560208301620013e0565b600061026082840312156200145457600080fd5b6200145e620012a1565b90506200146c83836200139b565b81526200147c60408301620013e0565b60208201526200148f60608301620013e0565b6040820152620014a260808301620013f8565b6060820152620014b560a08301620013f8565b6080820152620014c860c08301620013e0565b60a0820152620014db60e08301620013f8565b60c0820152610100620014f0818401620013e0565b60e083015261012062001505818501620013f8565b8284015261014091506200151b828501620013f8565b908301526101606200152f848201620013f8565b82840152610180915062001545828501620013f8565b908301526101a062001559848201620013e0565b828401526101c091506200156f828501620013e0565b908301526101e062001584858583016200140f565b82840152620015988561022086016200140f565b908301525092915050565b6000806000806000806102e08789031215620015be57600080fd5b863567ffffffffffffffff80821115620015d757600080fd5b620015e58a838b01620012c8565b97506020890135915080821115620015fc57600080fd5b6200160a8a838b01620012c8565b965060408901359150808211156200162157600080fd5b818901915089601f8301126200163657600080fd5b8135818111156200164657600080fd5b8a60208285010111156200165957600080fd5b602083019650809550505050620016736060880162001376565b915062001684886080890162001440565b90509295509295509295565b60005b83811015620016ad57818101518382015260200162001693565b50506000910152565b60008151808452620016d081602086016020860162001690565b601f01601f19169290920160200192915050565b602081526000620016f96020830184620016b6565b9392505050565b80516001600160a01b0316825260208101516200172860208401826001600160a01b03169052565b5060408101516200174460408401826001600160a01b03169052565b5060608101516200176060608401826001600160a01b03169052565b5060808101516200177c60808401826001600160a01b03169052565b5060a08101516200179860a08401826001600160a01b03169052565b5060c0810151620017b460c08401826001600160a01b03169052565b5060e0810151620017d060e08401826001600160a01b03169052565b50610100818101516001600160a01b03908116918401919091526101209182015116910152565b6001600160a01b0384811682526101a082019062001819602084018662001700565b808451166101608401528060208501511661018084015250949350505050565b600080604083850312156200184d57600080fd5b82356200185a816200135d565b91506200186a60208401620013e0565b90509250929050565b6001600160a01b03831681526040602082018190526000906200189990830184620016b6565b949350505050565b6101a08101620018b2828762001700565b6001600160a01b039490941661014082015265ffffffffffff928316610160820152911661018090910152919050565b6001600160a01b0394851681529290931660208301526001600160c01b039081166040830152909116606082015260800190565b6001600160a01b039290921682526001600160c01b0316602082015260400190565b600082516200194c81846020870162001690565b622929a960e91b920191825250600301919050565b600082516200197581846020870162001690565b65102a37b5b2b760d11b920191825250600601919050565b600060208284031215620019a057600080fd5b8151620016f9816200135d565b6001600160a01b038716815260c060208201819052600090620019d390830188620016b6565b8281036040840152620019e78188620016b6565b65ffffffffffff96909616606084015250506001600160c01b039283166080820152911660a0909101529392505050565b6001600160a01b03881681526101006020820181905260009062001a3f8382018a620016b6565b9050828103604084015262001a558189620016b6565b90508281036060840152858152858760208301376000602087830101526020601f19601f88011682010191505062001aa36080830185805182526020908101516001600160c01b0316910152565b825160c083015260208301516001600160c01b031660e083015298975050505050505050565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b038381168252604060208084018290528451918401829052600092858201929091906060860190855b8181101562001b2f57855185168352948301949183019160010162001b0f565b509098975050505050505050565b8051602080830151919081101562001b5f576000198160200360031b1b821691505b50919050565b634e487b7160e01b600052601160045260246000fd5b60ff818116838216019081111562001b975762001b9762001b65565b92915050565b60006001820162001bb25762001bb262001b65565b506001019056fe60806040526040516104d43803806104d4833981016040819052610022916102d1565b61002e82826000610035565b50506103ee565b61003e83610061565b60008251118061004b5750805b1561005c5761005a83836100a1565b505b505050565b61006a816100cd565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606100c683836040518060600160405280602781526020016104ad60279139610180565b9392505050565b6001600160a01b0381163b61013f5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60606001600160a01b0384163b6101e85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610136565b600080856001600160a01b031685604051610203919061039f565b600060405180830381855af49150503d806000811461023e576040519150601f19603f3d011682016040523d82523d6000602084013e610243565b606091505b50909250905061025482828661025e565b9695505050505050565b6060831561026d5750816100c6565b82511561027d5782518084602001fd5b8160405162461bcd60e51b815260040161013691906103bb565b634e487b7160e01b600052604160045260246000fd5b60005b838110156102c85781810151838201526020016102b0565b50506000910152565b600080604083850312156102e457600080fd5b82516001600160a01b03811681146102fb57600080fd5b60208401519092506001600160401b038082111561031857600080fd5b818501915085601f83011261032c57600080fd5b81518181111561033e5761033e610297565b604051601f8201601f19908116603f0116810190838211818310171561036657610366610297565b8160405282815288602084870101111561037f57600080fd5b6103908360208301602088016102ad565b80955050505050509250929050565b600082516103b18184602087016102ad565b9190910192915050565b60208152600082518060208401526103da8160408501602087016102ad565b601f01601f19169190910160400192915050565b60b1806103fc6000396000f3fe608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea2646970667358221220d696190f1462e196c18783d2bcdbe9f7498512203fe6ebde6d2044021dbc255d64736f6c63430008130033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65646101606040523480156200001257600080fd5b5060405162002e3138038062002e3183398101604081905262000035916200035d565b6001600160a01b038216620000815760405162461bcd60e51b815260206004820152600d60248201526c06d697373696e6720657263323609c1b60448201526064015b60405180910390fd5b6000816001600160c01b031611620000dc5760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206d617820747261646520766f6c756d650000000000000000604482015260640162000078565b816001600160a01b031663dffeadd06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200011b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001419190620003a7565b6001600160a01b0316608081905260408051632f2439b160e01b81529051632f2439b1916004808201926020929091908290030181865afa1580156200018b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b19190620003a7565b6001600160a01b031660a0816001600160a01b0316815250506080516001600160a01b031663979d7e866040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200020b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002319190620003a7565b6001600160a01b031660c0816001600160a01b0316815250506080516001600160a01b031663dc8af5f66040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200028b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002b19190620003a7565b6001600160a01b0390811660e05282166101008190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa15801562000303573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003299190620003ce565b60ff16610120526001600160c01b03166101405250620003f3565b6001600160a01b03811681146200035a57600080fd5b50565b600080604083850312156200037157600080fd5b82516200037e8162000344565b60208401519092506001600160c01b03811681146200039c57600080fd5b809150509250929050565b600060208284031215620003ba57600080fd5b8151620003c78162000344565b9392505050565b600060208284031215620003e157600080fd5b815160ff81168114620003c757600080fd5b60805160a05160c05160e051610100516101205161014051612950620004e1600039600061025e015260006101ac01526000818161023701528181610558015281816107440152610b4c0152600081816102ea015281816109040152818161099201528181610aaf01528181610c5601528181610eaf01528181610f570152818161132501526113b40152600081816102940152610ca901526000818161016b015281816103c2015281816104480152818161086a01528181610ada01528181610c82015261129601526000818161031101528181610ce301528181610d710152610e1001526129506000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c806396f80ae9116100ad578063dc8af5f611610071578063dc8af5f6146102e5578063dffeadd01461030c578063efd3614c14610333578063f0f615f8146103a3578063f8ac93e8146103ab57600080fd5b806396f80ae914610280578063979d7e861461028f578063a035b1fe146102b6578063a3e6ba94146102be578063c59b3d631461028057600080fd5b80633cb5d379116100f45780633cb5d379146101a757806354fd4d50146101e05780635580f72a14610207578063785e9e861461023257806395acc4ae1461025957600080fd5b80632428adc014610126578063271181ec1461015e5780632f2439b114610166578063372500ab146101a5575b600080fd5b610139610134366004612291565b6103b5565b604080516001600160c01b039384168152929091166020830152015b60405180910390f35b61013961066b565b61018d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610155565b005b6101ce7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff9091168152602001610155565b6040805180820182526005815264332e302e3160d81b6020820152905161015591906122b3565b61021a610215366004612319565b61071e565b6040516001600160c01b039091168152602001610155565b61018d7f000000000000000000000000000000000000000000000000000000000000000081565b61021a7f000000000000000000000000000000000000000000000000000000000000000081565b60405160008152602001610155565b61018d7f000000000000000000000000000000000000000000000000000000000000000081565b610139610791565b6102c6610849565b604080516001600160c01b039093168352602083019190915201610155565b61018d7f000000000000000000000000000000000000000000000000000000000000000081565b61018d7f000000000000000000000000000000000000000000000000000000000000000081565b600054600154600254600354610366936001600160c01b0316929165ffffffffffff80821692600160301b909204169085565b604080516001600160c01b039096168652602086019490945265ffffffffffff92831693850193909352166060830152608082015260a001610155565b6101a5610a4e565b6101a56000600155565b60008060008084610446577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a035b1fe6040518163ffffffff1660e01b81526004016040805180830381865afa15801561041d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104419190612352565b6104c7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663271181ec6040518163ffffffff1660e01b81526004016040805180830381865afa1580156104a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c79190612352565b91509150816001600160c01b03166000141580156104ee57506001600160c01b0381811614155b61052f5760405162461bcd60e51b815260206004820152600d60248201526c696e76616c696420707269636560981b60448201526064015b60405180910390fd5b806001600160c01b0316826001600160c01b0316111561055157610551612385565b60006105dd7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d8919061239b565b610a56565b9050806001600160c01b03166000036105fb57509094909350915050565b6000610605610a84565b8051909150610620906001600160c01b0316858460006111b8565b602082015190965061063e906001600160c01b0316848460026111b8565b9450846001600160c01b0316866001600160c01b0316111561066257610662612385565b50505050915091565b6040516290a2b760e61b81526001600482015260009081903090632428adc0906024016040805180830381865afa9250505080156106c6575060408051601f3d908101601f191682019092526106c391810190612352565b60015b610713573d8080156106f4576040519150601f19603f3d011682016040523d82523d6000602084013e6106f9565b606091505b50805160000361070857600080fd5b506000928392509050565b90925090509091565b565b6040516370a0823160e01b81526001600160a01b03828116600483015260009161078b917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156105b4573d6000803e3d6000fd5b92915050565b6040516290a2b760e61b81526000600482018190529081903090632428adc0906024016040805180830381865afa9250505080156107ec575060408051601f3d908101601f191682019092526107e991810190612352565b60015b610840573d80801561081a576040519150601f19603f3d011682016040523d82523d6000602084013e61081f565b606091505b50805160000361082e57600080fd5b506000926001600160c01b0392509050565b90939092509050565b6000804261038460006001015461086091906123ca565b1115806108fc57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663affed0e06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ea91906123dd565b60025465ffffffffffff908116911614155b8061098a57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638767e6386040518163ffffffff1660e01b8152600401602060405180830381865afa158015610960573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610984919061239b565b60035414155b80610a2b57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c76aeb126040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1291906123dd565b600254600160301b900465ffffffffffff908116911614155b15610a3857610a386111ef565b50506000546001546001600160c01b0390911691565b61071c6111ef565b60006001600160c01b03821115610a805760405163f44398f560e01b815260040160405180910390fd5b5090565b6040805180820190915260008082526020820152604051635523caaf60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063aa47955e906024016040805180830381865afa158015610b22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b469190612475565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637121c2736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ba8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bcc91906124b2565b9050806001600160c01b031682600001516001600160c01b031610610c00576001600160c01b031680835260208301525090565b60408051610180810182526000610140820181905261016082018190526080820181905260a0820181905260c0820181905260e08201819052610100820152606061012082018190528482526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166020808501919091527f00000000000000000000000000000000000000000000000000000000000000008216848601527f00000000000000000000000000000000000000000000000000000000000000008216928401929092528351634780a5e560e01b8152935192937f000000000000000000000000000000000000000000000000000000000000000090911692634780a5e5926004808401939192918290030181865afa158015610d2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5291906124cd565b81608001906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c99dc3dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df191906124cd565b8160a001906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166340c65f726040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9091906124cd565b8160c001906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637cbf6db26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2f91906124b2565b6001600160c01b031660e08201526040805163036cf50b60e21b815290516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691630db3d42c9160048083019260209291908290030181865afa158015610fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc691906124b2565b6001600160c01b0316610100820152606081015160408051635ab1bd5360e01b815290516000926001600160a01b031691635ab1bd5391600480830192869291908290030181865afa158015611020573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526110489190810190612582565b80515190915067ffffffffffffffff81111561106657611066612405565b60405190808252806020026020018201604052801561108f578160200160208202803683370190505b5061012083015260005b8151518110156111a45782604001516001600160a01b031663d3252db5836000015183815181106110cc576110cc612670565b6020026020010151846020015184815181106110ea576110ea612670565b60200260200101516040518363ffffffff1660e01b81526004016111249291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa158015611141573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116591906124b2565b836101200151828151811061117c5761117c612670565b6001600160c01b039092166020928302919091019091015261119d81612686565b9050611099565b506111af82826114a7565b94505050505090565b60006111e46105d8866001600160c01b0316866001600160c01b0316866001600160c01b031686611ba8565b90505b949350505050565b6000806111fa610791565b91509150816001600160c01b031660001415801561122157506001600160c01b0381811614155b61125d5760405162461bcd60e51b815260206004820152600d60248201526c696e76616c696420707269636560981b6044820152606401610526565b6040518060a0016040528060028385611276919061269f565b61128091906126dc565b6001600160c01b031681526020014281526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663affed0e06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112f2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061131691906123dd565b65ffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c76aeb126040518163ffffffff1660e01b8152600401602060405180830381865afa158015611381573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113a591906123dd565b65ffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638767e6386040518163ffffffff1660e01b8152600401602060405180830381865afa158015611410573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611434919061239b565b90528051600080546001600160c01b039092166001600160c01b03199092169190911790556020810151600155604081015160028054606084015165ffffffffffff908116600160301b026bffffffffffffffffffffffff19909216931692909217919091179055608001516003555050565b604080518082019091526000808252602082015260008084604001516001600160a01b031663271181ec6040518163ffffffff1660e01b81526004016040805180830381865afa1580156114ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115239190612352565b9150915060008560c001516001600160a01b0316637121c2736040518163ffffffff1660e01b8152600401602060405180830381865afa15801561156b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158f91906124b2565b9050806001600160c01b03168660000151602001516001600160c01b031611156115c65785516001600160c01b0382166020909101525b60008060005b875151811015611a6c578860c001516001600160a01b0316886000015182815181106115fa576115fa612670565b60200260200101516001600160a01b03160315611a5c5760008860200151828151811061162957611629612670565b602090810291909101810151908b0151604051632ac07b9560e11b81526001600160a01b039182166004820152911690635580f72a90602401602060405180830381865afa15801561167f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a391906124b2565b90508960a001516001600160a01b0316896000015183815181106116c9576116c9612670565b60200260200101516001600160a01b03160361178557611782896020015183815181106116f8576116f8612670565b602090810291909101015160808c0151604051632ac07b9560e11b81526001600160a01b039182166004820152911690635580f72a90602401602060405180830381865afa15801561174e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177291906124b2565b6001600160c01b03831690611c55565b90505b896101200151828151811061179c5761179c612670565b60200260200101516001600160c01b0316600003611871576000896020015183815181106117cc576117cc612670565b60200260200101516001600160a01b031663271181ec6040518163ffffffff1660e01b81526004016040805180830381865afa158015611810573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118349190612352565b5090506118648a60200151848151811061185057611850612670565b602002602001015183838e60e00151611c68565b61186f575050611a5c565b505b6000808a60200151848151811061188a5761188a612670565b60200260200101516001600160a01b031663a035b1fe6040518163ffffffff1660e01b81526004016040805180830381865afa1580156118ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f29190612352565b91509150600061193d8d600001516020015160028f6101200151888151811061191d5761191d612670565b60200260200101516001600160c01b0316611d129092919063ffffffff16565b9050836001600160c01b0316816001600160c01b03161115611993576119796119668583612702565b6001600160c01b038516908b60006111b8565b61198c906001600160c01b031688612722565b96506119c9565b6119b36119a08286612702565b6001600160c01b038416908c6002611d3f565b6119c6906001600160c01b031688612742565b96505b5060006119f18d600001516000015160008f6101200151888151811061191d5761191d612670565b90506000611a14611a028387612702565b6001600160c01b038616906000611d12565b90508d60e001516001600160c01b0316816001600160c01b031610611a475760e08e0151611a429082612702565b611a4a565b60005b611a54908861269f565b965050505050505b611a6581612686565b90506115cc565b506000821215611aa557611a826105d88361276a565b885160200151611a929190612702565b6001600160c01b03166020870152611b00565b8751602001516001600160c01b0390611ac0908216846123ca565b1115611ad8576001600160c01b036020870152611b00565b611ae182610a56565b885160200151611af1919061269f565b6001600160c01b031660208701525b610100880151611b3090611b1d90670de0b6b3a764000090611f44565b6001600160c01b038316908660006111b8565b885151611b3d919061269f565b6001600160c01b039081168752602087015184821691161115611b6a576001600160c01b03831660208701525b85602001516001600160c01b031686600001516001600160c01b03161115611b9d5760208601516001600160c01b031686525b505050505092915050565b600080611bb6868686611f50565b90506000836002811115611bcc57611bcc612786565b03611bd85790506111e7565b60008480611be857611be86126c6565b86880990506002846002811115611c0157611c01612786565b03611c1f578015611c1a57611c176001836123ca565b91505b611c4b565b6002611c2c60018761279c565b611c3691906127af565b811115611c4b57611c486001836123ca565b91505b5095945050505050565b6000611c61828461269f565b9392505050565b6000611c8a611c778385612033565b6001600160c01b03908116908616101590565b80156111e457506001611d08866001600160a01b0316633cb5d3796040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cd4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf891906127c3565b6001600160c01b03871690612082565b1195945050505050565b60006111e76105d8611d306001600160c01b038087169088166127e6565b670de0b6b3a764000085612090565b60006001600160c01b0385161580611d5e57506001600160c01b038416155b15611d6b575060006111e7565b6001600160c01b038581161480611d8a57506001600160c01b03848116145b80611d9c57506001600160c01b038316155b15611daf57506001600160c01b036111e7565b6000806000611dd0886001600160c01b0316886001600160c01b0316612138565b91509150856001600160c01b03168210611df6576001600160c01b0393505050506111e7565b6000866001600160c01b031680611e0f57611e0f6126c6565b886001600160c01b03168a6001600160c01b031609905081811115611e35576001830392505b90819003906001600160c01b03600088900388168116908816818181611e5d57611e5d6126c6565b049050818481611e6f57611e6f6126c6565b049350818260000381611e8457611e846126c6565b046001018502939093016002848103808602820302808602820302808602820302808602820302808602820302808602820302808602820302828102975091949190896002811115611ed857611ed8612786565b03611eef578315611eea576001870196505b611f1e565b6001896002811115611f0357611f03612786565b03611f1e576002600019830104841115611f1e576001870196505b5050505050506001600160c01b03801681106111e4576001600160c01b039150506111e7565b6000611c618284612702565b6000806000611f5f8686612138565b91509150838210611f835760405163f44398f560e01b815260040160405180910390fd5b60008480611f9357611f936126c6565b868809905081811115611fa7576001830392505b908190039060008590038516808681611fc257611fc26126c6565b049550808381611fd457611fd46126c6565b049250808160000381611fe957611fe96126c6565b046001019390930291909101600285810380870282030280870282030280870282030280870282030280870282030280870282030295860290039094029390930295945050505050565b6000806001600160c01b0383161561205f5761205a6001600160c01b038516846002612165565b612068565b6001600160c01b035b90506000816001600160c01b031611611c615760016111e7565b6000611c6183836000612198565b60008061209d84866127af565b905060008360028111156120b3576120b3612786565b036120bf579050611c61565b60018360028111156120d3576120d3612786565b036121125760026120e560018661279c565b6120ef91906127af565b6120f985876127fd565b111561210d578061210981612686565b9150505b6111e7565b600061211e85876127fd565b11156111e7578061212e81612686565b9695505050505050565b600080806000198486099050838502915081810392508181101561215d576001830392505b509250929050565b60006111e76105d8612188670de0b6b3a76400006001600160c01b0388166127e6565b856001600160c01b031685612090565b6000836001600160c01b03166000036121b357506000611c61565b6029198360000b136121ec5760028260028111156121d3576121d3612786565b146121df5760006121e2565b60015b60ff169050611c61565b8260000b6060136122105760405163f44398f560e01b815260040160405180910390fd5b61221b601284612811565b9250600061222b8460000b612279565b61223690600a61290e565b905060008460000b121561225d57612258856001600160c01b03168285612090565b612270565b612270816001600160c01b0387166127e6565b95945050505050565b6000808212612288578161078b565b61078b8261276a565b6000602082840312156122a357600080fd5b81358015158114611c6157600080fd5b600060208083528351808285015260005b818110156122e0578581018301518582016040015282016122c4565b506000604082860101526040601f19601f8301168501019250505092915050565b6001600160a01b038116811461231657600080fd5b50565b60006020828403121561232b57600080fd5b8135611c6181612301565b80516001600160c01b038116811461234d57600080fd5b919050565b6000806040838503121561236557600080fd5b61236e83612336565b915061237c60208401612336565b90509250929050565b634e487b7160e01b600052600160045260246000fd5b6000602082840312156123ad57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561078b5761078b6123b4565b6000602082840312156123ef57600080fd5b815165ffffffffffff81168114611c6157600080fd5b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561243e5761243e612405565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561246d5761246d612405565b604052919050565b60006040828403121561248757600080fd5b61248f61241b565b61249883612336565b81526124a660208401612336565b60208201529392505050565b6000602082840312156124c457600080fd5b611c6182612336565b6000602082840312156124df57600080fd5b8151611c6181612301565b600067ffffffffffffffff82111561250457612504612405565b5060051b60200190565b600082601f83011261251f57600080fd5b8151602061253461252f836124ea565b612444565b82815260059290921b8401810191818101908684111561255357600080fd5b8286015b8481101561257757805161256a81612301565b8352918301918301612557565b509695505050505050565b6000602080838503121561259557600080fd5b825167ffffffffffffffff808211156125ad57600080fd5b90840190604082870312156125c157600080fd5b6125c961241b565b8251828111156125d857600080fd5b8301601f810188136125e957600080fd5b80516125f761252f826124ea565b81815260059190911b8201860190868101908a83111561261657600080fd5b928701925b8284101561263d57835161262e81612301565b8252928701929087019061261b565b8452505050828401518281111561265357600080fd5b61265f8882860161250e565b948201949094529695505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201612698576126986123b4565b5060010190565b6001600160c01b038181168382160190808211156126bf576126bf6123b4565b5092915050565b634e487b7160e01b600052601260045260246000fd5b60006001600160c01b03838116806126f6576126f66126c6565b92169190910492915050565b6001600160c01b038281168282160390808211156126bf576126bf6123b4565b81810360008312801583831316838312821617156126bf576126bf6123b4565b8082018281126000831280158216821582161715612762576127626123b4565b505092915050565b6000600160ff1b820161277f5761277f6123b4565b5060000390565b634e487b7160e01b600052602160045260246000fd5b8181038181111561078b5761078b6123b4565b6000826127be576127be6126c6565b500490565b6000602082840312156127d557600080fd5b815160ff81168114611c6157600080fd5b808202811582820484141761078b5761078b6123b4565b60008261280c5761280c6126c6565b500690565b600082810b9082900b03607f198112607f8213171561078b5761078b6123b4565b600181815b8085111561215d578160001904821115612853576128536123b4565b8085161561286057918102915b93841c9390800290612837565b60008261287c5750600161078b565b816128895750600061078b565b816001811461289f57600281146128a9576128c5565b600191505061078b565b60ff8411156128ba576128ba6123b4565b50506001821b61078b565b5060208310610133831016604e8410600b84101617156128e8575081810a61078b565b6128f28383612832565b8060001904821115612906576129066123b4565b029392505050565b6000611c61838361286d56fea26469706673582212208418e8ccb96aa03f3752c57af4f4ecfef50b99efce14a3d52849c2a2f10a0acb64736f6c63430008130033a26469706673582212206e3e2fbe8b8f51fe4b833b1c730ed1837ef5a9c4f1545f1abcebabbbc1cc2ebb64736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000320623b8e4ff03373931769a31fc52a4e78b5d700000000000000000000000000b7ffc1f4ad541a4ed16b40d8c37f0929158d1010000000000000000000000007edd40933dfda0ecee1ad3e61a5044962284e1a6000000000000000000000000f5366f67ff66a3cefcb18809a762d5b5931febf8000000000000000000000000b6f01aa21defa4a4de33bed16bcc06cfd23b6a6f000000000000000000000000c98eafc9f249d90e3e35e729e3679dd75a899c10000000000000000000000000773cf50adcf1730964d4a9b664baed4b9ffc24500000000000000000000000005ccca36cbb66a4e4033b08b4f6d7bac96ba55cdc000000000000000000000000bbc532a80dd141449330c1232c953da6801aed010000000000000000000000000e8439a17ba5cbb2d9823c03a02566b9dd5d96ac00000000000000000000000099580fc649c02347ebc7750524caae5cacf9d34c0000000000000000000000009a5f8a9bb91a868b7501139eedb20dc129d28f040000000000000000000000005e3e13d3d2a0adfe16f8ef5e7a2992a88e9e65af0000000000000000000000005e3e13d3d2a0adfe16f8ef5e7a2992a88e9e65af0000000000000000000000004e9b97957a0d1f4c25e42ccc69e4d2665433fea30000000000000000000000002387c22727acb91519b80a15aef393ad40dfdb2f
-----Decoded View---------------
Arg [0] : rsr_ (address): 0x320623b8E4fF03373931769A31Fc52A4E78B5d70
Arg [1] : gnosis_ (address): 0x0b7fFc1f4AD541A4Ed16b40D8c37f0929158D101
Arg [2] : rsrAsset_ (address): 0x7edD40933DfdA0ecEe1ad3E61a5044962284e1A6
Arg [3] : implementations_ (tuple):
Arg [1] : main (address): 0xF5366f67FF66A3CefcB18809a762D5b5931FebF8
Arg [2] : components (tuple):
Arg [1] : rToken (address): 0xb6f01Aa21defA4a4DE33Bed16BcC06cfd23b6A6F
Arg [2] : stRSR (address): 0xC98eaFc9F249D90e3E35E729e3679DD75A899c10
Arg [3] : assetRegistry (address): 0x773cf50adCF1730964D4A9b664BaEd4b9FFC2450
Arg [4] : basketHandler (address): 0x5ccca36CbB66a4E4033B08b4F6D7bAc96bA55cDc
Arg [5] : backingManager (address): 0xBbC532A80DD141449330c1232C953Da6801Aed01
Arg [6] : distributor (address): 0x0e8439a17bA5cBb2D9823c03a02566B9dd5d96Ac
Arg [7] : furnace (address): 0x99580Fc649c02347eBc7750524CAAe5cAcf9d34c
Arg [8] : broker (address): 0x9A5F8A9bB91a868b7501139eEdB20dC129D28F04
Arg [9] : rsrTrader (address): 0x5e3e13d3d2a0adfe16f8EF5E7a2992A88E9e65AF
Arg [10] : rTokenTrader (address): 0x5e3e13d3d2a0adfe16f8EF5E7a2992A88E9e65AF
Arg [3] : trading (tuple):
Arg [1] : gnosisTrade (address): 0x4e9B97957a0d1F4c25E42Ccc69E4d2665433FEA3
Arg [2] : dutchTrade (address): 0x2387C22727ACb91519b80A15AEf393ad40dFdb2F
-----Encoded View---------------
16 Constructor Arguments found :
Arg [0] : 000000000000000000000000320623b8e4ff03373931769a31fc52a4e78b5d70
Arg [1] : 0000000000000000000000000b7ffc1f4ad541a4ed16b40d8c37f0929158d101
Arg [2] : 0000000000000000000000007edd40933dfda0ecee1ad3e61a5044962284e1a6
Arg [3] : 000000000000000000000000f5366f67ff66a3cefcb18809a762d5b5931febf8
Arg [4] : 000000000000000000000000b6f01aa21defa4a4de33bed16bcc06cfd23b6a6f
Arg [5] : 000000000000000000000000c98eafc9f249d90e3e35e729e3679dd75a899c10
Arg [6] : 000000000000000000000000773cf50adcf1730964d4a9b664baed4b9ffc2450
Arg [7] : 0000000000000000000000005ccca36cbb66a4e4033b08b4f6d7bac96ba55cdc
Arg [8] : 000000000000000000000000bbc532a80dd141449330c1232c953da6801aed01
Arg [9] : 0000000000000000000000000e8439a17ba5cbb2d9823c03a02566b9dd5d96ac
Arg [10] : 00000000000000000000000099580fc649c02347ebc7750524caae5cacf9d34c
Arg [11] : 0000000000000000000000009a5f8a9bb91a868b7501139eedb20dc129d28f04
Arg [12] : 0000000000000000000000005e3e13d3d2a0adfe16f8ef5e7a2992a88e9e65af
Arg [13] : 0000000000000000000000005e3e13d3d2a0adfe16f8ef5e7a2992a88e9e65af
Arg [14] : 0000000000000000000000004e9b97957a0d1f4c25e42ccc69e4d2665433fea3
Arg [15] : 0000000000000000000000002387c22727acb91519b80a15aef393ad40dfdb2f
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.