Feature Tip: Add private address tag to any address under My Name Tag !
Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 5 from a total of 5 transactions
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
StableMinter
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
No with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {BaseMinter} from "src/MintRedeem/BaseMinter.sol";
import {Order, OrderType, MintRedeemMode} from "src/MintRedeem/Structs.sol";
import {INUSD} from "src/interfaces/INUSD.sol";
import {IMinter} from "src/interfaces/IMinter.sol";
/// @title StableMinter
/// @notice A contract for minting NUSD using stablecoin collateral
/// @dev Accepts only stablecoin assets and processes mint orders from authorized router
contract StableMinter is BaseMinter, IMinter {
using SafeERC20 for IERC20;
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
/*//////////////////////////////////////////////////////////////
STORAGE
//////////////////////////////////////////////////////////////*/
/*//////////////////////////////////////////////////////////////
INITIALIZATION
//////////////////////////////////////////////////////////////*/
constructor(address _admin, address _NUSD, address _router, uint256 _maxMintPerBlock) {
_grantRole(DEFAULT_ADMIN_ROLE, _admin);
NUSD = INUSD(_NUSD);
_setRouter(_router);
_setMaxMintPerBlock(_maxMintPerBlock);
_setMinPrice(0.97e18);
}
/*//////////////////////////////////////////////////////////////
ADMIN FUNCTIONS
//////////////////////////////////////////////////////////////*/
/*//////////////////////////////////////////////////////////////
MINTING
//////////////////////////////////////////////////////////////*/
/// @notice Mint NUSD
/// @param order The order to mint
/// @dev Only the router can call this function
function mint(Order memory order) external onlyRouter returns (uint256) {
if (order.orderType != OrderType.MINT) revert InvalidOrder();
if (order.expiry < block.timestamp) revert OrderExpired();
_verifyOrder(order);
uint256 amountToMint = quoteDeposit(order.collateralAsset, order.collateralAmount);
if (amountToMint < order.nusdAmount) revert SlippageExceeded();
_belowMaxMintPerBlock(amountToMint);
mintedPerBlock[block.number] += amountToMint;
NUSD.mint(order.beneficiary, amountToMint);
return amountToMint;
}
/*//////////////////////////////////////////////////////////////
PUBLIC FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @notice Gets the mint mode for a given collateral asset and amount
/// @return The mint mode, if INSTANT, the mint will be served immediately, if QUEUED, the mint will be queued and served later
/// @dev For StableMinter, the mint mode is always INSTANT
function getMintMode(address, /*_asset*/ uint256 /*_amount*/ ) external pure returns (MintRedeemMode) {
return MintRedeemMode.INSTANT;
}
/// @notice Checks if the asset is supported
/// @param _collateralAsset The collateral asset to check
/// @return True if the asset is supported, false otherwise
function isAssetSupported(address _collateralAsset) external view returns (bool) {
return assetInfo[_collateralAsset].isSupported;
}
/// @notice Calculates the amount of NUSD that would be minted for a given token amount
/// @param _token Address of the token to quote
/// @param _amount Amount of tokens to quote
/// @return The amount of NUSD that would be minted
function quoteDeposit(address _token, uint256 _amount) public view returns (uint256) {
uint8 decimals = assetInfo[_token].decimals;
// We quote the price of the token in USD
uint256 unitPrice = assetInfo[_token].oracle.getQuote(10 ** decimals, _token, USD);
// If the price is less than the minimum price, we revert
if (unitPrice < minPrice) revert InvalidPrice();
// If the price is less than 1e18, we use the price as is, otherwise we use 1e18
// Select price favorable to the protocol
uint256 price = unitPrice < 1e18 ? unitPrice : 1e18;
// Normalize the amount to 18 decimals
uint256 normalizedAmount = _amount * (10 ** (18 - decimals));
uint256 oracleQuote = (price * normalizedAmount) / 1e18;
return oracleQuote;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {BaseMintRedeem} from "src/MintRedeem/BaseMintRedeem.sol";
/// @title BaseMinter
/// @notice Base contract for NUSD minting operations with minter-specific functionality
/// @dev Provides core functionality for managing minting limits and price protections
abstract contract BaseMinter is BaseMintRedeem {
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error MaxMintPerBlockExceeded();
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event MaxMintPerBlockSet(uint256 maxMintPerBlock);
/*//////////////////////////////////////////////////////////////
STORAGE
//////////////////////////////////////////////////////////////*/
/// @notice The minimum price of the asset to be accepted for minting
/// @dev This is a price protection for the user, we are assuming USDC USDT and USDe deposits
uint256 public minPrice;
/// @notice NUSD minted per block
mapping(uint256 blockNumber => uint256 amount) public mintedPerBlock;
/// @notice Max minted NUSD allowed per block
uint256 public maxMintPerBlock;
/*//////////////////////////////////////////////////////////////
ADMIN FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @notice Set the max minted NUSD allowed per block
/// @param _maxMintPerBlock The max minted NUSD allowed per block
function setMaxMintPerBlock(uint256 _maxMintPerBlock) external onlyRole(DEFAULT_ADMIN_ROLE) {
_setMaxMintPerBlock(_maxMintPerBlock);
}
/// @notice Set the minimum price of the asset to be accepted for minting
/// @param _minPrice The minimum price of the asset to be accepted for minting
function setMinPrice(uint256 _minPrice) external onlyRole(DEFAULT_ADMIN_ROLE) {
_setMinPrice(_minPrice);
}
/*//////////////////////////////////////////////////////////////
INTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @notice Set the minimum price of the asset to be accepted for minting
/// @param _minPrice The minimum price of the asset to be accepted for minting
function _setMinPrice(uint256 _minPrice) internal {
minPrice = _minPrice;
}
/// @notice Ensure that the already minted NUSD in the actual block plus the amount to be minted is not higher than the maxMintPerBlock var
/// @param mintAmount The NUSD amount to be minted
function _belowMaxMintPerBlock(uint256 mintAmount) internal view {
if (mintedPerBlock[block.number] + mintAmount > maxMintPerBlock) {
revert MaxMintPerBlockExceeded();
}
}
/// @notice Set the max minted NUSD allowed per block
/// @param _maxMintPerBlock The max minted NUSD allowed per block
function _setMaxMintPerBlock(uint256 _maxMintPerBlock) internal {
maxMintPerBlock = _maxMintPerBlock;
emit MaxMintPerBlockSet(_maxMintPerBlock);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {IPriceOracle} from "src/interfaces/IPriceOracle.sol";
enum OrderType {
MINT,
REDEEM
}
enum MintRedeemMode {
/// @dev Atomic mint against collateral
/// @dev Redeem directly from the liquid buffer
INSTANT,
/// @dev Queue the mint request and serve it later
/// @dev Queue the redemption request and serve it later
QUEUED
}
enum RequestStatus {
EMPTY,
PENDING,
COMPLETED,
CANCELLED
}
struct Order {
OrderType orderType;
uint256 expiry;
address benefactor;
address beneficiary;
address collateralAsset;
/// @dev When minting, this is the amount of collateral to deposit
/// @dev When redeeming, this is the minimum amount of collateral to receive
uint256 collateralAmount;
/// @dev When minting, this is the minimum amount of NUSD to receive
/// @dev When redeeming, this is the amount of NUSD to burn
uint256 nusdAmount;
/// @dev Additional data for the order, in case of future use for minters / redeemers
bytes additionalData;
}
struct Asset {
bool isSupported;
address asset;
uint8 decimals;
/// @dev Oracle rely on ERC7726 that comes with integrated checks https://github.com/euler-xyz/euler-price-oracle/
IPriceOracle oracle;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface INUSD is IERC20 {
function mint(address to, uint256 amount) external;
function burn(address from, uint256 amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {Order, MintRedeemMode} from "src/MintRedeem/Structs.sol";
interface IMinter {
function mint(Order memory order) external returns (uint256);
function quoteDeposit(address _token, uint256 _amount) external view returns (uint256);
function getMintMode(address _collateralAsset, uint256 _amount) external view returns (MintRedeemMode);
function isAssetSupported(address _collateralAsset) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IPriceOracle} from "src/interfaces/IPriceOracle.sol";
import {Asset, Order, OrderType} from "src/MintRedeem/Structs.sol";
import {INUSD} from "src/interfaces/INUSD.sol";
import {SingleAdminAccessControl} from "src/utils/SingleAdminAccessControl.sol";
/// @title BaseMintRedeem
/// @notice Base contract for NUSD minting and redeeming operations
/// @dev Provides core functionality for managing supported assets, price oracles
/// @dev Oracle rely on ERC7726 that comes with integrated checks https://github.com/euler-xyz/euler-price-oracle/
abstract contract BaseMintRedeem is SingleAdminAccessControl {
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error AssetNotSupported();
error InvalidInput();
error ZeroInput();
error OnlyRouter();
error InvalidOrder();
error SlippageExceeded();
error OrderExpired();
error InvalidPrice();
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event AssetAdded(address asset, address oracle);
event AssetRemoved(address asset);
event RouterSet(address router);
event MinPriceSet(uint256 minPrice);
event MaxPriceSet(uint256 maxPrice);
/*//////////////////////////////////////////////////////////////
STORAGE
//////////////////////////////////////////////////////////////*/
/// @notice USD address for Chainlink price feeds
address public constant USD = 0x0000000000000000000000000000000000000348;
/// @notice NUSD address
INUSD public immutable NUSD;
/// @notice Router address
address public router;
/// @notice Whether the asset is supported
mapping(address asset => Asset assetInfo) public assetInfo;
/*//////////////////////////////////////////////////////////////
ADMIN FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @notice Add an asset to the stable minter
/// @param _asset The asset to add
/// @param _oracle The oracle to add
function addAsset(address _asset, address _oracle) external onlyRole(DEFAULT_ADMIN_ROLE) {
_addAsset(_asset, _oracle);
}
/// @notice Remove an asset from the stable minter
/// @param _asset The asset to remove
function removeAsset(address _asset) external onlyRole(DEFAULT_ADMIN_ROLE) {
_removeAsset(_asset);
}
/// @notice Set the router address
/// @param _router The router address
function setRouter(address _router) external onlyRole(DEFAULT_ADMIN_ROLE) {
_setRouter(_router);
}
/*//////////////////////////////////////////////////////////////
VIEW FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @notice Get the asset info
/// @param _asset The asset to get the info for
/// @return assetInfo The asset info
function getAssetInfo(address _asset) external view returns (Asset memory) {
return assetInfo[_asset];
}
/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
/// @notice Only the router can call the function
modifier onlyRouter() {
if (msg.sender != router) revert OnlyRouter();
_;
}
/*//////////////////////////////////////////////////////////////
INTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @notice assert validity of order
/// @param order The order to verify
function _verifyOrder(Order memory order) internal pure {
if (order.beneficiary == address(0)) revert ZeroInput();
if (order.collateralAsset == address(0)) revert ZeroInput();
if (order.benefactor == address(0)) revert ZeroInput();
if (order.collateralAmount == 0) revert ZeroInput();
}
/// @notice Set the router address
/// @param _router The router address
function _setRouter(address _router) internal {
if (_router == address(0)) revert ZeroInput();
router = _router;
emit RouterSet(_router);
}
/// @notice Add an asset to the supported assets
/// @param _asset The asset to be added
/// @param _oracle The oracle for the asset
function _addAsset(address _asset, address _oracle) internal {
if (_asset == address(0) || _oracle == address(0)) revert ZeroInput();
if (_asset == address(NUSD)) revert AssetNotSupported();
assetInfo[_asset] = Asset({
isSupported: true,
asset: _asset,
decimals: IERC20Metadata(_asset).decimals(),
oracle: IPriceOracle(_oracle)
});
emit AssetAdded(_asset, _oracle);
}
/// @notice Remove an asset from the supported assets
/// @param _asset The asset to be removed
function _removeAsset(address _asset) internal {
delete assetInfo[_asset];
emit AssetRemoved(_asset);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
/// @title IPriceOracle
/// @custom:security-contact security@euler.xyz
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Common PriceOracle interface.
interface IPriceOracle {
/// @notice Get the name of the oracle.
/// @return The name of the oracle.
function name() external view returns (string memory);
/// @notice One-sided price: How much quote token you would get for inAmount of base token, assuming no price spread.
/// @param inAmount The amount of `base` to convert.
/// @param base The token that is being priced.
/// @param quote The token that is the unit of account.
/// @return outAmount The amount of `quote` that is equivalent to `inAmount` of `base`.
function getQuote(uint256 inAmount, address base, address quote) external view returns (uint256 outAmount);
/// @notice Two-sided price: How much quote token you would get/spend for selling/buying inAmount of base token.
/// @param inAmount The amount of `base` to convert.
/// @param base The token that is being priced.
/// @param quote The token that is the unit of account.
/// @return bidOutAmount The amount of `quote` you would get for selling `inAmount` of `base`.
/// @return askOutAmount The amount of `quote` you would spend for buying `inAmount` of `base`.
function getQuotes(uint256 inAmount, address base, address quote)
external
view
returns (uint256 bidOutAmount, uint256 askOutAmount);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
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
pragma solidity 0.8.26;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/interfaces/IERC5313.sol";
/**
* @title SingleAdminAccessControl
* @notice SingleAdminAccessControl is a contract that provides a single admin role
* @notice This contract is a simplified alternative to OpenZeppelin's AccessControlDefaultAdminRules
*/
abstract contract SingleAdminAccessControl is IERC5313, AccessControl {
error InvalidAdminChange();
error NotPendingAdmin();
event AdminTransferred(address indexed oldAdmin, address indexed newAdmin);
event AdminTransferRequested(address indexed oldAdmin, address indexed newAdmin);
address private _currentDefaultAdmin;
address private _pendingDefaultAdmin;
modifier notAdmin(bytes32 role) {
if (role == DEFAULT_ADMIN_ROLE) revert InvalidAdminChange();
_;
}
/// @notice Transfer the admin role to a new address
/// @notice This can ONLY be executed by the current admin
/// @param newAdmin address
function transferAdmin(address newAdmin) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (newAdmin == address(0) || newAdmin == _msgSender()) {
revert InvalidAdminChange();
}
_pendingDefaultAdmin = newAdmin;
emit AdminTransferRequested(_currentDefaultAdmin, newAdmin);
}
function acceptAdmin() external {
if (_msgSender() != _pendingDefaultAdmin) revert NotPendingAdmin();
_grantRole(DEFAULT_ADMIN_ROLE, _msgSender());
}
/// @notice grant a role
/// @notice can only be executed by the current single admin
/// @notice admin role cannot be granted externally
/// @param role bytes32
/// @param account address
function grantRole(bytes32 role, address account) public override onlyRole(DEFAULT_ADMIN_ROLE) notAdmin(role) {
_grantRole(role, account);
}
/// @notice revoke a role
/// @notice can only be executed by the current admin
/// @notice admin role cannot be revoked
/// @param role bytes32
/// @param account address
function revokeRole(bytes32 role, address account) public override onlyRole(DEFAULT_ADMIN_ROLE) notAdmin(role) {
_revokeRole(role, account);
}
/// @notice renounce the role of _msgSender()
/// @notice admin role cannot be renounced
/// @param role bytes32
/// @param account address
function renounceRole(bytes32 role, address account) public virtual override notAdmin(role) {
super.renounceRole(role, account);
}
/**
* @dev See {IERC5313-owner}.
*/
function owner() external view virtual returns (address) {
return _currentDefaultAdmin;
}
/**
* @notice no way to change admin without removing old admin first
*/
function _grantRole(bytes32 role, address account) internal override returns (bool) {
if (role == DEFAULT_ADMIN_ROLE) {
emit AdminTransferred(_currentDefaultAdmin, account);
_revokeRole(DEFAULT_ADMIN_ROLE, _currentDefaultAdmin);
_currentDefaultAdmin = account;
delete _pendingDefaultAdmin;
}
return super._grantRole(role, account);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @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[ERC 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 v5.3.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.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:
*
* ```solidity
* 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}:
*
* ```solidity
* 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. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @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 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 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 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 `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @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 Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5313.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface for the Light Contract Ownership Standard.
*
* A standardized minimal interface required to identify an account that controls a contract
*/
interface IERC5313 {
/**
* @dev Gets the address of the owner.
*/
function owner() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC-165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @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 to signal this.
*/
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. This account bears the admin role (for the granted role).
* Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
*/
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 `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 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);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}{
"remappings": [
"@openzeppelin/src/=lib/openzeppelin-contracts/contracts/",
"test/=test/",
"@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/",
"@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/",
"@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/",
"@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/",
"solidity-bytes-utils/=lib/solidity-bytes-utils/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"LayerZero-v2/=lib/LayerZero-v2/",
"createx-forge/=lib/createx-forge/",
"devtools/=lib/devtools/packages/toolbox-foundry/src/",
"ds-test/=lib/createx-forge/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": false,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_NUSD","type":"address"},{"internalType":"address","name":"_router","type":"address"},{"internalType":"uint256","name":"_maxMintPerBlock","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"AssetNotSupported","type":"error"},{"inputs":[],"name":"InvalidAdminChange","type":"error"},{"inputs":[],"name":"InvalidInput","type":"error"},{"inputs":[],"name":"InvalidOrder","type":"error"},{"inputs":[],"name":"InvalidPrice","type":"error"},{"inputs":[],"name":"MaxMintPerBlockExceeded","type":"error"},{"inputs":[],"name":"NotPendingAdmin","type":"error"},{"inputs":[],"name":"OnlyRouter","type":"error"},{"inputs":[],"name":"OrderExpired","type":"error"},{"inputs":[],"name":"SlippageExceeded","type":"error"},{"inputs":[],"name":"ZeroInput","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"address","name":"oracle","type":"address"}],"name":"AssetAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"}],"name":"AssetRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxMintPerBlock","type":"uint256"}],"name":"MaxMintPerBlockSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxPrice","type":"uint256"}],"name":"MaxPriceSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minPrice","type":"uint256"}],"name":"MinPriceSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"router","type":"address"}],"name":"RouterSet","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NUSD","outputs":[{"internalType":"contract INUSD","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USD","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address","name":"_oracle","type":"address"}],"name":"addAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"assetInfo","outputs":[{"internalType":"bool","name":"isSupported","type":"bool"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"contract IPriceOracle","name":"oracle","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"getAssetInfo","outputs":[{"components":[{"internalType":"bool","name":"isSupported","type":"bool"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"contract IPriceOracle","name":"oracle","type":"address"}],"internalType":"struct Asset","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"getMintMode","outputs":[{"internalType":"enum MintRedeemMode","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_collateralAsset","type":"address"}],"name":"isAssetSupported","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMintPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"benefactor","type":"address"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"address","name":"collateralAsset","type":"address"},{"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"internalType":"uint256","name":"nusdAmount","type":"uint256"},{"internalType":"bytes","name":"additionalData","type":"bytes"}],"internalType":"struct Order","name":"order","type":"tuple"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"mintedPerBlock","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"quoteDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"removeAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxMintPerBlock","type":"uint256"}],"name":"setMaxMintPerBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minPrice","type":"uint256"}],"name":"setMinPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_router","type":"address"}],"name":"setRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"transferAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a06040523461004a5761001d61001461015d565b9291909161020a565b61002561004f565b61274a6107d08239608051818181610bcd01528181611ad30152612464015261274a90f35b610055565b60405190565b5f80fd5b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b9061008190610059565b810190811060018060401b0382111761009957604052565b610063565b906100b16100aa61004f565b9283610077565b565b5f80fd5b60018060a01b031690565b6100cb906100b7565b90565b6100d7816100c2565b036100de57565b5f80fd5b905051906100ef826100ce565b565b90565b6100fd816100f1565b0361010457565b5f80fd5b90505190610115826100f4565b565b6080818303126101585761012d825f83016100e2565b9261015561013e84602085016100e2565b9361014c81604086016100e2565b93606001610108565b90565b6100b3565b61017b612f1a803803806101708161009e565b928339810190610117565b90919293565b90565b90565b5f1b90565b6101a061019b6101a592610181565b610187565b610184565b90565b6101b15f61018c565b90565b90565b6101cb6101c66101d0926100b7565b6101b4565b6100b7565b90565b6101dc906101b7565b90565b6101e8906101d3565b90565b90565b6102026101fd610207926101eb565b6101b4565b6100f1565b90565b9161022d6102359261022761023a96956102226101a8565b61034d565b506101df565b608052610458565b610551565b61025361024e670d7621dc582100006101ee565b610597565b565b5f90565b5f1c90565b60018060a01b031690565b61027561027a91610259565b61025e565b90565b6102879054610269565b90565b610293906101b7565b90565b61029f9061028a565b90565b5f0190565b906102b860018060a01b0391610187565b9181191691161790565b90565b906102da6102d56102e192610296565b6102c2565b82546102a7565b9055565b1b90565b9190600861030991029161030360018060a01b03846102e5565b926102e5565b9181191691161790565b919061032961032461033193610296565b6102c2565b9083546102e9565b9055565b5f90565b61034b91610345610335565b91610313565b565b906103809161035a610255565b508061037561036f61036a6101a8565b610184565b91610184565b14610383575b6106c7565b90565b61038d600161027d565b826103c16103bb7ff8ccb027dfcd135e000e9d45e6cc2d662578a8825d4c45b5e32e0adf67e79ec693610296565b91610296565b916103ca61004f565b806103d4816102a2565b0390a36103f26103e26101a8565b6103ec600161027d565b90610626565b506103fe8260016102c5565b6104095f6002610339565b61037b565b61042261041d61042792610181565b6101b4565b6100b7565b90565b6104339061040e565b90565b61043f906100c2565b9052565b9190610456905f60208501940190610436565b565b8061047361046d6104685f61042a565b6100c2565b916100c2565b146104be576104838160036102c5565b6104b97fc6b438e6a8a59579ce6a4406cbd203b740e0d47b458aae6596339bcd40c40d15916104b061004f565b91829182610443565b0390a1565b5f63af458c0760e01b8152806104d6600482016102a2565b0390fd5b906104e65f1991610187565b9181191691161790565b6105046104ff610509926100f1565b6101b4565b6100f1565b90565b90565b9061052461051f61052b926104f0565b61050c565b82546104da565b9055565b610538906100f1565b9052565b919061054f905f6020850194019061052f565b565b61055c81600761050f565b6105927fe1b368592558744bdb635eeeeddf890372561df0c1b3d0a05cd12b71ec6beba29161058961004f565b9182918261053c565b0390a1565b6105a290600561050f565b565b6105ad90610184565b90565b906105ba906105a4565b5f5260205260405f2090565b906105d090610296565b5f5260205260405f2090565b906105e860ff91610187565b9181191691161790565b151590565b610600906105f2565b90565b90565b9061061b610616610622926105f7565b610603565b82546105dc565b9055565b61062e610255565b5061063a818390610799565b5f146106c1576106605f61065b5f6106538186906105b0565b0185906105c6565b610606565b906106696107c2565b906106a66106a061069a7ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b956105a4565b92610296565b92610296565b926106af61004f565b806106b9816102a2565b0390a4600190565b50505f90565b6106cf610255565b506106e46106de828490610799565b156105f2565b5f1461076c5761070b60016107065f6106fe8186906105b0565b0185906105c6565b610606565b906107146107c2565b9061075161074b6107457f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d956105a4565b92610296565b92610296565b9261075a61004f565b80610764816102a2565b0390a4600190565b50505f90565b60ff1690565b61078461078991610259565b610772565b90565b6107969054610778565b90565b6107bf915f6107b46107ba936107ad610255565b50826105b0565b016105c6565b61078c565b90565b6107ca610335565b50339056fe60806040526004361015610013575b610fd4565b61001d5f356101cc565b806301ffc9a7146101c757806308cb7451146101c25780630e18b681146101bd5780631bf6c21b146101b8578063248a9ca3146101b35780632ba32991146101ae5780632f2ff15d146101a957806336568abe146101a4578063464b41581461019f5780634a5e42b11461019a5780635ea8cd121461019557806375829def146101905780638b0dcb4e1461018b5780638da5cb5b146101865780639079ace61461018157806391d148541461017c578063928907dd146101775780639cd2913614610172578063a217fddf1461016d578063afad2e1614610168578063c0d7865514610163578063c3db97b41461015e578063d2fe78e614610159578063d547741f14610154578063da4899971461014f578063e45be8eb1461014a5763f887ea400361000e57610f9f565b610f35565b610ef2565b610e91565b610e5c565b610c1d565b610b98565b610b63565b610a9d565b610a2f565b6109fa565b6109b5565b61097f565b61094a565b610911565b610735565b610702565b6106cf565b61069a565b610648565b610614565b6105b2565b6104c2565b610427565b6103c1565b610377565b610258565b60e01c90565b60405190565b5f80fd5b5f80fd5b5f80fd5b63ffffffff60e01b1690565b6101f9816101e4565b0361020057565b5f80fd5b90503590610211826101f0565b565b9060208282031261022c57610229915f01610204565b90565b6101dc565b151590565b61023f90610231565b9052565b9190610256905f60208501940190610236565b565b346102885761028461027361026e366004610213565b610fdc565b61027b6101d2565b91829182610243565b0390f35b6101d8565b60018060a01b031690565b6102a19061028d565b90565b6102ad81610298565b036102b457565b5f80fd5b905035906102c5826102a4565b565b90565b6102d3816102c7565b036102da57565b5f80fd5b905035906102eb826102ca565b565b91906040838203126103155780610309610312925f86016102b8565b936020016102de565b90565b6101dc565b634e487b7160e01b5f52602160045260245ffd5b6002111561033857565b61031a565b906103478261032e565b565b6103529061033d565b90565b61035e90610349565b9052565b9190610375905f60208501940190610355565b565b346103a8576103a461039361038d3660046102ed565b90611020565b61039b6101d2565b91829182610362565b0390f35b6101d8565b5f9103126103b757565b6101dc565b5f0190565b346103ef576103d13660046103ad565b6103d9611050565b6103e16101d2565b806103eb816103bc565b0390f35b6101d8565b61034890565b6104026103f4565b90565b61040e90610298565b9052565b9190610425905f60208501940190610405565b565b34610457576104373660046103ad565b6104536104426103fa565b61044a6101d2565b91829182610412565b0390f35b6101d8565b90565b6104688161045c565b0361046f57565b5f80fd5b905035906104808261045f565b565b9060208282031261049b57610498915f01610473565b90565b6101dc565b6104a99061045c565b9052565b91906104c0905f602085019401906104a0565b565b346104f2576104ee6104dd6104d8366004610482565b6110fa565b6104e56101d2565b918291826104ad565b0390f35b6101d8565b906020828203126105105761050d915f016102de565b90565b6101dc565b90565b61052c610527610531926102c7565b610515565b6102c7565b90565b9061053e90610518565b5f5260205260405f2090565b1c90565b90565b610561906008610566930261054a565b61054e565b90565b906105749154610551565b90565b61058d906105886006915f92610534565b610569565b90565b610599906102c7565b9052565b91906105b0905f60208501940190610590565b565b346105e2576105de6105cd6105c83660046104f7565b610577565b6105d56101d2565b9182918261059d565b0390f35b6101d8565b919060408382031261060f578061060361060c925f8601610473565b936020016102b8565b90565b6101dc565b346106435761062d6106273660046105e7565b9061118b565b6106356101d2565b8061063f816103bc565b0390f35b6101d8565b346106775761066161065b3660046105e7565b906111ea565b6106696101d2565b80610673816103bc565b0390f35b6101d8565b9060208282031261069557610692915f016102b8565b90565b6101dc565b346106ca576106c66106b56106b036600461067c565b6111f6565b6106bd6101d2565b91829182610243565b0390f35b6101d8565b346106fd576106e76106e236600461067c565b61123d565b6106ef6101d2565b806106f9816103bc565b0390f35b6101d8565b346107305761071a6107153660046104f7565b61126e565b6107226101d2565b8061072c816103bc565b0390f35b6101d8565b346107635761074d61074836600461067c565b6113bf565b6107556101d2565b8061075f816103bc565b0390f35b6101d8565b61077c6107776107819261028d565b610515565b61028d565b90565b61078d90610768565b90565b61079990610784565b90565b906107a690610790565b5f5260205260405f2090565b5f1c90565b60ff1690565b6107c96107ce916107b2565b6107b7565b90565b6107db90546107bd565b90565b60081c90565b60018060a01b031690565b6107fb610800916107de565b6107e4565b90565b61080d90546107ef565b90565b60a81c90565b60ff1690565b61082861082d91610810565b610816565b90565b61083a905461081c565b90565b60018060a01b031690565b610854610859916107b2565b61083d565b90565b6108669054610848565b90565b61087490600461079c565b906108805f83016107d1565b9161088c5f8201610803565b916108a4600161089d5f8501610830565b930161085c565b90565b60ff1690565b6108b6906108a7565b9052565b6108c390610784565b90565b6108cf906108ba565b9052565b61090861090f946108fe6060949897956108f4608086019a5f870190610236565b6020850190610405565b60408301906108ad565b01906108c6565b565b346109455761094161092c61092736600461067c565b610869565b906109389492946101d2565b948594856108d3565b0390f35b6101d8565b3461097a5761095a3660046103ad565b6109766109656113ce565b61096d6101d2565b91829182610412565b0390f35b6101d8565b346109b0576109ac61099b6109953660046102ed565b9061157f565b6109a36101d2565b9182918261059d565b0390f35b6101d8565b346109e6576109e26109d16109cb3660046105e7565b90611726565b6109d96101d2565b91829182610243565b0390f35b6101d8565b6109f760075f90610569565b90565b34610a2a57610a0a3660046103ad565b610a26610a156109eb565b610a1d6101d2565b9182918261059d565b0390f35b6101d8565b34610a5d57610a47610a423660046104f7565b611775565b610a4f6101d2565b80610a59816103bc565b0390f35b6101d8565b90565b5f1b90565b610a7e610a79610a8392610a62565b610a65565b61045c565b90565b610a8f5f610a6a565b90565b610a9a610a86565b90565b34610acd57610aad3660046103ad565b610ac9610ab8610a92565b610ac06101d2565b918291826104ad565b0390f35b6101d8565b610adb90610231565b9052565b610ae890610298565b9052565b610af5906108a7565b9052565b610b02906108ba565b9052565b90606080610b4c93610b1e5f8201515f860190610ad2565b610b3060208201516020860190610adf565b610b4260408201516040860190610aec565b0151910190610af9565b565b9190610b61905f60808501940190610b06565b565b34610b9357610b8f610b7e610b7936600461067c565b61189d565b610b866101d2565b91829182610b4e565b0390f35b6101d8565b34610bc657610bb0610bab36600461067c565b6118e2565b610bb86101d2565b80610bc2816103bc565b0390f35b6101d8565b7f000000000000000000000000000000000000000000000000000000000000000090565b610bf890610784565b90565b610c0490610bef565b9052565b9190610c1b905f60208501940190610bfb565b565b34610c4d57610c2d3660046103ad565b610c49610c38610bcb565b610c406101d2565b91829182610c08565b0390f35b6101d8565b5f80fd5b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b90610c7e90610c56565b810190811067ffffffffffffffff821117610c9857604052565b610c60565b90610cb0610ca96101d2565b9283610c74565b565b5f80fd5b60021115610cc057565b5f80fd5b90503590610cd182610cb6565b565b5f80fd5b5f80fd5b67ffffffffffffffff8111610cf957610cf5602091610c56565b0190565b610c60565b90825f939282370152565b90929192610d1e610d1982610cdb565b610c9d565b93818552602085019082840111610d3a57610d3892610cfe565b565b610cd7565b9080601f83011215610d5d57816020610d5a93359101610d09565b90565b610cd3565b91909161010081840312610e2257610d7b610100610c9d565b92610d88815f8401610cc4565b5f850152610d9981602084016102de565b6020850152610dab81604084016102b8565b6040850152610dbd81606084016102b8565b6060850152610dcf81608084016102b8565b6080850152610de18160a084016102de565b60a0850152610df38160c084016102de565b60c085015260e082013567ffffffffffffffff8111610e1d57610e169201610d3f565b60e0830152565b610cb2565b610c52565b90602082820312610e57575f82013567ffffffffffffffff8111610e5257610e4f9201610d62565b90565b6101e0565b6101dc565b34610e8c57610e88610e77610e72366004610e27565b611bd7565b610e7f6101d2565b9182918261059d565b0390f35b6101d8565b34610ec057610eaa610ea43660046105e7565b90611c5b565b610eb26101d2565b80610ebc816103bc565b0390f35b6101d8565b9190604083820312610eed5780610ee1610eea925f86016102b8565b936020016102b8565b90565b6101dc565b34610f2157610f0b610f05366004610ec5565b90611c8f565b610f136101d2565b80610f1d816103bc565b0390f35b6101d8565b610f3260055f90610569565b90565b34610f6557610f453660046103ad565b610f61610f50610f26565b610f586101d2565b9182918261059d565b0390f35b6101d8565b610f7a906008610f7f930261054a565b6107e4565b90565b90610f8d9154610f6a565b90565b610f9c60035f90610f82565b90565b34610fcf57610faf3660046103ad565b610fcb610fba610f90565b610fc26101d2565b91829182610412565b0390f35b6101d8565b5f80fd5b5f90565b610fe4610fd8565b5080610fff610ff9637965db0b60e01b6101e4565b916101e4565b1490811561100c575b5090565b6110169150611c9b565b5f611008565b5f90565b505061102a61101c565b505f90565b61103b611040916107b2565b6107e4565b90565b61104d905461102f565b90565b611058611cc1565b61107361106d6110686002611043565b610298565b91610298565b0361109457611091611083610a86565b61108b611cc1565b90611d32565b50565b5f63058d9a1b60e01b8152806110ac600482016103bc565b0390fd5b5f90565b6110bd9061045c565b90565b906110ca906110b4565b5f5260205260405f2090565b90565b6110e56110ea916107b2565b6110d6565b90565b6110f790546110d9565b90565b60016111126111189261110b6110b0565b505f6110c0565b016110ed565b90565b906111359161113061112b610a86565b611df3565b611137565b565b908161115261114c611147610a86565b61045c565b9161045c565b14611162576111609161117e565b565b5f63318bd07d60e11b81528061117a600482016103bc565b0390fd5b9061118891611d32565b50565b906111959161111b565b565b90816111b26111ac6111a7610a86565b61045c565b9161045c565b146111c2576111c0916111de565b565b5f63318bd07d60e11b8152806111da600482016103bc565b0390fd5b906111e891611e07565b565b906111f491611197565b565b5f61120e61121492611206610fd8565b50600461079c565b016107d1565b90565b6112309061122b611226610a86565b611df3565b611232565b565b61123b90611e86565b565b61124690611217565b565b6112619061125c611257610a86565b611df3565b611263565b565b61126c90611ed6565b565b61127790611248565b565b6112929061128d611288610a86565b611df3565b6112fa565b565b6112a86112a36112ad92610a62565b610515565b61028d565b90565b6112b990611294565b90565b906112cd60018060a01b0391610a65565b9181191691161790565b90565b906112ef6112ea6112f692610790565b6112d7565b82546112bc565b9055565b8061131561130f61130a5f6112b0565b610298565b91610298565b14801561139e575b6113825761132c8160026112da565b6113366001611043565b9061136a6113647fefdcbba819467e00b0262c12892dda980bac68580b72178e57a162368b80876693610790565b91610790565b916113736101d2565b8061137d816103bc565b0390a3565b5f63318bd07d60e11b81528061139a600482016103bc565b0390fd5b50806113b96113b36113ae611cc1565b610298565b91610298565b1461131d565b6113c890611279565b565b5f90565b6113d66113ca565b506113e16001611043565b90565b5f90565b634e487b7160e01b5f52601160045260245ffd5b611405906108a7565b604d811161141357600a0a90565b6113e8565b5f80fd5b60e01b90565b9050519061142f826102ca565b565b9060208282031261144a57611447915f01611422565b90565b6101dc565b60409061147861147f949695939661146e60608401985f850190610590565b6020830190610405565b0190610405565b565b6114896101d2565b3d5f823e3d90fd5b61149d6114a2916107b2565b61054e565b90565b6114af9054611491565b90565b90565b6114c96114c46114ce926114b2565b610515565b6102c7565b90565b90565b6114e86114e36114ed926114d1565b610515565b6108a7565b90565b6114fc611502916108a7565b916108a7565b90039060ff821161150f57565b6113e8565b611523611529919392936102c7565b926102c7565b916115358382026102c7565b92818404149015171561154457565b6113e8565b634e487b7160e01b5f52601260045260245ffd5b61156961156f916102c7565b916102c7565b90811561157a570490565b611549565b6115876113e4565b5061159e5f6115986004849061079c565b01610830565b9060206115c06115bb60016115b56004869061079c565b0161085c565b6108ba565b9163ae68676c926115f46115d3866113fc565b92946115ff6115e06103f4565b6115e86101d2565b9788968795869561141c565b85526004850161144f565b03915afa90811561170b575f916116dd575b50918261162f61162961162460056114a5565b6102c7565b916102c7565b106116c25761168561168b92846116a29561165a611654670de0b6b3a76400006114b5565b916102c7565b105f146116a55761167a61167f915b949261167560126114d4565b6114f0565b6113fc565b90611514565b90611514565b61169c670de0b6b3a76400006114b5565b9061155d565b90565b5061167f61167a6116bd670de0b6b3a76400006114b5565b611669565b5f62bfc92160e01b8152806116d9600482016103bc565b0390fd5b6116fe915060203d8111611704575b6116f68183610c74565b810190611431565b5f611611565b503d6116ec565b611481565b9061171a90610790565b5f5260205260405f2090565b61174c915f6117416117479361173a610fd8565b50826110c0565b01611710565b6107d1565b90565b6117689061176361175e610a86565b611df3565b61176a565b565b61177390611ee3565b565b61177e9061174f565b565b61178a6080610c9d565b90565b5f90565b5f90565b5f90565b5f90565b6117a5611780565b906020808080856117b461178d565b8152016117bf611791565b8152016117ca611795565b8152016117d5611799565b81525050565b6117e361179d565b90565b906117f090610231565b9052565b906117fe90610298565b9052565b9061180c906108a7565b9052565b61181990610298565b90565b9061182690611810565b9052565b9061188f611886600161183b611780565b9461185261184a5f83016107d1565b5f88016117e6565b6118696118605f8301610803565b602088016117f4565b6118806118775f8301610830565b60408801611802565b0161085c565b6060840161181c565b565b61189a9061182a565b90565b6118b46118b9916118ac6117db565b50600461079c565b611891565b90565b6118d5906118d06118cb610a86565b611df3565b6118d7565b565b6118e090611f29565b565b6118eb906118bc565b565b903361190a6119046118ff6003611043565b610298565b91610298565b0361191b5761191891611a09565b90565b5f639e41bdd760e01b815280611933600482016103bc565b0390fd5b6002111561194157565b61031a565b9061195082611937565b565b61195c9051611946565b90565b61196990516102c7565b90565b6119769051610298565b90565b61198861198e919392936102c7565b926102c7565b820180921161199957565b6113e8565b906119aa5f1991610a65565b9181191691161790565b90565b906119cc6119c76119d392610518565b6119b4565b825461199e565b9055565b5f9103126119e157565b6101dc565b916020611a07929493611a0060408201965f830190610405565b0190610590565b565b50611a155f8201611952565b611a27611a215f611946565b91611946565b03611bbb57611a386020820161195f565b611a4a611a44426102c7565b916102c7565b10611b9f57611a5881611fc7565b611a79611a676080830161196c565b611a7360a0840161195f565b9061157f565b9081611a98611a92611a8d60c0850161195f565b6102c7565b916102c7565b10611b8357611aa6826120dd565b611ace82611ac8611ab960064390610534565b91611ac3836114a5565b611979565b906119b7565b611af77f0000000000000000000000000000000000000000000000000000000000000000610bef565b90611b0960606340c10f19920161196c565b8392803b15611b7e57611b2f5f8094611b3a611b236101d2565b9788968795869461141c565b8452600484016119e6565b03925af18015611b7957611b4d575b5090565b611b6c905f3d8111611b72575b611b648183610c74565b8101906119d7565b5f611b49565b503d611b5a565b611481565b611418565b5f638199f5f360e01b815280611b9b600482016103bc565b0390fd5b5f6362b439dd60e11b815280611bb7600482016103bc565b0390fd5b5f63af61069360e01b815280611bd3600482016103bc565b0390fd5b611be890611be36113e4565b6118ed565b90565b90611c0591611c00611bfb610a86565b611df3565b611c07565b565b9081611c22611c1c611c17610a86565b61045c565b9161045c565b14611c3257611c3091611c4e565b565b5f63318bd07d60e11b815280611c4a600482016103bc565b0390fd5b90611c589161217d565b50565b90611c6591611beb565b565b90611c8191611c7c611c77610a86565b611df3565b611c83565b565b90611c8d91612431565b565b90611c9991611c67565b565b611ca3610fd8565b50611cbd611cb76301ffc9a760e01b6101e4565b916101e4565b1490565b611cc96113ca565b503390565b1b90565b91906008611cf2910291611cec60018060a01b0384611cce565b92611cce565b9181191691161790565b9190611d12611d0d611d1a93610790565b6112d7565b908354611cd2565b9055565b611d3091611d2a6113ca565b91611cfc565b565b90611d6591611d3f610fd8565b5080611d5a611d54611d4f610a86565b61045c565b9161045c565b14611d68575b61260b565b90565b611d726001611043565b82611da6611da07ff8ccb027dfcd135e000e9d45e6cc2d662578a8825d4c45b5e32e0adf67e79ec693610790565b91610790565b91611daf6101d2565b80611db9816103bc565b0390a3611dd7611dc7610a86565b611dd16001611043565b9061217d565b50611de38260016112da565b611dee5f6002611d1e565b611d60565b611e0590611dff611cc1565b906126d9565b565b9080611e22611e1c611e17611cc1565b610298565b91610298565b03611e3357611e309161217d565b50565b5f63334bd91960e11b815280611e4b600482016103bc565b0390fd5b60015f9182808201550155565b634e487b7160e01b5f525f60045260245ffd5b905f03611e8157611e7f90611e4f565b565b611e5c565b611e9b5f611e966004849061079c565b611e6f565b611ed17f37803e2125c48ee96c38ddf04e826daf335b0e1603579040fd275aba6d06b6fc91611ec86101d2565b91829182610412565b0390a1565b611ee19060056119b7565b565b611eee8160076119b7565b611f247fe1b368592558744bdb635eeeeddf890372561df0c1b3d0a05cd12b71ec6beba291611f1b6101d2565b9182918261059d565b0390a1565b80611f44611f3e611f395f6112b0565b610298565b91610298565b14611f8f57611f548160036112da565b611f8a7fc6b438e6a8a59579ce6a4406cbd203b740e0d47b458aae6596339bcd40c40d1591611f816101d2565b91829182610412565b0390a1565b5f63af458c0760e01b815280611fa7600482016103bc565b0390fd5b611fbf611fba611fc492610a62565b610515565b6102c7565b90565b611fd36060820161196c565b611fed611fe7611fe25f6112b0565b610298565b91610298565b146120c157611ffe6080820161196c565b61201861201261200d5f6112b0565b610298565b91610298565b146120a5576120296040820161196c565b61204361203d6120385f6112b0565b610298565b91610298565b146120895760a0612054910161195f565b6120666120605f611fab565b916102c7565b1461206d57565b5f63af458c0760e01b815280612085600482016103bc565b0390fd5b5f63af458c0760e01b8152806120a1600482016103bc565b0390fd5b5f63af458c0760e01b8152806120bd600482016103bc565b0390fd5b5f63af458c0760e01b8152806120d9600482016103bc565b0390fd5b6120fa906120f56120f060064390610534565b6114a5565b611979565b61211561210f61210a60076114a5565b6102c7565b916102c7565b1161211c57565b5f630fbf0bc960e01b815280612134600482016103bc565b0390fd5b9061214460ff91610a65565b9181191691161790565b61215790610231565b90565b90565b9061217261216d6121799261214e565b61215a565b8254612138565b9055565b612185610fd8565b50612191818390611726565b5f14612218576121b75f6121b25f6121aa8186906110c0565b018590611710565b61215d565b906121c0611cc1565b906121fd6121f76121f17ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b956110b4565b92610790565b92610790565b926122066101d2565b80612210816103bc565b0390a4600190565b50505f90565b61222790610768565b90565b6122339061221e565b90565b61223f90610784565b90565b61224b816108a7565b0361225257565b5f80fd5b9050519061226382612242565b565b9060208282031261227e5761227b915f01612256565b90565b6101dc565b61228c90610768565b90565b61229890612283565b90565b6122a56080610c9d565b90565b6122b29051610231565b90565b60081b90565b906122ce610100600160a81b03916122b5565b9181191691161790565b906122ed6122e86122f492610790565b6112d7565b82546122bb565b9055565b61230290516108a7565b90565b60a81b90565b9061231a60ff60a81b91612305565b9181191691161790565b61233861233361233d926108a7565b610515565b6108a7565b90565b90565b9061235861235361235f92612324565b612340565b825461230b565b9055565b61236d9051611810565b90565b61237990612283565b90565b90565b9061239461238f61239b92612370565b61237c565b82546112bc565b9055565b906123fa60606001612400946123c25f82016123bc5f88016122a8565b9061215d565b6123da5f82016123d46020880161196c565b906122d8565b6123f25f82016123ec604088016122f8565b90612343565b019201612363565b9061237f565b565b9061240c9161239f565b565b91602061242f92949361242860408201965f830190610405565b0190610405565b565b8061244c6124466124415f6112b0565b610298565b91610298565b1480156125e9575b6125cd578061249361248d6124887f0000000000000000000000000000000000000000000000000000000000000000610bef565b610298565b91610298565b146125b1576124c760018260206124b16124ac8661222a565b612236565b63313ce567906124bf6101d2565b95869261141c565b825281806124d7600482016103bc565b03915afa9081156125ac5761252861253192612542955f9161257e575b5061251f6125018961228f565b9361251661250d61229b565b975f89016117e6565b602087016117f4565b60408501611802565b6060830161181c565b61253d6004849061079c565b612402565b907f0bb5715f0f217c2fe9a0c877ea87d474380c641102f3440ee2a4c8b9d9790918916125796125706101d2565b9283928361240e565b0390a1565b61259f915060203d81116125a5575b6125978183610c74565b810190612265565b5f6124f4565b503d61258d565b611481565b5f63981a2a2b60e01b8152806125c9600482016103bc565b0390fd5b5f63af458c0760e01b8152806125e5600482016103bc565b0390fd5b50816126056125ff6125fa5f6112b0565b610298565b91610298565b14612454565b612613610fd8565b50612628612622828490611726565b15610231565b5f146126b05761264f600161264a5f6126428186906110c0565b018590611710565b61215d565b90612658611cc1565b9061269561268f6126897f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d956110b4565b92610790565b92610790565b9261269e6101d2565b806126a8816103bc565b0390a4600190565b50505f90565b9160206126d79294936126d060408201965f830190610405565b01906104a0565b565b906126ee6126e8838390611726565b15610231565b6126f6575050565b6127105f92839263e2517d3f60e01b8452600484016126b6565b0390fdfea2646970667358221220479ba8f25ee20bdcc5565798b2611081e015561e81c31c23562a557064c5fe1a64736f6c634300081a0033000000000000000000000000e78615f841c3c013173fbe7679d17442c8673cc1000000000000000000000000e556aba6fe6036275ec1f87eda296be72c811bce000000000000000000000000a052883ebee7354fc2aa0f9c727e657fdeca744a00000000000000000000000000000000000000000031a17e847807b1bc000000
Deployed Bytecode
0x60806040526004361015610013575b610fd4565b61001d5f356101cc565b806301ffc9a7146101c757806308cb7451146101c25780630e18b681146101bd5780631bf6c21b146101b8578063248a9ca3146101b35780632ba32991146101ae5780632f2ff15d146101a957806336568abe146101a4578063464b41581461019f5780634a5e42b11461019a5780635ea8cd121461019557806375829def146101905780638b0dcb4e1461018b5780638da5cb5b146101865780639079ace61461018157806391d148541461017c578063928907dd146101775780639cd2913614610172578063a217fddf1461016d578063afad2e1614610168578063c0d7865514610163578063c3db97b41461015e578063d2fe78e614610159578063d547741f14610154578063da4899971461014f578063e45be8eb1461014a5763f887ea400361000e57610f9f565b610f35565b610ef2565b610e91565b610e5c565b610c1d565b610b98565b610b63565b610a9d565b610a2f565b6109fa565b6109b5565b61097f565b61094a565b610911565b610735565b610702565b6106cf565b61069a565b610648565b610614565b6105b2565b6104c2565b610427565b6103c1565b610377565b610258565b60e01c90565b60405190565b5f80fd5b5f80fd5b5f80fd5b63ffffffff60e01b1690565b6101f9816101e4565b0361020057565b5f80fd5b90503590610211826101f0565b565b9060208282031261022c57610229915f01610204565b90565b6101dc565b151590565b61023f90610231565b9052565b9190610256905f60208501940190610236565b565b346102885761028461027361026e366004610213565b610fdc565b61027b6101d2565b91829182610243565b0390f35b6101d8565b60018060a01b031690565b6102a19061028d565b90565b6102ad81610298565b036102b457565b5f80fd5b905035906102c5826102a4565b565b90565b6102d3816102c7565b036102da57565b5f80fd5b905035906102eb826102ca565b565b91906040838203126103155780610309610312925f86016102b8565b936020016102de565b90565b6101dc565b634e487b7160e01b5f52602160045260245ffd5b6002111561033857565b61031a565b906103478261032e565b565b6103529061033d565b90565b61035e90610349565b9052565b9190610375905f60208501940190610355565b565b346103a8576103a461039361038d3660046102ed565b90611020565b61039b6101d2565b91829182610362565b0390f35b6101d8565b5f9103126103b757565b6101dc565b5f0190565b346103ef576103d13660046103ad565b6103d9611050565b6103e16101d2565b806103eb816103bc565b0390f35b6101d8565b61034890565b6104026103f4565b90565b61040e90610298565b9052565b9190610425905f60208501940190610405565b565b34610457576104373660046103ad565b6104536104426103fa565b61044a6101d2565b91829182610412565b0390f35b6101d8565b90565b6104688161045c565b0361046f57565b5f80fd5b905035906104808261045f565b565b9060208282031261049b57610498915f01610473565b90565b6101dc565b6104a99061045c565b9052565b91906104c0905f602085019401906104a0565b565b346104f2576104ee6104dd6104d8366004610482565b6110fa565b6104e56101d2565b918291826104ad565b0390f35b6101d8565b906020828203126105105761050d915f016102de565b90565b6101dc565b90565b61052c610527610531926102c7565b610515565b6102c7565b90565b9061053e90610518565b5f5260205260405f2090565b1c90565b90565b610561906008610566930261054a565b61054e565b90565b906105749154610551565b90565b61058d906105886006915f92610534565b610569565b90565b610599906102c7565b9052565b91906105b0905f60208501940190610590565b565b346105e2576105de6105cd6105c83660046104f7565b610577565b6105d56101d2565b9182918261059d565b0390f35b6101d8565b919060408382031261060f578061060361060c925f8601610473565b936020016102b8565b90565b6101dc565b346106435761062d6106273660046105e7565b9061118b565b6106356101d2565b8061063f816103bc565b0390f35b6101d8565b346106775761066161065b3660046105e7565b906111ea565b6106696101d2565b80610673816103bc565b0390f35b6101d8565b9060208282031261069557610692915f016102b8565b90565b6101dc565b346106ca576106c66106b56106b036600461067c565b6111f6565b6106bd6101d2565b91829182610243565b0390f35b6101d8565b346106fd576106e76106e236600461067c565b61123d565b6106ef6101d2565b806106f9816103bc565b0390f35b6101d8565b346107305761071a6107153660046104f7565b61126e565b6107226101d2565b8061072c816103bc565b0390f35b6101d8565b346107635761074d61074836600461067c565b6113bf565b6107556101d2565b8061075f816103bc565b0390f35b6101d8565b61077c6107776107819261028d565b610515565b61028d565b90565b61078d90610768565b90565b61079990610784565b90565b906107a690610790565b5f5260205260405f2090565b5f1c90565b60ff1690565b6107c96107ce916107b2565b6107b7565b90565b6107db90546107bd565b90565b60081c90565b60018060a01b031690565b6107fb610800916107de565b6107e4565b90565b61080d90546107ef565b90565b60a81c90565b60ff1690565b61082861082d91610810565b610816565b90565b61083a905461081c565b90565b60018060a01b031690565b610854610859916107b2565b61083d565b90565b6108669054610848565b90565b61087490600461079c565b906108805f83016107d1565b9161088c5f8201610803565b916108a4600161089d5f8501610830565b930161085c565b90565b60ff1690565b6108b6906108a7565b9052565b6108c390610784565b90565b6108cf906108ba565b9052565b61090861090f946108fe6060949897956108f4608086019a5f870190610236565b6020850190610405565b60408301906108ad565b01906108c6565b565b346109455761094161092c61092736600461067c565b610869565b906109389492946101d2565b948594856108d3565b0390f35b6101d8565b3461097a5761095a3660046103ad565b6109766109656113ce565b61096d6101d2565b91829182610412565b0390f35b6101d8565b346109b0576109ac61099b6109953660046102ed565b9061157f565b6109a36101d2565b9182918261059d565b0390f35b6101d8565b346109e6576109e26109d16109cb3660046105e7565b90611726565b6109d96101d2565b91829182610243565b0390f35b6101d8565b6109f760075f90610569565b90565b34610a2a57610a0a3660046103ad565b610a26610a156109eb565b610a1d6101d2565b9182918261059d565b0390f35b6101d8565b34610a5d57610a47610a423660046104f7565b611775565b610a4f6101d2565b80610a59816103bc565b0390f35b6101d8565b90565b5f1b90565b610a7e610a79610a8392610a62565b610a65565b61045c565b90565b610a8f5f610a6a565b90565b610a9a610a86565b90565b34610acd57610aad3660046103ad565b610ac9610ab8610a92565b610ac06101d2565b918291826104ad565b0390f35b6101d8565b610adb90610231565b9052565b610ae890610298565b9052565b610af5906108a7565b9052565b610b02906108ba565b9052565b90606080610b4c93610b1e5f8201515f860190610ad2565b610b3060208201516020860190610adf565b610b4260408201516040860190610aec565b0151910190610af9565b565b9190610b61905f60808501940190610b06565b565b34610b9357610b8f610b7e610b7936600461067c565b61189d565b610b866101d2565b91829182610b4e565b0390f35b6101d8565b34610bc657610bb0610bab36600461067c565b6118e2565b610bb86101d2565b80610bc2816103bc565b0390f35b6101d8565b7f000000000000000000000000e556aba6fe6036275ec1f87eda296be72c811bce90565b610bf890610784565b90565b610c0490610bef565b9052565b9190610c1b905f60208501940190610bfb565b565b34610c4d57610c2d3660046103ad565b610c49610c38610bcb565b610c406101d2565b91829182610c08565b0390f35b6101d8565b5f80fd5b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b90610c7e90610c56565b810190811067ffffffffffffffff821117610c9857604052565b610c60565b90610cb0610ca96101d2565b9283610c74565b565b5f80fd5b60021115610cc057565b5f80fd5b90503590610cd182610cb6565b565b5f80fd5b5f80fd5b67ffffffffffffffff8111610cf957610cf5602091610c56565b0190565b610c60565b90825f939282370152565b90929192610d1e610d1982610cdb565b610c9d565b93818552602085019082840111610d3a57610d3892610cfe565b565b610cd7565b9080601f83011215610d5d57816020610d5a93359101610d09565b90565b610cd3565b91909161010081840312610e2257610d7b610100610c9d565b92610d88815f8401610cc4565b5f850152610d9981602084016102de565b6020850152610dab81604084016102b8565b6040850152610dbd81606084016102b8565b6060850152610dcf81608084016102b8565b6080850152610de18160a084016102de565b60a0850152610df38160c084016102de565b60c085015260e082013567ffffffffffffffff8111610e1d57610e169201610d3f565b60e0830152565b610cb2565b610c52565b90602082820312610e57575f82013567ffffffffffffffff8111610e5257610e4f9201610d62565b90565b6101e0565b6101dc565b34610e8c57610e88610e77610e72366004610e27565b611bd7565b610e7f6101d2565b9182918261059d565b0390f35b6101d8565b34610ec057610eaa610ea43660046105e7565b90611c5b565b610eb26101d2565b80610ebc816103bc565b0390f35b6101d8565b9190604083820312610eed5780610ee1610eea925f86016102b8565b936020016102b8565b90565b6101dc565b34610f2157610f0b610f05366004610ec5565b90611c8f565b610f136101d2565b80610f1d816103bc565b0390f35b6101d8565b610f3260055f90610569565b90565b34610f6557610f453660046103ad565b610f61610f50610f26565b610f586101d2565b9182918261059d565b0390f35b6101d8565b610f7a906008610f7f930261054a565b6107e4565b90565b90610f8d9154610f6a565b90565b610f9c60035f90610f82565b90565b34610fcf57610faf3660046103ad565b610fcb610fba610f90565b610fc26101d2565b91829182610412565b0390f35b6101d8565b5f80fd5b5f90565b610fe4610fd8565b5080610fff610ff9637965db0b60e01b6101e4565b916101e4565b1490811561100c575b5090565b6110169150611c9b565b5f611008565b5f90565b505061102a61101c565b505f90565b61103b611040916107b2565b6107e4565b90565b61104d905461102f565b90565b611058611cc1565b61107361106d6110686002611043565b610298565b91610298565b0361109457611091611083610a86565b61108b611cc1565b90611d32565b50565b5f63058d9a1b60e01b8152806110ac600482016103bc565b0390fd5b5f90565b6110bd9061045c565b90565b906110ca906110b4565b5f5260205260405f2090565b90565b6110e56110ea916107b2565b6110d6565b90565b6110f790546110d9565b90565b60016111126111189261110b6110b0565b505f6110c0565b016110ed565b90565b906111359161113061112b610a86565b611df3565b611137565b565b908161115261114c611147610a86565b61045c565b9161045c565b14611162576111609161117e565b565b5f63318bd07d60e11b81528061117a600482016103bc565b0390fd5b9061118891611d32565b50565b906111959161111b565b565b90816111b26111ac6111a7610a86565b61045c565b9161045c565b146111c2576111c0916111de565b565b5f63318bd07d60e11b8152806111da600482016103bc565b0390fd5b906111e891611e07565b565b906111f491611197565b565b5f61120e61121492611206610fd8565b50600461079c565b016107d1565b90565b6112309061122b611226610a86565b611df3565b611232565b565b61123b90611e86565b565b61124690611217565b565b6112619061125c611257610a86565b611df3565b611263565b565b61126c90611ed6565b565b61127790611248565b565b6112929061128d611288610a86565b611df3565b6112fa565b565b6112a86112a36112ad92610a62565b610515565b61028d565b90565b6112b990611294565b90565b906112cd60018060a01b0391610a65565b9181191691161790565b90565b906112ef6112ea6112f692610790565b6112d7565b82546112bc565b9055565b8061131561130f61130a5f6112b0565b610298565b91610298565b14801561139e575b6113825761132c8160026112da565b6113366001611043565b9061136a6113647fefdcbba819467e00b0262c12892dda980bac68580b72178e57a162368b80876693610790565b91610790565b916113736101d2565b8061137d816103bc565b0390a3565b5f63318bd07d60e11b81528061139a600482016103bc565b0390fd5b50806113b96113b36113ae611cc1565b610298565b91610298565b1461131d565b6113c890611279565b565b5f90565b6113d66113ca565b506113e16001611043565b90565b5f90565b634e487b7160e01b5f52601160045260245ffd5b611405906108a7565b604d811161141357600a0a90565b6113e8565b5f80fd5b60e01b90565b9050519061142f826102ca565b565b9060208282031261144a57611447915f01611422565b90565b6101dc565b60409061147861147f949695939661146e60608401985f850190610590565b6020830190610405565b0190610405565b565b6114896101d2565b3d5f823e3d90fd5b61149d6114a2916107b2565b61054e565b90565b6114af9054611491565b90565b90565b6114c96114c46114ce926114b2565b610515565b6102c7565b90565b90565b6114e86114e36114ed926114d1565b610515565b6108a7565b90565b6114fc611502916108a7565b916108a7565b90039060ff821161150f57565b6113e8565b611523611529919392936102c7565b926102c7565b916115358382026102c7565b92818404149015171561154457565b6113e8565b634e487b7160e01b5f52601260045260245ffd5b61156961156f916102c7565b916102c7565b90811561157a570490565b611549565b6115876113e4565b5061159e5f6115986004849061079c565b01610830565b9060206115c06115bb60016115b56004869061079c565b0161085c565b6108ba565b9163ae68676c926115f46115d3866113fc565b92946115ff6115e06103f4565b6115e86101d2565b9788968795869561141c565b85526004850161144f565b03915afa90811561170b575f916116dd575b50918261162f61162961162460056114a5565b6102c7565b916102c7565b106116c25761168561168b92846116a29561165a611654670de0b6b3a76400006114b5565b916102c7565b105f146116a55761167a61167f915b949261167560126114d4565b6114f0565b6113fc565b90611514565b90611514565b61169c670de0b6b3a76400006114b5565b9061155d565b90565b5061167f61167a6116bd670de0b6b3a76400006114b5565b611669565b5f62bfc92160e01b8152806116d9600482016103bc565b0390fd5b6116fe915060203d8111611704575b6116f68183610c74565b810190611431565b5f611611565b503d6116ec565b611481565b9061171a90610790565b5f5260205260405f2090565b61174c915f6117416117479361173a610fd8565b50826110c0565b01611710565b6107d1565b90565b6117689061176361175e610a86565b611df3565b61176a565b565b61177390611ee3565b565b61177e9061174f565b565b61178a6080610c9d565b90565b5f90565b5f90565b5f90565b5f90565b6117a5611780565b906020808080856117b461178d565b8152016117bf611791565b8152016117ca611795565b8152016117d5611799565b81525050565b6117e361179d565b90565b906117f090610231565b9052565b906117fe90610298565b9052565b9061180c906108a7565b9052565b61181990610298565b90565b9061182690611810565b9052565b9061188f611886600161183b611780565b9461185261184a5f83016107d1565b5f88016117e6565b6118696118605f8301610803565b602088016117f4565b6118806118775f8301610830565b60408801611802565b0161085c565b6060840161181c565b565b61189a9061182a565b90565b6118b46118b9916118ac6117db565b50600461079c565b611891565b90565b6118d5906118d06118cb610a86565b611df3565b6118d7565b565b6118e090611f29565b565b6118eb906118bc565b565b903361190a6119046118ff6003611043565b610298565b91610298565b0361191b5761191891611a09565b90565b5f639e41bdd760e01b815280611933600482016103bc565b0390fd5b6002111561194157565b61031a565b9061195082611937565b565b61195c9051611946565b90565b61196990516102c7565b90565b6119769051610298565b90565b61198861198e919392936102c7565b926102c7565b820180921161199957565b6113e8565b906119aa5f1991610a65565b9181191691161790565b90565b906119cc6119c76119d392610518565b6119b4565b825461199e565b9055565b5f9103126119e157565b6101dc565b916020611a07929493611a0060408201965f830190610405565b0190610590565b565b50611a155f8201611952565b611a27611a215f611946565b91611946565b03611bbb57611a386020820161195f565b611a4a611a44426102c7565b916102c7565b10611b9f57611a5881611fc7565b611a79611a676080830161196c565b611a7360a0840161195f565b9061157f565b9081611a98611a92611a8d60c0850161195f565b6102c7565b916102c7565b10611b8357611aa6826120dd565b611ace82611ac8611ab960064390610534565b91611ac3836114a5565b611979565b906119b7565b611af77f000000000000000000000000e556aba6fe6036275ec1f87eda296be72c811bce610bef565b90611b0960606340c10f19920161196c565b8392803b15611b7e57611b2f5f8094611b3a611b236101d2565b9788968795869461141c565b8452600484016119e6565b03925af18015611b7957611b4d575b5090565b611b6c905f3d8111611b72575b611b648183610c74565b8101906119d7565b5f611b49565b503d611b5a565b611481565b611418565b5f638199f5f360e01b815280611b9b600482016103bc565b0390fd5b5f6362b439dd60e11b815280611bb7600482016103bc565b0390fd5b5f63af61069360e01b815280611bd3600482016103bc565b0390fd5b611be890611be36113e4565b6118ed565b90565b90611c0591611c00611bfb610a86565b611df3565b611c07565b565b9081611c22611c1c611c17610a86565b61045c565b9161045c565b14611c3257611c3091611c4e565b565b5f63318bd07d60e11b815280611c4a600482016103bc565b0390fd5b90611c589161217d565b50565b90611c6591611beb565b565b90611c8191611c7c611c77610a86565b611df3565b611c83565b565b90611c8d91612431565b565b90611c9991611c67565b565b611ca3610fd8565b50611cbd611cb76301ffc9a760e01b6101e4565b916101e4565b1490565b611cc96113ca565b503390565b1b90565b91906008611cf2910291611cec60018060a01b0384611cce565b92611cce565b9181191691161790565b9190611d12611d0d611d1a93610790565b6112d7565b908354611cd2565b9055565b611d3091611d2a6113ca565b91611cfc565b565b90611d6591611d3f610fd8565b5080611d5a611d54611d4f610a86565b61045c565b9161045c565b14611d68575b61260b565b90565b611d726001611043565b82611da6611da07ff8ccb027dfcd135e000e9d45e6cc2d662578a8825d4c45b5e32e0adf67e79ec693610790565b91610790565b91611daf6101d2565b80611db9816103bc565b0390a3611dd7611dc7610a86565b611dd16001611043565b9061217d565b50611de38260016112da565b611dee5f6002611d1e565b611d60565b611e0590611dff611cc1565b906126d9565b565b9080611e22611e1c611e17611cc1565b610298565b91610298565b03611e3357611e309161217d565b50565b5f63334bd91960e11b815280611e4b600482016103bc565b0390fd5b60015f9182808201550155565b634e487b7160e01b5f525f60045260245ffd5b905f03611e8157611e7f90611e4f565b565b611e5c565b611e9b5f611e966004849061079c565b611e6f565b611ed17f37803e2125c48ee96c38ddf04e826daf335b0e1603579040fd275aba6d06b6fc91611ec86101d2565b91829182610412565b0390a1565b611ee19060056119b7565b565b611eee8160076119b7565b611f247fe1b368592558744bdb635eeeeddf890372561df0c1b3d0a05cd12b71ec6beba291611f1b6101d2565b9182918261059d565b0390a1565b80611f44611f3e611f395f6112b0565b610298565b91610298565b14611f8f57611f548160036112da565b611f8a7fc6b438e6a8a59579ce6a4406cbd203b740e0d47b458aae6596339bcd40c40d1591611f816101d2565b91829182610412565b0390a1565b5f63af458c0760e01b815280611fa7600482016103bc565b0390fd5b611fbf611fba611fc492610a62565b610515565b6102c7565b90565b611fd36060820161196c565b611fed611fe7611fe25f6112b0565b610298565b91610298565b146120c157611ffe6080820161196c565b61201861201261200d5f6112b0565b610298565b91610298565b146120a5576120296040820161196c565b61204361203d6120385f6112b0565b610298565b91610298565b146120895760a0612054910161195f565b6120666120605f611fab565b916102c7565b1461206d57565b5f63af458c0760e01b815280612085600482016103bc565b0390fd5b5f63af458c0760e01b8152806120a1600482016103bc565b0390fd5b5f63af458c0760e01b8152806120bd600482016103bc565b0390fd5b5f63af458c0760e01b8152806120d9600482016103bc565b0390fd5b6120fa906120f56120f060064390610534565b6114a5565b611979565b61211561210f61210a60076114a5565b6102c7565b916102c7565b1161211c57565b5f630fbf0bc960e01b815280612134600482016103bc565b0390fd5b9061214460ff91610a65565b9181191691161790565b61215790610231565b90565b90565b9061217261216d6121799261214e565b61215a565b8254612138565b9055565b612185610fd8565b50612191818390611726565b5f14612218576121b75f6121b25f6121aa8186906110c0565b018590611710565b61215d565b906121c0611cc1565b906121fd6121f76121f17ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b956110b4565b92610790565b92610790565b926122066101d2565b80612210816103bc565b0390a4600190565b50505f90565b61222790610768565b90565b6122339061221e565b90565b61223f90610784565b90565b61224b816108a7565b0361225257565b5f80fd5b9050519061226382612242565b565b9060208282031261227e5761227b915f01612256565b90565b6101dc565b61228c90610768565b90565b61229890612283565b90565b6122a56080610c9d565b90565b6122b29051610231565b90565b60081b90565b906122ce610100600160a81b03916122b5565b9181191691161790565b906122ed6122e86122f492610790565b6112d7565b82546122bb565b9055565b61230290516108a7565b90565b60a81b90565b9061231a60ff60a81b91612305565b9181191691161790565b61233861233361233d926108a7565b610515565b6108a7565b90565b90565b9061235861235361235f92612324565b612340565b825461230b565b9055565b61236d9051611810565b90565b61237990612283565b90565b90565b9061239461238f61239b92612370565b61237c565b82546112bc565b9055565b906123fa60606001612400946123c25f82016123bc5f88016122a8565b9061215d565b6123da5f82016123d46020880161196c565b906122d8565b6123f25f82016123ec604088016122f8565b90612343565b019201612363565b9061237f565b565b9061240c9161239f565b565b91602061242f92949361242860408201965f830190610405565b0190610405565b565b8061244c6124466124415f6112b0565b610298565b91610298565b1480156125e9575b6125cd578061249361248d6124887f000000000000000000000000e556aba6fe6036275ec1f87eda296be72c811bce610bef565b610298565b91610298565b146125b1576124c760018260206124b16124ac8661222a565b612236565b63313ce567906124bf6101d2565b95869261141c565b825281806124d7600482016103bc565b03915afa9081156125ac5761252861253192612542955f9161257e575b5061251f6125018961228f565b9361251661250d61229b565b975f89016117e6565b602087016117f4565b60408501611802565b6060830161181c565b61253d6004849061079c565b612402565b907f0bb5715f0f217c2fe9a0c877ea87d474380c641102f3440ee2a4c8b9d9790918916125796125706101d2565b9283928361240e565b0390a1565b61259f915060203d81116125a5575b6125978183610c74565b810190612265565b5f6124f4565b503d61258d565b611481565b5f63981a2a2b60e01b8152806125c9600482016103bc565b0390fd5b5f63af458c0760e01b8152806125e5600482016103bc565b0390fd5b50816126056125ff6125fa5f6112b0565b610298565b91610298565b14612454565b612613610fd8565b50612628612622828490611726565b15610231565b5f146126b05761264f600161264a5f6126428186906110c0565b018590611710565b61215d565b90612658611cc1565b9061269561268f6126897f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d956110b4565b92610790565b92610790565b9261269e6101d2565b806126a8816103bc565b0390a4600190565b50505f90565b9160206126d79294936126d060408201965f830190610405565b01906104a0565b565b906126ee6126e8838390611726565b15610231565b6126f6575050565b6127105f92839263e2517d3f60e01b8452600484016126b6565b0390fdfea2646970667358221220479ba8f25ee20bdcc5565798b2611081e015561e81c31c23562a557064c5fe1a64736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000e78615f841c3c013173fbe7679d17442c8673cc1000000000000000000000000e556aba6fe6036275ec1f87eda296be72c811bce000000000000000000000000a052883ebee7354fc2aa0f9c727e657fdeca744a00000000000000000000000000000000000000000031a17e847807b1bc000000
-----Decoded View---------------
Arg [0] : _admin (address): 0xE78615F841c3C013173FBE7679d17442C8673Cc1
Arg [1] : _NUSD (address): 0xE556ABa6fe6036275Ec1f87eda296BE72C811BCE
Arg [2] : _router (address): 0xa052883ebEe7354FC2Aa0f9c727E657FdeCa744a
Arg [3] : _maxMintPerBlock (uint256): 60000000000000000000000000
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000e78615f841c3c013173fbe7679d17442c8673cc1
Arg [1] : 000000000000000000000000e556aba6fe6036275ec1f87eda296be72c811bce
Arg [2] : 000000000000000000000000a052883ebee7354fc2aa0f9c727e657fdeca744a
Arg [3] : 00000000000000000000000000000000000000000031a17e847807b1bc000000
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.