Feature Tip: Add private address tag to any address under My Name Tag !
Latest 25 from a total of 46,365 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Mint With Attest... | 24584949 | 43 secs ago | IN | 0 ETH | 0.00067195 | ||||
| Redeem With Atte... | 24584948 | 55 secs ago | IN | 0 ETH | 0.00090121 | ||||
| Redeem With Atte... | 24584947 | 1 min ago | IN | 0 ETH | 0.00090132 | ||||
| Mint With Attest... | 24584945 | 1 min ago | IN | 0 ETH | 0.00089134 | ||||
| Redeem With Atte... | 24584943 | 1 min ago | IN | 0 ETH | 0.00090667 | ||||
| Mint With Attest... | 24584940 | 2 mins ago | IN | 0 ETH | 0.00090616 | ||||
| Redeem With Atte... | 24584939 | 2 mins ago | IN | 0 ETH | 0.00090681 | ||||
| Mint With Attest... | 24584937 | 3 mins ago | IN | 0 ETH | 0.00089782 | ||||
| Redeem With Atte... | 24584934 | 3 mins ago | IN | 0 ETH | 0.00014836 | ||||
| Redeem With Atte... | 24584932 | 4 mins ago | IN | 0 ETH | 0.00090867 | ||||
| Mint With Attest... | 24584930 | 4 mins ago | IN | 0 ETH | 0.00088272 | ||||
| Mint With Attest... | 24584929 | 4 mins ago | IN | 0 ETH | 0.00088238 | ||||
| Redeem With Atte... | 24584928 | 4 mins ago | IN | 0 ETH | 0.00088303 | ||||
| Mint With Attest... | 24584919 | 6 mins ago | IN | 0 ETH | 0.00090444 | ||||
| Redeem With Atte... | 24584918 | 6 mins ago | IN | 0 ETH | 0.0009098 | ||||
| Mint With Attest... | 24584909 | 8 mins ago | IN | 0 ETH | 0.00065852 | ||||
| Mint With Attest... | 24584908 | 8 mins ago | IN | 0 ETH | 0.00089818 | ||||
| Mint With Attest... | 24584907 | 9 mins ago | IN | 0 ETH | 0.00089821 | ||||
| Redeem With Atte... | 24584903 | 9 mins ago | IN | 0 ETH | 0.00091075 | ||||
| Mint With Attest... | 24584901 | 10 mins ago | IN | 0 ETH | 0.00091134 | ||||
| Mint With Attest... | 24584899 | 10 mins ago | IN | 0 ETH | 0.0009194 | ||||
| Mint With Attest... | 24584897 | 11 mins ago | IN | 0 ETH | 0.00091528 | ||||
| Redeem With Atte... | 24584895 | 11 mins ago | IN | 0 ETH | 0.00014293 | ||||
| Redeem With Atte... | 24584892 | 12 mins ago | IN | 0 ETH | 0.00090375 | ||||
| Mint With Attest... | 24584884 | 13 mins ago | IN | 0 ETH | 0.00016485 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
GMTokenManager
Compiler Version
v0.8.16+commit.07a7930e
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
/**SPDX-License-Identifier: BUSL-1.1
▄▄█████████▄
╓██▀└ ,╓▄▄▄, '▀██▄
██▀ ▄██▀▀╙╙▀▀██▄ └██µ ,, ,, , ,,, ,,,
██ ,██¬ ▄████▄ ▀█▄ ╙█▄ ▄███▀▀███▄ ███▄ ██ ███▀▀▀███▄ ▄███▀▀███,
██ ██ ╒█▀' ╙█▌ ╙█▌ ██ ▐██ ███ █████, ██ ██▌ └██▌ ██▌ └██▌
██ ▐█▌ ██ ╟█ █▌ ╟█ ██▌ ▐██ ██ └███ ██ ██▌ ╟██ j██ ╟██
╟█ ██ ╙██ ▄█▀ ▐█▌ ██ ╙██ ██▌ ██ ╙████ ██▌ ▄██▀ ██▌ ,██▀
██ "██, ╙▀▀███████████⌐ ╙████████▀ ██ ╙██ ███████▀▀ ╙███████▀`
██▄ ╙▀██▄▄▄▄▄,,, ¬─ '─¬
╙▀██▄ '╙╙╙▀▀▀▀▀▀▀▀
╙▀▀██████R⌐
*/
pragma solidity 0.8.16;
import "contracts/globalMarkets/tokenManager/issuanceHours/IIssuanceHours.sol";
import "contracts/xManager/interfaces/IOndoIDRegistry.sol";
import "contracts/xManager/interfaces/IOndoRateLimiter.sol";
import "contracts/interfaces/IRWALike.sol";
import "contracts/globalMarkets/tokenManager/IGMTokenManagerErrors.sol";
import "contracts/globalMarkets/tokenManager/IGMTokenManagerEvents.sol";
import "contracts/external/openzeppelin/contracts/access/AccessControlEnumerable.sol";
import "contracts/external/openzeppelin/contracts/security/ReentrancyGuard.sol";
import "contracts/external/openzeppelin/contracts/token/SafeERC20.sol";
import "contracts/external/openzeppelin/contracts/utils/cryptography/EIP712.sol";
import "contracts/external/openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "contracts/globalMarkets/tokenManager/IGMTokenManager.sol";
import "contracts/globalMarkets/tokenManager/sanityCheckOracle/IOndoSanityCheckOracle.sol";
import "contracts/globalMarkets/USDonManager/IUSDonManager.sol";
/**
* @title GMTokenManager
* @author Ondo Finance
* @notice Contract for managing tokenized equity assets
* @notice The GMTokenManager contract contains the core logic for processing minting
* and redemptions of GM tokens.
* The responsibilities of this contract are:
* - Verifying attestation signatures
* - Calculating the amount of GM tokens and USDon to mint and burn
* based on the quote attestation that was received
* - Performing appropriate sanity checks on the quote attestation
* - Enforcing the minimum deposit and redemption amounts and ensuring the
* quote price is in line with the rough oracle price
* - Ensuring users are registered with the OndoIDRegistry
* - Checking user-specific and global rate limits
*/
contract GMTokenManager is
EIP712,
IGMTokenManager,
IGMTokenManagerEvents,
IGMTokenManagerErrors,
ReentrancyGuard,
AccessControlEnumerable
{
using SafeERC20 for IERC20;
/// The identifier address used in OndoIDRegistry to validate KYC for all GM token issuance
address public gmIdentifier =
address(uint160(uint256(keccak256(abi.encodePacked("global_markets")))));
/// Role for signing attestations
bytes32 public constant ATTESTATION_SIGNER_ROLE =
keccak256("ATTESTATION_SIGNER_ROLE");
/// Type hash for EIP-712 quote signatures
bytes32 public constant QUOTE_TYPEHASH =
keccak256(
"Quote(uint256 chainId,uint256 attestationId,bytes32 userId,address asset,uint256 price,uint256 quantity,uint256 expiration,uint8 side,bytes32 additionalData)"
);
/// Mapping of attestation IDs to whether they have been redeemed
mapping(uint256 => bool) public executedAttestationIds;
/// Monotonically increasing ID for each execution of a quote
uint256 public executionId = 0;
/// The decimals normalizer for the GM token
uint256 public constant GM_NORMALIZER = 1e18;
/// Role to configure the contract
bytes32 public constant CONFIGURER_ROLE = keccak256("CONFIGURER_ROLE");
/// Role to pause minting and redemptions
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
/// Role to unpause functionality
bytes32 public constant UNPAUSER_ROLE = keccak256("UNPAUSER_ROLE");
/// Role to manually service a mint of GM tokens
bytes32 public constant ADMIN_MINT_ROLE = keccak256("ADMIN_MINT_ROLE");
/// The token that can be used to subscribe to a GM token and can be received when redeeming a GM token
address public immutable usdon;
/// The address of the USDon manager used for swapping with other tokens
IUSDonManager public usdonManager;
/**
* @notice Minimum USD amount required to subscribe to a GM token, denoted in USD with 18
* decimals.
*/
uint256 public minimumDepositUSD;
/**
* @notice Minimum USD amount required to perform an GM token redemption to be allowed,
* denoted in USD with 18 decimals
*/
uint256 public minimumRedemptionUSD;
/// Whether mints are paused for this contract
bool public globalMintingPaused;
/// Whether redemptions are paused for this contract
bool public globalRedeemingPaused;
/// Whether mints are paused for a specific gm asset
mapping(address => bool) public gmTokenMintingPaused;
/// Whether redemptions are paused for a specific gm asset
mapping(address => bool) public gmTokenRedemptionsPaused;
/// The `OndoIDRegistry` contract address
IOndoIDRegistry public ondoIDRegistry;
/// The `OndoRateLimiter` contract address
IOndoRateLimiter public ondoRateLimiter;
/// The `IssuanceHours` contract for managing market hours
IIssuanceHours public issuanceHours;
/// The `OndoSanityCheckOracle` contract for validating the price of the GM token
IOndoSanityCheckOracle public sanityCheckOracle;
/// Map of all GM tokens that are accepted for minting and redemptions
mapping(address => bool) public gmTokenAccepted;
/**
* @param _defaultAdmin The default admin role for the contract
* @param _usdon The address of the USDon token used for minting and redemptions
* @param _minimumDepositUSD The minimum subscription amount, denoted in USD with 18 decimals
* @param _minimumRedemptionUSD The minimum redemption amount, denoted in USD with 18 decimals
*/
constructor(
address _defaultAdmin,
address _usdon,
uint256 _minimumDepositUSD,
uint256 _minimumRedemptionUSD
) EIP712("OndoGMTokenManager", "1") {
if (_usdon == address(0)) revert USDonAddressCantBeZero();
usdon = _usdon;
minimumDepositUSD = _minimumDepositUSD;
minimumRedemptionUSD = _minimumRedemptionUSD;
_grantRole(DEFAULT_ADMIN_ROLE, _defaultAdmin);
}
/**
* @notice Called by users to mint GM tokens with a quote attestation using USDon
* @param quote The quote to mint GM tokens with
* @param signature The signature of the quote attestation
* @param depositToken The token the user would like to deposit in return for GM Tokens.
* If not USDon, this will be reliant on the ability to swap for USDon in the USDonManager
* @param depositTokenAmount The amount of depositToken the user wishes to spend to purchase USDon atomically in the transaction
* @return The amount of GM tokens minted to the user
* @dev If the deposit token is not USDon and the depositTokenAmount is not enough to swap for USDon
* worth quantity * price as specified in the quote, the transaction will fail as the `mintUSDonValue`
* is passed in to the minimum RWA received field in `subscribe`.
*/
function mintWithAttestation(
Quote calldata quote,
bytes memory signature,
address depositToken,
uint256 depositTokenAmount
)
public
override
nonReentrant
whenMintingNotPaused(quote.asset)
returns (uint256)
{
if (depositToken == address(0)) revert TokenAddressCantBeZero();
if (quote.side != QuoteSide.BUY) revert InvalidQuoteSide();
bytes32 userId = ondoIDRegistry.getRegisteredID(gmIdentifier, _msgSender());
if (userId == bytes32(0)) revert UserNotRegistered();
_verifyQuote(quote, signature, userId);
executedAttestationIds[quote.attestationId] = true;
// USD values are normalized to 18 decimals
uint256 mintUSDonValue = (quote.quantity * quote.price) / GM_NORMALIZER;
if (mintUSDonValue < minimumDepositUSD) revert DepositAmountTooSmall();
ondoRateLimiter.checkAndUpdateRateLimit(
IOndoRateLimiter.TransactionType.SUBSCRIPTION,
quote.asset,
userId,
mintUSDonValue
);
// Transfer usdon into the contract
if (depositToken == address(usdon)) {
IERC20(usdon).safeTransferFrom(
_msgSender(),
address(this),
mintUSDonValue
);
} else {
if (address(usdonManager) == address(0)) revert USDonManagerNotEnabled();
IERC20(depositToken).safeTransferFrom(
_msgSender(),
address(this),
depositTokenAmount
);
IERC20(depositToken).forceApprove(
address(usdonManager),
depositTokenAmount
);
uint256 receivedOnUsd = usdonManager.subscribe(
depositToken,
depositTokenAmount,
mintUSDonValue
);
// If the deposit token is not USDon, we need to refund the user if they sent more than
// the required amount of USDon to mint the GM tokens
uint256 refund = receivedOnUsd - mintUSDonValue;
if (refund > 0) {
IERC20(usdon).safeTransfer(_msgSender(), refund);
}
}
IRWALike(usdon).burn(mintUSDonValue);
// actually mint the token to the user
IRWALike(quote.asset).mint(_msgSender(), quote.quantity);
_emitTradeExecuted(quote);
return quote.quantity;
}
/**
* @notice Called by users to redeem GM tokens for USDon
* @param quote The quote to redeem GM tokens with
* @param signature The signature of the quote attestation
* @param receiveToken The token the user would like to receive. If it is not USDon,
* transaction success will depend on liquidity in USDonManager
* @param minimumReceiveAmount The minimum amount of tokens the user would like to receive
* - ONLY applicable if the user requests a non-USDon token
* @return The amount of USDon minted
*/
function redeemWithAttestation(
Quote calldata quote,
bytes memory signature,
address receiveToken,
uint256 minimumReceiveAmount
)
public
override
nonReentrant
whenRedeemNotPaused(quote.asset)
returns (uint256)
{
if (receiveToken == address(0)) revert TokenAddressCantBeZero();
if (quote.side != QuoteSide.SELL) revert InvalidQuoteSide();
bytes32 userId = ondoIDRegistry.getRegisteredID(gmIdentifier, _msgSender());
if (userId == bytes32(0)) revert UserNotRegistered();
_verifyQuote(quote, signature, userId);
executedAttestationIds[quote.attestationId] = true;
// burn the GM tokens
IERC20(quote.asset).safeTransferFrom(
_msgSender(),
address(this),
quote.quantity
);
IRWALike(quote.asset).burn(quote.quantity);
// USD values are normalized to 18 decimals
uint256 redemptionUSDonValue = (quote.quantity * quote.price) /
GM_NORMALIZER;
if (redemptionUSDonValue < minimumRedemptionUSD)
revert RedemptionAmountTooSmall();
ondoRateLimiter.checkAndUpdateRateLimit(
IOndoRateLimiter.TransactionType.REDEMPTION,
quote.asset,
userId,
redemptionUSDonValue
);
// Mint USDon to the contract
IRWALike(usdon).mint(address(this), redemptionUSDonValue);
if (receiveToken == address(usdon)) {
IERC20(usdon).safeTransfer(_msgSender(), redemptionUSDonValue);
} else {
if (address(usdonManager) == address(0)) revert USDonManagerNotEnabled();
IERC20(usdon).approve(address(usdonManager), redemptionUSDonValue);
uint256 receiveAmount = usdonManager.redeem(
redemptionUSDonValue,
receiveToken,
minimumReceiveAmount
);
IERC20(receiveToken).safeTransfer(_msgSender(), receiveAmount);
}
_emitTradeExecuted(quote);
return redemptionUSDonValue;
}
/**
* @notice Verifies the signature of the quote
* @param quote The quote to verify
* @param signature The signature to verify
* @param userId The user ID of the user executing the quote
*/
function _verifyQuote(
Quote calldata quote,
bytes memory signature,
bytes32 userId
) internal {
// Ensure the attestation isn't being reused
if (executedAttestationIds[quote.attestationId])
revert AttestationAlreadyExecuted();
if (block.timestamp > quote.expiration) revert AttestationExpired();
if (userId != quote.userId) revert UserIdMismatch(userId, quote.userId);
issuanceHours.checkIsValidHours();
sanityCheckOracle.validatePrice(quote.asset, quote.price);
if (gmTokenAccepted[quote.asset] == false) revert GMTokenNotRegistered();
if (quote.chainId != block.chainid) revert InvalidChainId();
bytes32 digest = _hashTypedDataV4(
keccak256(
abi.encode(
QUOTE_TYPEHASH,
quote.chainId,
quote.attestationId,
quote.userId,
quote.asset,
quote.price,
quote.quantity,
quote.expiration,
quote.side,
quote.additionalData
)
)
);
address signer = ECDSA.recover(digest, signature);
if (!hasRole(ATTESTATION_SIGNER_ROLE, signer))
revert InvalidAttestationSigner();
}
/**
* @notice Emits a `TradeExecuted` event and increments the `executionId`
* @param quote The quote to emit the event for
* @dev The only purpose of this is to prevent stack too deep errors from unpacking the large struct.
* Increments executionId before emitting to provide a unique ID for each trade.
*/
function _emitTradeExecuted(Quote calldata quote) internal {
emit TradeExecuted(
++executionId,
quote.attestationId,
quote.chainId,
quote.userId,
quote.side,
quote.asset,
quote.price,
quote.quantity,
quote.expiration,
quote.additionalData
);
}
/**
* @notice Admin function to service a subscription whose corresponding deposit been made outside
* of this contracts system.
* @param gmToken The address of the GM token to mint
* @param recipient The address to send the GM tokens to
* @param gmTokenAmount The amount of GM tokens to mint and/or transfer
* @param metadata Additional metadata to emit with the subscription
*/
function adminProcessMint(
address gmToken,
address recipient,
uint256 gmTokenAmount,
bytes32 metadata
) external whenMintingNotPaused(gmToken) onlyRole(ADMIN_MINT_ROLE) {
if (!gmTokenAccepted[gmToken]) revert GMTokenNotRegistered();
bytes32 userId = ondoIDRegistry.getRegisteredID(gmIdentifier, recipient);
if (userId == bytes32(0)) revert UserNotRegistered();
// Actually mint the token to the user
IRWALike(gmToken).mint(recipient, gmTokenAmount);
emit AdminMint(recipient, userId, gmToken, gmTokenAmount, metadata);
}
/**
* @notice Sets the `IssuanceHours` contract
* @param _issuanceHours The `IssuanceHours` contract address
*/
function setIssuanceHours(
address _issuanceHours
) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (_issuanceHours == address(0)) revert IssuanceHoursAddressCantBeZero();
emit IssuanceHoursSet(address(issuanceHours), _issuanceHours);
issuanceHours = IIssuanceHours(_issuanceHours);
}
/**
* @notice Sets the `OndoSanityCheckOracle` contract
* @param _sanityCheckOracle The new `OndoSanityCheckOracle` contract address
*/
function setSanityCheckOracle(
address _sanityCheckOracle
) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (_sanityCheckOracle == address(0))
revert SanityCheckOracleAddressCantBeZero();
emit OndoSanityCheckOracleSet(
address(sanityCheckOracle),
_sanityCheckOracle
);
sanityCheckOracle = IOndoSanityCheckOracle(_sanityCheckOracle);
}
/**
* @notice Sets the `OndoIDRegistry` contract
* @param _ondoIDRegistry The `OndoIDRegistry` contract address
*/
function setOndoIDRegistry(
address _ondoIDRegistry
) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (_ondoIDRegistry == address(0)) revert IDRegistryAddressCantBeZero();
emit OndoIDRegistrySet(address(ondoIDRegistry), _ondoIDRegistry);
ondoIDRegistry = IOndoIDRegistry(_ondoIDRegistry);
// Ensure that the `OndoIDRegistry` interface is supported
ondoIDRegistry.getRegisteredID(gmIdentifier, address(this));
}
/**
* @notice Sets the `OndoRateLimiter` contract
* @param _ondoRateLimiter The `OndoRateLimiter` contract address
*/
function setOndoRateLimiter(
address _ondoRateLimiter
) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (_ondoRateLimiter == address(0)) revert RateLimiterAddressCantBeZero();
emit OndoRateLimiterSet(address(ondoRateLimiter), _ondoRateLimiter);
ondoRateLimiter = IOndoRateLimiter(_ondoRateLimiter);
}
/**
* @notice Sets the `USDonManager` contract
* @param _usdonManager The `USDonManager` contract address
*/
function setUSDonManager(
address _usdonManager
) external onlyRole(DEFAULT_ADMIN_ROLE) {
emit USDonManagerSet(address(usdonManager), _usdonManager);
usdonManager = IUSDonManager(_usdonManager);
}
/**
* @notice Sets whether a token is accepted for mints and redemptions on this contract
* @param token The address of the token
* @param accepted Whether the token is accepted for mints and redemptions
*/
function setGMTokenRegistrationStatus(
address token,
bool accepted
) external onlyRole(CONFIGURER_ROLE) {
if (token == address(0)) revert TokenAddressCantBeZero();
gmTokenAccepted[token] = accepted;
emit GMTokenRegistered(token, accepted);
}
/**
* @notice Sets the minimum amount required for a subscription
* @param _minimumDepositUSD The minimum amount required to subscribe, denoted in
* USD with 18 decimals
*/
function setMinimumDepositAmount(
uint256 _minimumDepositUSD
) external onlyRole(CONFIGURER_ROLE) {
emit MinimumDepositAmountSet(minimumDepositUSD, _minimumDepositUSD);
minimumDepositUSD = _minimumDepositUSD;
}
/**
* @notice Sets the minimum amount to redeem
* @param _minimumRedemptionUSD The minimum amount required to redeem,
* denoted in USD with 18.
*/
function setMinimumRedemptionAmount(
uint256 _minimumRedemptionUSD
) external onlyRole(CONFIGURER_ROLE) {
emit MinimumRedemptionAmountSet(
minimumRedemptionUSD,
_minimumRedemptionUSD
);
minimumRedemptionUSD = _minimumRedemptionUSD;
}
/**
* @notice Rescue and transfer tokens locked in this contract
* @param token The address of the token
* @param to The address of the recipient
* @param amount The amount of token to transfer
*/
function retrieveTokens(
address token,
address to,
uint256 amount
) external onlyRole(DEFAULT_ADMIN_ROLE) {
IERC20(token).safeTransfer(to, amount);
}
/**
* @notice Returns the domain separator for EIP712
* @return The domain separator
*/
function getDomainSeparator() public view returns (bytes32) {
return _domainSeparatorV4();
}
/*//////////////////////////////////////////////////////////////
Pause/Unpause
//////////////////////////////////////////////////////////////*/
/**
* @notice Globally pause the minting functionality
*/
function pauseGlobalMints() external onlyRole(PAUSER_ROLE) {
globalMintingPaused = true;
emit GlobalMintingPaused();
}
/**
* @notice Globally unpause the minting functionality
*/
function unpauseGlobalMints() external onlyRole(UNPAUSER_ROLE) {
globalMintingPaused = false;
emit GlobalMintingUnpaused();
}
/**
* @notice Globally pause the redeem functionality
*/
function pauseGlobalRedeems() external onlyRole(PAUSER_ROLE) {
globalRedeemingPaused = true;
emit GlobalRedeemingPaused();
}
/**
* @notice Globally unpause the redeem functionality
*/
function unpauseGlobalRedeems() external onlyRole(UNPAUSER_ROLE) {
globalRedeemingPaused = false;
emit GlobalRedeemingUnpaused();
}
/**
* @notice Pauses minting for a specific GM token
* @param gmToken The address of the GM token
*/
function pauseGMTokenMints(address gmToken) external onlyRole(PAUSER_ROLE) {
gmTokenMintingPaused[gmToken] = true;
emit GMTokenMintingPaused(gmToken);
}
/**
* @notice Unpauses minting for a specific GM token
* @param gmToken The address of the GM token
*/
function unpauseGMTokenMints(
address gmToken
) external onlyRole(UNPAUSER_ROLE) {
gmTokenMintingPaused[gmToken] = false;
emit GMTokenMintingUnpaused(gmToken);
}
/**
* @notice Pauses redemption for a specific GM token
* @param gmToken The address of the GM token
*/
function pauseGMTokenRedemptions(
address gmToken
) external onlyRole(PAUSER_ROLE) {
gmTokenRedemptionsPaused[gmToken] = true;
emit GMTokenRedeemingPaused(gmToken);
}
/**
* @notice Unpauses redemption for a specific GM token
* @param gmToken The address of the GM token
*/
function unpauseGMTokenRedemptions(
address gmToken
) external onlyRole(UNPAUSER_ROLE) {
gmTokenRedemptionsPaused[gmToken] = false;
emit GMTokenRedeemingUnpaused(gmToken);
}
/**
* @notice Ensure that the subscribe functionality is not paused
* @param gmToken The address of the GM token to check
* @dev Reverts if either global minting or token-specific minting is paused
*/
modifier whenMintingNotPaused(address gmToken) {
if (globalMintingPaused) revert GlobalMintsPaused();
if (gmTokenMintingPaused[gmToken]) revert GMTokenMintsPaused();
_;
}
/**
* @notice Ensure that the redeem functionality is not paused
* @param gmToken The address of the GM token to check
* @dev Reverts if either global redemptions or token-specific redemptions are paused
*/
modifier whenRedeemNotPaused(address gmToken) {
if (globalRedeemingPaused) revert GlobalRedemptionsPaused();
if (gmTokenRedemptionsPaused[gmToken]) revert GMTokenRedemptionsPaused();
_;
}
}// SPDX-License-Identifier: BUSL-1.1
/*
▄▄█████████▄
╓██▀└ ,╓▄▄▄, '▀██▄
██▀ ▄██▀▀╙╙▀▀██▄ └██µ ,, ,, , ,,, ,,,
██ ,██¬ ▄████▄ ▀█▄ ╙█▄ ▄███▀▀███▄ ███▄ ██ ███▀▀▀███▄ ▄███▀▀███,
██ ██ ╒█▀' ╙█▌ ╙█▌ ██ ▐██ ███ █████, ██ ██▌ └██▌ ██▌ └██▌
██ ▐█▌ ██ ╟█ █▌ ╟█ ██▌ ▐██ ██ └███ ██ ██▌ ╟██ j██ ╟██
╟█ ██ ╙██ ▄█▀ ▐█▌ ██ ╙██ ██▌ ██ ╙████ ██▌ ▄██▀ ██▌ ,██▀
██ "██, ╙▀▀███████████⌐ ╙████████▀ ██ ╙██ ███████▀▀ ╙███████▀`
██▄ ╙▀██▄▄▄▄▄,,, ¬─ '─¬
╙▀██▄ '╙╙╙▀▀▀▀▀▀▀▀
╙▀▀██████R⌐
*/
pragma solidity 0.8.16;
/**
* @title IIssuanceHours
* @author Ondo Finance
* @notice Interface for checking if current time is within valid market hours
*/
interface IIssuanceHours {
function checkIsValidHours() external;
}// SPDX-License-Identifier: BUSL-1.1
/*
▄▄█████████▄
╓██▀└ ,╓▄▄▄, '▀██▄
██▀ ▄██▀▀╙╙▀▀██▄ └██µ ,, ,, , ,,, ,,,
██ ,██¬ ▄████▄ ▀█▄ ╙█▄ ▄███▀▀███▄ ███▄ ██ ███▀▀▀███▄ ▄███▀▀███,
██ ██ ╒█▀' ╙█▌ ╙█▌ ██ ▐██ ███ █████, ██ ██▌ └██▌ ██▌ └██▌
██ ▐█▌ ██ ╟█ █▌ ╟█ ██▌ ▐██ ██ └███ ██ ██▌ ╟██ j██ ╟██
╟█ ██ ╙██ ▄█▀ ▐█▌ ██ ╙██ ██▌ ██ ╙████ ██▌ ▄██▀ ██▌ ,██▀
██ "██, ╙▀▀███████████⌐ ╙████████▀ ██ ╙██ ███████▀▀ ╙███████▀`
██▄ ╙▀██▄▄▄▄▄,,, ¬─ '─¬
╙▀██▄ '╙╙╙▀▀▀▀▀▀▀▀
╙▀▀██████R⌐
*/
pragma solidity 0.8.16;
interface IOndoIDRegistry {
function getRegisteredID(
address rwaToken,
address user
) external view returns (bytes32 userID);
}// SPDX-License-Identifier: MIT
/*
▄▄█████████▄
╓██▀└ ,╓▄▄▄, '▀██▄
██▀ ▄██▀▀╙╙▀▀██▄ └██µ ,, ,, , ,,, ,,,
██ ,██¬ ▄████▄ ▀█▄ ╙█▄ ▄███▀▀███▄ ███▄ ██ ███▀▀▀███▄ ▄███▀▀███,
██ ██ ╒█▀' ╙█▌ ╙█▌ ██ ▐██ ███ █████, ██ ██▌ └██▌ ██▌ └██▌
██ ▐█▌ ██ ╟█ █▌ ╟█ ██▌ ▐██ ██ └███ ██ ██▌ ╟██ j██ ╟██
╟█ ██ ╙██ ▄█▀ ▐█▌ ██ ╙██ ██▌ ██ ╙████ ██▌ ▄██▀ ██▌ ,██▀
██ "██, ╙▀▀███████████⌐ ╙████████▀ ██ ╙██ ███████▀▀ ╙███████▀`
██▄ ╙▀██▄▄▄▄▄,,, ¬─ '─¬
╙▀██▄ '╙╙╙▀▀▀▀▀▀▀▀
╙▀▀██████R⌐
*/
pragma solidity 0.8.16;
interface IOndoRateLimiter {
enum TransactionType {
SUBSCRIPTION,
REDEMPTION
}
function checkAndUpdateRateLimit(
TransactionType transactionType,
address rwaToken,
bytes32 userID,
uint256 usdValue
) external;
}/**SPDX-License-Identifier: BUSL-1.1
▄▄█████████▄
╓██▀└ ,╓▄▄▄, '▀██▄
██▀ ▄██▀▀╙╙▀▀██▄ └██µ ,, ,, , ,,, ,,,
██ ,██¬ ▄████▄ ▀█▄ ╙█▄ ▄███▀▀███▄ ███▄ ██ ███▀▀▀███▄ ▄███▀▀███,
██ ██ ╒█▀' ╙█▌ ╙█▌ ██ ▐██ ███ █████, ██ ██▌ └██▌ ██▌ └██▌
██ ▐█▌ ██ ╟█ █▌ ╟█ ██▌ ▐██ ██ └███ ██ ██▌ ╟██ j██ ╟██
╟█ ██ ╙██ ▄█▀ ▐█▌ ██ ╙██ ██▌ ██ ╙████ ██▌ ▄██▀ ██▌ ,██▀
██ "██, ╙▀▀███████████⌐ ╙████████▀ ██ ╙██ ███████▀▀ ╙███████▀`
██▄ ╙▀██▄▄▄▄▄,,, ¬─ '─¬
╙▀██▄ '╙╙╙▀▀▀▀▀▀▀▀
╙▀▀██████R⌐
*/
pragma solidity 0.8.16;
// This interface is not inherited directly by RWA, instead, it is a
// subset of functions provided by all RWA tokens that the RWA Hub
// Client uses.
import "contracts/external/openzeppelin/contracts/token/IERC20.sol";
interface IRWALike is IERC20 {
function mint(address to, uint256 amount) external;
function burn(uint256 amount) external;
function burnFrom(address from, uint256 amount) external;
}// SPDX-License-Identifier: BUSL-1.1
/*
▄▄█████████▄
╓██▀└ ,╓▄▄▄, '▀██▄
██▀ ▄██▀▀╙╙▀▀██▄ └██µ ,, ,, , ,,, ,,,
██ ,██¬ ▄████▄ ▀█▄ ╙█▄ ▄███▀▀███▄ ███▄ ██ ███▀▀▀███▄ ▄███▀▀███,
██ ██ ╒█▀' ╙█▌ ╙█▌ ██ ▐██ ███ █████, ██ ██▌ └██▌ ██▌ └██▌
██ ▐█▌ ██ ╟█ █▌ ╟█ ██▌ ▐██ ██ └███ ██ ██▌ ╟██ j██ ╟██
╟█ ██ ╙██ ▄█▀ ▐█▌ ██ ╙██ ██▌ ██ ╙████ ██▌ ▄██▀ ██▌ ,██▀
██ "██, ╙▀▀███████████⌐ ╙████████▀ ██ ╙██ ███████▀▀ ╙███████▀`
██▄ ╙▀██▄▄▄▄▄,,, ¬─ '─¬
╙▀██▄ '╙╙╙▀▀▀▀▀▀▀▀
╙▀▀██████R⌐
*/
pragma solidity 0.8.16;
/**
* @title IGMTokenManagerErrors
* @author Ondo Finance
* @notice Isolated contract for all errors emitted by the GMTokenManager contract
*/
interface IGMTokenManagerErrors {
/// Error emitted when the token address is zero
error TokenAddressCantBeZero();
/// Error emitted when the deposit amount is too small
error DepositAmountTooSmall();
/// Error emitted when the user is not registered with the ID registry
error UserNotRegistered();
/// Error emitted when the redemption amount is too small
error RedemptionAmountTooSmall();
/// Error emitted when attempting to set the `OndoIDRegistry` address to zero
error IDRegistryAddressCantBeZero();
/// Error emitted when attempting to set the `OndoRateLimiter` address to zero
error RateLimiterAddressCantBeZero();
/// Error emitted when the minting functionality is paused
error GlobalMintsPaused();
/// Error emitted when the redemption functionality is paused
error GlobalRedemptionsPaused();
/// Error emitted when the minting functionality is paused for a specific token
error GMTokenMintsPaused();
/// Error emitted when the redemption functionality is paused for a specific token
error GMTokenRedemptionsPaused();
/// Error emitted attempting to set the `OndoSanityCheckOracle` address to zero
error SanityCheckOracleAddressCantBeZero();
/// Custom error for expired attestations
error AttestationExpired();
/// Custom error for attestion signed by unverifid signer
error InvalidAttestationSigner();
/// Custom error for invalid chain ID
error InvalidChainId();
/// Custom error for invalid quote direction
error InvalidQuoteSide();
/// Custom error for user ID mismatch
error UserIdMismatch(bytes32 expected, bytes32 actual);
/// Custom error for already redeemed attestations
error AttestationAlreadyExecuted();
/// Error emitted when attempting to set the `IssuanceHours` address to zero
error IssuanceHoursAddressCantBeZero();
// Error emitted when attempting to use an USDon manager reliant function when the USDon manager is set to zero
error USDonManagerNotEnabled();
/// Error emitted when the GM Token is not registered for minting/redemption
error GMTokenNotRegistered();
/// Error emitted when attempting to set the `USDon` address to zero
error USDonAddressCantBeZero();
}// SPDX-License-Identifier: BUSL-1.1
/*
▄▄█████████▄
╓██▀└ ,╓▄▄▄, '▀██▄
██▀ ▄██▀▀╙╙▀▀██▄ └██µ ,, ,, , ,,, ,,,
██ ,██¬ ▄████▄ ▀█▄ ╙█▄ ▄███▀▀███▄ ███▄ ██ ███▀▀▀███▄ ▄███▀▀███,
██ ██ ╒█▀' ╙█▌ ╙█▌ ██ ▐██ ███ █████, ██ ██▌ └██▌ ██▌ └██▌
██ ▐█▌ ██ ╟█ █▌ ╟█ ██▌ ▐██ ██ └███ ██ ██▌ ╟██ j██ ╟██
╟█ ██ ╙██ ▄█▀ ▐█▌ ██ ╙██ ██▌ ██ ╙████ ██▌ ▄██▀ ██▌ ,██▀
██ "██, ╙▀▀███████████⌐ ╙████████▀ ██ ╙██ ███████▀▀ ╙███████▀`
██▄ ╙▀██▄▄▄▄▄,,, ¬─ '─¬
╙▀██▄ '╙╙╙▀▀▀▀▀▀▀▀
╙▀▀██████R⌐
*/
pragma solidity 0.8.16;
/**
* @title IGMTokenManagerEvents
* @author Ondo Finance
* @notice Isolated contract for all events emitted by the GMTokenManager contract
*/
interface IGMTokenManagerEvents {
/**
* @notice Event emitted when an admin completes a mint for a recipient
* @param recipient The address of the recipient that receives the RWA tokens
* @param recipientId The user ID of the recipient
* @param rwaToken The address of the RWA token being minted
* @param rwaAmount The amount of RWA tokens minted in decimals of the RWA token
* @param metadata Additional metadata to associate with the mint
*/
event AdminMint(
address indexed recipient,
bytes32 indexed recipientId,
address indexed rwaToken,
uint256 rwaAmount,
bytes32 metadata
);
/**
* @notice Event emitted when the `OndoIDRegistry` contract is set
* @param oldOndoIDRegistry The old `OndoIDRegistry` contract address
* @param newOndoIDRegistry The new `OndoIDRegistry` contract address
*/
event OndoIDRegistrySet(
address indexed oldOndoIDRegistry,
address indexed newOndoIDRegistry
);
/**
* @notice Event emitted when the `OndoRateLimiter` contract is set
* @param oldOndoRateLimiter The old `OndoRateLimiter` contract address
* @param newOndoRateLimiter The new `OndoRateLimiter` contract address
*/
event OndoRateLimiterSet(
address indexed oldOndoRateLimiter,
address indexed newOndoRateLimiter
);
/**
* @notice Event emitted when subscription minimum is set
* @param oldMinDepositAmount Old subscription minimum
* @param newMinDepositAmount New subscription minimum
*/
event MinimumDepositAmountSet(
uint256 indexed oldMinDepositAmount,
uint256 indexed newMinDepositAmount
);
/**
* @notice Event emitted when redeem minimum is set
* @param oldMinRedemptionAmount Old redeem minimum
* @param newMinRedemptionAmount New redeem minimum
*/
event MinimumRedemptionAmountSet(
uint256 indexed oldMinRedemptionAmount,
uint256 indexed newMinRedemptionAmount
);
/**
* @notice Event emitted when the `OndoSanityCheckOracle` contract is set
* @param oldOndoSanityCheckOracle The old `OndoSanityCheckOracle` contract address
* @param newOndoSanityCheckOracle The new `OndoSanityCheckOracle` contract address
*/
event OndoSanityCheckOracleSet(
address indexed oldOndoSanityCheckOracle,
address indexed newOndoSanityCheckOracle
);
/**
* @notice Event emitted when the `IssuanceHours` contract is set
* @param oldIssuanceHours The old `IssuanceHours` contract address
* @param newIssuanceHours The new `IssuanceHours` contract address
*/
event IssuanceHoursSet(
address indexed oldIssuanceHours,
address indexed newIssuanceHours
);
/**
* @notice Event emitted when the `USDonManager` contract is set
* @param oldUSDonManager The old `USDonManager` contract address
* @param newUSDonManager The new `USDonManager` contract address
*/
event USDonManagerSet(
address indexed oldUSDonManager,
address indexed newUSDonManager
);
/**
* @notice Event emitted when the accepted GM token is set
* @param gmToken The address of the GM token
* @param registered Whether the GM token is registered
*/
event GMTokenRegistered(address indexed gmToken, bool indexed registered);
/// Event emitted when minting functionality is paused
event GlobalMintingPaused();
/// Event emitted when minting functionality is unpaused
event GlobalMintingUnpaused();
/// Event emitted when redeem functionality is paused
event GlobalRedeemingPaused();
/// Event emitted when redeem functionality is unpaused
event GlobalRedeemingUnpaused();
/**
* @notice Event emitted when minting is paused for a specific GM token
* @param gmToken The address of the GM token
*/
event GMTokenMintingPaused(address indexed gmToken);
/**
* @notice Event emitted when minting is unpaused for a specific GM token
* @param gmToken The address of the GM token
*/
event GMTokenMintingUnpaused(address indexed gmToken);
/**
* @notice Event emitted when redemption is paused for a specific GM token
* @param gmToken The address of the GM token
*/
event GMTokenRedeemingPaused(address indexed gmToken);
/**
* @notice Event emitted when redemption is unpaused for a specific GM token
* @param gmToken The address of the GM token
*/
event GMTokenRedeemingUnpaused(address indexed gmToken);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)
pragma solidity ^0.8.0;
import "contracts/external/openzeppelin/contracts/access/IAccessControlEnumerable.sol";
import "contracts/external/openzeppelin/contracts/access/AccessControl.sol";
import "contracts/external/openzeppelin/contracts/utils/EnumerableSet.sol";
/**
* @dev Extension of {AccessControl} that allows enumerating the members of each role.
*/
abstract contract AccessControlEnumerable is
IAccessControlEnumerable,
AccessControl
{
using EnumerableSet for EnumerableSet.AddressSet;
mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override
returns (bool)
{
return
interfaceId == type(IAccessControlEnumerable).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index)
public
view
virtual
override
returns (address)
{
return _roleMembers[role].at(index);
}
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role)
public
view
virtual
override
returns (uint256)
{
return _roleMembers[role].length();
}
/**
* @dev Overload {_grantRole} to track enumerable memberships
*/
function _grantRole(bytes32 role, address account) internal virtual override {
super._grantRole(role, account);
_roleMembers[role].add(account);
}
/**
* @dev Overload {_revokeRole} to track enumerable memberships
*/
function _revokeRole(bytes32 role, address account)
internal
virtual
override
{
super._revokeRole(role, account);
_roleMembers[role].remove(account);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "contracts/external/openzeppelin/contracts/token/IERC20.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 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 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
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.0;
import "./ECDSA.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
* thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
* they need in their contracts using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* _Available since v3.4._
*/
abstract contract EIP712 {
/* solhint-disable var-name-mixedcase */
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
// invalidate the cached domain separator if the chain id changes.
bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
uint256 private immutable _CACHED_CHAIN_ID;
address private immutable _CACHED_THIS;
bytes32 private immutable _HASHED_NAME;
bytes32 private immutable _HASHED_VERSION;
bytes32 private immutable _TYPE_HASH;
/* solhint-enable var-name-mixedcase */
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
constructor(string memory name, string memory version) {
bytes32 hashedName = keccak256(bytes(name));
bytes32 hashedVersion = keccak256(bytes(version));
bytes32 typeHash = keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
_HASHED_NAME = hashedName;
_HASHED_VERSION = hashedVersion;
_CACHED_CHAIN_ID = block.chainid;
_CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
_CACHED_THIS = address(this);
_TYPE_HASH = typeHash;
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
return _CACHED_DOMAIN_SEPARATOR;
} else {
return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
}
}
function _buildDomainSeparator(
bytes32 typeHash,
bytes32 nameHash,
bytes32 versionHash
) private view returns (bytes32) {
return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}/**SPDX-License-Identifier: BUSL-1.1
▄▄█████████▄
╓██▀└ ,╓▄▄▄, '▀██▄
██▀ ▄██▀▀╙╙▀▀██▄ └██µ ,, ,, , ,,, ,,,
██ ,██¬ ▄████▄ ▀█▄ ╙█▄ ▄███▀▀███▄ ███▄ ██ ███▀▀▀███▄ ▄███▀▀███,
██ ██ ╒█▀' ╙█▌ ╙█▌ ██ ▐██ ███ █████, ██ ██▌ └██▌ ██▌ └██▌
██ ▐█▌ ██ ╟█ █▌ ╟█ ██▌ ▐██ ██ └███ ██ ██▌ ╟██ j██ ╟██
╟█ ██ ╙██ ▄█▀ ▐█▌ ██ ╙██ ██▌ ██ ╙████ ██▌ ▄██▀ ██▌ ,██▀
██ "██, ╙▀▀███████████⌐ ╙████████▀ ██ ╙██ ███████▀▀ ╙███████▀`
██▄ ╙▀██▄▄▄▄▄,,, ¬─ '─¬
╙▀██▄ '╙╙╙▀▀▀▀▀▀▀▀
╙▀▀██████R⌐
*/
pragma solidity 0.8.16;
/**
* @title IGMTokenManager
* @author Ondo Finance
* @notice Interface for interacting with the GMTokenManager contract
*/
interface IGMTokenManager {
enum QuoteSide {
/// Indicates that the user is buying GM tokens
BUY,
/// Indicates that the user is selling GM tokens
SELL
}
/**
* @notice Quote struct that is signed by the attestation signer
* @param attestationId The ID of the quote
* @param chainId The chain ID of the quote is intended for
* @param userId The user ID the quote is intended for
* @param asset The address of the GM token being bought or sold
* @param price The price of the GM token in USD with 18 decimals
* @param quantity The quantity of GM tokens being bought or sold
* @param expiration The expiration of the quote in seconds since the epoch
* @param side The direction of the quote (BUY or SELL)
* @param additionalData Any additional data that is needed for the quote
*/
struct Quote {
uint256 chainId;
uint256 attestationId;
bytes32 userId;
address asset;
uint256 price;
uint256 quantity;
uint256 expiration;
QuoteSide side;
bytes32 additionalData;
}
/**
* @notice Event emitted when a trade is executed with an attestation
* @param executionId The monotonically increasing ID of the trade
* @param attestationId The ID of the quote
* @param chainId The chain ID the quote is intended to be used
* @param userId The user ID the quote is intended for
* @param side The direction of the quote (BUY or SELL)
* @param asset The address of the GM token being bought or sold
* @param price The price of the GM token in USD with 18 decimals
* @param quantity The quantity of GM tokens being bought or sold
* @param expiration The expiration of the quote in seconds since the epoch
* @param additionalData Any additional data that is needed for the quote
*/
event TradeExecuted(
uint256 executionId,
uint256 attestationId,
uint256 chainId,
bytes32 userId,
QuoteSide side,
address asset,
uint256 price,
uint256 quantity,
uint256 expiration,
bytes32 additionalData
);
function mintWithAttestation(
Quote calldata quote,
bytes memory signature,
address depositToken,
uint256 depositAmount
) external returns (uint256 receivedGmTokenAmount);
function redeemWithAttestation(
Quote calldata quote,
bytes memory signature,
address receiveToken,
uint256 minimumReceiveAmount
) external returns (uint256 redemptionUSDonValue);
}/**SPDX-License-Identifier: BUSL-1.1
▄▄█████████▄
╓██▀└ ,╓▄▄▄, '▀██▄
██▀ ▄██▀▀╙╙▀▀██▄ └██µ ,, ,, , ,,, ,,,
██ ,██¬ ▄████▄ ▀█▄ ╙█▄ ▄███▀▀███▄ ███▄ ██ ███▀▀▀███▄ ▄███▀▀███,
██ ██ ╒█▀' ╙█▌ ╙█▌ ██ ▐██ ███ █████, ██ ██▌ └██▌ ██▌ └██▌
██ ▐█▌ ██ ╟█ █▌ ╟█ ██▌ ▐██ ██ └███ ██ ██▌ ╟██ j██ ╟██
╟█ ██ ╙██ ▄█▀ ▐█▌ ██ ╙██ ██▌ ██ ╙████ ██▌ ▄██▀ ██▌ ,██▀
██ "██, ╙▀▀███████████⌐ ╙████████▀ ██ ╙██ ███████▀▀ ╙███████▀`
██▄ ╙▀██▄▄▄▄▄,,, ¬─ '─¬
╙▀██▄ '╙╙╙▀▀▀▀▀▀▀▀
╙▀▀██████R⌐
*/
pragma solidity 0.8.16;
/**
* @title IOndoSanityCheckOracle
* @author Ondo Finance
* @notice Interface for validating prices with the sanity check oracle
*/
interface IOndoSanityCheckOracle {
function validatePrice(address token, uint256 price) external view;
}// SPDX-License-Identifier: BUSL-1.1
/*
▄▄█████████▄
╓██▀└ ,╓▄▄▄, '▀██▄
██▀ ▄██▀▀╙╙▀▀██▄ └██µ ,, ,, , ,,, ,,,
██ ,██¬ ▄████▄ ▀█▄ ╙█▄ ▄███▀▀███▄ ███▄ ██ ███▀▀▀███▄ ▄███▀▀███,
██ ██ ╒█▀' ╙█▌ ╙█▌ ██ ▐██ ███ █████, ██ ██▌ └██▌ ██▌ └██▌
██ ▐█▌ ██ ╟█ █▌ ╟█ ██▌ ▐██ ██ └███ ██ ██▌ ╟██ j██ ╟██
╟█ ██ ╙██ ▄█▀ ▐█▌ ██ ╙██ ██▌ ██ ╙████ ██▌ ▄██▀ ██▌ ,██▀
██ "██, ╙▀▀███████████⌐ ╙████████▀ ██ ╙██ ███████▀▀ ╙███████▀`
██▄ ╙▀██▄▄▄▄▄,,, ¬─ '─¬
╙▀██▄ '╙╙╙▀▀▀▀▀▀▀▀
╙▀▀██████R⌐
*/
pragma solidity 0.8.16;
/**
* @title IUSDonManager
* @author Ondo Finance
* @notice This contract provides an interface for conducting instant USDon swaps.
*/
interface IUSDonManager {
function subscribe(
address depositToken,
uint256 depositAmount,
uint256 minimumRwaReceived
) external returns (uint256 rwaAmountOut);
function redeem(
uint256 rwaAmount,
address receivingToken,
uint256 minimumTokenReceived
) external returns (uint256 receiveTokenAmount);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender)
external
view
returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
/**
* @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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)
pragma solidity ^0.8.0;
import "contracts/external/openzeppelin/contracts/access/IAccessControl.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/
interface IAccessControlEnumerable is IAccessControl {
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index)
external
view
returns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "contracts/external/openzeppelin/contracts/access/IAccessControl.sol";
import "contracts/external/openzeppelin/contracts/utils/Context.sol";
import "contracts/external/openzeppelin/contracts/utils/Strings.sol";
import "contracts/external/openzeppelin/contracts/utils/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:
*
* ```
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role, _msgSender());
_;
}
/**
* @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
override
returns (bool)
{
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role)
public
view
virtual
override
returns (bytes32)
{
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account)
public
virtual
override
onlyRole(getRoleAdmin(role))
{
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account)
public
virtual
override
onlyRole(getRoleAdmin(role))
{
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(
account == _msgSender(),
"AccessControl: can only renounce roles for self"
);
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastvalue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastvalue;
// Update the index for the moved value
set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value)
private
view
returns (bool)
{
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value)
internal
returns (bool)
{
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value)
internal
view
returns (bool)
{
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index)
internal
view
returns (bytes32)
{
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set)
internal
view
returns (bytes32[] memory)
{
return _values(set._inner);
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value)
internal
returns (bool)
{
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value)
internal
view
returns (bool)
{
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index)
internal
view
returns (address)
{
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set)
internal
view
returns (address[] memory)
{
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value)
internal
view
returns (bool)
{
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index)
internal
view
returns (uint256)
{
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set)
internal
view
returns (uint256[] memory)
{
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length)
internal
pure
returns (string memory)
{
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(
bytes32 indexed role,
bytes32 indexed previousAdminRole,
bytes32 indexed newAdminRole
);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(
bytes32 indexed role,
address indexed account,
address indexed sender
);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(
bytes32 indexed role,
address indexed account,
address indexed sender
);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "contracts/external/openzeppelin/contracts/utils/IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override
returns (bool)
{
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface 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[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"remappings": [
"eth-gas-reporter/=node_modules/eth-gas-reporter/",
"forge-tests/=forge-tests/",
"lib/=lib/",
"@aragon/=node_modules/@aragon/",
"@ensdomains/=node_modules/@ensdomains/",
"@openzeppelin/=node_modules/@openzeppelin/",
"@uniswap/=node_modules/@uniswap/",
"forge-std/=lib/forge-std/src/",
"hardhat-deploy/=node_modules/hardhat-deploy/",
"hardhat/=node_modules/hardhat/",
"math/=node_modules/@aragon/os/contracts/lib/math/",
"misc/=node_modules/@aragon/os/contracts/lib/misc/",
"solidity-bytes-utils/=node_modules/solidity-bytes-utils/",
"standards/=node_modules/@aragon/os/contracts/lib/standards/",
"token/=node_modules/@aragon/os/contracts/lib/token/",
"truffle/=node_modules/truffle/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_defaultAdmin","type":"address"},{"internalType":"address","name":"_usdon","type":"address"},{"internalType":"uint256","name":"_minimumDepositUSD","type":"uint256"},{"internalType":"uint256","name":"_minimumRedemptionUSD","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AttestationAlreadyExecuted","type":"error"},{"inputs":[],"name":"AttestationExpired","type":"error"},{"inputs":[],"name":"DepositAmountTooSmall","type":"error"},{"inputs":[],"name":"GMTokenMintsPaused","type":"error"},{"inputs":[],"name":"GMTokenNotRegistered","type":"error"},{"inputs":[],"name":"GMTokenRedemptionsPaused","type":"error"},{"inputs":[],"name":"GlobalMintsPaused","type":"error"},{"inputs":[],"name":"GlobalRedemptionsPaused","type":"error"},{"inputs":[],"name":"IDRegistryAddressCantBeZero","type":"error"},{"inputs":[],"name":"InvalidAttestationSigner","type":"error"},{"inputs":[],"name":"InvalidChainId","type":"error"},{"inputs":[],"name":"InvalidQuoteSide","type":"error"},{"inputs":[],"name":"IssuanceHoursAddressCantBeZero","type":"error"},{"inputs":[],"name":"RateLimiterAddressCantBeZero","type":"error"},{"inputs":[],"name":"RedemptionAmountTooSmall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SanityCheckOracleAddressCantBeZero","type":"error"},{"inputs":[],"name":"TokenAddressCantBeZero","type":"error"},{"inputs":[],"name":"USDonAddressCantBeZero","type":"error"},{"inputs":[],"name":"USDonManagerNotEnabled","type":"error"},{"inputs":[{"internalType":"bytes32","name":"expected","type":"bytes32"},{"internalType":"bytes32","name":"actual","type":"bytes32"}],"name":"UserIdMismatch","type":"error"},{"inputs":[],"name":"UserNotRegistered","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"bytes32","name":"recipientId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"rwaToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"rwaAmount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"metadata","type":"bytes32"}],"name":"AdminMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"gmToken","type":"address"}],"name":"GMTokenMintingPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"gmToken","type":"address"}],"name":"GMTokenMintingUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"gmToken","type":"address"}],"name":"GMTokenRedeemingPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"gmToken","type":"address"}],"name":"GMTokenRedeemingUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"gmToken","type":"address"},{"indexed":true,"internalType":"bool","name":"registered","type":"bool"}],"name":"GMTokenRegistered","type":"event"},{"anonymous":false,"inputs":[],"name":"GlobalMintingPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"GlobalMintingUnpaused","type":"event"},{"anonymous":false,"inputs":[],"name":"GlobalRedeemingPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"GlobalRedeemingUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldIssuanceHours","type":"address"},{"indexed":true,"internalType":"address","name":"newIssuanceHours","type":"address"}],"name":"IssuanceHoursSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"oldMinDepositAmount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newMinDepositAmount","type":"uint256"}],"name":"MinimumDepositAmountSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"oldMinRedemptionAmount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newMinRedemptionAmount","type":"uint256"}],"name":"MinimumRedemptionAmountSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOndoIDRegistry","type":"address"},{"indexed":true,"internalType":"address","name":"newOndoIDRegistry","type":"address"}],"name":"OndoIDRegistrySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOndoRateLimiter","type":"address"},{"indexed":true,"internalType":"address","name":"newOndoRateLimiter","type":"address"}],"name":"OndoRateLimiterSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOndoSanityCheckOracle","type":"address"},{"indexed":true,"internalType":"address","name":"newOndoSanityCheckOracle","type":"address"}],"name":"OndoSanityCheckOracleSet","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":"uint256","name":"executionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"attestationId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"userId","type":"bytes32"},{"indexed":false,"internalType":"enum IGMTokenManager.QuoteSide","name":"side","type":"uint8"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"expiration","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"additionalData","type":"bytes32"}],"name":"TradeExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldUSDonManager","type":"address"},{"indexed":true,"internalType":"address","name":"newUSDonManager","type":"address"}],"name":"USDonManagerSet","type":"event"},{"inputs":[],"name":"ADMIN_MINT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ATTESTATION_SIGNER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CONFIGURER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GM_NORMALIZER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUOTE_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNPAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"gmToken","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"gmTokenAmount","type":"uint256"},{"internalType":"bytes32","name":"metadata","type":"bytes32"}],"name":"adminProcessMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"executedAttestationIds","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"executionId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDomainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","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":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalMintingPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalRedeemingPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gmIdentifier","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"gmTokenAccepted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"gmTokenMintingPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"gmTokenRedemptionsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":[],"name":"issuanceHours","outputs":[{"internalType":"contract IIssuanceHours","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumDepositUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumRedemptionUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"attestationId","type":"uint256"},{"internalType":"bytes32","name":"userId","type":"bytes32"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"enum IGMTokenManager.QuoteSide","name":"side","type":"uint8"},{"internalType":"bytes32","name":"additionalData","type":"bytes32"}],"internalType":"struct IGMTokenManager.Quote","name":"quote","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"depositToken","type":"address"},{"internalType":"uint256","name":"depositTokenAmount","type":"uint256"}],"name":"mintWithAttestation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ondoIDRegistry","outputs":[{"internalType":"contract IOndoIDRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ondoRateLimiter","outputs":[{"internalType":"contract IOndoRateLimiter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"gmToken","type":"address"}],"name":"pauseGMTokenMints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"gmToken","type":"address"}],"name":"pauseGMTokenRedemptions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauseGlobalMints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauseGlobalRedeems","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"attestationId","type":"uint256"},{"internalType":"bytes32","name":"userId","type":"bytes32"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"enum IGMTokenManager.QuoteSide","name":"side","type":"uint8"},{"internalType":"bytes32","name":"additionalData","type":"bytes32"}],"internalType":"struct IGMTokenManager.Quote","name":"quote","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"receiveToken","type":"address"},{"internalType":"uint256","name":"minimumReceiveAmount","type":"uint256"}],"name":"redeemWithAttestation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"retrieveTokens","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":"sanityCheckOracle","outputs":[{"internalType":"contract IOndoSanityCheckOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"accepted","type":"bool"}],"name":"setGMTokenRegistrationStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_issuanceHours","type":"address"}],"name":"setIssuanceHours","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minimumDepositUSD","type":"uint256"}],"name":"setMinimumDepositAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minimumRedemptionUSD","type":"uint256"}],"name":"setMinimumRedemptionAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_ondoIDRegistry","type":"address"}],"name":"setOndoIDRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_ondoRateLimiter","type":"address"}],"name":"setOndoRateLimiter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sanityCheckOracle","type":"address"}],"name":"setSanityCheckOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_usdonManager","type":"address"}],"name":"setUSDonManager","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":"gmToken","type":"address"}],"name":"unpauseGMTokenMints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"gmToken","type":"address"}],"name":"unpauseGMTokenRedemptions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpauseGlobalMints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpauseGlobalRedeems","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdon","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usdonManager","outputs":[{"internalType":"contract IUSDonManager","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6d676c6f62616c5f6d61726b65747360901b61018052600e6101605261018e604052600380546001600160a01b03191673428ecb70e90d1527a5f5e177789f51747b883f3417905560006005553480156200005957600080fd5b506040516200361a3803806200361a8339810160408190526200007c916200032a565b604080518082018252601281527127b73237a3a6aa37b5b2b726b0b730b3b2b960711b6020808301918252835180850190945260018452603160f81b908401528151902060e08190527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66101008190524660a0529192917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f620001648184846040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b6080523060c052610120525050600160005550506001600160a01b038316620001a057604051632f5edb4360e11b815260040160405180910390fd5b6001600160a01b0383166101405260078290556008819055620001c5600085620001cf565b5050505062000372565b620001e682826200021260201b62001d841760201c565b60008281526002602090815260409091206200020d91839062001def6200029b821b17901c565b505050565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff16620002975760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45b5050565b6000620002b2836001600160a01b038416620002bb565b90505b92915050565b60008181526001830160205260408120546200030457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620002b5565b506000620002b5565b80516001600160a01b03811681146200032557600080fd5b919050565b600080600080608085870312156200034157600080fd5b6200034c856200030d565b93506200035c602086016200030d565b6040860151606090960151949790965092505050565b60805160a05160c05160e05161010051610120516101405161321c620003fe6000396000818161068b01528181610e9201528181610ece01528181610fff0152818161103f015281816115d30152818161163b01526116d20152600061242b0152600061247a01526000612455015260006123ae015260006123d801526000612402015261321c6000f3fe608060405234801561001057600080fd5b50600436106103275760003560e01c80637b0e1c57116101b8578063b28996b511610104578063e63ab1e9116100a2578063ed24911d1161007c578063ed24911d1461073d578063ed2a354014610745578063f758161514610758578063fb1bb9de1461077f57600080fd5b8063e63ab1e914610708578063eb27fa531461071d578063ebaf3f211461072a57600080fd5b8063c7f8e171116100de578063c7f8e171146106c0578063c875edf6146106cf578063ca15c873146106e2578063d547741f146106f557600080fd5b8063b28996b514610663578063bd5d370c14610686578063c768b145146106ad57600080fd5b80639010d07c11610171578063a217fddf1161014b578063a217fddf14610620578063aab483d614610628578063abbb9f4c1461063b578063ad129e771461065057600080fd5b80639010d07c146105d357806391d14854146105e65780639c617c7e146105f957600080fd5b80637b0e1c5714610577578063811400fa1461058a57806381d69bba1461059d57806384b78414146105a55780638c6f4ab7146105b85780638f8eb812146105ca57600080fd5b8063445df08b11610277578063531acc13116102305780636269ff8f1161020a5780636269ff8f1461053057806369d3605c146105535780636eefea491461055b57806376ce2dad1461056e57600080fd5b8063531acc13146104f157806355358afb146104fa5780635c0478d11461050d57600080fd5b8063445df08b1461046f57806348c6ca77146104825780634ef1ccd1146104955780634f23c343146104a85780635010af4d146104bb57806350aaef5a146104ce57600080fd5b8063246b3502116102e45780632d50bb74116102be5780632d50bb74146104235780632f2ff15d146104365780633483369d1461044957806336568abe1461045c57600080fd5b8063246b3502146103e4578063248a9ca3146103f75780632542dbfd1461041b57600080fd5b806301ffc9a71461032c5780630250f9fe1461035457806303cad6451461035e57806305ac4e0b146103895780630e16f0c81461039c57806323991e4b146103d1575b600080fd5b61033f61033a366004612bd4565b610794565b60405190151581526020015b60405180910390f35b61035c6107bf565b005b600354610371906001600160a01b031681565b6040516001600160a01b03909116815260200161034b565b61035c610397366004612c1a565b61080f565b6103c37f507caaa5b2a5a027bc340a5334d9220583b7d60d846ee2aabc76e37d69a7253b81565b60405190815260200161034b565b61035c6103df366004612c1a565b610872565b61035c6103f2366004612c43565b61096b565b6103c3610405366004612c7a565b6000908152600160208190526040909120015490565b61035c610a00565b61035c610431366004612c1a565b610a52565b61035c610444366004612c93565b610ab8565b61035c610457366004612c1a565b610adf565b61035c61046a366004612c93565b610b48565b6103c361047d366004612cd5565b610bcb565b61035c610490366004612c1a565b611145565b61035c6104a3366004612c7a565b6111a8565b600654610371906001600160a01b031681565b600f54610371906001600160a01b031681565b61033f6104dc366004612c7a565b60046020526000908152604090205460ff1681565b6103c360075481565b600e54610371906001600160a01b031681565b61033f61051b366004612c1a565b60106020526000908152604090205460ff1681565b61033f61053e366004612c1a565b600a6020526000908152604090205460ff1681565b61035c6111f6565b6103c3610569366004612cd5565b61124a565b6103c360055481565b61035c610585366004612dbb565b6117f2565b600d54610371906001600160a01b031681565b61035c611818565b61035c6105b3366004612c1a565b611867565b60095461033f90610100900460ff1681565b6103c360085481565b6103716105e1366004612df7565b6118f7565b61033f6105f4366004612c93565b611916565b6103c37f023d9737d781c665e5048e4dfd034f07fec540e8ecb2336b3d85a375b90a3a3581565b6103c3600081565b61035c610636366004612c7a565b611941565b6103c360008051602061318783398151915281565b61035c61065e366004612c1a565b61198f565b61033f610671366004612c1a565b600b6020526000908152604090205460ff1681565b6103717f000000000000000000000000000000000000000000000000000000000000000081565b600c54610371906001600160a01b031681565b6103c3670de0b6b3a764000081565b61035c6106dd366004612c1a565b611a1f565b6103c36106f0366004612c7a565b611a85565b61035c610703366004612c93565b611a9c565b6103c36000805160206131c783398151915281565b60095461033f9060ff1681565b61035c610738366004612c1a565b611ac3565b6103c3611b53565b61035c610753366004612e19565b611b62565b6103c37faa6d9093095fdf69cb4e18b3e4053e238ec6e2d5a083964634b640da3b8f44a481565b6103c36000805160206131a783398151915281565b60006001600160e01b03198216635a05180f60e01b14806107b957506107b982611e04565b92915050565b6000805160206131a78339815191526107d88133611e39565b6009805461ff00191690556040517f8cba7e15b16021395abffdc05ba74a88afd2b3dce03e075ddb041760a389068890600090a150565b6000805160206131a78339815191526108288133611e39565b6001600160a01b0382166000818152600b6020526040808220805460ff19169055517ff7db4b816293b43fac22e1773acf5d3774a3d70ab993f04995406fadd92b546a9190a25050565b600061087e8133611e39565b6001600160a01b0382166108a557604051633d04535360e21b815260040160405180910390fd5b600c546040516001600160a01b038085169216907ff78e014ab86d7bb38135262d64726cef2e151dae47c0947a1d6bb970702c30d690600090a3600c80546001600160a01b0319166001600160a01b03848116918217909255600354604051637f19077160e01b81529216600483015230602483015290637f19077190604401602060405180830381865afa158015610942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109669190612e5b565b505050565b6000805160206131878339815191526109848133611e39565b6001600160a01b0383166109ab5760405163885ce5f160e01b815260040160405180910390fd5b6001600160a01b038316600081815260106020526040808220805460ff191686151590811790915590519092917f8f1a189329487ea2f651b3797ac87d45216b42a18c01a7335169539b76df133891a3505050565b6000805160206131c7833981519152610a198133611e39565b6009805460ff191660011790556040517f94eae7ff948a5ddfb0e5f291aa214ae9dd7d12ea33086a414143bc4a3408734190600090a150565b6000805160206131c7833981519152610a6b8133611e39565b6001600160a01b0382166000818152600b6020526040808220805460ff19166001179055517fcacc4dbd81af0cceec871b59f5155fa60dc3a52b970778ba54b2cf66f0b5deeb9190a25050565b60008281526001602081905260409091200154610ad58133611e39565b6109668383611e9d565b6000610aeb8133611e39565b6006546040516001600160a01b038085169216907fad45eab3ddda99c8b095504a58e25095a54c31dc487bb3eed9c0a9112ee4eaa890600090a350600680546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381163314610bbd5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b610bc78282611ebf565b5050565b6000600260005403610c1f5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bb4565b6002600055610c346080860160608701612c1a565b60095460ff1615610c58576040516331852b7360e21b815260040160405180910390fd5b6001600160a01b0381166000908152600a602052604090205460ff1615610c915760405162e4b17560e11b815260040160405180910390fd5b6001600160a01b038416610cb85760405163885ce5f160e01b815260040160405180910390fd5b6000610ccb610100880160e08901612e8a565b6001811115610cdc57610cdc612e74565b14610cfa576040516326b1c87960e21b815260040160405180910390fd5b600c546003546000916001600160a01b0390811691637f1907719116336040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604401602060405180830381865afa158015610d62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d869190612e5b565b905080610da657604051632163950f60e01b815260040160405180910390fd5b610db1878783611ee1565b6020808801356000908152600490915260408120805460ff19166001179055670de0b6b3a7640000610deb60808a013560a08b0135612ec1565b610df59190612ee0565b9050600754811015610e1a576040516367627d0760e01b815260040160405180910390fd5b600d546001600160a01b0316637d4945b76000610e3d60808c0160608d01612c1a565b85856040518563ffffffff1660e01b8152600401610e5e9493929190612f20565b600060405180830381600087803b158015610e7857600080fd5b505af1158015610e8c573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316866001600160a01b031603610f0357610efe7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163330846121cb565b611029565b6006546001600160a01b0316610f2c5760405163cdce50bd60e01b815260040160405180910390fd5b610f416001600160a01b0387163330886121cb565b600654610f5b906001600160a01b03888116911687612232565b6006546040516322d4a17560e01b81526001600160a01b038881166004830152602482018890526044820184905260009216906322d4a175906064016020604051808303816000875af1158015610fb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fda9190612e5b565b90506000610fe88383612f52565b9050801561102657611026335b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690836122c2565b50505b604051630852cd8d60e31b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c6890602401600060405180830381600087803b15801561108b57600080fd5b505af115801561109f573d6000803e3d6000fd5b506110b4925050506080890160608a01612c1a565b6001600160a01b03166340c10f19336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260a08b01356024820152604401600060405180830381600087803b15801561110e57600080fd5b505af1158015611122573d6000803e3d6000fd5b5050505061112f886122f3565b5050600160005550505060a09092013592915050565b6000805160206131a783398151915261115e8133611e39565b6001600160a01b0382166000818152600a6020526040808220805460ff19169055517f8ea8fa511d23c1a22f92d6480c103dff2994b522f89b46b18c9493130d1121de9190a25050565b6000805160206131878339815191526111c18133611e39565b6008546040518391907ffdaf6ed728cef208e62328a008209556f8281f3062b14dd08aaaa90fa159421190600090a350600855565b6000805160206131c783398151915261120f8133611e39565b6009805461ff0019166101001790556040517f694abd7c120a829fef1aac704885e405362fcd69c82f114ccec2959a402633c590600090a150565b600060026000540361129e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bb4565b60026000556112b36080860160608701612c1a565b600954610100900460ff16156112dc576040516378b17b4360e11b815260040160405180910390fd5b6001600160a01b0381166000908152600b602052604090205460ff16156113165760405163877009f360e01b815260040160405180910390fd5b6001600160a01b03841661133d5760405163885ce5f160e01b815260040160405180910390fd5b6001611350610100880160e08901612e8a565b600181111561136157611361612e74565b1461137f576040516326b1c87960e21b815260040160405180910390fd5b600c546003546000916001600160a01b0390811691637f1907719116336040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604401602060405180830381865afa1580156113e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061140b9190612e5b565b90508061142b57604051632163950f60e01b815260040160405180910390fd5b611436878783611ee1565b6020808801356000908152600490915260409020805460ff1916600117905561148661145f3390565b3060a08a013561147560808c0160608d01612c1a565b6001600160a01b03169291906121cb565b6114966080880160608901612c1a565b604051630852cd8d60e31b815260a089013560048201526001600160a01b0391909116906342966c6890602401600060405180830381600087803b1580156114dd57600080fd5b505af11580156114f1573d6000803e3d6000fd5b505050506000670de0b6b3a764000088608001358960a001356115149190612ec1565b61151e9190612ee0565b90506008548110156115435760405163680116dd60e11b815260040160405180910390fd5b600d546001600160a01b0316637d4945b7600161156660808c0160608d01612c1a565b85856040518563ffffffff1660e01b81526004016115879493929190612f20565b600060405180830381600087803b1580156115a157600080fd5b505af11580156115b5573d6000803e3d6000fd5b50506040516340c10f1960e01b8152306004820152602481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692506340c10f199150604401600060405180830381600087803b15801561162157600080fd5b505af1158015611635573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316866001600160a01b0316036116805761167b33610ff5565b6117d9565b6006546001600160a01b03166116a95760405163cdce50bd60e01b815260040160405180910390fd5b60065460405163095ea7b360e01b81526001600160a01b039182166004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000009091169063095ea7b3906044016020604051808303816000875af115801561171d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117419190612f65565b5060065460405163d878016160e01b8152600481018390526001600160a01b03888116602483015260448201889052600092169063d8780161906064016020604051808303816000875af115801561179d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c19190612e5b565b90506117d76001600160a01b03881633836122c2565b505b6117e2886122f3565b6001600055979650505050505050565b60006117fe8133611e39565b6118126001600160a01b03851684846122c2565b50505050565b6000805160206131a78339815191526118318133611e39565b6009805460ff191690556040517f7c5bd2c6bf55553fb8379a172f2f9d0369fc18a7bf82a47486ac611a9215060190600090a150565b60006118738133611e39565b6001600160a01b03821661189a576040516301acb6d760e01b815260040160405180910390fd5b600f546040516001600160a01b038085169216907f7c40bb6767b8c6caf208ae3b9558c37a91b5710f5157deb182aae429ac24d33690600090a350600f80546001600160a01b0319166001600160a01b0392909216919091179055565b600082815260026020526040812061190f908361238b565b9392505050565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b60008051602061318783398151915261195a8133611e39565b6007546040518391907fe6e25add7363f8f8a40cbea9810d3115a33703b10972ef759104219b0065743690600090a350600755565b600061199b8133611e39565b6001600160a01b0382166119c257604051633aa9ba3360e01b815260040160405180910390fd5b600d546040516001600160a01b038085169216907fc54bf4c3067c1d8f65e053dafb5dbb699615b1b527d2866bd0223102bb2e692d90600090a350600d80546001600160a01b0319166001600160a01b0392909216919091179055565b6000805160206131c7833981519152611a388133611e39565b6001600160a01b0382166000818152600a6020526040808220805460ff19166001179055517f0de7e27328f4d5d9fc5797bf8cc1f3ca9c0d366a83aae68215e9e7dbf156a1f19190a25050565b60008181526002602052604081206107b990612397565b60008281526001602081905260409091200154611ab98133611e39565b6109668383611ebf565b6000611acf8133611e39565b6001600160a01b038216611af657604051630e1164bf60e21b815260040160405180910390fd5b600e546040516001600160a01b038085169216907fcaf02d44223f855a96856532b7f6b262b8c1e57639d6ea29ff00f49b65d6a0be90600090a350600e80546001600160a01b0319166001600160a01b0392909216919091179055565b6000611b5d6123a1565b905090565b600954849060ff1615611b88576040516331852b7360e21b815260040160405180910390fd5b6001600160a01b0381166000908152600a602052604090205460ff1615611bc15760405162e4b17560e11b815260040160405180910390fd5b7f507caaa5b2a5a027bc340a5334d9220583b7d60d846ee2aabc76e37d69a7253b611bec8133611e39565b6001600160a01b03861660009081526010602052604090205460ff16611c25576040516326b5ecf360e01b815260040160405180910390fd5b600c54600354604051637f19077160e01b81526001600160a01b03918216600482015287821660248201526000929190911690637f19077190604401602060405180830381865afa158015611c7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ca29190612e5b565b905080611cc257604051632163950f60e01b815260040160405180910390fd5b6040516340c10f1960e01b81526001600160a01b038781166004830152602482018790528816906340c10f1990604401600060405180830381600087803b158015611d0c57600080fd5b505af1158015611d20573d6000803e3d6000fd5b50505050866001600160a01b031681876001600160a01b03167f64246d088e96d6b1bbb49bd2ab458376867796a99add0e25a88c53bcee7ddbdf8888604051611d73929190918252602082015260400190565b60405180910390a450505050505050565b611d8e8282611916565b610bc75760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b600061190f836001600160a01b0384166124c8565b60006001600160e01b03198216637965db0b60e01b14806107b957506301ffc9a760e01b6001600160e01b03198316146107b9565b611e438282611916565b610bc757611e5b816001600160a01b03166014612517565b611e66836020612517565b604051602001611e77929190612fa6565b60408051601f198184030181529082905262461bcd60e51b8252610bb49160040161301b565b611ea78282611d84565b60008281526002602052604090206109669082611def565b611ec982826126b3565b6000828152600260205260409020610966908261271a565b60208084013560009081526004909152604090205460ff1615611f17576040516308d0ea5b60e31b815260040160405180910390fd5b8260c00135421115611f3c5760405163716dcc3960e01b815260040160405180910390fd5b82604001358114611f6d576040805163748b3dc360e11b815260048101839052908401356024820152604401610bb4565b600e60009054906101000a90046001600160a01b03166001600160a01b031663e8c7e7286040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611fbd57600080fd5b505af1158015611fd1573d6000803e3d6000fd5b5050600f546001600160a01b0316915063fd45a4339050611ff86080860160608701612c1a565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526080860135602482015260440160006040518083038186803b15801561204157600080fd5b505afa158015612055573d6000803e3d6000fd5b50505050601060008460600160208101906120709190612c1a565b6001600160a01b03168152602081019190915260400160009081205460ff16151590036120b0576040516326b5ecf360e01b815260040160405180910390fd5b823546146120d157604051633d23e4d160e11b815260040160405180910390fd5b600061216d7faa6d9093095fdf69cb4e18b3e4053e238ec6e2d5a083964634b640da3b8f44a485356020870135604088013561211360808a0160608b01612c1a565b60808a013560a08b013560c08c01356121336101008e0160e08f01612e8a565b8d61010001356040516020016121529a9998979695949392919061304e565b6040516020818303038152906040528051906020012061272f565b9050600061217b828561277d565b90506121a77f023d9737d781c665e5048e4dfd034f07fec540e8ecb2336b3d85a375b90a3a3582611916565b6121c45760405163127a982d60e01b815260040160405180910390fd5b5050505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526118129186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506127a1565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526122838482612812565b611812576040516001600160a01b038481166024830152600060448301526122b891869182169063095ea7b390606401612200565b61181284826127a1565b6040516001600160a01b0383811660248301526044820183905261096691859182169063a9059cbb90606401612200565b7fdfe4debbd7bc491e9db43820916e30a4ef9490863fc22b1e79e2f76013901035600560008154612323906130b2565b9182905550602083013583356040850135612345610100870160e08801612e8a565b6123556080880160608901612c1a565b87608001358860a001358960c001358a61010001356040516123809a999897969594939291906130cb565b60405180910390a150565b600061190f8383612861565b60006107b9825490565b6000306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480156123fa57507f000000000000000000000000000000000000000000000000000000000000000046145b1561242457507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b600081815260018301602052604081205461250f575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556107b9565b5060006107b9565b60606000612526836002612ec1565b612531906002613130565b67ffffffffffffffff81111561254957612549612cbf565b6040519080825280601f01601f191660200182016040528015612573576020820181803683370190505b509050600360fc1b8160008151811061258e5761258e613143565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106125bd576125bd613143565b60200101906001600160f81b031916908160001a90535060006125e1846002612ec1565b6125ec906001613130565b90505b6001811115612664576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061262057612620613143565b1a60f81b82828151811061263657612636613143565b60200101906001600160f81b031916908160001a90535060049490941c9361265d81613159565b90506125ef565b50831561190f5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610bb4565b6126bd8282611916565b15610bc75760008281526001602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600061190f836001600160a01b03841661288b565b60006107b961273c6123a1565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b600080600061278c858561297e565b91509150612799816129c3565b509392505050565b600080602060008451602086016000885af1806127c4576040513d6000823e3d81fd5b50506000513d915081156127dc5780600114156127e9565b6001600160a01b0384163b155b1561181257604051635274afe760e01b81526001600160a01b0385166004820152602401610bb4565b6000806000806020600086516020880160008a5af192503d91506000519050828015612857575081156128485780600114612857565b6000866001600160a01b03163b115b9695505050505050565b600082600001828154811061287857612878613143565b9060005260206000200154905092915050565b600081815260018301602052604081205480156129745760006128af600183612f52565b85549091506000906128c390600190612f52565b90508181146129285760008660000182815481106128e3576128e3613143565b906000526020600020015490508087600001848154811061290657612906613143565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061293957612939613170565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506107b9565b60009150506107b9565b60008082516041036129b45760208301516040840151606085015160001a6129a887828585612b10565b945094505050506129bc565b506000905060025b9250929050565b60008160048111156129d7576129d7612e74565b036129df5750565b60018160048111156129f3576129f3612e74565b03612a405760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610bb4565b6002816004811115612a5457612a54612e74565b03612aa15760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610bb4565b6003816004811115612ab557612ab5612e74565b03612b0d5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610bb4565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115612b475750600090506003612bcb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612b9b573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612bc457600060019250925050612bcb565b9150600090505b94509492505050565b600060208284031215612be657600080fd5b81356001600160e01b03198116811461190f57600080fd5b80356001600160a01b0381168114612c1557600080fd5b919050565b600060208284031215612c2c57600080fd5b61190f82612bfe565b8015158114612b0d57600080fd5b60008060408385031215612c5657600080fd5b612c5f83612bfe565b91506020830135612c6f81612c35565b809150509250929050565b600060208284031215612c8c57600080fd5b5035919050565b60008060408385031215612ca657600080fd5b82359150612cb660208401612bfe565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b600080600080848603610180811215612ced57600080fd5b61012080821215612cfd57600080fd5b869550850135905067ffffffffffffffff80821115612d1b57600080fd5b818701915087601f830112612d2f57600080fd5b813581811115612d4157612d41612cbf565b604051601f8201601f19908116603f01168101908382118183101715612d6957612d69612cbf565b816040528281528a6020848701011115612d8257600080fd5b826020860160208301376000602084830101528097505050505050612daa6101408601612bfe565b939692955092936101600135925050565b600080600060608486031215612dd057600080fd5b612dd984612bfe565b9250612de760208501612bfe565b9150604084013590509250925092565b60008060408385031215612e0a57600080fd5b50508035926020909101359150565b60008060008060808587031215612e2f57600080fd5b612e3885612bfe565b9350612e4660208601612bfe565b93969395505050506040820135916060013590565b600060208284031215612e6d57600080fd5b5051919050565b634e487b7160e01b600052602160045260246000fd5b600060208284031215612e9c57600080fd5b81356002811061190f57600080fd5b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615612edb57612edb612eab565b500290565b600082612efd57634e487b7160e01b600052601260045260246000fd5b500490565b60028110612b0d57634e487b7160e01b600052602160045260246000fd5b60808101612f2d86612f02565b9481526001600160a01b03939093166020840152604083019190915260609091015290565b818103818111156107b9576107b9612eab565b600060208284031215612f7757600080fd5b815161190f81612c35565b60005b83811015612f9d578181015183820152602001612f85565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351612fde816017850160208801612f82565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835161300f816028840160208801612f82565b01602801949350505050565b602081526000825180602084015261303a816040850160208701612f82565b601f01601f19169190910160400192915050565b8a8152602081018a905260408101899052606081018890526001600160a01b038716608082015260a0810186905260c0810185905260e08101849052610140810161309884612f02565b610100820193909352610120015298975050505050505050565b6000600182016130c4576130c4612eab565b5060010190565b6000610140820190508b82528a60208301528960408301528860608301526130f288612f02565b60808201979097526001600160a01b039590951660a086015260c085019390935260e084019190915261010083015261012090910152949350505050565b808201808211156107b9576107b9612eab565b634e487b7160e01b600052603260045260246000fd5b60008161316857613168612eab565b506000190190565b634e487b7160e01b600052603160045260246000fdfef45c97b23e2beeefda80e1ce5cb3e234aa7b6888ad5cbabb75bfd654dd8e102d427da25fe773164f88948d3e215c94b6554e2ed5e5f203a821c9f2f6131cf75a65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862aa2646970667358221220e211d9dde0d4ad5835acdb86363cbd2b4d1eb9b33248d0affbd6f834922125e364736f6c6343000810003300000000000000000000000054b5aae5bda007db744ea762460a96f24bc1f4ad000000000000000000000000ace8e719899f6e91831b18ae746c9a965c2119f10000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000de0b6b3a7640000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103275760003560e01c80637b0e1c57116101b8578063b28996b511610104578063e63ab1e9116100a2578063ed24911d1161007c578063ed24911d1461073d578063ed2a354014610745578063f758161514610758578063fb1bb9de1461077f57600080fd5b8063e63ab1e914610708578063eb27fa531461071d578063ebaf3f211461072a57600080fd5b8063c7f8e171116100de578063c7f8e171146106c0578063c875edf6146106cf578063ca15c873146106e2578063d547741f146106f557600080fd5b8063b28996b514610663578063bd5d370c14610686578063c768b145146106ad57600080fd5b80639010d07c11610171578063a217fddf1161014b578063a217fddf14610620578063aab483d614610628578063abbb9f4c1461063b578063ad129e771461065057600080fd5b80639010d07c146105d357806391d14854146105e65780639c617c7e146105f957600080fd5b80637b0e1c5714610577578063811400fa1461058a57806381d69bba1461059d57806384b78414146105a55780638c6f4ab7146105b85780638f8eb812146105ca57600080fd5b8063445df08b11610277578063531acc13116102305780636269ff8f1161020a5780636269ff8f1461053057806369d3605c146105535780636eefea491461055b57806376ce2dad1461056e57600080fd5b8063531acc13146104f157806355358afb146104fa5780635c0478d11461050d57600080fd5b8063445df08b1461046f57806348c6ca77146104825780634ef1ccd1146104955780634f23c343146104a85780635010af4d146104bb57806350aaef5a146104ce57600080fd5b8063246b3502116102e45780632d50bb74116102be5780632d50bb74146104235780632f2ff15d146104365780633483369d1461044957806336568abe1461045c57600080fd5b8063246b3502146103e4578063248a9ca3146103f75780632542dbfd1461041b57600080fd5b806301ffc9a71461032c5780630250f9fe1461035457806303cad6451461035e57806305ac4e0b146103895780630e16f0c81461039c57806323991e4b146103d1575b600080fd5b61033f61033a366004612bd4565b610794565b60405190151581526020015b60405180910390f35b61035c6107bf565b005b600354610371906001600160a01b031681565b6040516001600160a01b03909116815260200161034b565b61035c610397366004612c1a565b61080f565b6103c37f507caaa5b2a5a027bc340a5334d9220583b7d60d846ee2aabc76e37d69a7253b81565b60405190815260200161034b565b61035c6103df366004612c1a565b610872565b61035c6103f2366004612c43565b61096b565b6103c3610405366004612c7a565b6000908152600160208190526040909120015490565b61035c610a00565b61035c610431366004612c1a565b610a52565b61035c610444366004612c93565b610ab8565b61035c610457366004612c1a565b610adf565b61035c61046a366004612c93565b610b48565b6103c361047d366004612cd5565b610bcb565b61035c610490366004612c1a565b611145565b61035c6104a3366004612c7a565b6111a8565b600654610371906001600160a01b031681565b600f54610371906001600160a01b031681565b61033f6104dc366004612c7a565b60046020526000908152604090205460ff1681565b6103c360075481565b600e54610371906001600160a01b031681565b61033f61051b366004612c1a565b60106020526000908152604090205460ff1681565b61033f61053e366004612c1a565b600a6020526000908152604090205460ff1681565b61035c6111f6565b6103c3610569366004612cd5565b61124a565b6103c360055481565b61035c610585366004612dbb565b6117f2565b600d54610371906001600160a01b031681565b61035c611818565b61035c6105b3366004612c1a565b611867565b60095461033f90610100900460ff1681565b6103c360085481565b6103716105e1366004612df7565b6118f7565b61033f6105f4366004612c93565b611916565b6103c37f023d9737d781c665e5048e4dfd034f07fec540e8ecb2336b3d85a375b90a3a3581565b6103c3600081565b61035c610636366004612c7a565b611941565b6103c360008051602061318783398151915281565b61035c61065e366004612c1a565b61198f565b61033f610671366004612c1a565b600b6020526000908152604090205460ff1681565b6103717f000000000000000000000000ace8e719899f6e91831b18ae746c9a965c2119f181565b600c54610371906001600160a01b031681565b6103c3670de0b6b3a764000081565b61035c6106dd366004612c1a565b611a1f565b6103c36106f0366004612c7a565b611a85565b61035c610703366004612c93565b611a9c565b6103c36000805160206131c783398151915281565b60095461033f9060ff1681565b61035c610738366004612c1a565b611ac3565b6103c3611b53565b61035c610753366004612e19565b611b62565b6103c37faa6d9093095fdf69cb4e18b3e4053e238ec6e2d5a083964634b640da3b8f44a481565b6103c36000805160206131a783398151915281565b60006001600160e01b03198216635a05180f60e01b14806107b957506107b982611e04565b92915050565b6000805160206131a78339815191526107d88133611e39565b6009805461ff00191690556040517f8cba7e15b16021395abffdc05ba74a88afd2b3dce03e075ddb041760a389068890600090a150565b6000805160206131a78339815191526108288133611e39565b6001600160a01b0382166000818152600b6020526040808220805460ff19169055517ff7db4b816293b43fac22e1773acf5d3774a3d70ab993f04995406fadd92b546a9190a25050565b600061087e8133611e39565b6001600160a01b0382166108a557604051633d04535360e21b815260040160405180910390fd5b600c546040516001600160a01b038085169216907ff78e014ab86d7bb38135262d64726cef2e151dae47c0947a1d6bb970702c30d690600090a3600c80546001600160a01b0319166001600160a01b03848116918217909255600354604051637f19077160e01b81529216600483015230602483015290637f19077190604401602060405180830381865afa158015610942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109669190612e5b565b505050565b6000805160206131878339815191526109848133611e39565b6001600160a01b0383166109ab5760405163885ce5f160e01b815260040160405180910390fd5b6001600160a01b038316600081815260106020526040808220805460ff191686151590811790915590519092917f8f1a189329487ea2f651b3797ac87d45216b42a18c01a7335169539b76df133891a3505050565b6000805160206131c7833981519152610a198133611e39565b6009805460ff191660011790556040517f94eae7ff948a5ddfb0e5f291aa214ae9dd7d12ea33086a414143bc4a3408734190600090a150565b6000805160206131c7833981519152610a6b8133611e39565b6001600160a01b0382166000818152600b6020526040808220805460ff19166001179055517fcacc4dbd81af0cceec871b59f5155fa60dc3a52b970778ba54b2cf66f0b5deeb9190a25050565b60008281526001602081905260409091200154610ad58133611e39565b6109668383611e9d565b6000610aeb8133611e39565b6006546040516001600160a01b038085169216907fad45eab3ddda99c8b095504a58e25095a54c31dc487bb3eed9c0a9112ee4eaa890600090a350600680546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381163314610bbd5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b610bc78282611ebf565b5050565b6000600260005403610c1f5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bb4565b6002600055610c346080860160608701612c1a565b60095460ff1615610c58576040516331852b7360e21b815260040160405180910390fd5b6001600160a01b0381166000908152600a602052604090205460ff1615610c915760405162e4b17560e11b815260040160405180910390fd5b6001600160a01b038416610cb85760405163885ce5f160e01b815260040160405180910390fd5b6000610ccb610100880160e08901612e8a565b6001811115610cdc57610cdc612e74565b14610cfa576040516326b1c87960e21b815260040160405180910390fd5b600c546003546000916001600160a01b0390811691637f1907719116336040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604401602060405180830381865afa158015610d62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d869190612e5b565b905080610da657604051632163950f60e01b815260040160405180910390fd5b610db1878783611ee1565b6020808801356000908152600490915260408120805460ff19166001179055670de0b6b3a7640000610deb60808a013560a08b0135612ec1565b610df59190612ee0565b9050600754811015610e1a576040516367627d0760e01b815260040160405180910390fd5b600d546001600160a01b0316637d4945b76000610e3d60808c0160608d01612c1a565b85856040518563ffffffff1660e01b8152600401610e5e9493929190612f20565b600060405180830381600087803b158015610e7857600080fd5b505af1158015610e8c573d6000803e3d6000fd5b505050507f000000000000000000000000ace8e719899f6e91831b18ae746c9a965c2119f16001600160a01b0316866001600160a01b031603610f0357610efe7f000000000000000000000000ace8e719899f6e91831b18ae746c9a965c2119f16001600160a01b03163330846121cb565b611029565b6006546001600160a01b0316610f2c5760405163cdce50bd60e01b815260040160405180910390fd5b610f416001600160a01b0387163330886121cb565b600654610f5b906001600160a01b03888116911687612232565b6006546040516322d4a17560e01b81526001600160a01b038881166004830152602482018890526044820184905260009216906322d4a175906064016020604051808303816000875af1158015610fb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fda9190612e5b565b90506000610fe88383612f52565b9050801561102657611026335b6001600160a01b037f000000000000000000000000ace8e719899f6e91831b18ae746c9a965c2119f11690836122c2565b50505b604051630852cd8d60e31b8152600481018290527f000000000000000000000000ace8e719899f6e91831b18ae746c9a965c2119f16001600160a01b0316906342966c6890602401600060405180830381600087803b15801561108b57600080fd5b505af115801561109f573d6000803e3d6000fd5b506110b4925050506080890160608a01612c1a565b6001600160a01b03166340c10f19336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260a08b01356024820152604401600060405180830381600087803b15801561110e57600080fd5b505af1158015611122573d6000803e3d6000fd5b5050505061112f886122f3565b5050600160005550505060a09092013592915050565b6000805160206131a783398151915261115e8133611e39565b6001600160a01b0382166000818152600a6020526040808220805460ff19169055517f8ea8fa511d23c1a22f92d6480c103dff2994b522f89b46b18c9493130d1121de9190a25050565b6000805160206131878339815191526111c18133611e39565b6008546040518391907ffdaf6ed728cef208e62328a008209556f8281f3062b14dd08aaaa90fa159421190600090a350600855565b6000805160206131c783398151915261120f8133611e39565b6009805461ff0019166101001790556040517f694abd7c120a829fef1aac704885e405362fcd69c82f114ccec2959a402633c590600090a150565b600060026000540361129e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bb4565b60026000556112b36080860160608701612c1a565b600954610100900460ff16156112dc576040516378b17b4360e11b815260040160405180910390fd5b6001600160a01b0381166000908152600b602052604090205460ff16156113165760405163877009f360e01b815260040160405180910390fd5b6001600160a01b03841661133d5760405163885ce5f160e01b815260040160405180910390fd5b6001611350610100880160e08901612e8a565b600181111561136157611361612e74565b1461137f576040516326b1c87960e21b815260040160405180910390fd5b600c546003546000916001600160a01b0390811691637f1907719116336040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604401602060405180830381865afa1580156113e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061140b9190612e5b565b90508061142b57604051632163950f60e01b815260040160405180910390fd5b611436878783611ee1565b6020808801356000908152600490915260409020805460ff1916600117905561148661145f3390565b3060a08a013561147560808c0160608d01612c1a565b6001600160a01b03169291906121cb565b6114966080880160608901612c1a565b604051630852cd8d60e31b815260a089013560048201526001600160a01b0391909116906342966c6890602401600060405180830381600087803b1580156114dd57600080fd5b505af11580156114f1573d6000803e3d6000fd5b505050506000670de0b6b3a764000088608001358960a001356115149190612ec1565b61151e9190612ee0565b90506008548110156115435760405163680116dd60e11b815260040160405180910390fd5b600d546001600160a01b0316637d4945b7600161156660808c0160608d01612c1a565b85856040518563ffffffff1660e01b81526004016115879493929190612f20565b600060405180830381600087803b1580156115a157600080fd5b505af11580156115b5573d6000803e3d6000fd5b50506040516340c10f1960e01b8152306004820152602481018490527f000000000000000000000000ace8e719899f6e91831b18ae746c9a965c2119f16001600160a01b031692506340c10f199150604401600060405180830381600087803b15801561162157600080fd5b505af1158015611635573d6000803e3d6000fd5b505050507f000000000000000000000000ace8e719899f6e91831b18ae746c9a965c2119f16001600160a01b0316866001600160a01b0316036116805761167b33610ff5565b6117d9565b6006546001600160a01b03166116a95760405163cdce50bd60e01b815260040160405180910390fd5b60065460405163095ea7b360e01b81526001600160a01b039182166004820152602481018390527f000000000000000000000000ace8e719899f6e91831b18ae746c9a965c2119f19091169063095ea7b3906044016020604051808303816000875af115801561171d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117419190612f65565b5060065460405163d878016160e01b8152600481018390526001600160a01b03888116602483015260448201889052600092169063d8780161906064016020604051808303816000875af115801561179d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c19190612e5b565b90506117d76001600160a01b03881633836122c2565b505b6117e2886122f3565b6001600055979650505050505050565b60006117fe8133611e39565b6118126001600160a01b03851684846122c2565b50505050565b6000805160206131a78339815191526118318133611e39565b6009805460ff191690556040517f7c5bd2c6bf55553fb8379a172f2f9d0369fc18a7bf82a47486ac611a9215060190600090a150565b60006118738133611e39565b6001600160a01b03821661189a576040516301acb6d760e01b815260040160405180910390fd5b600f546040516001600160a01b038085169216907f7c40bb6767b8c6caf208ae3b9558c37a91b5710f5157deb182aae429ac24d33690600090a350600f80546001600160a01b0319166001600160a01b0392909216919091179055565b600082815260026020526040812061190f908361238b565b9392505050565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b60008051602061318783398151915261195a8133611e39565b6007546040518391907fe6e25add7363f8f8a40cbea9810d3115a33703b10972ef759104219b0065743690600090a350600755565b600061199b8133611e39565b6001600160a01b0382166119c257604051633aa9ba3360e01b815260040160405180910390fd5b600d546040516001600160a01b038085169216907fc54bf4c3067c1d8f65e053dafb5dbb699615b1b527d2866bd0223102bb2e692d90600090a350600d80546001600160a01b0319166001600160a01b0392909216919091179055565b6000805160206131c7833981519152611a388133611e39565b6001600160a01b0382166000818152600a6020526040808220805460ff19166001179055517f0de7e27328f4d5d9fc5797bf8cc1f3ca9c0d366a83aae68215e9e7dbf156a1f19190a25050565b60008181526002602052604081206107b990612397565b60008281526001602081905260409091200154611ab98133611e39565b6109668383611ebf565b6000611acf8133611e39565b6001600160a01b038216611af657604051630e1164bf60e21b815260040160405180910390fd5b600e546040516001600160a01b038085169216907fcaf02d44223f855a96856532b7f6b262b8c1e57639d6ea29ff00f49b65d6a0be90600090a350600e80546001600160a01b0319166001600160a01b0392909216919091179055565b6000611b5d6123a1565b905090565b600954849060ff1615611b88576040516331852b7360e21b815260040160405180910390fd5b6001600160a01b0381166000908152600a602052604090205460ff1615611bc15760405162e4b17560e11b815260040160405180910390fd5b7f507caaa5b2a5a027bc340a5334d9220583b7d60d846ee2aabc76e37d69a7253b611bec8133611e39565b6001600160a01b03861660009081526010602052604090205460ff16611c25576040516326b5ecf360e01b815260040160405180910390fd5b600c54600354604051637f19077160e01b81526001600160a01b03918216600482015287821660248201526000929190911690637f19077190604401602060405180830381865afa158015611c7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ca29190612e5b565b905080611cc257604051632163950f60e01b815260040160405180910390fd5b6040516340c10f1960e01b81526001600160a01b038781166004830152602482018790528816906340c10f1990604401600060405180830381600087803b158015611d0c57600080fd5b505af1158015611d20573d6000803e3d6000fd5b50505050866001600160a01b031681876001600160a01b03167f64246d088e96d6b1bbb49bd2ab458376867796a99add0e25a88c53bcee7ddbdf8888604051611d73929190918252602082015260400190565b60405180910390a450505050505050565b611d8e8282611916565b610bc75760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b600061190f836001600160a01b0384166124c8565b60006001600160e01b03198216637965db0b60e01b14806107b957506301ffc9a760e01b6001600160e01b03198316146107b9565b611e438282611916565b610bc757611e5b816001600160a01b03166014612517565b611e66836020612517565b604051602001611e77929190612fa6565b60408051601f198184030181529082905262461bcd60e51b8252610bb49160040161301b565b611ea78282611d84565b60008281526002602052604090206109669082611def565b611ec982826126b3565b6000828152600260205260409020610966908261271a565b60208084013560009081526004909152604090205460ff1615611f17576040516308d0ea5b60e31b815260040160405180910390fd5b8260c00135421115611f3c5760405163716dcc3960e01b815260040160405180910390fd5b82604001358114611f6d576040805163748b3dc360e11b815260048101839052908401356024820152604401610bb4565b600e60009054906101000a90046001600160a01b03166001600160a01b031663e8c7e7286040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611fbd57600080fd5b505af1158015611fd1573d6000803e3d6000fd5b5050600f546001600160a01b0316915063fd45a4339050611ff86080860160608701612c1a565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526080860135602482015260440160006040518083038186803b15801561204157600080fd5b505afa158015612055573d6000803e3d6000fd5b50505050601060008460600160208101906120709190612c1a565b6001600160a01b03168152602081019190915260400160009081205460ff16151590036120b0576040516326b5ecf360e01b815260040160405180910390fd5b823546146120d157604051633d23e4d160e11b815260040160405180910390fd5b600061216d7faa6d9093095fdf69cb4e18b3e4053e238ec6e2d5a083964634b640da3b8f44a485356020870135604088013561211360808a0160608b01612c1a565b60808a013560a08b013560c08c01356121336101008e0160e08f01612e8a565b8d61010001356040516020016121529a9998979695949392919061304e565b6040516020818303038152906040528051906020012061272f565b9050600061217b828561277d565b90506121a77f023d9737d781c665e5048e4dfd034f07fec540e8ecb2336b3d85a375b90a3a3582611916565b6121c45760405163127a982d60e01b815260040160405180910390fd5b5050505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526118129186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506127a1565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526122838482612812565b611812576040516001600160a01b038481166024830152600060448301526122b891869182169063095ea7b390606401612200565b61181284826127a1565b6040516001600160a01b0383811660248301526044820183905261096691859182169063a9059cbb90606401612200565b7fdfe4debbd7bc491e9db43820916e30a4ef9490863fc22b1e79e2f76013901035600560008154612323906130b2565b9182905550602083013583356040850135612345610100870160e08801612e8a565b6123556080880160608901612c1a565b87608001358860a001358960c001358a61010001356040516123809a999897969594939291906130cb565b60405180910390a150565b600061190f8383612861565b60006107b9825490565b6000306001600160a01b037f0000000000000000000000002c158bc456e027b2affccadf1bdbd9f5fc4c5c8c161480156123fa57507f000000000000000000000000000000000000000000000000000000000000000146145b1561242457507fe366cab15d2bf3f9f295fa4d4f299170e44e971d8e7f1808dfef3c453692222c90565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527f95ed386835dc204e5cd2629625d0c3fb319cf204ef02efd869f16db3cc0f04ce828401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b600081815260018301602052604081205461250f575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556107b9565b5060006107b9565b60606000612526836002612ec1565b612531906002613130565b67ffffffffffffffff81111561254957612549612cbf565b6040519080825280601f01601f191660200182016040528015612573576020820181803683370190505b509050600360fc1b8160008151811061258e5761258e613143565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106125bd576125bd613143565b60200101906001600160f81b031916908160001a90535060006125e1846002612ec1565b6125ec906001613130565b90505b6001811115612664576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061262057612620613143565b1a60f81b82828151811061263657612636613143565b60200101906001600160f81b031916908160001a90535060049490941c9361265d81613159565b90506125ef565b50831561190f5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610bb4565b6126bd8282611916565b15610bc75760008281526001602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600061190f836001600160a01b03841661288b565b60006107b961273c6123a1565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b600080600061278c858561297e565b91509150612799816129c3565b509392505050565b600080602060008451602086016000885af1806127c4576040513d6000823e3d81fd5b50506000513d915081156127dc5780600114156127e9565b6001600160a01b0384163b155b1561181257604051635274afe760e01b81526001600160a01b0385166004820152602401610bb4565b6000806000806020600086516020880160008a5af192503d91506000519050828015612857575081156128485780600114612857565b6000866001600160a01b03163b115b9695505050505050565b600082600001828154811061287857612878613143565b9060005260206000200154905092915050565b600081815260018301602052604081205480156129745760006128af600183612f52565b85549091506000906128c390600190612f52565b90508181146129285760008660000182815481106128e3576128e3613143565b906000526020600020015490508087600001848154811061290657612906613143565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061293957612939613170565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506107b9565b60009150506107b9565b60008082516041036129b45760208301516040840151606085015160001a6129a887828585612b10565b945094505050506129bc565b506000905060025b9250929050565b60008160048111156129d7576129d7612e74565b036129df5750565b60018160048111156129f3576129f3612e74565b03612a405760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610bb4565b6002816004811115612a5457612a54612e74565b03612aa15760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610bb4565b6003816004811115612ab557612ab5612e74565b03612b0d5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610bb4565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115612b475750600090506003612bcb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612b9b573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612bc457600060019250925050612bcb565b9150600090505b94509492505050565b600060208284031215612be657600080fd5b81356001600160e01b03198116811461190f57600080fd5b80356001600160a01b0381168114612c1557600080fd5b919050565b600060208284031215612c2c57600080fd5b61190f82612bfe565b8015158114612b0d57600080fd5b60008060408385031215612c5657600080fd5b612c5f83612bfe565b91506020830135612c6f81612c35565b809150509250929050565b600060208284031215612c8c57600080fd5b5035919050565b60008060408385031215612ca657600080fd5b82359150612cb660208401612bfe565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b600080600080848603610180811215612ced57600080fd5b61012080821215612cfd57600080fd5b869550850135905067ffffffffffffffff80821115612d1b57600080fd5b818701915087601f830112612d2f57600080fd5b813581811115612d4157612d41612cbf565b604051601f8201601f19908116603f01168101908382118183101715612d6957612d69612cbf565b816040528281528a6020848701011115612d8257600080fd5b826020860160208301376000602084830101528097505050505050612daa6101408601612bfe565b939692955092936101600135925050565b600080600060608486031215612dd057600080fd5b612dd984612bfe565b9250612de760208501612bfe565b9150604084013590509250925092565b60008060408385031215612e0a57600080fd5b50508035926020909101359150565b60008060008060808587031215612e2f57600080fd5b612e3885612bfe565b9350612e4660208601612bfe565b93969395505050506040820135916060013590565b600060208284031215612e6d57600080fd5b5051919050565b634e487b7160e01b600052602160045260246000fd5b600060208284031215612e9c57600080fd5b81356002811061190f57600080fd5b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615612edb57612edb612eab565b500290565b600082612efd57634e487b7160e01b600052601260045260246000fd5b500490565b60028110612b0d57634e487b7160e01b600052602160045260246000fd5b60808101612f2d86612f02565b9481526001600160a01b03939093166020840152604083019190915260609091015290565b818103818111156107b9576107b9612eab565b600060208284031215612f7757600080fd5b815161190f81612c35565b60005b83811015612f9d578181015183820152602001612f85565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351612fde816017850160208801612f82565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835161300f816028840160208801612f82565b01602801949350505050565b602081526000825180602084015261303a816040850160208701612f82565b601f01601f19169190910160400192915050565b8a8152602081018a905260408101899052606081018890526001600160a01b038716608082015260a0810186905260c0810185905260e08101849052610140810161309884612f02565b610100820193909352610120015298975050505050505050565b6000600182016130c4576130c4612eab565b5060010190565b6000610140820190508b82528a60208301528960408301528860608301526130f288612f02565b60808201979097526001600160a01b039590951660a086015260c085019390935260e084019190915261010083015261012090910152949350505050565b808201808211156107b9576107b9612eab565b634e487b7160e01b600052603260045260246000fd5b60008161316857613168612eab565b506000190190565b634e487b7160e01b600052603160045260246000fdfef45c97b23e2beeefda80e1ce5cb3e234aa7b6888ad5cbabb75bfd654dd8e102d427da25fe773164f88948d3e215c94b6554e2ed5e5f203a821c9f2f6131cf75a65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862aa2646970667358221220e211d9dde0d4ad5835acdb86363cbd2b4d1eb9b33248d0affbd6f834922125e364736f6c63430008100033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000054b5aae5bda007db744ea762460a96f24bc1f4ad000000000000000000000000ace8e719899f6e91831b18ae746c9a965c2119f10000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000de0b6b3a7640000
-----Decoded View---------------
Arg [0] : _defaultAdmin (address): 0x54b5Aae5bdA007DB744Ea762460A96F24BC1F4ad
Arg [1] : _usdon (address): 0xAcE8E719899F6E91831B18AE746C9A965c2119F1
Arg [2] : _minimumDepositUSD (uint256): 1000000000000000000
Arg [3] : _minimumRedemptionUSD (uint256): 1000000000000000000
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000054b5aae5bda007db744ea762460a96f24bc1f4ad
Arg [1] : 000000000000000000000000ace8e719899f6e91831b18ae746c9a965c2119f1
Arg [2] : 0000000000000000000000000000000000000000000000000de0b6b3a7640000
Arg [3] : 0000000000000000000000000000000000000000000000000de0b6b3a7640000
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.