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
|
||
|---|---|---|---|---|---|---|---|
| 0x61014060 | 16956074 | 990 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16956074 | 990 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16956074 | 990 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16956074 | 990 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16956074 | 990 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16956074 | 990 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16956074 | 990 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16956074 | 990 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16956074 | 990 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16956074 | 990 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16956074 | 990 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16956074 | 990 days ago | Contract Creation | 0 ETH | |||
| 0x61014060 | 16853406 | 1004 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16853406 | 1004 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16853406 | 1004 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16853406 | 1004 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16853406 | 1004 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16853406 | 1004 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16853406 | 1004 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16853406 | 1004 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16853406 | 1004 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16853406 | 1004 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16853406 | 1004 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 16853406 | 1004 days ago | Contract Creation | 0 ETH | |||
| 0x61014060 | 16794040 | 1013 days ago | Contract Creation | 0 ETH |
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.17+commit.8df45f5f
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.17;
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_.trade) != 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 all roles 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);
// 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.trade, params.auctionLength);
// 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
);
}
// 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.grantRole(SHORT_FREEZER, owner);
main.grantRole(LONG_FREEZER, owner);
main.grantRole(PAUSER, owner);
main.renounceRole(OWNER, address(this));
main.renounceRole(SHORT_FREEZER, address(this));
main.renounceRole(LONG_FREEZER, address(this));
main.renounceRole(PAUSER, address(this));
emit RTokenCreated(main, components.rToken, components.stRSR, owner, version());
return (address(components.rToken));
}
}// 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);
// getRoundData and latestRoundData should both raise "No data present"
// if they do not have data to report, instead of returning unset values
// which could be misinterpreted as actual reported values.
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.17;
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";
/**
* @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);
/// @param {UoA} The max trade volume, in UoA
function maxTradeVolume() external view returns (uint192);
}
interface TestIAsset is IAsset {
function chainlinkFeed() external view returns (AggregatorV3Interface);
}
/// 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);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.17;
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;
/// @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);
function register(IAsset asset) external returns (bool);
function swapRegistered(IAsset asset) external returns (bool swapped);
function unregister(IAsset asset) external;
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.17;
import "@openzeppelin/contracts/token/ERC20/IERC20.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.
* - If already collateralized, excess assets are transferred to RevenueTraders.
*
* `manageTokens(erc20s)` and `manageTokensSortedOrder(erc20s)` are handles for getting at the
* same underlying functionality. The former allows an ERC20 list in any order, while the
* latter requires a sorted array, and executes in O(n) rather than O(n^2) time. In the
* vast majority of cases we expect the the O(n^2) function to be acceptable.
*/
interface IBackingManager is IComponent, ITrading {
event TradingDelaySet(uint48 indexed oldVal, uint48 indexed newVal);
event BackingBufferSet(uint192 indexed oldVal, uint192 indexed 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;
/// Maintain the overall backing policy; handout assets otherwise
/// @dev Performs a uniqueness check on the erc20s list in O(n^2)
/// @custom:interaction
function manageTokens(IERC20[] memory erc20s) external;
/// Maintain the overall backing policy; handout assets otherwise
/// @dev Tokens must be in sorted order!
/// @dev Performs a uniqueness check on the erc20s list in O(n)
/// @custom:interaction
function manageTokensSortedOrder(IERC20[] memory 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.17;
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 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 indexed max, IERC20[] erc20s);
// Initialization
function init(IMain main_) 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;
/// @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);
/// @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 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);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.17;
import "./IAsset.sol";
import "./IComponent.sol";
import "./IGnosis.sol";
import "./ITrade.sol";
/// 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 AuctionLengthSet(uint48 indexed oldVal, uint48 indexed newVal);
event DisabledSet(bool indexed prevVal, bool indexed newVal);
// Initialization
function init(
IMain main_,
IGnosis gnosis_,
ITrade tradeImplementation_,
uint48 auctionLength_
) external;
/// Request a trade from the broker
/// @dev Requires setting an allowance in advance
/// @custom:interaction
function openTrade(TradeRequest memory req) external returns (ITrade);
/// Only callable by one of the trading contracts the broker deploys
function reportViolation() external;
function disabled() external view returns (bool);
}
interface TestIBroker is IBroker {
function gnosis() external view returns (IGnosis);
function auctionLength() external view returns (uint48);
function setAuctionLength(uint48 newAuctionLength) external;
function setDisabled(bool disabled_) external;
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.17;
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.17;
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 12s period
//
// === StRSR ===
uint48 unstakingDelay; // {s} the "thawing time" of staked RSR before withdrawal
//
// === BackingManager ===
uint48 tradingDelay; // {s} how long to wait until starting auctions after switching basket
uint48 auctionLength; // {s} the length of an 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;
ITrade trade;
}
/**
* @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
);
//
/// 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);
}
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.17;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IComponent.sol";
struct RevenueShare {
uint16 rTokenDist; // {revShare} A value between [0, 10,000]
uint16 rsrDist; // {revShare} A value between [0, 10,000]
}
/// Assumes no more than 1024 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 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 indexed 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
/// @custom:interaction
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.17;
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 indexed oldRatio, uint192 indexed 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.17;
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.17;
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 indexed oldVal, uint48 indexed 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 indexed oldDuration, uint48 indexed 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 indexed oldDuration, uint48 indexed newDuration);
/// Emitted when the system is paused or unpaused
/// @param oldVal The old value of `paused`
/// @param newVal The new value of `paused`
event PausedSet(bool indexed oldVal, bool indexed newVal);
/**
* Paused: Disable everything except for OWNER actions, RToken.redeem, StRSR.stake,
* and StRSR.payoutRewards
* Frozen: Disable everything except for OWNER actions + StRSR.stake (for governance)
*/
function pausedOrFrozen() 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 pause() external;
function unpause() external;
}
interface IComponentRegistry {
// === Component setters/getters ===
event RTokenSet(IRToken indexed oldVal, IRToken indexed newVal);
function rToken() external view returns (IRToken);
event StRSRSet(IStRSR indexed oldVal, IStRSR indexed newVal);
function stRSR() external view returns (IStRSR);
event AssetRegistrySet(IAssetRegistry indexed oldVal, IAssetRegistry indexed newVal);
function assetRegistry() external view returns (IAssetRegistry);
event BasketHandlerSet(IBasketHandler indexed oldVal, IBasketHandler indexed newVal);
function basketHandler() external view returns (IBasketHandler);
event BackingManagerSet(IBackingManager indexed oldVal, IBackingManager indexed newVal);
function backingManager() external view returns (IBackingManager);
event DistributorSet(IDistributor indexed oldVal, IDistributor indexed newVal);
function distributor() external view returns (IDistributor);
event RSRTraderSet(IRevenueTrader indexed oldVal, IRevenueTrader indexed newVal);
function rsrTrader() external view returns (IRevenueTrader);
event RTokenTraderSet(IRevenueTrader indexed oldVal, IRevenueTrader indexed newVal);
function rTokenTrader() external view returns (IRevenueTrader);
event FurnaceSet(IFurnace indexed oldVal, IFurnace indexed newVal);
function furnace() external view returns (IFurnace);
event BrokerSet(IBroker indexed oldVal, IBroker indexed 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 paused() external view returns (bool);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.17;
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;
/// Processes a single token; unpermissioned
/// @dev Intended to be used with multicall
/// @custom:interaction
function manageToken(IERC20 sell) external;
}
// solhint-disable-next-line no-empty-blocks
interface TestIRevenueTrader is IRevenueTrader, TestITrading {
function tokenToBuy() external view returns (IERC20);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.17;
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 indexed amount);
/// Claim rewards earned by holding a balance of the ERC20 token
/// Must emit `RewardsClaimed` for each token rewards are claimed for
/// @dev delegatecall: there be dragons here!
/// @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
/// @dev delegatecall: there be dragons here!
/// @custom:interaction
function claimRewardsSingle(IERC20 erc20) external;
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.17;
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 indexed 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 indexed 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
/// @param amount {qRTok} The quantity {qRToken} of RToken to redeem
/// @param basketNonce The nonce of the basket the redemption should be from; else reverts
/// @custom:interaction
function redeem(uint256 amount, uint48 basketNonce) external;
/// Redeem RToken for basket collateral to a particular recipient
/// @param recipient The address to receive the backing collateral tokens
/// @param amount {qRTok} The quantity {qRToken} of RToken to redeem
/// @param basketNonce The nonce of the basket the redemption should be from; else reverts
/// @custom:interaction
function redeemTo(
address recipient,
uint256 amount,
uint48 basketNonce
) external;
/// Mints a quantity of RToken to the `recipient`, callable only by the BackingManager
/// @param recipient The recipient of the newly minted RToken
/// @param amount {qRTok} The amount to be minted
/// @custom:protected
function mint(address recipient, uint256 amount) external;
/// Melt a quantity of RToken from the caller's account
/// @param amount {qRTok} The amount to be melted
function melt(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.17;
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 indexed 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 whenever the exchange rate changes
event ExchangeRateSet(uint192 indexed oldVal, uint192 indexed newVal);
/// Emitted whenever RSR are paids out
event RewardsPaid(uint256 indexed 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 indexed oldVal, uint48 indexed newVal);
event RewardRatioSet(uint192 indexed oldVal, uint192 indexed newVal);
// Initialization
function init(
IMain main_,
string memory name_,
string memory symbol_,
uint48 unstakingDelay_,
uint192 rewardRatio_
) 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;
/// Seize RSR, only callable by main.backingManager()
/// @custom:protected
function seizeRSR(uint256 amount) 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 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.17;
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
/**
* Simple generalized trading interface for all Trade contracts to obey
*
* Usage: if (canSettle()) settle()
*/
interface ITrade {
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);
/// 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);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.17;
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 indexed oldVal, uint192 indexed newVal);
event MinTradeVolumeSet(uint192 indexed oldVal, uint192 indexed 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
/// @custom:refresher
function settleTrade(IERC20 sell) external;
/// @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);
/// Light wrapper around FixLib.mulDiv to support try-catch
function mulDivCeil(
uint192 x,
uint192 y,
uint192 z
) external pure returns (uint192);
}
interface TestITrading is ITrading {
/// @custom:governance
function setMaxTradeSlippage(uint192 val) external;
/// @custom:governance
function setMinTradeVolume(uint192 val) external;
/// @return The number of ongoing trades open
function tradesOpen() external view returns (uint48);
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.17;
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.17; /// @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)); } } // ================ 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.17;
// 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.17;
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);
// Calculate available amount after supply change
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);
}
// Update cached values
throttle.lastAvailable = available;
throttle.lastTimestamp = uint48(block.timestamp);
}
/// @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.17;
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
* - Paused: only allow OWNER actions, redemption, staking, and rewards payout
*
* Typically freezing thaws on its own in a predetemined number of blocks.
* However, OWNER can also freeze forever.
*/
/// 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 ===
bool public paused;
/* ==== 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 all roles
// - OWNER is the admin role for all roles
// - longFreezes[caller] == LONG_FREEZE_CHARGES
// - 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);
address msgSender = _msgSender();
_grantRole(OWNER, msgSender);
_grantRole(SHORT_FREEZER, msgSender);
_grantRole(LONG_FREEZER, msgSender);
_grantRole(PAUSER, msgSender);
longFreezes[msgSender] = LONG_FREEZE_CHARGES;
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() external 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 paused) == paused || (now < unfreezeAt)
function pausedOrFrozen() public view returns (bool) {
return paused || 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: paused' = true
function pause() external onlyRole(PAUSER) {
emit PausedSet(paused, true);
paused = true;
}
// checks: caller has PAUSER
// effects: paused' = false
function unpause() external onlyRole(PAUSER) {
emit PausedSet(paused, false);
paused = 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.17;
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.17;
import "../interfaces/IVersioned.sol";
// This value should be updated on each release
string constant VERSION = "2.0.0";
/**
* @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.17;
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
function poke() external {
// == Refresher ==
assetRegistry.refresh();
// == CE block ==
require(!pausedOrFrozen(), "paused or 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.17;
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 reg;
IStRSR stRSR;
IERC20 rsr;
IRToken rToken;
// Gov Vars
uint192 minTradeVolume; // {UoA}
uint192 maxTradeSlippage; // {1}
}
/**
* @title RecollateralizationLibP1
* @notice An informal extension of the Trading mixin that provides trade preparation views
* Users:
* - BackingManager
* - RTokenAsset
*
* 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.
// This is the "main loop" for recollateralization trading:
// actions:
// let range = basketRange(all erc20s)
// let trade = nextTradePair(...)
// if trade.sell is not a defaulted collateral, prepareTradeToCoverDeficit(...)
// otherwise, prepareTradeSell(...) with a 0 minBuyAmount
function prepareRecollateralizationTrade(IBackingManager bm, BasketRange memory basketsHeld)
external
view
returns (bool doTrade, TradeRequest memory req)
{
// === Prepare cached values ===
IMain main = bm.main();
TradingContext memory ctx = TradingContext({
basketsHeld: basketsHeld,
bm: bm,
bh: main.basketHandler(),
reg: main.assetRegistry(),
stRSR: main.stRSR(),
rsr: main.rsr(),
rToken: main.rToken(),
minTradeVolume: bm.minTradeVolume(),
maxTradeSlippage: bm.maxTradeSlippage()
});
Registry memory reg = ctx.reg.getRegistry();
// ============================
// 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);
}
// If we are selling an unpriced asset or UNSOUND collateral, do not try to cover deficit
if (
trade.sellPrice == 0 ||
(trade.sell.isCollateral() &&
ICollateral(address(trade.sell)).status() != CollateralStatus.SOUND)
) {
(doTrade, req) = trade.prepareTradeSell(ctx.minTradeVolume, ctx.maxTradeSlippage);
} else {
(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);
}
// Compute the target basket range
// Algorithm intuition: Trade conservatively. Quantify uncertainty based on the proportion of
// token balances requiring trading vs not requiring trading. Decrease uncertainty the largest
// amount possible with each trade.
//
// How do we know this algorithm converges?
// Assumption: constant prices
// 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 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 unfavorable prices,
// incurring 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 basketPriceLow, uint192 basketPriceHigh) = ctx.bh.price(); // {UoA/BU}
// Cap ctx.basketsHeld.top
if (ctx.basketsHeld.top > ctx.rToken.basketsNeeded()) {
ctx.basketsHeld.top = ctx.rToken.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
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)));
}
uint192 q = ctx.bh.quantityUnsafe(reg.erc20s[i], reg.assets[i]); // {tok/BU}
{
// 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 (
q == 0 &&
!TradeLib.isEnoughToSell(reg.assets[i], bal, lotLow, ctx.minTradeVolume)
) continue;
}
(uint192 low, uint192 high) = reg.assets[i].price(); // {UoA/tok}
// 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 = q.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, basketPriceHigh, 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(ctx.bm.safeMulDivCeil(high, bal - anchor, basketPriceLow))
);
// needs overflow protection: using high price of asset which can be FIX_MAX
}
}
// range.bottom: pessimistic case
// add-in surplus baskets relative to ctx.basketsHeld.bottom
{
// {tok} = {tok/BU} * {BU}
uint192 anchor = q.mul(ctx.basketsHeld.bottom, FLOOR);
// (1) Sell tokens 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.
val = (val < ctx.minTradeVolume) ? 0 : val - ctx.minTradeVolume;
// (3) Buy BUs at their high price with the remaining value
// (4) Assume maximum slippage in trade
// {BU} = {UoA} * {1} / {UoA/BU}
range.bottom += val.mulDiv(
FIX_ONE.minus(ctx.maxTradeSlippage),
basketPriceHigh,
FLOOR
);
}
}
// ==== (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
range.bottom += ctx.basketsHeld.bottom;
// reverting on overflow is appropriate here
// ==== (3/3) Enforce (range.bottom <= range.top <= basketsNeeded) ====
if (range.top > ctx.rToken.basketsNeeded()) range.top = ctx.rToken.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)
/// sellPrice {UoA/sellTok} The worst-case price of the sell token on secondary markets
/// buyPrice {UoA/sellTok} 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.sellPrice` 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.buyPrice` 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.
// 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
// No space on the stack to cache erc20s.length
for (uint256 i = 0; i < reg.erc20s.length; ++i) {
if (reg.erc20s[i] == ctx.rsr) 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.bh.quantityUnsafe(reg.erc20s[i], reg.assets[i]),
CEIL
); // {tok}
if (bal.gt(needed)) {
uint192 low; // {UoA/sellTok}
// this wonky block is just for getting around the stack limit
{
uint192 high; // {UoA/sellTok}
(low, high) = reg.assets[i].price(); // {UoA/sellTok}
// Skip worthless assets
if (high == 0) continue;
}
(uint192 lotLow, ) = reg.assets[i].lotPrice(); // {UoA/sellTok}
// {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.sellPrice = low;
maxes.surplusStatus = status;
maxes.surplus = delta;
}
} else {
// needed(Bottom): token balance needed at bottom of the basket range
needed = range.bottom.mul(
ctx.bh.quantityUnsafe(reg.erc20s[i], reg.assets[i]),
CEIL
); // {buyTok};
if (bal.lt(needed)) {
uint192 amtShort = needed.minus(bal); // {buyTok}
(, uint192 high) = reg.assets[i].price(); // {UoA/buyTok}
// {UoA} = {buyTok} * {UoA/buyTok}
uint192 delta = amtShort.mul(high, CEIL);
// The best asset to buy is whichever asset has the largest deficit
if (delta.gt(maxes.deficit)) {
trade.buy = ICollateral(address(reg.assets[i]));
trade.buyAmount = amtShort;
trade.buyPrice = high;
maxes.deficit = delta;
}
}
}
}
// Use RSR if needed
if (address(trade.sell) == address(0) && address(trade.buy) != address(0)) {
IAsset rsrAsset = ctx.reg.toAsset(ctx.rsr);
uint192 rsrAvailable = rsrAsset.bal(address(ctx.bm)).plus(
rsrAsset.bal(address(ctx.stRSR))
);
(uint192 low, uint192 high) = rsrAsset.price(); // {UoA/tok}
(uint192 lotLow, ) = rsrAsset.lotPrice(); // {UoA/tok}
if (
high > 0 &&
TradeLib.isEnoughToSell(rsrAsset, rsrAvailable, lotLow, ctx.minTradeVolume)
) {
trade.sell = rsrAsset;
trade.sellAmount = rsrAvailable;
trade.sellPrice = low;
}
}
}
/// @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.17;
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}
uint192 sellPrice; // {UoA/sellTok} can be 0
uint192 buyPrice; // {UoA/buyTok}
}
/**
* @title TradeLib
* @notice An internal lib for preparing individual trades on particular asset pairs
* Users:
* - BackingManagerLib
* - 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 quantity to purchase.
/// @param trade:
/// sell != 0, sellAmount >= 0 {sellTok}, sellPrice >= 0 {UoA/sellTok}
/// buy != 0, buyAmount (unused) {buyTok}, buyPrice > 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.buyPrice ~=
// trade.sellAmount * trade.sellPrice * (1-maxTradeSlippage),
// req.sellAmount == min(trade.sell.maxTradeSize().toQTok(), trade.sellAmount.toQTok(sell)
// 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.buyPrice > 0 && trade.buyPrice < FIX_MAX && trade.sellPrice < FIX_MAX);
(uint192 lotLow, uint192 lotHigh) = trade.sell.lotPrice();
// Don't sell dust
if (!isEnoughToSell(trade.sell, trade.sellAmount, lotLow, minTradeVolume)) {
return (false, req);
}
// Cap sell amount
uint192 maxSell = maxTradeSize(trade.sell, lotHigh); // {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 = safeMulDivCeil(
ITrading(address(this)),
s.mul(FIX_ONE.minus(maxTradeSlippage)),
trade.sellPrice, // {UoA/sellTok}
trade.buyPrice // {UoA/buyTok}
);
// {*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 (true, 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 the sell asset's maxTradeVolume().
/// @param trade:
/// sell != 0
/// buy != 0
/// sellAmount (unused) {sellTok}
/// buyAmount >= 0 {buyTok}
/// sellPrice > 0 {UoA/sellTok}
/// buyPrice > 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 * (trade.buyPrice / trade.sellPrice) / (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()).toQTok(trade.buy)
// 1 < req.sellAmount <= min(trade.sellAmount.toQTok(trade.sell),
// sell.maxTradeSize().toQTok(trade.sell))
// req.minBuyAmount ~= trade.sellAmount * sellPrice / buyPrice * (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.sellPrice > 0 &&
trade.sellPrice < FIX_MAX &&
trade.buyPrice > 0 &&
trade.buyPrice < FIX_MAX
);
// Don't buy dust.
trade.buyAmount = fixMax(trade.buyAmount, minTradeSize(minTradeVolume, trade.buyPrice));
// {sellTok} = {buyTok} * {UoA/buyTok} / {UoA/sellTok}
uint192 exactSellAmount = trade.buyAmount.mulDiv(trade.buyPrice, trade.sellPrice, 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;
}
/// @return The result of FixLib.mulDiv bounded from above by FIX_MAX in the case of overflow
function safeMulDivCeil(
ITrading trader,
uint192 x,
uint192 y,
uint192 z
) internal pure returns (uint192) {
try trader.mulDivCeil(x, y, z) returns (uint192 result) {
return result;
} catch Panic(uint256 errorCode) {
// 0x11: overflow
// 0x12: div-by-zero
// untestable:
// Overflow is protected against and checked for in FixLib.mulDiv()
// Div-by-zero is NOT protected against, but no caller will ever use 0 for z
assert(errorCode == 0x11 || errorCode == 0x12);
} catch (bytes memory reason) {
assert(keccak256(reason) == UIntOutofBoundsHash);
}
return FIX_MAX;
}
// === 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 maxTradeSize for an asset based on the asset's maxTradeVolume and price
/// @return {tok} The max trade size for the asset in whole tokens
function maxTradeSize(IAsset asset, uint192 price) private view returns (uint192) {
// untestable:
// Price cannot be 0, it would've been filtered before in `prepareTradeSell`
uint192 size = price == 0 ? FIX_MAX : asset.maxTradeVolume().div(price, FLOOR);
return size > 0 ? size : 1;
}
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.17;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "../../interfaces/IAsset.sol";
import "./OracleLib.sol";
contract Asset is IAsset {
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} Seconds that an oracle value is considered valid
uint192 public immutable oracleError; // {1} The max % deviation allowed by the oracle
// === 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
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
/// @param low {UoA/tok} The low price estimate
/// @param 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 delta = p.mul(oracleError);
return (p - delta, p + delta, 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 >= priceTimeout) return (0, 0); // no price after timeout elapses
// {1} = {s} / {s}
uint192 lotMultiplier = divuu(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 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
/// @dev Use delegatecall
function claimRewards() external virtual {}
// solhint-enable no-empty-blocks
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.17;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "../../libraries/Fixed.sol";
error StalePrice();
/// Used by asset plugins to price their collateral
library OracleLib {
/// @dev Use for on-the-fly calculations that should revert
/// @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)
{
(uint80 roundId, int256 p, , uint256 updateTime, uint80 answeredInRound) = chainlinkFeed
.latestRoundData();
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();
// {UoA/tok}
return shiftl_toFix(uint256(p), -int8(chainlinkFeed.decimals()));
}
}// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.17;
import "../../p1/mixins/RecollateralizationLib.sol";
import "../../interfaces/IMain.sol";
import "../../interfaces/IRToken.sol";
import "./Asset.sol";
/// Once an RToken gets large enough to get a price feed, replacing this asset with
/// a simpler one will do wonders for gas usage
contract RTokenAsset is IAsset {
using FixLib for uint192;
using OracleLib for AggregatorV3Interface;
// Component addresses are not mutable in protocol, so it's safe to cache these
IBasketHandler public immutable basketHandler;
IAssetRegistry public immutable assetRegistry;
IBackingManager public immutable backingManager;
IERC20Metadata public immutable erc20;
uint8 public immutable erc20Decimals;
uint192 public immutable override maxTradeVolume; // {UoA}
/// @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");
IMain 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
/// @param low {UoA/tok} The low price estimate
/// @param high {UoA/tok} The high price estimate
function tryPrice() external view virtual returns (uint192 low, uint192 high) {
(uint192 lowBUPrice, uint192 highBUPrice) = basketHandler.price(); // {UoA/BU}
// 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);
high = range.top.mulDiv(highBUPrice, supply);
}
// solhint-disable no-empty-blocks
function refresh() public virtual override {
// No need to save lastPrice; can piggyback off the backing collateral's lotPrice()
}
// solhint-enable no-empty-blocks
/// Should not revert
/// @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) {
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
/// @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) {
(uint192 buLow, uint192 buHigh) = basketHandler.lotPrice(); // {UoA/BU}
// 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 (buLow, buHigh);
BasketRange memory range = basketRange(); // {BU}
// {UoA/tok} = {BU} * {UoA/BU} / {tok}
lotLow = range.bottom.mulDiv(buLow, supply);
lotHigh = range.top.mulDiv(buHigh, supply);
}
/// @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 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
/// @dev Use delegatecall
function claimRewards() external virtual {}
// solhint-enable no-empty-blocks
// ==== Private ====
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.
IMain main = backingManager.main();
TradingContext memory ctx = TradingContext({
basketsHeld: basketsHeld,
bm: backingManager,
bh: main.basketHandler(),
reg: main.assetRegistry(),
stRSR: main.stRSR(),
rsr: main.rsr(),
rToken: main.rToken(),
minTradeVolume: backingManager.minTradeVolume(),
maxTradeSlippage: backingManager.maxTradeSlippage()
});
Registry memory reg = assetRegistry.getRegistry();
// will exclude UoA value from RToken balances at BackingManager
range = RecollateralizationLibP1.basketRange(ctx, reg);
}
}
}{
"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"},{"internalType":"contract ITrade","name":"trade","type":"address"}],"internalType":"struct Implementations","name":"implementations_","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"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":"uint48","name":"tradingDelay","type":"uint48"},{"internalType":"uint48","name":"auctionLength","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":[],"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"},{"internalType":"contract ITrade","name":"trade","type":"address"}],"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
60e06040523480156200001157600080fd5b50604051620050d0380380620050d08339810160408190526200003491620003b0565b6001600160a01b038416158015906200005557506001600160a01b03831615155b80156200006a57506001600160a01b03821615155b801562000080575080516001600160a01b031615155b801562000099575060408101516001600160a01b031615155b8015620000b657506020810151604001516001600160a01b031615155b8015620000d357506020810151608001516001600160a01b031615155b8015620000f057506020810151606001516001600160a01b031615155b80156200010d5750602081015160e001516001600160a01b031615155b80156200012a5750602081015160a001516001600160a01b031615155b8015620001475750602081015160c001516001600160a01b031615155b8015620001655750602081015161010001516001600160a01b031615155b8015620001835750602081015161012001516001600160a01b031615155b80156200019d57506020810151516001600160a01b031615155b8015620001b9575060208082015101516001600160a01b031615155b620001fc5760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b604482015260640160405180910390fd5b6001600160a01b03938416608090815292841660a090815291841660c09081528151600080546001600160a01b03199081169288169290921790556020808401518051600180548516918a1691909117905590810151600280548416918916919091179055604080820151600380548516918a169190911790556060820151600480548516918a1691909117905595810151600580548416918916919091179055938401516006805483169188169190911790559083015160078054831691871691909117905560e083015160088054831691871691909117905561010083015160098054831691871691909117905561012090920151600a805484169186169190911790559190910151600b8054909216921691909117905562000537565b6001600160a01b03811681146200033257600080fd5b50565b604051606081016001600160401b03811182821017156200036657634e487b7160e01b600052604160045260246000fd5b60405290565b60405161014081016001600160401b03811182821017156200036657634e487b7160e01b600052604160045260246000fd5b8051620003ab816200031c565b919050565b6000806000808486036101e0811215620003c957600080fd5b8551620003d6816200031c565b6020870151909550620003e9816200031c565b6040870151909450620003fc816200031c565b9250610180605f1982018113156200041357600080fd5b6200041d62000335565b60608801516200042d816200031c565b8152610140607f1984018113156200044457600080fd5b6200044e6200036c565b93506200045e60808a016200039e565b84526200046e60a08a016200039e565b60208501526200048160c08a016200039e565b60408501526200049460e08a016200039e565b6060850152610100620004a9818b016200039e565b6080860152610120620004be818c016200039e565b60a0870152620004d0838c016200039e565b60c0870152620004e46101608c016200039e565b60e0870152620004f6858c016200039e565b82870152620005096101a08c016200039e565b81870152505050826020820152620005256101c089016200039e565b60408201529598949750929550505050565b60805160a05160c051614b4e62000582600039600081816101f30152610d8601526000818160dd0152610a9901526000818161021b015281816106e101526108a30152614b4e6000f3fe60806040523480156200001157600080fd5b5060043610620000875760003560e01c8063313eb1c21162000062578063313eb1c214620001b457806354fd4d5014620001cb578063929832ef14620001ed578063c99dc3dd146200021557600080fd5b80631d2e2cc4146200008c578063238c8aad14620000d757806330e9012c1462000118575b600080fd5b620000bf604051806040016040528060138152602001720e4cae6cae4eccae0e4dee8dec6ded85ccae8d606b1b81525081565b604051620000ce919062001582565b60405180910390f35b620000ff7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001620000ce565b60005460408051610140810182526001546001600160a01b039081168252600254811660208301526003548116928201929092526004548216606082015260055482166080820152600654821660a0820152600754821660c0820152600854821660e08201526009548216610100820152600a548216610120820152600b54620001a3938316921683565b604051620000ce9392919062001695565b620000ff620001c5366004620019ce565b6200023d565b6040805180820190915260058152640322e302e360dc1b6020820152620000bf565b620000ff7f000000000000000000000000000000000000000000000000000000000000000081565b620000ff7f000000000000000000000000000000000000000000000000000000000000000081565b60006001600160a01b038316158015906200026157506001600160a01b0383163014155b620002a25760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b21037bbb732b960991b604482015260640160405180910390fd5b6000805460408051838152602081019091526001600160a01b0390911690604051620002ce9062001512565b620002db92919062001abb565b604051809103906000f080158015620002f8573d6000803e3d6000fd5b5060015460408051600080825260208201928390529394506001600160a01b039092169190620003289062001512565b6200033592919062001abb565b604051809103906000f08015801562000352573d6000803e3d6000fd5b5060408051610140810182526001600160a01b0383811682526002548351600080825260208281019096529596509293840192911690604051620003969062001512565b620003a392919062001abb565b604051809103906000f080158015620003c0573d6000803e3d6000fd5b506001600160a01b0390811682526003546040805160008152602080820192839052909401939190921691620003f69062001512565b6200040392919062001abb565b604051809103906000f08015801562000420573d6000803e3d6000fd5b506001600160a01b0390811682526004546040805160008152602080820192839052909401939190921691620004569062001512565b6200046392919062001abb565b604051809103906000f08015801562000480573d6000803e3d6000fd5b506001600160a01b0390811682526005546040805160008152602080820192839052909401939190921691620004b69062001512565b620004c392919062001abb565b604051809103906000f080158015620004e0573d6000803e3d6000fd5b506001600160a01b0390811682526006546040805160008152602080820192839052909401939190921691620005169062001512565b6200052392919062001abb565b604051809103906000f08015801562000540573d6000803e3d6000fd5b506001600160a01b0390811682526007546040805160008152602080820192839052909401939190921691620005769062001512565b6200058392919062001abb565b604051809103906000f080158015620005a0573d6000803e3d6000fd5b506001600160a01b0390811682526008546040805160008152602080820192839052909401939190921691620005d69062001512565b620005e392919062001abb565b604051809103906000f08015801562000600573d6000803e3d6000fd5b506001600160a01b0390811682526009546040805160008152602080820192839052909401939190921691620006369062001512565b6200064392919062001abb565b604051809103906000f08015801562000660573d6000803e3d6000fd5b506001600160a01b039081168252600a546040805160008152602080820192839052909401939190921691620006969062001512565b620006a392919062001abb565b604051809103906000f080158015620006c0573d6000803e3d6000fd5b506001600160a01b03168152509050826001600160a01b031663992e1d6a827f0000000000000000000000000000000000000000000000000000000000000000886060015189608001516040518563ffffffff1660e01b81526004016200072b949392919062001ae9565b600060405180830381600087803b1580156200074657600080fd5b505af11580156200075b573d6000803e3d6000fd5b505050608082015160e087015161012088015161014089015160208a015160405163bcaeb7b960e01b81526001600160a01b038a8116600483015265ffffffffffff90951660248201526001600160c01b03938416604482015291831660648301529190911660848201529116915063bcaeb7b99060a401600060405180830381600087803b158015620007ee57600080fd5b505af115801562000803573d6000803e3d6000fd5b505050606082015160405163066ad14f60e21b81526001600160a01b03868116600483015290911691506319ab453c90602401600060405180830381600087803b1580156200085157600080fd5b505af115801562000866573d6000803e3d6000fd5b50505061010082015161014087015160208801516040516322c9f15d60e21b81526001600160a01b039093169350638b27c57492620008cc9288927f00000000000000000000000000000000000000000000000000000000000000009260040162001b2a565b600060405180830381600087803b158015620008e757600080fd5b505af1158015620008fc573d6000803e3d6000fd5b50505061012082015161014087015160208801516040516322c9f15d60e21b81526001600160a01b039093169350638b27c5749262000942928892889260040162001b2a565b600060405180830381600087803b1580156200095d57600080fd5b505af115801562000972573d6000803e3d6000fd5b5050505060a0810151855160405163133cdbb560e31b81526001600160a01b038681166004830152825161ffff908116602484015260209093015190921660448201529116906399e6dda890606401600060405180830381600087803b158015620009dc57600080fd5b505af1158015620009f1573d6000803e3d6000fd5b5050505060c081015160a0860151604051630f3058d560e31b81526001600160a01b0386811660048301526001600160c01b039092166024820152911690637982c6a890604401600060405180830381600087803b15801562000a5357600080fd5b505af115801562000a68573d6000803e3d6000fd5b5050505060e0810151600b5461010087015160405163642606a760e01b81526001600160a01b0387811660048301527f000000000000000000000000000000000000000000000000000000000000000081166024830152928316604482015265ffffffffffff909116606482015291169063642606a790608401600060405180830381600087803b15801562000afd57600080fd5b505af115801562000b12573d6000803e3d6000fd5b50505050600062000b238a62001390565b60405160200162000b35919062001b5e565b604051602081830303815290604052905060008160405160200162000b5b919062001b87565b6040516020818303038152906040529050846001600160a01b0316634780a5e56040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000bab573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000bd1919062001bb3565b6001600160a01b031663ac559da18683858b60c001518c60a001516040518663ffffffff1660e01b815260040162000c0e95949392919062001bd3565b600060405180830381600087803b15801562000c2957600080fd5b505af115801562000c3e573d6000803e3d6000fd5b50505050505080600001516001600160a01b031663f17d835c848c8c8c8c8b61016001518c61018001516040518863ffffffff1660e01b815260040162000c8c979695949392919062001c38565b600060405180830381600087803b15801562000ca757600080fd5b505af115801562000cbc573d6000803e3d6000fd5b50600092506002915062000ccd9050565b60405190808252806020026020018201604052801562000cf7578160200160208202803683370190505b5090508160000151866040015160405162000d129062001520565b6001600160a01b0390921682526001600160c01b03166020820152604001604051809103906000f08015801562000d4d573d6000803e3d6000fd5b508160008151811062000d645762000d6462001ce9565b60200260200101906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000000000000000000000000000000000000000000008160018151811062000dbb5762000dbb62001ce9565b6001600160a01b0392831660209182029290920101526040808401519051631e2d1e7560e11b8152911690633c5a3cea9062000dfe908790859060040162001cff565b600060405180830381600087803b15801562000e1957600080fd5b505af115801562000e2e573d6000803e3d6000fd5b50505050836001600160a01b0316632f2ff15d6040518060400160405280600581526020016427aba722a960d91b81525062000e6a9062001d5d565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b038a166024820152604401600060405180830381600087803b15801562000eb357600080fd5b505af115801562000ec8573d6000803e3d6000fd5b50505050836001600160a01b0316632f2ff15d6040518060400160405280600d81526020016c29a427a92a2fa32922a2ad22a960991b81525062000f0c9062001d5d565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b038a166024820152604401600060405180830381600087803b15801562000f5557600080fd5b505af115801562000f6a573d6000803e3d6000fd5b50505050836001600160a01b0316632f2ff15d6040518060400160405280600c81526020016b2627a723afa32922a2ad22a960a11b81525062000fad9062001d5d565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b038a166024820152604401600060405180830381600087803b15801562000ff657600080fd5b505af11580156200100b573d6000803e3d6000fd5b50505050836001600160a01b0316632f2ff15d604051806040016040528060068152602001652820aaa9a2a960d11b815250620010489062001d5d565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b038a166024820152604401600060405180830381600087803b1580156200109157600080fd5b505af1158015620010a6573d6000803e3d6000fd5b50505050836001600160a01b03166336568abe6040518060400160405280600581526020016427aba722a960d91b815250620010e29062001d5d565b6040516001600160e01b031960e084901b1681526004810191909152306024820152604401600060405180830381600087803b1580156200112257600080fd5b505af115801562001137573d6000803e3d6000fd5b50505050836001600160a01b03166336568abe6040518060400160405280600d81526020016c29a427a92a2fa32922a2ad22a960991b8152506200117b9062001d5d565b6040516001600160e01b031960e084901b1681526004810191909152306024820152604401600060405180830381600087803b158015620011bb57600080fd5b505af1158015620011d0573d6000803e3d6000fd5b50505050836001600160a01b03166336568abe6040518060400160405280600c81526020016b2627a723afa32922a2ad22a960a11b815250620012139062001d5d565b6040516001600160e01b031960e084901b1681526004810191909152306024820152604401600060405180830381600087803b1580156200125357600080fd5b505af115801562001268573d6000803e3d6000fd5b50505050836001600160a01b03166336568abe604051806040016040528060068152602001652820aaa9a2a960d11b815250620012a59062001d5d565b6040516001600160e01b031960e084901b1681526004810191909152306024820152604401600060405180830381600087803b158015620012e557600080fd5b505af1158015620012fa573d6000803e3d6000fd5b50505050866001600160a01b031682600001516001600160a01b0316856001600160a01b03167f27a62b7d4a7ee7a705ae91fe5a3ad74f32fc3d14e82eb82c3730630601ce9ae68560200151620013696040805180820190915260058152640322e302e360dc1b602082015290565b6040516200137992919062001abb565b60405180910390a450519998505050505050505050565b606060008290506000815167ffffffffffffffff811115620013b657620013b6620016c9565b6040519080825280601f01601f191660200182016040528015620013e1576020820181803683370190505b50905060005b82518110156200150a57604183828151811062001408576200140862001ce9565b016020015160f81c108015906200143c5750605a83828151811062001431576200143162001ce9565b016020015160f81c11155b15620014a85782818151811062001457576200145762001ce9565b602001015160f81c60f81b60f81c602062001473919062001d9b565b60f81b8282815181106200148b576200148b62001ce9565b60200101906001600160f81b031916908160001a905350620014f5565b828181518110620014bd57620014bd62001ce9565b602001015160f81c60f81b828281518110620014dd57620014dd62001ce9565b60200101906001600160f81b031916908160001a9053505b80620015018162001dbd565b915050620013e7565b509392505050565b61070d8062001dda83390190565b61263280620024e783390190565b60005b838110156200154b57818101518382015260200162001531565b50506000910152565b600081518084526200156e8160208601602086016200152e565b601f01601f19169290920160200192915050565b60208152600062001597602083018462001554565b9392505050565b80516001600160a01b031682526020810151620015c660208401826001600160a01b03169052565b506040810151620015e260408401826001600160a01b03169052565b506060810151620015fe60608401826001600160a01b03169052565b5060808101516200161a60808401826001600160a01b03169052565b5060a08101516200163660a08401826001600160a01b03169052565b5060c08101516200165260c08401826001600160a01b03169052565b5060e08101516200166e60e08401826001600160a01b03169052565b50610100818101516001600160a01b03908116918401919091526101209182015116910152565b6001600160a01b038481168252610180820190620016b760208401866200159e565b80841661016084015250949350505050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715620017055762001705620016c9565b60405290565b6040516101a0810167ffffffffffffffff81118282101715620017055762001705620016c9565b600082601f8301126200174457600080fd5b813567ffffffffffffffff80821115620017625762001762620016c9565b604051601f8301601f19908116603f011681019082821181831017156200178d576200178d620016c9565b81604052838152866020858801011115620017a757600080fd5b836020870160208301376000602085830101528094505050505092915050565b6001600160a01b0381168114620017dd57600080fd5b50565b8035620017ed81620017c7565b919050565b803561ffff81168114620017ed57600080fd5b6000604082840312156200181857600080fd5b62001822620016df565b90506200182f82620017f2565b81526200183f60208301620017f2565b602082015292915050565b80356001600160c01b0381168114620017ed57600080fd5b803565ffffffffffff81168114620017ed57600080fd5b6000604082840312156200188c57600080fd5b62001896620016df565b9050813581526200183f602083016200184a565b60006102008284031215620018be57600080fd5b620018c86200170b565b9050620018d6838362001805565b8152620018e6604083016200184a565b6020820152620018f9606083016200184a565b60408201526200190c6080830162001862565b60608201526200191f60a0830162001862565b60808201526200193260c083016200184a565b60a08201526200194560e0830162001862565b60c08201526101006200195a81840162001862565b60e08301526101206200196f81850162001862565b828401526101409150620019858285016200184a565b90830152610160620019998482016200184a565b828401526101809150620019b08583860162001879565b90830152620019c4846101c0850162001879565b9082015292915050565b6000806000806000806102808789031215620019e957600080fd5b863567ffffffffffffffff8082111562001a0257600080fd5b62001a108a838b0162001732565b9750602089013591508082111562001a2757600080fd5b62001a358a838b0162001732565b9650604089013591508082111562001a4c57600080fd5b818901915089601f83011262001a6157600080fd5b81358181111562001a7157600080fd5b8a602082850101111562001a8457600080fd5b60208301965080955050505062001a9e60608801620017e0565b915062001aaf8860808901620018aa565b90509295509295509295565b6001600160a01b038316815260406020820181905260009062001ae19083018462001554565b949350505050565b6101a0810162001afa82876200159e565b6001600160a01b039490941661014082015265ffffffffffff928316610160820152911661018090910152919050565b6001600160a01b0394851681529290931660208301526001600160c01b039081166040830152909116606082015260800190565b6000825162001b728184602087016200152e565b622929a960e91b920191825250600301919050565b6000825162001b9b8184602087016200152e565b65102a37b5b2b760d11b920191825250600601919050565b60006020828403121562001bc657600080fd5b81516200159781620017c7565b6001600160a01b038616815260a06020820181905260009062001bf99083018762001554565b828103604084015262001c0d818762001554565b65ffffffffffff95909516606084015250506001600160c01b03919091166080909101529392505050565b6001600160a01b03881681526101006020820181905260009062001c5f8382018a62001554565b9050828103604084015262001c75818962001554565b90508281036060840152858152858760208301376000602087830101526020601f19601f88011682010191505062001cc36080830185805182526020908101516001600160c01b0316910152565b825160c083015260208301516001600160c01b031660e083015298975050505050505050565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b038381168252604060208084018290528451918401829052600092858201929091906060860190855b8181101562001d4f57855185168352948301949183019160010162001d2f565b509098975050505050505050565b8051602080830151919081101562001d7f576000198160200360031b1b821691505b50919050565b634e487b7160e01b600052601160045260246000fd5b60ff818116838216019081111562001db75762001db762001d85565b92915050565b60006001820162001dd25762001dd262001d85565b506001019056fe608060405260405161070d38038061070d8339810160408190526100229161030c565b61002e82826000610035565b5050610429565b61003e8361006b565b60008251118061004b5750805b156100665761006483836100ab60201b6100291760201c565b505b505050565b610074816100d7565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606100d083836040518060600160405280602781526020016106e6602791396101a9565b9392505050565b6100ea8161028760201b6100551760201c565b6101515760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b806101887f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b61029660201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606001600160a01b0384163b6102115760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610148565b600080856001600160a01b03168560405161022c91906103da565b600060405180830381855af49150503d8060008114610267576040519150601f19603f3d011682016040523d82523d6000602084013e61026c565b606091505b50909250905061027d828286610299565b9695505050505050565b6001600160a01b03163b151590565b90565b606083156102a85750816100d0565b8251156102b85782518084602001fd5b8160405162461bcd60e51b815260040161014891906103f6565b634e487b7160e01b600052604160045260246000fd5b60005b838110156103035781810151838201526020016102eb565b50506000910152565b6000806040838503121561031f57600080fd5b82516001600160a01b038116811461033657600080fd5b60208401519092506001600160401b038082111561035357600080fd5b818501915085601f83011261036757600080fd5b815181811115610379576103796102d2565b604051601f8201601f19908116603f011681019083821181831017156103a1576103a16102d2565b816040528281528860208487010111156103ba57600080fd5b6103cb8360208301602088016102e8565b80955050505050509250929050565b600082516103ec8184602087016102e8565b9190910192915050565b60208152600082518060208401526104158160408501602087016102e8565b601f01601f19169190910160400192915050565b6102ae806104386000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b61009f565b565b606061004e8383604051806060016040528060278152602001610252602791396100c3565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156100be573d6000f35b3d6000fd5b60606001600160a01b0384163b6101305760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084015b60405180910390fd5b600080856001600160a01b03168560405161014b9190610202565b600060405180830381855af49150503d8060008114610186576040519150601f19603f3d011682016040523d82523d6000602084013e61018b565b606091505b509150915061019b8282866101a5565b9695505050505050565b606083156101b457508161004e565b8251156101c45782518084602001fd5b8160405162461bcd60e51b8152600401610127919061021e565b60005b838110156101f95781810151838201526020016101e1565b50506000910152565b600082516102148184602087016101de565b9190910192915050565b602081526000825180602084015261023d8160408501602087016101de565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220db939c051e19763602ef3156f6b81bc6bc3dbeeff1b6514103fdcb69ddee4a5364736f6c63430008110033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65646101406040523480156200001257600080fd5b506040516200263238038062002632833981016040819052620000359162000352565b6001600160a01b038216620000815760405162461bcd60e51b815260206004820152600d60248201526c06d697373696e6720657263323609c1b60448201526064015b60405180910390fd5b6000816001600160c01b031611620000dc5760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206d617820747261646520766f6c756d650000000000000000604482015260640162000078565b6000826001600160a01b031663dffeadd06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200011d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200014391906200039c565b9050806001600160a01b0316632f2439b16040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000184573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001aa91906200039c565b6001600160a01b03166080816001600160a01b031681525050806001600160a01b031663979d7e866040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000202573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022891906200039c565b6001600160a01b031660a0816001600160a01b031681525050806001600160a01b031663dc8af5f66040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000280573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002a691906200039c565b6001600160a01b0390811660c052831660e08190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015620002f7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200031d9190620003c3565b60ff1661010052506001600160c01b03166101205250620003e8565b6001600160a01b03811681146200034f57600080fd5b50565b600080604083850312156200036657600080fd5b8251620003738162000339565b60208401519092506001600160c01b03811681146200039157600080fd5b809150509250929050565b600060208284031215620003af57600080fd5b8151620003bc8162000339565b9392505050565b600060208284031215620003d657600080fd5b815160ff81168114620003bc57600080fd5b60805160a05160c05160e05161010051610120516121a66200048c60003960006101da015260006101470152600081816101ab015281816102f301528181610404015261068901526000818161023f015281816105ec01528181610741015281816107d901528181610a380152610ac80152600081816102010152610b5a0152600081816101060152818161026901528181610459015261061701526121a66000f3fe608060405234801561001057600080fd5b50600436106100cf5760003560e01c80637d1ea1371161008c578063a035b1fe11610066578063a035b1fe14610223578063c59b3d631461022b578063dc8af5f61461023a578063f8ac93e81461014057600080fd5b80637d1ea137146101cd57806395acc4ae146101d5578063979d7e86146101fc57600080fd5b8063271181ec146100d45780632f2439b114610101578063372500ab146101405780633cb5d379146101425780635580f72a1461017b578063785e9e86146101a6575b600080fd5b6100dc610261565b604080516001600160c01b039384168152929091166020830152015b60405180910390f35b6101287f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100f8565b005b6101697f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016100f8565b61018e610189366004611b66565b6103de565b6040516001600160c01b0390911681526020016100f8565b6101287f000000000000000000000000000000000000000000000000000000000000000081565b6100dc610451565b61018e7f000000000000000000000000000000000000000000000000000000000000000081565b6101287f000000000000000000000000000000000000000000000000000000000000000081565b6100dc6104b4565b604051600081526020016100f8565b6101287f000000000000000000000000000000000000000000000000000000000000000081565b6000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663271181ec6040518163ffffffff1660e01b81526004016040805180830381865afa1580156102c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102e89190611b9f565b9150915060006103787f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561034f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103739190611bd2565b610593565b9050806001600160c01b0316600003610395575090939092509050565b600061039f6105c1565b80519091506103b8906001600160c01b03168584610bf4565b60208201519096506103d4906001600160c01b03168484610bf4565b9450505050509091565b6040516370a0823160e01b81526001600160a01b03828116600483015260009161044b917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561034f573d6000803e3d6000fd5b92915050565b6000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a035b1fe6040518163ffffffff1660e01b81526004016040805180830381865afa1580156102c4573d6000803e3d6000fd5b600080306001600160a01b0316637d1ea1376040518163ffffffff1660e01b81526004016040805180830381865afa925050508015610510575060408051601f3d908101601f1916820190925261050d91810190611b9f565b60015b610564573d80801561053e576040519150601f19603f3d011682016040523d82523d6000602084013e610543565b606091505b50805160000361055257600080fd5b506000926001600160c01b0392509050565b806001600160c01b0316826001600160c01b0316111561058657610586611beb565b90939092509050565b9091565b60006001600160c01b038211156105bd5760405163f44398f560e01b815260040160405180910390fd5b5090565b6040805180820190915260008082526020820152604051635523caaf60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063aa47955e906024016040805180830381865afa15801561065f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106839190611c71565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637121c2736040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107099190611ccc565b9050806001600160c01b031682600001516001600160c01b03161061073d576001600160c01b031680835260208301525090565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dffeadd06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561079d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c19190611ce7565b905060006040518061012001604052808581526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001836001600160a01b0316632f2439b16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610844573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108689190611ce7565b6001600160a01b03168152602001836001600160a01b031663979d7e866040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d89190611ce7565b6001600160a01b03168152602001836001600160a01b0316634780a5e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015610924573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109489190611ce7565b6001600160a01b03168152602001836001600160a01b031663c99dc3dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610994573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b89190611ce7565b6001600160a01b03168152602001836001600160a01b03166340c65f726040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a289190611ce7565b6001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637cbf6db26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab89190611ccc565b6001600160c01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630db3d42c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b489190611ccc565b6001600160c01b0316815250905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635ab1bd536040518163ffffffff1660e01b8152600401600060405180830381865afa158015610bb6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bde9190810190611d9c565b9050610bea8282610c0d565b9550505050505090565b6000610c0384848460006114e7565b90505b9392505050565b604080518082019091526000808252602082015260008084604001516001600160a01b031663a035b1fe6040518163ffffffff1660e01b81526004016040805180830381865afa158015610c65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c899190611b9f565b915091508460c001516001600160a01b0316637121c2736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ccf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf39190611ccc565b6001600160c01b03168560000151602001516001600160c01b03161115610d8e578460c001516001600160a01b0316637121c2736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7a9190611ccc565b85516001600160c01b039091166020909101525b6000805b8551518110156112f2578660c001516001600160a01b031686600001518281518110610dc057610dc0611e8a565b60200260200101516001600160a01b031603156112e257600086602001518281518110610def57610def611e8a565b60209081029190910181015190890151604051632ac07b9560e11b81526001600160a01b039182166004820152911690635580f72a90602401602060405180830381865afa158015610e45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e699190611ccc565b90508760a001516001600160a01b031687600001518381518110610e8f57610e8f611e8a565b60200260200101516001600160a01b031603610f4b57610f4887602001518381518110610ebe57610ebe611e8a565b602090810291909101015160808a0151604051632ac07b9560e11b81526001600160a01b039182166004820152911690635580f72a90602401602060405180830381865afa158015610f14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f389190611ccc565b6001600160c01b0383169061151e565b90505b600088604001516001600160a01b031663d3252db589600001518581518110610f7657610f76611e8a565b60200260200101518a602001518681518110610f9457610f94611e8a565b60200260200101516040518363ffffffff1660e01b8152600401610fce9291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa158015610feb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100f9190611ccc565b905060008860200151848151811061102957611029611e8a565b60200260200101516001600160a01b031663271181ec6040518163ffffffff1660e01b81526004016040805180830381865afa15801561106d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110919190611b9f565b5090506001600160c01b0382161580156110d557506110d3896020015185815181106110bf576110bf611e8a565b602002602001015184838d60e0015161152a565b155b156110e2575050506112e2565b50600080896020015185815181106110fc576110fc611e8a565b60200260200101516001600160a01b031663a035b1fe6040518163ffffffff1660e01b81526004016040805180830381865afa158015611140573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111649190611b9f565b8c51602001519193509150600090611188906001600160c01b0386169060026115d4565b9050846001600160c01b0316816001600160c01b031611156111de576111c46111b18683611eb6565b6001600160c01b038516908a60006114e7565b6111d7906001600160c01b031688611edd565b9650611218565b611202826111ec8388611eb6565b60208f01516001600160a01b031691908c611601565b611215906001600160c01b031688611efd565b96505b508a5151600090611234906001600160c01b03861690836115d4565b905060006112576112458388611eb6565b6001600160c01b0386169060006115d4565b90508c60e001516001600160c01b0316816001600160c01b03161061128a5760e08d01516112859082611eb6565b61128d565b60005b6101008e01519091506112c0906112ad90670de0b6b3a764000090611754565b6001600160c01b038316908b60006114e7565b8b518c906112cf908390611f25565b6001600160c01b03169052505050505050505b6112eb81611f45565b9050610d92565b50600081121561132b5761130861037382611f5e565b8651602001516113189190611eb6565b6001600160c01b03166020850152611386565b8551602001516001600160c01b039061134690821683611f7a565b111561135e576001600160c01b036020850152611386565b61136781610593565b8651602001516113779190611f25565b6001600160c01b031660208501525b85515184518590611398908390611f25565b9150906001600160c01b031690816001600160c01b0316815250508560c001516001600160a01b0316637121c2736040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114199190611ccc565b6001600160c01b031684602001516001600160c01b031611156114ab578560c001516001600160a01b0316637121c2736040518163ffffffff1660e01b8152600401602060405180830381865afa158015611478573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149c9190611ccc565b6001600160c01b031660208501525b83602001516001600160c01b031684600001516001600160c01b031611156114de5760208401516001600160c01b031684525b50505092915050565b6000611513610373866001600160c01b0316866001600160c01b0316866001600160c01b031686611760565b90505b949350505050565b6000610c068284611f25565b600061154c611539838561180d565b6001600160c01b03908116908616101590565b8015611513575060016115ca866001600160a01b0316633cb5d3796040518163ffffffff1660e01b8152600401602060405180830381865afa158015611596573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ba9190611f8d565b6001600160c01b0387169061185c565b1195945050505050565b6000610c036103736115f26001600160c01b03808716908816611fb0565b670de0b6b3a76400008561186a565b60405163551ef62560e01b81526001600160c01b0380851660048301528084166024830152821660448201526000906001600160a01b0386169063551ef62590606401602060405180830381865afa92505050801561167d575060408051601f3d908101601f1916820190925261167a91810190611ccc565b60015b61173c57611689611fc7565b634e487b71036116c75761169b611fe3565b906116a657506116c7565b80601114806116b55750806012145b6116c1576116c1611beb565b50611743565b3d8080156116f1576040519150601f19603f3d011682016040523d82523d6000602084013e6116f6565b606091505b50604080516004815260248101909152602080820180516001600160e01b031663f44398f560e01b1781529151909120825191830191909120146116c1576116c1611beb565b9050611516565b506001600160c01b03949350505050565b6000610c068284611eb6565b60008061176e868686611912565b9050600083600281111561178457611784612000565b03611790579050611516565b600084806117a0576117a0612016565b868809905060028460028111156117b9576117b9612000565b036117d75780156117d2576117cf600183611f7a565b91505b611803565b60026117e460018761202c565b6117ee919061203f565b81111561180357611800600183611f7a565b91505b5095945050505050565b6000806001600160c01b03831615611839576118346001600160c01b0385168460026119f5565b611842565b6001600160c01b035b90506000816001600160c01b031611610c06576001611516565b6000610c0683836000611a28565b600080611877848661203f565b9050600083600281111561188d5761188d612000565b03611899579050610c06565b60018360028111156118ad576118ad612000565b036118ec5760026118bf60018661202c565b6118c9919061203f565b6118d38587612053565b11156118e757806118e381611f45565b9150505b610c03565b60006118f88587612053565b1115610c03578061190881611f45565b9695505050505050565b60008060006119218686611b09565b915091508382106119455760405163f44398f560e01b815260040160405180910390fd5b6000848061195557611955612016565b868809905081811115611969576001830392505b90819003906000859003851680868161198457611984612016565b04955080838161199657611996612016565b0492508081600003816119ab576119ab612016565b046001019390930291909101600285810380870282030280870282030280870282030280870282030280870282030280870282030295860290039094029390930295945050505050565b6000610c03610373611a18670de0b6b3a76400006001600160c01b038816611fb0565b856001600160c01b03168561186a565b6000836001600160c01b0316600003611a4357506000610c06565b6029198360000b13611a7c576002826002811115611a6357611a63612000565b14611a6f576000611a72565b60015b60ff169050610c06565b8260000b606013611aa05760405163f44398f560e01b815260040160405180910390fd5b611aab601284612067565b92506000611abb8460000b611b36565b611ac690600a612164565b905060008460000b1215611aed57611ae8856001600160c01b0316828561186a565b611b00565b611b00816001600160c01b038716611fb0565b95945050505050565b6000808060001984860990508385029150818103925081811015611b2e576001830392505b509250929050565b6000808212611b45578161044b565b61044b82611f5e565b6001600160a01b0381168114611b6357600080fd5b50565b600060208284031215611b7857600080fd5b8135610c0681611b4e565b80516001600160c01b0381168114611b9a57600080fd5b919050565b60008060408385031215611bb257600080fd5b611bbb83611b83565b9150611bc960208401611b83565b90509250929050565b600060208284031215611be457600080fd5b5051919050565b634e487b7160e01b600052600160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611c3a57611c3a611c01565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611c6957611c69611c01565b604052919050565b600060408284031215611c8357600080fd5b6040516040810181811067ffffffffffffffff82111715611ca657611ca6611c01565b604052611cb283611b83565b8152611cc060208401611b83565b60208201529392505050565b600060208284031215611cde57600080fd5b610c0682611b83565b600060208284031215611cf957600080fd5b8151610c0681611b4e565b600067ffffffffffffffff821115611d1e57611d1e611c01565b5060051b60200190565b600082601f830112611d3957600080fd5b81516020611d4e611d4983611d04565b611c40565b82815260059290921b84018101918181019086841115611d6d57600080fd5b8286015b84811015611d91578051611d8481611b4e565b8352918301918301611d71565b509695505050505050565b60006020808385031215611daf57600080fd5b825167ffffffffffffffff80821115611dc757600080fd5b9084019060408287031215611ddb57600080fd5b611de3611c17565b825182811115611df257600080fd5b8301601f81018813611e0357600080fd5b8051611e11611d4982611d04565b81815260059190911b8201860190868101908a831115611e3057600080fd5b928701925b82841015611e57578351611e4881611b4e565b82529287019290870190611e35565b84525050508284015182811115611e6d57600080fd5b611e7988828601611d28565b948201949094529695505050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6001600160c01b03828116828216039080821115611ed657611ed6611ea0565b5092915050565b8181036000831280158383131683831282161715611ed657611ed6611ea0565b8082018281126000831280158216821582161715611f1d57611f1d611ea0565b505092915050565b6001600160c01b03818116838216019080821115611ed657611ed6611ea0565b600060018201611f5757611f57611ea0565b5060010190565b6000600160ff1b8201611f7357611f73611ea0565b5060000390565b8082018082111561044b5761044b611ea0565b600060208284031215611f9f57600080fd5b815160ff81168114610c0657600080fd5b808202811582820484141761044b5761044b611ea0565b600060033d1115611fe05760046000803e5060005160e01c5b90565b60008060233d111561058f576020600460003e5050600051600191565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b8181038181111561044b5761044b611ea0565b60008261204e5761204e612016565b500490565b60008261206257612062612016565b500690565b600082810b9082900b03607f198112607f8213171561044b5761044b611ea0565b600181815b80851115611b2e5781600019048211156120a9576120a9611ea0565b808516156120b657918102915b93841c939080029061208d565b6000826120d25750600161044b565b816120df5750600061044b565b81600181146120f557600281146120ff5761211b565b600191505061044b565b60ff84111561211057612110611ea0565b50506001821b61044b565b5060208310610133831016604e8410600b841016171561213e575081810a61044b565b6121488383612088565b806000190482111561215c5761215c611ea0565b029392505050565b6000610c0683836120c356fea2646970667358221220afb6ebec2a42c95a52d07d1438c4244016326489b424f104a60e7cd1ccbcbea964736f6c63430008110033a2646970667358221220880cb5fd832583d1046272d8f08eced9e8b9e28550463d890521df0a925c939c64736f6c63430008110033000000000000000000000000320623b8e4ff03373931769a31fc52a4e78b5d700000000000000000000000000b7ffc1f4ad541a4ed16b40d8c37f0929158d1010000000000000000000000002c312da96f98a5b7822270f69afd2d7ae8e748dc000000000000000000000000143c35bfe04720394ebd18abeca83ea9d8bede2f000000000000000000000000ecbba78d8cd654dfc582cb7fcf31d8a2a0b7a6cc00000000000000000000000030b29539b5302ebce52479275dfc9dfabb66a0470000000000000000000000005a004f70b2450e909b4048050c585549ab8afeb80000000000000000000000000ef3c7fe9c1cf7352d52e2867652b7547defdbe5000000000000000000000000a0d4b6ad503e776457dbf4695d462ddf8621a1cc000000000000000000000000c78c5a84f30317b5f7d87170ec21dc73df38d569000000000000000000000000393002573ea4a3d74a80f3b1af436a3ee3a30c960000000000000000000000005a0f5e19e963206ec78fe8bf5fa53108918dd898000000000000000000000000e5bd2249118b6a4b39be195951579dc9af05029a000000000000000000000000e5bd2249118b6a4b39be195951579dc9af05029a000000000000000000000000ac543ee89a2238945f7d7ad4d9cf958721f9757c
Deployed Bytecode
0x60806040523480156200001157600080fd5b5060043610620000875760003560e01c8063313eb1c21162000062578063313eb1c214620001b457806354fd4d5014620001cb578063929832ef14620001ed578063c99dc3dd146200021557600080fd5b80631d2e2cc4146200008c578063238c8aad14620000d757806330e9012c1462000118575b600080fd5b620000bf604051806040016040528060138152602001720e4cae6cae4eccae0e4dee8dec6ded85ccae8d606b1b81525081565b604051620000ce919062001582565b60405180910390f35b620000ff7f0000000000000000000000000b7ffc1f4ad541a4ed16b40d8c37f0929158d10181565b6040516001600160a01b039091168152602001620000ce565b60005460408051610140810182526001546001600160a01b039081168252600254811660208301526003548116928201929092526004548216606082015260055482166080820152600654821660a0820152600754821660c0820152600854821660e08201526009548216610100820152600a548216610120820152600b54620001a3938316921683565b604051620000ce9392919062001695565b620000ff620001c5366004620019ce565b6200023d565b6040805180820190915260058152640322e302e360dc1b6020820152620000bf565b620000ff7f0000000000000000000000002c312da96f98a5b7822270f69afd2d7ae8e748dc81565b620000ff7f000000000000000000000000320623b8e4ff03373931769a31fc52a4e78b5d7081565b60006001600160a01b038316158015906200026157506001600160a01b0383163014155b620002a25760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b21037bbb732b960991b604482015260640160405180910390fd5b6000805460408051838152602081019091526001600160a01b0390911690604051620002ce9062001512565b620002db92919062001abb565b604051809103906000f080158015620002f8573d6000803e3d6000fd5b5060015460408051600080825260208201928390529394506001600160a01b039092169190620003289062001512565b6200033592919062001abb565b604051809103906000f08015801562000352573d6000803e3d6000fd5b5060408051610140810182526001600160a01b0383811682526002548351600080825260208281019096529596509293840192911690604051620003969062001512565b620003a392919062001abb565b604051809103906000f080158015620003c0573d6000803e3d6000fd5b506001600160a01b0390811682526003546040805160008152602080820192839052909401939190921691620003f69062001512565b6200040392919062001abb565b604051809103906000f08015801562000420573d6000803e3d6000fd5b506001600160a01b0390811682526004546040805160008152602080820192839052909401939190921691620004569062001512565b6200046392919062001abb565b604051809103906000f08015801562000480573d6000803e3d6000fd5b506001600160a01b0390811682526005546040805160008152602080820192839052909401939190921691620004b69062001512565b620004c392919062001abb565b604051809103906000f080158015620004e0573d6000803e3d6000fd5b506001600160a01b0390811682526006546040805160008152602080820192839052909401939190921691620005169062001512565b6200052392919062001abb565b604051809103906000f08015801562000540573d6000803e3d6000fd5b506001600160a01b0390811682526007546040805160008152602080820192839052909401939190921691620005769062001512565b6200058392919062001abb565b604051809103906000f080158015620005a0573d6000803e3d6000fd5b506001600160a01b0390811682526008546040805160008152602080820192839052909401939190921691620005d69062001512565b620005e392919062001abb565b604051809103906000f08015801562000600573d6000803e3d6000fd5b506001600160a01b0390811682526009546040805160008152602080820192839052909401939190921691620006369062001512565b6200064392919062001abb565b604051809103906000f08015801562000660573d6000803e3d6000fd5b506001600160a01b039081168252600a546040805160008152602080820192839052909401939190921691620006969062001512565b620006a392919062001abb565b604051809103906000f080158015620006c0573d6000803e3d6000fd5b506001600160a01b03168152509050826001600160a01b031663992e1d6a827f000000000000000000000000320623b8e4ff03373931769a31fc52a4e78b5d70886060015189608001516040518563ffffffff1660e01b81526004016200072b949392919062001ae9565b600060405180830381600087803b1580156200074657600080fd5b505af11580156200075b573d6000803e3d6000fd5b505050608082015160e087015161012088015161014089015160208a015160405163bcaeb7b960e01b81526001600160a01b038a8116600483015265ffffffffffff90951660248201526001600160c01b03938416604482015291831660648301529190911660848201529116915063bcaeb7b99060a401600060405180830381600087803b158015620007ee57600080fd5b505af115801562000803573d6000803e3d6000fd5b505050606082015160405163066ad14f60e21b81526001600160a01b03868116600483015290911691506319ab453c90602401600060405180830381600087803b1580156200085157600080fd5b505af115801562000866573d6000803e3d6000fd5b50505061010082015161014087015160208801516040516322c9f15d60e21b81526001600160a01b039093169350638b27c57492620008cc9288927f000000000000000000000000320623b8e4ff03373931769a31fc52a4e78b5d709260040162001b2a565b600060405180830381600087803b158015620008e757600080fd5b505af1158015620008fc573d6000803e3d6000fd5b50505061012082015161014087015160208801516040516322c9f15d60e21b81526001600160a01b039093169350638b27c5749262000942928892889260040162001b2a565b600060405180830381600087803b1580156200095d57600080fd5b505af115801562000972573d6000803e3d6000fd5b5050505060a0810151855160405163133cdbb560e31b81526001600160a01b038681166004830152825161ffff908116602484015260209093015190921660448201529116906399e6dda890606401600060405180830381600087803b158015620009dc57600080fd5b505af1158015620009f1573d6000803e3d6000fd5b5050505060c081015160a0860151604051630f3058d560e31b81526001600160a01b0386811660048301526001600160c01b039092166024820152911690637982c6a890604401600060405180830381600087803b15801562000a5357600080fd5b505af115801562000a68573d6000803e3d6000fd5b5050505060e0810151600b5461010087015160405163642606a760e01b81526001600160a01b0387811660048301527f0000000000000000000000000b7ffc1f4ad541a4ed16b40d8c37f0929158d10181166024830152928316604482015265ffffffffffff909116606482015291169063642606a790608401600060405180830381600087803b15801562000afd57600080fd5b505af115801562000b12573d6000803e3d6000fd5b50505050600062000b238a62001390565b60405160200162000b35919062001b5e565b604051602081830303815290604052905060008160405160200162000b5b919062001b87565b6040516020818303038152906040529050846001600160a01b0316634780a5e56040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000bab573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000bd1919062001bb3565b6001600160a01b031663ac559da18683858b60c001518c60a001516040518663ffffffff1660e01b815260040162000c0e95949392919062001bd3565b600060405180830381600087803b15801562000c2957600080fd5b505af115801562000c3e573d6000803e3d6000fd5b50505050505080600001516001600160a01b031663f17d835c848c8c8c8c8b61016001518c61018001516040518863ffffffff1660e01b815260040162000c8c979695949392919062001c38565b600060405180830381600087803b15801562000ca757600080fd5b505af115801562000cbc573d6000803e3d6000fd5b50600092506002915062000ccd9050565b60405190808252806020026020018201604052801562000cf7578160200160208202803683370190505b5090508160000151866040015160405162000d129062001520565b6001600160a01b0390921682526001600160c01b03166020820152604001604051809103906000f08015801562000d4d573d6000803e3d6000fd5b508160008151811062000d645762000d6462001ce9565b60200260200101906001600160a01b031690816001600160a01b0316815250507f0000000000000000000000002c312da96f98a5b7822270f69afd2d7ae8e748dc8160018151811062000dbb5762000dbb62001ce9565b6001600160a01b0392831660209182029290920101526040808401519051631e2d1e7560e11b8152911690633c5a3cea9062000dfe908790859060040162001cff565b600060405180830381600087803b15801562000e1957600080fd5b505af115801562000e2e573d6000803e3d6000fd5b50505050836001600160a01b0316632f2ff15d6040518060400160405280600581526020016427aba722a960d91b81525062000e6a9062001d5d565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b038a166024820152604401600060405180830381600087803b15801562000eb357600080fd5b505af115801562000ec8573d6000803e3d6000fd5b50505050836001600160a01b0316632f2ff15d6040518060400160405280600d81526020016c29a427a92a2fa32922a2ad22a960991b81525062000f0c9062001d5d565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b038a166024820152604401600060405180830381600087803b15801562000f5557600080fd5b505af115801562000f6a573d6000803e3d6000fd5b50505050836001600160a01b0316632f2ff15d6040518060400160405280600c81526020016b2627a723afa32922a2ad22a960a11b81525062000fad9062001d5d565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b038a166024820152604401600060405180830381600087803b15801562000ff657600080fd5b505af11580156200100b573d6000803e3d6000fd5b50505050836001600160a01b0316632f2ff15d604051806040016040528060068152602001652820aaa9a2a960d11b815250620010489062001d5d565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b038a166024820152604401600060405180830381600087803b1580156200109157600080fd5b505af1158015620010a6573d6000803e3d6000fd5b50505050836001600160a01b03166336568abe6040518060400160405280600581526020016427aba722a960d91b815250620010e29062001d5d565b6040516001600160e01b031960e084901b1681526004810191909152306024820152604401600060405180830381600087803b1580156200112257600080fd5b505af115801562001137573d6000803e3d6000fd5b50505050836001600160a01b03166336568abe6040518060400160405280600d81526020016c29a427a92a2fa32922a2ad22a960991b8152506200117b9062001d5d565b6040516001600160e01b031960e084901b1681526004810191909152306024820152604401600060405180830381600087803b158015620011bb57600080fd5b505af1158015620011d0573d6000803e3d6000fd5b50505050836001600160a01b03166336568abe6040518060400160405280600c81526020016b2627a723afa32922a2ad22a960a11b815250620012139062001d5d565b6040516001600160e01b031960e084901b1681526004810191909152306024820152604401600060405180830381600087803b1580156200125357600080fd5b505af115801562001268573d6000803e3d6000fd5b50505050836001600160a01b03166336568abe604051806040016040528060068152602001652820aaa9a2a960d11b815250620012a59062001d5d565b6040516001600160e01b031960e084901b1681526004810191909152306024820152604401600060405180830381600087803b158015620012e557600080fd5b505af1158015620012fa573d6000803e3d6000fd5b50505050866001600160a01b031682600001516001600160a01b0316856001600160a01b03167f27a62b7d4a7ee7a705ae91fe5a3ad74f32fc3d14e82eb82c3730630601ce9ae68560200151620013696040805180820190915260058152640322e302e360dc1b602082015290565b6040516200137992919062001abb565b60405180910390a450519998505050505050505050565b606060008290506000815167ffffffffffffffff811115620013b657620013b6620016c9565b6040519080825280601f01601f191660200182016040528015620013e1576020820181803683370190505b50905060005b82518110156200150a57604183828151811062001408576200140862001ce9565b016020015160f81c108015906200143c5750605a83828151811062001431576200143162001ce9565b016020015160f81c11155b15620014a85782818151811062001457576200145762001ce9565b602001015160f81c60f81b60f81c602062001473919062001d9b565b60f81b8282815181106200148b576200148b62001ce9565b60200101906001600160f81b031916908160001a905350620014f5565b828181518110620014bd57620014bd62001ce9565b602001015160f81c60f81b828281518110620014dd57620014dd62001ce9565b60200101906001600160f81b031916908160001a9053505b80620015018162001dbd565b915050620013e7565b509392505050565b61070d8062001dda83390190565b61263280620024e783390190565b60005b838110156200154b57818101518382015260200162001531565b50506000910152565b600081518084526200156e8160208601602086016200152e565b601f01601f19169290920160200192915050565b60208152600062001597602083018462001554565b9392505050565b80516001600160a01b031682526020810151620015c660208401826001600160a01b03169052565b506040810151620015e260408401826001600160a01b03169052565b506060810151620015fe60608401826001600160a01b03169052565b5060808101516200161a60808401826001600160a01b03169052565b5060a08101516200163660a08401826001600160a01b03169052565b5060c08101516200165260c08401826001600160a01b03169052565b5060e08101516200166e60e08401826001600160a01b03169052565b50610100818101516001600160a01b03908116918401919091526101209182015116910152565b6001600160a01b038481168252610180820190620016b760208401866200159e565b80841661016084015250949350505050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715620017055762001705620016c9565b60405290565b6040516101a0810167ffffffffffffffff81118282101715620017055762001705620016c9565b600082601f8301126200174457600080fd5b813567ffffffffffffffff80821115620017625762001762620016c9565b604051601f8301601f19908116603f011681019082821181831017156200178d576200178d620016c9565b81604052838152866020858801011115620017a757600080fd5b836020870160208301376000602085830101528094505050505092915050565b6001600160a01b0381168114620017dd57600080fd5b50565b8035620017ed81620017c7565b919050565b803561ffff81168114620017ed57600080fd5b6000604082840312156200181857600080fd5b62001822620016df565b90506200182f82620017f2565b81526200183f60208301620017f2565b602082015292915050565b80356001600160c01b0381168114620017ed57600080fd5b803565ffffffffffff81168114620017ed57600080fd5b6000604082840312156200188c57600080fd5b62001896620016df565b9050813581526200183f602083016200184a565b60006102008284031215620018be57600080fd5b620018c86200170b565b9050620018d6838362001805565b8152620018e6604083016200184a565b6020820152620018f9606083016200184a565b60408201526200190c6080830162001862565b60608201526200191f60a0830162001862565b60808201526200193260c083016200184a565b60a08201526200194560e0830162001862565b60c08201526101006200195a81840162001862565b60e08301526101206200196f81850162001862565b828401526101409150620019858285016200184a565b90830152610160620019998482016200184a565b828401526101809150620019b08583860162001879565b90830152620019c4846101c0850162001879565b9082015292915050565b6000806000806000806102808789031215620019e957600080fd5b863567ffffffffffffffff8082111562001a0257600080fd5b62001a108a838b0162001732565b9750602089013591508082111562001a2757600080fd5b62001a358a838b0162001732565b9650604089013591508082111562001a4c57600080fd5b818901915089601f83011262001a6157600080fd5b81358181111562001a7157600080fd5b8a602082850101111562001a8457600080fd5b60208301965080955050505062001a9e60608801620017e0565b915062001aaf8860808901620018aa565b90509295509295509295565b6001600160a01b038316815260406020820181905260009062001ae19083018462001554565b949350505050565b6101a0810162001afa82876200159e565b6001600160a01b039490941661014082015265ffffffffffff928316610160820152911661018090910152919050565b6001600160a01b0394851681529290931660208301526001600160c01b039081166040830152909116606082015260800190565b6000825162001b728184602087016200152e565b622929a960e91b920191825250600301919050565b6000825162001b9b8184602087016200152e565b65102a37b5b2b760d11b920191825250600601919050565b60006020828403121562001bc657600080fd5b81516200159781620017c7565b6001600160a01b038616815260a06020820181905260009062001bf99083018762001554565b828103604084015262001c0d818762001554565b65ffffffffffff95909516606084015250506001600160c01b03919091166080909101529392505050565b6001600160a01b03881681526101006020820181905260009062001c5f8382018a62001554565b9050828103604084015262001c75818962001554565b90508281036060840152858152858760208301376000602087830101526020601f19601f88011682010191505062001cc36080830185805182526020908101516001600160c01b0316910152565b825160c083015260208301516001600160c01b031660e083015298975050505050505050565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b038381168252604060208084018290528451918401829052600092858201929091906060860190855b8181101562001d4f57855185168352948301949183019160010162001d2f565b509098975050505050505050565b8051602080830151919081101562001d7f576000198160200360031b1b821691505b50919050565b634e487b7160e01b600052601160045260246000fd5b60ff818116838216019081111562001db75762001db762001d85565b92915050565b60006001820162001dd25762001dd262001d85565b506001019056fe608060405260405161070d38038061070d8339810160408190526100229161030c565b61002e82826000610035565b5050610429565b61003e8361006b565b60008251118061004b5750805b156100665761006483836100ab60201b6100291760201c565b505b505050565b610074816100d7565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606100d083836040518060600160405280602781526020016106e6602791396101a9565b9392505050565b6100ea8161028760201b6100551760201c565b6101515760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b806101887f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b61029660201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606001600160a01b0384163b6102115760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610148565b600080856001600160a01b03168560405161022c91906103da565b600060405180830381855af49150503d8060008114610267576040519150601f19603f3d011682016040523d82523d6000602084013e61026c565b606091505b50909250905061027d828286610299565b9695505050505050565b6001600160a01b03163b151590565b90565b606083156102a85750816100d0565b8251156102b85782518084602001fd5b8160405162461bcd60e51b815260040161014891906103f6565b634e487b7160e01b600052604160045260246000fd5b60005b838110156103035781810151838201526020016102eb565b50506000910152565b6000806040838503121561031f57600080fd5b82516001600160a01b038116811461033657600080fd5b60208401519092506001600160401b038082111561035357600080fd5b818501915085601f83011261036757600080fd5b815181811115610379576103796102d2565b604051601f8201601f19908116603f011681019083821181831017156103a1576103a16102d2565b816040528281528860208487010111156103ba57600080fd5b6103cb8360208301602088016102e8565b80955050505050509250929050565b600082516103ec8184602087016102e8565b9190910192915050565b60208152600082518060208401526104158160408501602087016102e8565b601f01601f19169190910160400192915050565b6102ae806104386000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b61009f565b565b606061004e8383604051806060016040528060278152602001610252602791396100c3565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156100be573d6000f35b3d6000fd5b60606001600160a01b0384163b6101305760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084015b60405180910390fd5b600080856001600160a01b03168560405161014b9190610202565b600060405180830381855af49150503d8060008114610186576040519150601f19603f3d011682016040523d82523d6000602084013e61018b565b606091505b509150915061019b8282866101a5565b9695505050505050565b606083156101b457508161004e565b8251156101c45782518084602001fd5b8160405162461bcd60e51b8152600401610127919061021e565b60005b838110156101f95781810151838201526020016101e1565b50506000910152565b600082516102148184602087016101de565b9190910192915050565b602081526000825180602084015261023d8160408501602087016101de565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220db939c051e19763602ef3156f6b81bc6bc3dbeeff1b6514103fdcb69ddee4a5364736f6c63430008110033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65646101406040523480156200001257600080fd5b506040516200263238038062002632833981016040819052620000359162000352565b6001600160a01b038216620000815760405162461bcd60e51b815260206004820152600d60248201526c06d697373696e6720657263323609c1b60448201526064015b60405180910390fd5b6000816001600160c01b031611620000dc5760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206d617820747261646520766f6c756d650000000000000000604482015260640162000078565b6000826001600160a01b031663dffeadd06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200011d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200014391906200039c565b9050806001600160a01b0316632f2439b16040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000184573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001aa91906200039c565b6001600160a01b03166080816001600160a01b031681525050806001600160a01b031663979d7e866040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000202573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022891906200039c565b6001600160a01b031660a0816001600160a01b031681525050806001600160a01b031663dc8af5f66040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000280573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002a691906200039c565b6001600160a01b0390811660c052831660e08190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015620002f7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200031d9190620003c3565b60ff1661010052506001600160c01b03166101205250620003e8565b6001600160a01b03811681146200034f57600080fd5b50565b600080604083850312156200036657600080fd5b8251620003738162000339565b60208401519092506001600160c01b03811681146200039157600080fd5b809150509250929050565b600060208284031215620003af57600080fd5b8151620003bc8162000339565b9392505050565b600060208284031215620003d657600080fd5b815160ff81168114620003bc57600080fd5b60805160a05160c05160e05161010051610120516121a66200048c60003960006101da015260006101470152600081816101ab015281816102f301528181610404015261068901526000818161023f015281816105ec01528181610741015281816107d901528181610a380152610ac80152600081816102010152610b5a0152600081816101060152818161026901528181610459015261061701526121a66000f3fe608060405234801561001057600080fd5b50600436106100cf5760003560e01c80637d1ea1371161008c578063a035b1fe11610066578063a035b1fe14610223578063c59b3d631461022b578063dc8af5f61461023a578063f8ac93e81461014057600080fd5b80637d1ea137146101cd57806395acc4ae146101d5578063979d7e86146101fc57600080fd5b8063271181ec146100d45780632f2439b114610101578063372500ab146101405780633cb5d379146101425780635580f72a1461017b578063785e9e86146101a6575b600080fd5b6100dc610261565b604080516001600160c01b039384168152929091166020830152015b60405180910390f35b6101287f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100f8565b005b6101697f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016100f8565b61018e610189366004611b66565b6103de565b6040516001600160c01b0390911681526020016100f8565b6101287f000000000000000000000000000000000000000000000000000000000000000081565b6100dc610451565b61018e7f000000000000000000000000000000000000000000000000000000000000000081565b6101287f000000000000000000000000000000000000000000000000000000000000000081565b6100dc6104b4565b604051600081526020016100f8565b6101287f000000000000000000000000000000000000000000000000000000000000000081565b6000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663271181ec6040518163ffffffff1660e01b81526004016040805180830381865afa1580156102c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102e89190611b9f565b9150915060006103787f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561034f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103739190611bd2565b610593565b9050806001600160c01b0316600003610395575090939092509050565b600061039f6105c1565b80519091506103b8906001600160c01b03168584610bf4565b60208201519096506103d4906001600160c01b03168484610bf4565b9450505050509091565b6040516370a0823160e01b81526001600160a01b03828116600483015260009161044b917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561034f573d6000803e3d6000fd5b92915050565b6000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a035b1fe6040518163ffffffff1660e01b81526004016040805180830381865afa1580156102c4573d6000803e3d6000fd5b600080306001600160a01b0316637d1ea1376040518163ffffffff1660e01b81526004016040805180830381865afa925050508015610510575060408051601f3d908101601f1916820190925261050d91810190611b9f565b60015b610564573d80801561053e576040519150601f19603f3d011682016040523d82523d6000602084013e610543565b606091505b50805160000361055257600080fd5b506000926001600160c01b0392509050565b806001600160c01b0316826001600160c01b0316111561058657610586611beb565b90939092509050565b9091565b60006001600160c01b038211156105bd5760405163f44398f560e01b815260040160405180910390fd5b5090565b6040805180820190915260008082526020820152604051635523caaf60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063aa47955e906024016040805180830381865afa15801561065f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106839190611c71565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637121c2736040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107099190611ccc565b9050806001600160c01b031682600001516001600160c01b03161061073d576001600160c01b031680835260208301525090565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dffeadd06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561079d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c19190611ce7565b905060006040518061012001604052808581526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001836001600160a01b0316632f2439b16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610844573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108689190611ce7565b6001600160a01b03168152602001836001600160a01b031663979d7e866040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d89190611ce7565b6001600160a01b03168152602001836001600160a01b0316634780a5e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015610924573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109489190611ce7565b6001600160a01b03168152602001836001600160a01b031663c99dc3dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610994573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b89190611ce7565b6001600160a01b03168152602001836001600160a01b03166340c65f726040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a289190611ce7565b6001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637cbf6db26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab89190611ccc565b6001600160c01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630db3d42c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b489190611ccc565b6001600160c01b0316815250905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635ab1bd536040518163ffffffff1660e01b8152600401600060405180830381865afa158015610bb6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bde9190810190611d9c565b9050610bea8282610c0d565b9550505050505090565b6000610c0384848460006114e7565b90505b9392505050565b604080518082019091526000808252602082015260008084604001516001600160a01b031663a035b1fe6040518163ffffffff1660e01b81526004016040805180830381865afa158015610c65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c899190611b9f565b915091508460c001516001600160a01b0316637121c2736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ccf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf39190611ccc565b6001600160c01b03168560000151602001516001600160c01b03161115610d8e578460c001516001600160a01b0316637121c2736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7a9190611ccc565b85516001600160c01b039091166020909101525b6000805b8551518110156112f2578660c001516001600160a01b031686600001518281518110610dc057610dc0611e8a565b60200260200101516001600160a01b031603156112e257600086602001518281518110610def57610def611e8a565b60209081029190910181015190890151604051632ac07b9560e11b81526001600160a01b039182166004820152911690635580f72a90602401602060405180830381865afa158015610e45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e699190611ccc565b90508760a001516001600160a01b031687600001518381518110610e8f57610e8f611e8a565b60200260200101516001600160a01b031603610f4b57610f4887602001518381518110610ebe57610ebe611e8a565b602090810291909101015160808a0151604051632ac07b9560e11b81526001600160a01b039182166004820152911690635580f72a90602401602060405180830381865afa158015610f14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f389190611ccc565b6001600160c01b0383169061151e565b90505b600088604001516001600160a01b031663d3252db589600001518581518110610f7657610f76611e8a565b60200260200101518a602001518681518110610f9457610f94611e8a565b60200260200101516040518363ffffffff1660e01b8152600401610fce9291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa158015610feb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100f9190611ccc565b905060008860200151848151811061102957611029611e8a565b60200260200101516001600160a01b031663271181ec6040518163ffffffff1660e01b81526004016040805180830381865afa15801561106d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110919190611b9f565b5090506001600160c01b0382161580156110d557506110d3896020015185815181106110bf576110bf611e8a565b602002602001015184838d60e0015161152a565b155b156110e2575050506112e2565b50600080896020015185815181106110fc576110fc611e8a565b60200260200101516001600160a01b031663a035b1fe6040518163ffffffff1660e01b81526004016040805180830381865afa158015611140573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111649190611b9f565b8c51602001519193509150600090611188906001600160c01b0386169060026115d4565b9050846001600160c01b0316816001600160c01b031611156111de576111c46111b18683611eb6565b6001600160c01b038516908a60006114e7565b6111d7906001600160c01b031688611edd565b9650611218565b611202826111ec8388611eb6565b60208f01516001600160a01b031691908c611601565b611215906001600160c01b031688611efd565b96505b508a5151600090611234906001600160c01b03861690836115d4565b905060006112576112458388611eb6565b6001600160c01b0386169060006115d4565b90508c60e001516001600160c01b0316816001600160c01b03161061128a5760e08d01516112859082611eb6565b61128d565b60005b6101008e01519091506112c0906112ad90670de0b6b3a764000090611754565b6001600160c01b038316908b60006114e7565b8b518c906112cf908390611f25565b6001600160c01b03169052505050505050505b6112eb81611f45565b9050610d92565b50600081121561132b5761130861037382611f5e565b8651602001516113189190611eb6565b6001600160c01b03166020850152611386565b8551602001516001600160c01b039061134690821683611f7a565b111561135e576001600160c01b036020850152611386565b61136781610593565b8651602001516113779190611f25565b6001600160c01b031660208501525b85515184518590611398908390611f25565b9150906001600160c01b031690816001600160c01b0316815250508560c001516001600160a01b0316637121c2736040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114199190611ccc565b6001600160c01b031684602001516001600160c01b031611156114ab578560c001516001600160a01b0316637121c2736040518163ffffffff1660e01b8152600401602060405180830381865afa158015611478573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149c9190611ccc565b6001600160c01b031660208501525b83602001516001600160c01b031684600001516001600160c01b031611156114de5760208401516001600160c01b031684525b50505092915050565b6000611513610373866001600160c01b0316866001600160c01b0316866001600160c01b031686611760565b90505b949350505050565b6000610c068284611f25565b600061154c611539838561180d565b6001600160c01b03908116908616101590565b8015611513575060016115ca866001600160a01b0316633cb5d3796040518163ffffffff1660e01b8152600401602060405180830381865afa158015611596573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ba9190611f8d565b6001600160c01b0387169061185c565b1195945050505050565b6000610c036103736115f26001600160c01b03808716908816611fb0565b670de0b6b3a76400008561186a565b60405163551ef62560e01b81526001600160c01b0380851660048301528084166024830152821660448201526000906001600160a01b0386169063551ef62590606401602060405180830381865afa92505050801561167d575060408051601f3d908101601f1916820190925261167a91810190611ccc565b60015b61173c57611689611fc7565b634e487b71036116c75761169b611fe3565b906116a657506116c7565b80601114806116b55750806012145b6116c1576116c1611beb565b50611743565b3d8080156116f1576040519150601f19603f3d011682016040523d82523d6000602084013e6116f6565b606091505b50604080516004815260248101909152602080820180516001600160e01b031663f44398f560e01b1781529151909120825191830191909120146116c1576116c1611beb565b9050611516565b506001600160c01b03949350505050565b6000610c068284611eb6565b60008061176e868686611912565b9050600083600281111561178457611784612000565b03611790579050611516565b600084806117a0576117a0612016565b868809905060028460028111156117b9576117b9612000565b036117d75780156117d2576117cf600183611f7a565b91505b611803565b60026117e460018761202c565b6117ee919061203f565b81111561180357611800600183611f7a565b91505b5095945050505050565b6000806001600160c01b03831615611839576118346001600160c01b0385168460026119f5565b611842565b6001600160c01b035b90506000816001600160c01b031611610c06576001611516565b6000610c0683836000611a28565b600080611877848661203f565b9050600083600281111561188d5761188d612000565b03611899579050610c06565b60018360028111156118ad576118ad612000565b036118ec5760026118bf60018661202c565b6118c9919061203f565b6118d38587612053565b11156118e757806118e381611f45565b9150505b610c03565b60006118f88587612053565b1115610c03578061190881611f45565b9695505050505050565b60008060006119218686611b09565b915091508382106119455760405163f44398f560e01b815260040160405180910390fd5b6000848061195557611955612016565b868809905081811115611969576001830392505b90819003906000859003851680868161198457611984612016565b04955080838161199657611996612016565b0492508081600003816119ab576119ab612016565b046001019390930291909101600285810380870282030280870282030280870282030280870282030280870282030280870282030295860290039094029390930295945050505050565b6000610c03610373611a18670de0b6b3a76400006001600160c01b038816611fb0565b856001600160c01b03168561186a565b6000836001600160c01b0316600003611a4357506000610c06565b6029198360000b13611a7c576002826002811115611a6357611a63612000565b14611a6f576000611a72565b60015b60ff169050610c06565b8260000b606013611aa05760405163f44398f560e01b815260040160405180910390fd5b611aab601284612067565b92506000611abb8460000b611b36565b611ac690600a612164565b905060008460000b1215611aed57611ae8856001600160c01b0316828561186a565b611b00565b611b00816001600160c01b038716611fb0565b95945050505050565b6000808060001984860990508385029150818103925081811015611b2e576001830392505b509250929050565b6000808212611b45578161044b565b61044b82611f5e565b6001600160a01b0381168114611b6357600080fd5b50565b600060208284031215611b7857600080fd5b8135610c0681611b4e565b80516001600160c01b0381168114611b9a57600080fd5b919050565b60008060408385031215611bb257600080fd5b611bbb83611b83565b9150611bc960208401611b83565b90509250929050565b600060208284031215611be457600080fd5b5051919050565b634e487b7160e01b600052600160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611c3a57611c3a611c01565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611c6957611c69611c01565b604052919050565b600060408284031215611c8357600080fd5b6040516040810181811067ffffffffffffffff82111715611ca657611ca6611c01565b604052611cb283611b83565b8152611cc060208401611b83565b60208201529392505050565b600060208284031215611cde57600080fd5b610c0682611b83565b600060208284031215611cf957600080fd5b8151610c0681611b4e565b600067ffffffffffffffff821115611d1e57611d1e611c01565b5060051b60200190565b600082601f830112611d3957600080fd5b81516020611d4e611d4983611d04565b611c40565b82815260059290921b84018101918181019086841115611d6d57600080fd5b8286015b84811015611d91578051611d8481611b4e565b8352918301918301611d71565b509695505050505050565b60006020808385031215611daf57600080fd5b825167ffffffffffffffff80821115611dc757600080fd5b9084019060408287031215611ddb57600080fd5b611de3611c17565b825182811115611df257600080fd5b8301601f81018813611e0357600080fd5b8051611e11611d4982611d04565b81815260059190911b8201860190868101908a831115611e3057600080fd5b928701925b82841015611e57578351611e4881611b4e565b82529287019290870190611e35565b84525050508284015182811115611e6d57600080fd5b611e7988828601611d28565b948201949094529695505050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6001600160c01b03828116828216039080821115611ed657611ed6611ea0565b5092915050565b8181036000831280158383131683831282161715611ed657611ed6611ea0565b8082018281126000831280158216821582161715611f1d57611f1d611ea0565b505092915050565b6001600160c01b03818116838216019080821115611ed657611ed6611ea0565b600060018201611f5757611f57611ea0565b5060010190565b6000600160ff1b8201611f7357611f73611ea0565b5060000390565b8082018082111561044b5761044b611ea0565b600060208284031215611f9f57600080fd5b815160ff81168114610c0657600080fd5b808202811582820484141761044b5761044b611ea0565b600060033d1115611fe05760046000803e5060005160e01c5b90565b60008060233d111561058f576020600460003e5050600051600191565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b8181038181111561044b5761044b611ea0565b60008261204e5761204e612016565b500490565b60008261206257612062612016565b500690565b600082810b9082900b03607f198112607f8213171561044b5761044b611ea0565b600181815b80851115611b2e5781600019048211156120a9576120a9611ea0565b808516156120b657918102915b93841c939080029061208d565b6000826120d25750600161044b565b816120df5750600061044b565b81600181146120f557600281146120ff5761211b565b600191505061044b565b60ff84111561211057612110611ea0565b50506001821b61044b565b5060208310610133831016604e8410600b841016171561213e575081810a61044b565b6121488383612088565b806000190482111561215c5761215c611ea0565b029392505050565b6000610c0683836120c356fea2646970667358221220afb6ebec2a42c95a52d07d1438c4244016326489b424f104a60e7cd1ccbcbea964736f6c63430008110033a2646970667358221220880cb5fd832583d1046272d8f08eced9e8b9e28550463d890521df0a925c939c64736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000320623b8e4ff03373931769a31fc52a4e78b5d700000000000000000000000000b7ffc1f4ad541a4ed16b40d8c37f0929158d1010000000000000000000000002c312da96f98a5b7822270f69afd2d7ae8e748dc000000000000000000000000143c35bfe04720394ebd18abeca83ea9d8bede2f000000000000000000000000ecbba78d8cd654dfc582cb7fcf31d8a2a0b7a6cc00000000000000000000000030b29539b5302ebce52479275dfc9dfabb66a0470000000000000000000000005a004f70b2450e909b4048050c585549ab8afeb80000000000000000000000000ef3c7fe9c1cf7352d52e2867652b7547defdbe5000000000000000000000000a0d4b6ad503e776457dbf4695d462ddf8621a1cc000000000000000000000000c78c5a84f30317b5f7d87170ec21dc73df38d569000000000000000000000000393002573ea4a3d74a80f3b1af436a3ee3a30c960000000000000000000000005a0f5e19e963206ec78fe8bf5fa53108918dd898000000000000000000000000e5bd2249118b6a4b39be195951579dc9af05029a000000000000000000000000e5bd2249118b6a4b39be195951579dc9af05029a000000000000000000000000ac543ee89a2238945f7d7ad4d9cf958721f9757c
-----Decoded View---------------
Arg [0] : rsr_ (address): 0x320623b8E4fF03373931769A31Fc52A4E78B5d70
Arg [1] : gnosis_ (address): 0x0b7fFc1f4AD541A4Ed16b40D8c37f0929158D101
Arg [2] : rsrAsset_ (address): 0x2C312da96F98a5B7822270F69AFd2D7aE8E748DC
Arg [3] : implementations_ (tuple):
Arg [1] : main (address): 0x143C35bFe04720394eBd18AbECa83eA9D8BEdE2F
Arg [2] : components (tuple):
Arg [1] : rToken (address): 0xEcbBA78d8cD654DFC582cB7FCF31D8a2A0B7A6cC
Arg [2] : stRSR (address): 0x30B29539b5302Ebce52479275dfC9DFAbb66A047
Arg [3] : assetRegistry (address): 0x5a004F70b2450E909B4048050c585549Ab8afeB8
Arg [4] : basketHandler (address): 0x0Ef3c7fE9c1cF7352D52E2867652b7547DeFdbe5
Arg [5] : backingManager (address): 0xa0D4b6aD503E776457dBF4695d462DdF8621A1CC
Arg [6] : distributor (address): 0xc78c5a84F30317B5F7D87170Ec21DC73Df38d569
Arg [7] : furnace (address): 0x393002573ea4A3d74A80F3B1Af436a3ee3A30c96
Arg [8] : broker (address): 0x5a0f5e19E963206ec78FE8BF5fa53108918DD898
Arg [9] : rsrTrader (address): 0xE5bD2249118b6a4B39Be195951579dC9Af05029a
Arg [10] : rTokenTrader (address): 0xE5bD2249118b6a4B39Be195951579dC9Af05029a
Arg [3] : trade (address): 0xAc543Ee89A2238945f7D7Ad4d9Cf958721f9757c
-----Encoded View---------------
15 Constructor Arguments found :
Arg [0] : 000000000000000000000000320623b8e4ff03373931769a31fc52a4e78b5d70
Arg [1] : 0000000000000000000000000b7ffc1f4ad541a4ed16b40d8c37f0929158d101
Arg [2] : 0000000000000000000000002c312da96f98a5b7822270f69afd2d7ae8e748dc
Arg [3] : 000000000000000000000000143c35bfe04720394ebd18abeca83ea9d8bede2f
Arg [4] : 000000000000000000000000ecbba78d8cd654dfc582cb7fcf31d8a2a0b7a6cc
Arg [5] : 00000000000000000000000030b29539b5302ebce52479275dfc9dfabb66a047
Arg [6] : 0000000000000000000000005a004f70b2450e909b4048050c585549ab8afeb8
Arg [7] : 0000000000000000000000000ef3c7fe9c1cf7352d52e2867652b7547defdbe5
Arg [8] : 000000000000000000000000a0d4b6ad503e776457dbf4695d462ddf8621a1cc
Arg [9] : 000000000000000000000000c78c5a84f30317b5f7d87170ec21dc73df38d569
Arg [10] : 000000000000000000000000393002573ea4a3d74a80f3b1af436a3ee3a30c96
Arg [11] : 0000000000000000000000005a0f5e19e963206ec78fe8bf5fa53108918dd898
Arg [12] : 000000000000000000000000e5bd2249118b6a4b39be195951579dc9af05029a
Arg [13] : 000000000000000000000000e5bd2249118b6a4b39be195951579dc9af05029a
Arg [14] : 000000000000000000000000ac543ee89a2238945f7d7ad4d9cf958721f9757c
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 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.