More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 50 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Burn | 23656910 | 120 days ago | IN | 0 ETH | 0.00000296 | ||||
| Burn | 23656903 | 120 days ago | IN | 0 ETH | 0.00000339 | ||||
| Admin Withdraw B... | 23656901 | 120 days ago | IN | 0 ETH | 0.00000493 | ||||
| Burn | 23656898 | 120 days ago | IN | 0 ETH | 0.00000371 | ||||
| Burn | 23656889 | 120 days ago | IN | 0 ETH | 0.00000347 | ||||
| Admin Withdraw B... | 23656887 | 120 days ago | IN | 0 ETH | 0.00000764 | ||||
| Burn | 23656880 | 120 days ago | IN | 0 ETH | 0.00000364 | ||||
| Burn | 23656871 | 120 days ago | IN | 0 ETH | 0.0000035 | ||||
| Burn | 23656863 | 120 days ago | IN | 0 ETH | 0.00000355 | ||||
| Burn | 23656852 | 120 days ago | IN | 0 ETH | 0.00000332 | ||||
| Burn | 23656824 | 120 days ago | IN | 0 ETH | 0.00000327 | ||||
| Burn | 23656818 | 120 days ago | IN | 0 ETH | 0.00000322 | ||||
| Burn | 23656814 | 120 days ago | IN | 0 ETH | 0.0000033 | ||||
| Burn | 23656802 | 120 days ago | IN | 0 ETH | 0.0000035 | ||||
| Set CPI | 23648603 | 121 days ago | IN | 0 ETH | 0.00001078 | ||||
| Pause | 23620686 | 125 days ago | IN | 0 ETH | 0.00000507 | ||||
| Deposit | 23576757 | 131 days ago | IN | 0 ETH | 0.0003003 | ||||
| Admin Withdraw B... | 23570852 | 132 days ago | IN | 0 ETH | 0.00004134 | ||||
| Withdraw | 23570329 | 132 days ago | IN | 0 ETH | 0.00025172 | ||||
| Deposit | 23556694 | 134 days ago | IN | 0 ETH | 0.00011571 | ||||
| Deposit | 23556648 | 134 days ago | IN | 0 ETH | 0.00017651 | ||||
| Deposit | 23483330 | 144 days ago | IN | 0 ETH | 0.00026831 | ||||
| Deposit | 23471162 | 146 days ago | IN | 0 ETH | 0.00033043 | ||||
| Deposit | 23451504 | 148 days ago | IN | 0 ETH | 0.00014623 | ||||
| Deposit | 23356462 | 162 days ago | IN | 0 ETH | 0.00005502 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
USDiCoin
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 1000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
/// @title USDiCoin - A CPI-adjusted, USD-backed stablecoin with tiered mint/burn fees, role-based access control, and peg checks
contract USDiCoin is ERC20, AccessControl, Pausable, ReentrancyGuard {
using SafeERC20 for IERC20;
//////////////////////////////
// Constants & Immutables
//////////////////////////////
bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE");
uint256 public constant whitelistChangeDelay = 12 hours;
IERC20 public immutable backingToken;
uint256 public constant startingCPI = 315605;
bool public whitelistEnabled;
//////////////////////////////
// State Variables
//////////////////////////////
struct FeeTier {
uint256 min;
uint256 max;
uint256 mintFee;
uint256 burnFee;
}
FeeTier[] public feeTiers;
mapping(uint256 => uint256) public monthlyCPI;
mapping(uint256 => uint256) public monthlyStartTime;
mapping(address => uint256) public whitelistStartTime;
mapping(address => string) public lastWithdrawLog;
mapping(address => string) public lastDepositLog;
mapping(address => bool) public blacklist;
address public treasury;
uint256 public minimumFee = 1 * 1e6;
//////////////////////////////
// Events
//////////////////////////////
event Deposit(address indexed from, uint256 amount, uint256 fee);
event Withdrawal(address indexed to, uint256 amount, uint256 fee);
event CPIUpdated(uint256 yearMonth, uint256 newCPI);
event MonthlyStartTimeSet(uint256 yearMonth, uint256 startTime);
event BackingInjected(address indexed from, uint256 amount);
event BackingWithdrawn(address indexed to, uint256 amount);
event WhitelistRequested(address indexed account, uint256 readyTime);
event StartingCPISet(uint256 startingCPI);
event ManualMint(address indexed to, uint256 amount, string reason, uint256 timestamp);
event ManualBurn(address indexed from, uint256 amount, string reason, uint256 timestamp);
event WhitelistRemoved(address indexed account);
event MinimumFeeChanged(uint256 oldMinimumFee, uint256 newMinimumFee);
event TreasuryChanged(address oldTreasury, address newTreasury);
event Blacklisted(address indexed account);
event Unblacklisted(address indexed account);
//////////////////////////////
// Constructor
//////////////////////////////
constructor(address _backingToken)
ERC20("USDi Coin", "USDi")
{
require(_backingToken != address(0), "Invalid backing token address");
backingToken = IERC20(_backingToken);
treasury = msg.sender;
whitelistEnabled = false;
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(MANAGER_ROLE, msg.sender);
whitelistStartTime[msg.sender] = block.timestamp;
emit WhitelistRequested(msg.sender, block.timestamp);
emit StartingCPISet(startingCPI);
// set fee tiers
feeTiers.push(FeeTier(0, 100_000e6, 50, 100));
feeTiers.push(FeeTier(100_000e6 + 1, 999_999e6, 20, 50));
feeTiers.push(FeeTier(1_000_000e6, 4_999_999e6, 5, 10));
feeTiers.push(FeeTier(5_000_000e6, 9_999_999e6, 0, 5));
feeTiers.push(FeeTier(10_000_000e6, 199_999_999e6, 0, 2));
feeTiers.push(FeeTier(200_000_000e6, 1_000_000_000e6, 2, 5));
// set knownmonthly CPIs
monthlyCPI[202412] = 315605;
monthlyCPI[202501] = 317671;
monthlyCPI[202502] = 319082;
monthlyCPI[202503] = 319799;
monthlyCPI[202504] = 320795;
monthlyCPI[202505] = 321465;
monthlyCPI[202506] = 322561;
// set monthly start times for 2025
monthlyStartTime[202501] = 1735707600;
monthlyStartTime[202502] = 1738386000;
monthlyStartTime[202503] = 1740805200;
monthlyStartTime[202504] = 1743480000;
monthlyStartTime[202505] = 1746072000;
monthlyStartTime[202506] = 1748750400;
monthlyStartTime[202507] = 1751342400;
monthlyStartTime[202508] = 1754020800;
monthlyStartTime[202509] = 1756699200;
monthlyStartTime[202510] = 1759291200;
monthlyStartTime[202511] = 1761969600;
monthlyStartTime[202512] = 1764565200;
// set monthly start times for 2026
monthlyStartTime[202601] = 1767243600;
monthlyStartTime[202602] = 1769922000;
monthlyStartTime[202603] = 1772341200;
monthlyStartTime[202604] = 1775016000;
monthlyStartTime[202605] = 1777608000;
monthlyStartTime[202606] = 1780286400;
monthlyStartTime[202607] = 1782878400;
monthlyStartTime[202608] = 1785556800;
monthlyStartTime[202609] = 1788235200;
monthlyStartTime[202610] = 1790827200;
monthlyStartTime[202611] = 1793505600;
monthlyStartTime[202612] = 1796101200;
// preload blacklist with OFAC addresses
blacklist[0x098B716B8Aaf21512996dC57EB0615e2383E2f96] = true;
blacklist[0xa0e1c89Ef1a489c9C7dE96311eD5Ce5D32c20E4B] = true;
blacklist[0x3Cffd56B47B7b41c56258D9C7731ABaDc360E073] = true;
blacklist[0x53b6936513e738f44FB50d2b9476730C0Ab3Bfc1] = true;
blacklist[0x35fB6f6DB4fb05e6A4cE86f2C93691425626d4b1] = true;
blacklist[0xF7B31119c2682c88d88D455dBb9d5932c65Cf1bE] = true;
blacklist[0x3e37627dEAA754090fBFbb8bd226c1CE66D255e9] = true;
blacklist[0x08723392Ed15743cc38513C4925f5e6be5c17243] = true;
blacklist[0x7F367cC41522cE07553e823bf3be79A889DEbe1B] = true;
blacklist[0xd882cFc20F52f2599D84b8e8D58C7FB62cfE344b] = true;
blacklist[0x901bb9583b24D97e995513C6778dc6888AB6870e] = true;
blacklist[0xA7e5d5A720f06526557c513402f2e6B5fA20b008] = true;
blacklist[0x8576aCC5C05D6Ce88f4e49bf65BdF0C62F91353C] = true;
blacklist[0x1da5821544e25c636c1417Ba96Ade4Cf6D2f9B5A] = true;
blacklist[0x7Db418b5D567A4e0E8c59Ad71BE1FcE48f3E6107] = true;
blacklist[0x72a5843cc08275C8171E582972Aa4fDa8C397B2A] = true;
blacklist[0x7F19720A857F834887FC9A7bC0a0fBe7Fc7f8102] = true;
blacklist[0x9F4cda013E354b8fC285BF4b9A60460cEe7f7Ea9] = true;
blacklist[0x3CBdeD43EFdAf0FC77b9C55F6fC9988fCC9b757d] = true;
blacklist[0x2f389cE8bD8ff92De3402FFCe4691d17fC4f6535] = true;
blacklist[0x19Aa5Fe80D33a56D56c78e82eA5E50E5d80b4Dff] = true;
blacklist[0xe7aa314c77F4233C18C6CC84384A9247c0cf367B] = true;
blacklist[0x308eD4B7b49797e1A98D3818bFF6fe5385410370] = true;
blacklist[0x67d40EE1A85bf4a4Bb7Ffae16De985e8427B6b45] = true;
blacklist[0x6F1cA141A28907F78Ebaa64fb83A9088b02A8352] = true;
blacklist[0x48549A34AE37b12F6a30566245176994e17C6b4A] = true;
blacklist[0x5512d943eD1f7c8a43F3435C85F7aB68b30121b0] = true;
blacklist[0xC455f7fd3e0e12afd51fba5c106909934D8A0e4a] = true;
blacklist[0x7FF9cFad3877F21d41Da833E2F775dB0569eE3D9] = true;
blacklist[0xc2a3829F459B3Edd87791c74cD45402BA0a20Be3] = true;
blacklist[0x3AD9dB589d201A710Ed237c829c7860Ba86510Fc] = true;
blacklist[0x83E5bC4Ffa856BB84Bb88581f5Dd62A433A25e0D] = true;
blacklist[0x08b2eFdcdB8822EfE5ad0Eae55517cf5DC544251] = true;
blacklist[0x04DBA1194ee10112fE6C3207C0687DEf0e78baCf] = true;
blacklist[0x0Ee5067b06776A89CcC7dC8Ee369984AD7Db5e06] = true;
blacklist[0x502371699497d08D5339c870851898D6D72521Dd] = true;
blacklist[0x5A14E72060c11313E38738009254a90968F58f51] = true;
blacklist[0xEFE301d259F525cA1ba74A7977b80D5b060B3ccA] = true;
blacklist[0xD0975B32cEa532eaDDdFC9c60481976e39dB3472] = true;
blacklist[0x1967D8Af5Bd86A497fb3DD7899A020e47560dAAF] = true;
blacklist[0x39D908dac893CBCB53Cc86e0ECc369aA4DeF1A29] = true;
blacklist[0x4F47Bc496083C727c5fbe3CE9CDf2B0f6496270c] = true;
blacklist[0x97B1043ABD9E6FC31681635166d430a458D14F9C] = true;
blacklist[0xb6f5ec1A0a9cd1526536D3F0426c429529471F40] = true;
blacklist[0xE1D865c3D669dCc8c57c8D023140CB204e672ee4] = true;
blacklist[0x9C2Bc757B66F24D60F016B6237F8CdD414a879Fa] = true;
blacklist[0xdcbEfFBECcE100cCE9E4b153C4e15cB885643193] = true;
blacklist[0x5f48C2A71B2CC96e3F0CCae4E39318Ff0dc375b2] = true;
blacklist[0x5A7a51bFb49F190e5A6060a5bc6052Ac14a3b59f] = true;
blacklist[0xeD6e0A7e4Ac94D976eeBfB82ccf777A3c6baD921] = true;
blacklist[0x797d7Ae72EbddCDea2a346c1834E04d1F8dF102b] = true;
blacklist[0x931546D9e66836AbF687d2bc64B30407bAc8C568] = true;
blacklist[0x43fa21d92141BA9db43052492E0DeEE5aa5f0A93] = true;
blacklist[0x6Be0aE71e6c41f2f9D0D1A3B8d0f75E6f6A0b46e] = true;
blacklist[0x530A64c0Ce595026a4A556b703644228179E2d57] = true;
blacklist[0x983a81ca6FB1e441266D2FbcB7D8E530AC2E05A2] = true;
blacklist[0x961C5Be54a2ffC17CF4Cb021d863c42daCd47Fc1] = true;
blacklist[0xE950DC316b836e4EeFb8308bf32Bf7C72a1358FF] = true;
blacklist[0x21B8d56BDA776bbE68655A16895afd96F5534feD] = true;
blacklist[0xf3701F445b6BDaFeDbcA97D1e477357839e4120D] = true;
blacklist[0x19F8f2B0915Daa12a3f5C9CF01dF9E24D53794F7] = true;
blacklist[0x0931cA4D13BB4ba75D9B7132AB690265D749a5E7] = true;
blacklist[0x1999EF52700c34De7EC2b68a28aAFB37db0C5ade] = true;
blacklist[0xd5ED34b52AC4ab84d8FA8A231a3218bbF01Ed510] = true;
}
//////////////////////////////
// Modifiers
//////////////////////////////
modifier onlyManagerOrAdmin() {
require(
hasRole(MANAGER_ROLE, msg.sender) || hasRole(DEFAULT_ADMIN_ROLE, msg.sender),
"Not manager or admin"
);
_;
}
//////////////////////////////
// External Functions
//////////////////////////////
// User Operations
function deposit(uint256 amount) external nonReentrant whenNotPaused {
_requireNotBlacklisted(msg.sender);
if (whitelistEnabled) {
_requireWhitelisted(msg.sender);
}
require(amount > 0, "Amount must be greater than 0");
backingToken.safeTransferFrom(msg.sender, address(this), amount);
uint256 fee = getFee(amount, true);
if (fee < minimumFee) {
fee = minimumFee;
}
uint256 netAmount = amount - fee;
require(netAmount > 0, "Fee exceeds deposit");
uint256 currentCPI = getProratedCPI();
uint256 adjustedAmount = (netAmount * startingCPI) / currentCPI;
_mint(msg.sender, adjustedAmount);
backingToken.safeTransfer(treasury, fee);
lastDepositLog[msg.sender] = string(
abi.encodePacked(
"timestamp: ",
Strings.toString(block.timestamp),
", proratedCPI: ",
Strings.toString(currentCPI)
)
);
emit Deposit(msg.sender, amount, fee);
}
function withdraw(uint256 amount) external nonReentrant whenNotPaused {
_requireNotBlacklisted(msg.sender);
if (whitelistEnabled) {
_requireWhitelisted(msg.sender);
}
require(amount > 0, "Amount must be greater than 0");
require(balanceOf(msg.sender) >= amount, "Insufficient balance");
_burn(msg.sender, amount);
uint256 currentCPI = getProratedCPI();
uint256 backingAmount = (amount * currentCPI) / startingCPI;
uint256 fee = getFee(backingAmount, false);
if (fee < minimumFee) {
fee = minimumFee;
}
require(backingAmount > fee, "Fee exceeds withdrawal amount");
uint256 netAmount = backingAmount - fee;
backingToken.safeTransfer(msg.sender, netAmount);
backingToken.safeTransfer(treasury, fee);
lastWithdrawLog[msg.sender] = string(
abi.encodePacked(
"timestamp: ",
Strings.toString(block.timestamp),
", proratedCPI: ",
Strings.toString(currentCPI)
)
);
emit Withdrawal(msg.sender, netAmount, fee);
}
// Admin Operations
function adminInjectBacking(uint256 amount) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(amount > 0, "Amount must be > 0");
backingToken.safeTransferFrom(msg.sender, address(this), amount);
emit BackingInjected(msg.sender, amount);
}
function adminWithdrawBacking(address to, uint256 amount) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(to != address(0), "Invalid recipient");
require(amount > 0, "Amount must be > 0");
backingToken.safeTransfer(to, amount);
emit BackingWithdrawn(to, amount);
}
function mint(address to, uint256 amount, string memory reason) external onlyRole(DEFAULT_ADMIN_ROLE) {
_mint(to, amount);
string memory baseReason = bytes(reason).length > 0 ? reason : "manual mint";
emit ManualMint(to, amount, baseReason, block.timestamp);
}
function burn(address from, uint256 amount, string memory reason) external onlyRole(DEFAULT_ADMIN_ROLE) {
_burn(from, amount);
string memory baseReason = bytes(reason).length > 0 ? reason : "manual burn";
emit ManualBurn(from, amount, baseReason, block.timestamp);
}
function addFeeTier(uint256 min, uint256 max, uint256 mintFee, uint256 burnFee)
external
onlyRole(DEFAULT_ADMIN_ROLE)
{
require(mintFee >= 0 && mintFee <= 500, "Mint fee must be between 0 and 500 bps");
require(burnFee >= 0 && burnFee <= 500, "Burn fee must be between 0 and 500 bps");
feeTiers.push(FeeTier(min, max, mintFee, burnFee));
}
function updateFeeTier(uint256 index, uint256 min, uint256 max, uint256 mintFee, uint256 burnFee)
external
onlyRole(DEFAULT_ADMIN_ROLE)
{
require(index < feeTiers.length, "Invalid index");
require(mintFee >= 0 && mintFee <= 500, "Mint fee must be between 0 and 500 bps");
require(burnFee >= 0 && burnFee <= 500, "Burn fee must be between 0 and 500 bps");
feeTiers[index] = FeeTier(min, max, mintFee, burnFee);
}
function removeFeeTier(uint256 index) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(index < feeTiers.length, "Invalid index");
feeTiers[index] = feeTiers[feeTiers.length - 1];
feeTiers.pop();
}
function setMinimumFee(uint256 newMinimumFee) external onlyRole(DEFAULT_ADMIN_ROLE) {
uint256 oldMinimumFee = minimumFee;
minimumFee = newMinimumFee;
emit MinimumFeeChanged(oldMinimumFee, newMinimumFee);
}
function setTreasury(address newTreasury) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(newTreasury != address(0), "Invalid treasury address");
address oldTreasury = treasury;
treasury = newTreasury;
emit TreasuryChanged(oldTreasury, newTreasury);
}
function scheduleWhitelist(address account) external onlyManagerOrAdmin {
require(account != address(0), "Invalid address");
require(whitelistStartTime[account] == 0, "Already in whitelist");
uint256 readyTime = block.timestamp + whitelistChangeDelay;
whitelistStartTime[account] = readyTime;
emit WhitelistRequested(account, readyTime);
}
function removeFromWhitelist(address account) external onlyManagerOrAdmin {
whitelistStartTime[account] = 0;
emit WhitelistRemoved(account);
}
function addToBlacklist(address account) external onlyManagerOrAdmin {
blacklist[account] = true;
emit Blacklisted(account);
}
function removeFromBlacklist(address account) external onlyManagerOrAdmin {
blacklist[account] = false;
emit Unblacklisted(account);
}
function pause() external onlyManagerOrAdmin {
_pause();
}
function unpause() external onlyManagerOrAdmin {
_unpause();
}
function setCPI(uint256 yearMonth, uint256 cpiValue) external {
uint256 existing = monthlyCPI[yearMonth];
if (existing == 0) {
require(
hasRole(MANAGER_ROLE, msg.sender) || hasRole(DEFAULT_ADMIN_ROLE, msg.sender),
"Not authorized to set CPI"
);
} else {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Only admin can overwrite CPI");
}
monthlyCPI[yearMonth] = cpiValue;
emit CPIUpdated(yearMonth, cpiValue);
}
function setMonthlyStartTime(uint256 yearMonth, uint256 startTime) external onlyRole(DEFAULT_ADMIN_ROLE) {
monthlyStartTime[yearMonth] = startTime;
emit MonthlyStartTimeSet(yearMonth, startTime);
}
function enableWhitelist() external onlyRole(DEFAULT_ADMIN_ROLE) {
whitelistEnabled = true;
}
function disableWhitelist() external onlyRole(DEFAULT_ADMIN_ROLE) {
whitelistEnabled = false;
}
//////////////////////////////
// Public Functions
//////////////////////////////
function decimals() public pure override returns (uint8) {
return 6;
}
function getFee(uint256 amount, bool isMint) public view returns (uint256) {
for (uint256 i = 0; i < feeTiers.length; i++) {
if (amount >= feeTiers[i].min && amount <= feeTiers[i].max) {
uint256 bps = isMint ? feeTiers[i].mintFee : feeTiers[i].burnFee;
return (amount * bps) / 10000;
}
}
revert("No matching fee tier found");
}
function getProratedCPI() public view returns (uint256) {
uint256 realNowYM = _getRealCurrentYearMonth();
uint256 cpiCurrentYM = _shiftYearMonth(realNowYM, -2);
uint256 cpiPreviousYM = _shiftYearMonth(realNowYM, -3);
uint256 cpiCurrent = monthlyCPI[cpiCurrentYM];
uint256 cpiPrevious = monthlyCPI[cpiPreviousYM];
require(cpiPrevious > 0 && cpiCurrent > 0, "No CPI data available");
uint256 startOfCurrent = monthlyStartTime[realNowYM];
uint256 startOfNext = monthlyStartTime[_nextYM(realNowYM)];
if (block.timestamp < startOfCurrent) {
return cpiPrevious;
}
if (block.timestamp >= startOfNext) {
return cpiCurrent;
}
uint256 timeElapsed = block.timestamp - startOfCurrent;
uint256 monthLength = startOfNext - startOfCurrent;
uint256 fraction = (timeElapsed * 1e18) / monthLength;
return ((cpiPrevious * (1e18 - fraction)) + (cpiCurrent * fraction)) / 1e18;
}
function isWhitelisted(address account) external view returns (bool) {
uint256 start = whitelistStartTime[account];
if (start == 0) {
return false;
}
return (block.timestamp >= start);
}
function _requireNotBlacklisted(address account) internal view {
require(!blacklist[account], "Blacklisted");
}
//////////////////////////////
// Internal Functions
//////////////////////////////
function _requireWhitelisted(address account) internal view {
require(
whitelistStartTime[account] != 0 && block.timestamp >= whitelistStartTime[account],
"Not whitelisted or delay not passed"
);
}
function _decodeYearMonth(uint256 yearMonth) internal pure returns (uint256 year, uint256 month) {
year = yearMonth / 100;
month = yearMonth % 100;
}
function _nextYM(uint256 yearMonth) internal pure returns (uint256) {
(uint256 y, uint256 m) = _decodeYearMonth(yearMonth);
if (m == 12) {
y += 1;
m = 1;
} else {
m += 1;
}
return y * 100 + m;
}
function _shiftYearMonth(uint256 yearMonth, int256 monthsDelta) internal pure returns (uint256) {
(uint256 year, uint256 month) = _decodeYearMonth(yearMonth);
int256 iYear = int256(year);
int256 iMonth = int256(month);
iMonth += monthsDelta;
while (iMonth > 12) {
iMonth -= 12;
iYear += 1;
}
while (iMonth < 1) {
iMonth += 12;
iYear -= 1;
}
require(iYear >= 1970, "Year out of range");
return uint256(iYear) * 100 + uint256(iMonth);
}
function _getRealCurrentYearMonth() internal view returns (uint256) {
return ((block.timestamp / 31536000) + 1970) * 100 + ((block.timestamp % 31536000) / 2628000) + 1;
}
//////////////////////////////
// Function Overrides
//////////////////////////////
function _transfer(address from, address to, uint256 amount) internal override {
_requireNotBlacklisted(from);
_requireNotBlacklisted(to);
super._transfer(from, to, amount);
}
function _mint(address to, uint256 amount) internal override {
_requireNotBlacklisted(to);
super._mint(to, amount);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(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 `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" 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.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}// 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 (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @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.encodeWithSelector(token.transfer.selector, 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.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 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.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @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.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @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 silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @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] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}{
"optimizer": {
"enabled": true,
"runs": 1000
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_backingToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BackingInjected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BackingWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"Blacklisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"yearMonth","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCPI","type":"uint256"}],"name":"CPIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"string","name":"reason","type":"string"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"ManualBurn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"string","name":"reason","type":"string"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"ManualMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMinimumFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMinimumFee","type":"uint256"}],"name":"MinimumFeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"yearMonth","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"}],"name":"MonthlyStartTimeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","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":"startingCPI","type":"uint256"}],"name":"StartingCPISet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldTreasury","type":"address"},{"indexed":false,"internalType":"address","name":"newTreasury","type":"address"}],"name":"TreasuryChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"Unblacklisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"WhitelistRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"readyTime","type":"uint256"}],"name":"WhitelistRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Withdrawal","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"},{"internalType":"uint256","name":"mintFee","type":"uint256"},{"internalType":"uint256","name":"burnFee","type":"uint256"}],"name":"addFeeTier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addToBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"adminInjectBacking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"adminWithdrawBacking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"backingToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"blacklist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"reason","type":"string"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disableWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"feeTiers","outputs":[{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"},{"internalType":"uint256","name":"mintFee","type":"uint256"},{"internalType":"uint256","name":"burnFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isMint","type":"bool"}],"name":"getFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProratedCPI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastDepositLog","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastWithdrawLog","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"reason","type":"string"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"monthlyCPI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"monthlyStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"removeFeeTier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"removeFromBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"removeFromWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"scheduleWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"yearMonth","type":"uint256"},{"internalType":"uint256","name":"cpiValue","type":"uint256"}],"name":"setCPI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMinimumFee","type":"uint256"}],"name":"setMinimumFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"yearMonth","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"}],"name":"setMonthlyStartTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTreasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startingCPI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"},{"internalType":"uint256","name":"mintFee","type":"uint256"},{"internalType":"uint256","name":"burnFee","type":"uint256"}],"name":"updateFeeTier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"whitelistChangeDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whitelistEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelistStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a0604052620f424060115534801561001757600080fd5b506040516157c03803806157c08339810160408190526100369161173c565b604051806040016040528060098152602001682aa9a2349021b7b4b760b91b815250604051806040016040528060048152602001635553446960e01b8152508160039081610084919061180b565b506004610091828261180b565b50506006805460ff191690555060016007556001600160a01b0381166100fd5760405162461bcd60e51b815260206004820152601d60248201527f496e76616c6964206261636b696e6720746f6b656e2061646472657373000000604482015260640160405180910390fd5b6001600160a01b038116608052601080546001600160a01b031916339081179091556008805460ff1916905561013590600090611699565b61015f7f241ecf16d79d0f8dbfb92cbc07fe17840425976cf0667f022fe9877caa831b0833611699565b336000818152600c6020908152604091829020429081905591519182527f57f2df100d4ab28ca291e2986ed1c62e7c78cb054257ae2a811ce2a31edf91dc910160405180910390a26040516204d0d581527f9192df3095fa00f2699f2d49d4e1c8e395e2e2eb05bc5a30ede5a64131878fd29060200160405180910390a1600960405180608001604052806000815260200164174876e800815260200160328152602001606481525090806001815401808255809150506001900390600052602060002090600402016000909190919091506000820151816000015560208201518160010155604082015181600201556060820151816003015550506009604051806080016040528064174876e801815260200164e8d495cdc0815260200160148152602001603281525090806001815401808255809150506001900390600052602060002090600402016000909190919091506000820151816000015560208201518160010155604082015181600201556060820151816003015550506009604051806080016040528064e8d4a51000815260200165048c272a0dc0815260200160058152602001600a81525090806001815401808255809150506001900390600052602060002090600402016000909190919091506000820151816000015560208201518160010155604082015181600201556060820151816003015550506009604051806080016040528065048c2739500081526020016509184e635dc081526020016000815260200160058152509080600181540180825580915050600190039060005260206000209060040201600090919091909150600082015181600001556020820151816001015560408201518160020155606082015181600301555050600960405180608001604052806509184e72a000815260200165b5e620e53dc0815260200160008152602001600281525090806001815401808255809150506001900390600052602060002090600402016000909190919091506000820151816000015560208201518160010155604082015181600201556060820151816003015550506009604051806080016040528065b5e620f48000815260200166038d7ea4c68000815260200160028152602001600581525090806001815401808255809150506001900390600052602060002090600402016000909190919091506000820151816000015560208201518160010155604082015181600201556060820151816003015550506204d0d5600a6000620316ac8152602001908152602001600020819055506204d8e7600a6000620317058152602001908152602001600020819055506204de6a600a6000620317068152602001908152602001600020819055506204e137600a6000620317078152602001908152602001600020819055506204e51b600a6000620317088152602001908152602001600020819055506204e7b9600a6000620317098152602001908152602001600020819055506204ec01600a60006203170a815260200190815260200160002081905550636774cbd0600b60006203170581526020019081526020016000208190555063679daa50600b6000620317068152602001908152602001600020819055506367c29450600b6000620317078152602001908152602001600020819055506367eb64c0600b600062031708815260200190815260200160002081905550636812f1c0600b60006203170981526020019081526020016000208190555063683bd040600b60006203170a8152602001908152602001600020819055506368635d40600b60006203170b81526020019081526020016000208190555063688c3bc0600b60006203170c8152602001908152602001600020819055506368b51a40600b60006203170d8152602001908152602001600020819055506368dca740600b60006203170e81526020019081526020016000208190555063690585c0600b60006203170f81526020019081526020016000208190555063692d20d0600b600062031710815260200190815260200160002081905550636955ff50600b60006203176981526020019081526020016000208190555063697eddd0600b60006203176a8152602001908152602001600020819055506369a3c7d0600b60006203176b8152602001908152602001600020819055506369cc9840600b60006203176c8152602001908152602001600020819055506369f42540600b60006203176d815260200190815260200160002081905550636a1d03c0600b60006203176e815260200190815260200160002081905550636a4490c0600b60006203176f815260200190815260200160002081905550636a6d6f40600b600062031770815260200190815260200160002081905550636a964dc0600b600062031771815260200190815260200160002081905550636abddac0600b600062031772815260200190815260200160002081905550636ae6b940600b600062031773815260200190815260200160002081905550636b0e5450600b6000620317748152602001908152602001600020819055506001600f600073098b716b8aaf21512996dc57eb0615e2383e2f966001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f600073a0e1c89ef1a489c9c7de96311ed5ce5d32c20e4b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f6000733cffd56b47b7b41c56258d9c7731abadc360e0736001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f60007353b6936513e738f44fb50d2b9476730c0ab3bfc16001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f60007335fb6f6db4fb05e6a4ce86f2c93691425626d4b16001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f600073f7b31119c2682c88d88d455dbb9d5932c65cf1be6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f6000733e37627deaa754090fbfbb8bd226c1ce66d255e96001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f60007308723392ed15743cc38513c4925f5e6be5c172436001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f6000737f367cc41522ce07553e823bf3be79a889debe1b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f600073d882cfc20f52f2599d84b8e8d58c7fb62cfe344b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f600073901bb9583b24d97e995513c6778dc6888ab6870e6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f600073a7e5d5a720f06526557c513402f2e6b5fa20b0086001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f6000738576acc5c05d6ce88f4e49bf65bdf0c62f91353c6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f6000731da5821544e25c636c1417ba96ade4cf6d2f9b5a6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f6000737db418b5d567a4e0e8c59ad71be1fce48f3e61076001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f60007372a5843cc08275c8171e582972aa4fda8c397b2a6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f6000737f19720a857f834887fc9a7bc0a0fbe7fc7f81026001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f6000739f4cda013e354b8fc285bf4b9a60460cee7f7ea96001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f6000733cbded43efdaf0fc77b9c55f6fc9988fcc9b757d6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f6000732f389ce8bd8ff92de3402ffce4691d17fc4f65356001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f60007319aa5fe80d33a56d56c78e82ea5e50e5d80b4dff6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600f600073e7aa314c77f4233c18c6cc84384a9247c0cf367b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff02191690831515021790555050600f6020527f14f79acbc1bb2db875743dfa2902950cd7a44f89ba39df170a78cfcc2005a6788054600160ff1991821681179092557f7acd55498adbe343943e711c1145ceba36152c99ec94454a87383bc9b0596f7b80548216831790557f8040c9993604573ba093ca221ce90a5b1d5b194e3de6fc2b313ca45b418644f180548216831790557ffa1818299b69ae7eeea4983bb62755f818bc010cc62bc248d3baa699f3b3b3cc80548216831790557fd606cae5ee5c5f36b335a0f22cb34b6c5f6fca8768b3b5f441f296cd67cbce3f80548216831790557f7ea5ebecfea0fdbaa4689547a55be9191c4c8d65a39d8eb464b696db9c14618f80548216831790557f9aac84b290380fbba4651aa24ab45c3d7067790e33e245e6d18ffc00ddd5410880548216831790557f66c138c8f2936f61aec9d55ead3c4cf27a396dd5e86e1bbc6a123053012207d280548216831790557f6587e6d811ff2df739378c045422ef65fb37fd06f1ebf9c4d93423d03b8cb9a080548216831790557ff7ed560b1806df6336145df81bbe30940f25eac58f01c767fc5040b5b328087180548216831790557f8c4c871b76e7c88671dc28da90035553830f43b7ceb41a2c98a3444462418be180548216831790557fd875b4fdefc3d830b9c77c3db29ad4fc402fa8e0a8aa00f99d8eb23f8967607480548216831790557f8749a86a2799293f3f6dd075a4e76ae30c6dafb06578cbc14ea1d173e16d3ce180548216831790557f8146bf452105e97218fd998314378866bc8aacc53eaad8752020ac020cc5679980548216831790557f6b561c8c760434b4ce07f5d94a7f09db5cc6dd55947267ab360ae7dbeef7b16580548216831790557f80a62142cd40c80c4c595419250b867f0b8b36cece1afa933f83f7eb7cbdd0cd80548216831790557f98f340153e4afaaaee4fd769d1e393ab72d1df1adc84fcfd0268def05ff6dedb80548216831790557f3a7c9d6fcf2878e06366b72fadc12ce6e3458b1e6f5f026c3a0a5249ff40b4ce80548216831790557f2ab80fcfbaf2819c4c8bde0cacf9136e5a266d433bc633cf586ebed7b722e71c80548216831790557fff784c1147a077caac0c0f5a3604d746b0bab5f87683b8f94bf52e1af22a2fcc80548216831790557f8a9d1fbaf880a3b12183de1d9b1aa7f096378bcc387852ca0fd277249c169c8e80548216831790557f147c79e23f980744a21fcf74e1b41442fc83ef44fdd61bcb3e7806e1a8d0fcb880548216831790557fa092cdc067eaa44ee86ffe4d9f73714a238cd14226a5b900deeae67da7796a6c80548216831790557f0a0f6c18681833ead6b4a73a43fabf2f4167222d4010d04c4a37b1f8ad6d2a1680548216831790557f42b8dad6deb8a1311585414ee4ea939f11b9f99e92a503652e76b55bbb051a2480548216831790557f5cc5ec7d382557d461ac5b38554e4c8ce14730dc2c59c2a4291a152956d6144380548216831790557fc9e49e1278742e7129d0875665b7798e4ce32872d2c95f60cbbade5ed00d53b780548216831790557f8c624fe8cf07ead7c77fa568d640912796129e025a57d68b8aa113a8f2f4d0e580548216831790557f6912f20f13f092d6ec8b3af9ba2d3c60ad614b4c9c9a9cd915f0e7134f64a17480548216831790557f81b12ce90ef666cd4ba645b7d382293eed93b57e061509c00552d39c929d64b180548216831790557feb2bc5e323ebf6a1ad9396f45e0f0a70fce5f7a3a1b4c1c72385d69470d2046880548216831790557f8bbbfd0341ada21121b0d3fcc2d2c45abbb921356e0feb3974c295b0e458347680548216831790557fb2b0880ab386a169996581f60e8f422b4fa64255facf4150936e0591e238b0b080548216831790557f3086567fcf682b2cdf7eefcdf8a70d0839f1a67461f5326df9e79f533adaa5a080548216831790557fb7c7caf3fd5abec8f01a09d020ee95fba6fb27cc3afa6bd3b64f640de7832c1980548216831790557f652c6c79eba514fe2ba1ce4a88f7ad2a394c32ed2faff569d65ec7c4a16a63fd80548216831790557f06298a47942fcb5e4b6c081b87bfc1af34d9db1e1ae24a32ac394a2c7ff06a0a80548216831790557f714cc0129558841eee3afc7539158707a5e5d9f76b51f9005944b1545122db6d80548216831790557fae28506018e2979257e1352450caf41300c607217ea0f847d89544c8445fa2ad80548216831790557f608c7e371b82289e57c88e41a7e050083306d723b9b68945ffc9b82c62fff8aa80548216831790557f7f8e13eea75819115e698db9b8b87773b842e2767a5b26a9c044cc65ceb4287c805482168317905573d5ed34b52ac4ab84d8fa8a231a3218bbf01ed5106000527f78a00bf48e8aa2d3639f0a76a607cc0be15bccb7f1ccadc1ed8f3e8ae3338a8d805490911690911790556118c9565b60008281526005602090815260408083206001600160a01b038516845290915290205460ff166117385760008281526005602090815260408083206001600160a01b03851684529091529020805460ff191660011790556116f73390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b60006020828403121561174e57600080fd5b81516001600160a01b038116811461176557600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061179657607f821691505b6020821081036117b657634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561180657806000526020600020601f840160051c810160208510156117e35750805b601f840160051c820191505b8181101561180357600081556001016117ef565b50505b505050565b81516001600160401b038111156118245761182461176c565b611838816118328454611782565b846117bc565b6020601f82116001811461186c57600083156118545750848201515b600019600385901b1c1916600184901b178455611803565b600084815260208120601f198516915b8281101561189c578785015182556020948501946001909201910161187c565b50848210156118ba5786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b608051613eb261190e6000396000818161058f01528181610a4201528181610f3e01528181610f7601528181611d2701528181611e0e015261221a0152613eb26000f3fe608060405234801561001057600080fd5b50600436106103835760003560e01c806361d027b3116101de578063b6b55f251161010f578063d547741f116100ad578063ec87621c1161007c578063ec87621c14610807578063edddee1a1461082e578063f0f4426014610836578063f9f92be41461084957600080fd5b8063d547741f146107a0578063d6b0f484146107b3578063dd62ed3e146107bb578063e333f146146107f457600080fd5b8063cdfb2b4e116100e9578063cdfb2b4e14610769578063d0262ceb14610771578063d3fc986414610784578063d495ee281461079757600080fd5b8063b6b55f2514610730578063c5461d2114610743578063c64318e81461075657600080fd5b806391d148541161017c5780639c9795b2116101565780639c9795b2146106ef578063a217fddf14610702578063a457c2d71461070a578063a9059cbb1461071d57600080fd5b806391d14854146106a457806394b14f3c146106dd57806395d89b41146106e757600080fd5b806384215a46116101b857806384215a46146106635780638456cb59146106765780638aaf37651461067e5780638ab1d6811461069157600080fd5b806361d027b3146106075780636245af4a1461061a57806370a082311461063a57600080fd5b80632e1a7d4d116102b857806342b53e5f1161025657806351fb012d1161023057806351fb012d146105c9578063537df3b6146105d657806354a30576146105e95780635c975abb146105fc57600080fd5b806342b53e5f1461056457806344337ea11461057757806347e621b71461058a57600080fd5b806336568abe1161029257806336568abe1461052357806339509351146105365780633af32abf146105495780633f4ba83a1461055c57600080fd5b80632e1a7d4d146104ee5780632f2ff15d14610501578063313ce5671461051457600080fd5b806316b54c26116103255780631a7626e7116102ff5780631a7626e71461047c578063230ed44a1461048557806323b872dd146104b8578063248a9ca3146104cb57600080fd5b806316b54c261461044e57806318160ddd14610461578063182a75061461046957600080fd5b80630a4c0ca3116103615780630a4c0ca3146103d85780630d4b40fb1461040657806312f30c751461042657806315f570dc1461043b57600080fd5b806301ffc9a71461038857806306fdde03146103b0578063095ea7b3146103c5575b600080fd5b61039b61039636600461375e565b61086c565b60405190151581526020015b60405180910390f35b6103b86108d5565b6040516103a791906137d8565b61039b6103d3366004613807565b610967565b6103f86103e6366004613831565b600c6020526000908152604090205481565b6040519081526020016103a7565b6103f861041436600461384c565b600b6020526000908152604090205481565b610439610434366004613807565b61097f565b005b61043961044936600461387b565b610ab1565b61043961045c36600461394e565b610b5b565b6002546103f8565b61043961047736600461384c565b610cf8565b6103f860115481565b61049861049336600461384c565b610d4a565b6040805194855260208501939093529183015260608201526080016103a7565b61039b6104c6366004613980565b610d84565b6103f86104d936600461384c565b60009081526005602052604090206001015490565b6104396104fc36600461384c565b610da8565b61043961050f3660046139bd565b611037565b604051600681526020016103a7565b6104396105313660046139bd565b611061565b61039b610544366004613807565b6110ed565b61039b610557366004613831565b61112c565b61043961115e565b61043961057236600461384c565b611216565b610439610585366004613831565b611316565b6105b17f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016103a7565b60085461039b9060ff1681565b6104396105e4366004613831565b611410565b6104396105f7366004613831565b611507565b60065460ff1661039b565b6010546105b1906001600160a01b031681565b6103f861062836600461384c565b600a6020526000908152604090205481565b6103f8610648366004613831565b6001600160a01b031660009081526020819052604090205490565b6103b8610671366004613831565b6116dc565b610439611776565b61043961068c3660046139e9565b61182c565b61043961069f366004613831565b6119af565b61039b6106b23660046139bd565b60009182526005602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6103f86204d0d581565b6103b8611aa1565b6103f86106fd366004613a32565b611ab0565b6103f8600081565b61039b610718366004613807565b611be5565b61039b61072b366004613807565b611c8f565b61043961073e36600461384c565b611c9d565b610439610751366004613a62565b611eba565b6103b8610764366004613831565b612053565b61043961206c565b61043961077f366004613a62565b612087565b61043961079236600461387b565b6120da565b6103f861a8c081565b6104396107ae3660046139bd565b612175565b61043961219a565b6103f86107c9366004613a84565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b61043961080236600461384c565b6121b2565b6103f87f241ecf16d79d0f8dbfb92cbc07fe17840425976cf0667f022fe9877caa831b0881565b6103f8612274565b610439610844366004613831565b6123f8565b61039b610857366004613831565b600f6020526000908152604090205460ff1681565b60006001600160e01b031982167f7965db0b0000000000000000000000000000000000000000000000000000000014806108cf57507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b92915050565b6060600380546108e490613aae565b80601f016020809104026020016040519081016040528092919081815260200182805461091090613aae565b801561095d5780601f106109325761010080835404028352916020019161095d565b820191906000526020600020905b81548152906001019060200180831161094057829003601f168201915b5050505050905090565b6000336109758185856124cb565b5060019392505050565b600061098a81612623565b6001600160a01b0383166109e55760405162461bcd60e51b815260206004820152601160248201527f496e76616c696420726563697069656e7400000000000000000000000000000060448201526064015b60405180910390fd5b60008211610a355760405162461bcd60e51b815260206004820152601260248201527f416d6f756e74206d757374206265203e2030000000000000000000000000000060448201526064016109dc565b610a696001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016848461262d565b826001600160a01b03167f02d97641906fb7b62434b440b5998869ebf88faae661ffa33f3179b64a1ae71b83604051610aa491815260200190565b60405180910390a2505050565b6000610abc81612623565b610ac684846126be565b600080835111610b0b576040518060400160405280600b81526020017f6d616e75616c206275726e000000000000000000000000000000000000000000815250610b0d565b825b9050846001600160a01b03167f153e4c4bf18e12e4ee1b475b3e2717cf9db66291bc2184246821fe033027febb858342604051610b4c93929190613ae8565b60405180910390a25050505050565b6000610b6681612623565b6101f4831115610bc75760405162461bcd60e51b815260206004820152602660248201527f4d696e7420666565206d757374206265206265747765656e203020616e64203560448201526530302062707360d01b60648201526084016109dc565b6101f4821115610c285760405162461bcd60e51b815260206004820152602660248201527f4275726e20666565206d757374206265206265747765656e203020616e64203560448201526530302062707360d01b60648201526084016109dc565b5060408051608081018252948552602085019384528401918252606084019081526009805460018101825560009190915293517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af60049095029485015591517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b0840155517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b1830155517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b290910155565b6000610d0381612623565b601180549083905560408051828152602081018590527f42af500532a73708ee46cb952e653f5a82c5aede53857b7bfc1ec76d46bc1a5291015b60405180910390a1505050565b60098181548110610d5a57600080fd5b60009182526020909120600490910201805460018201546002830154600390930154919350919084565b600033610d92858285612827565b610d9d8585856128b9565b506001949350505050565b610db06128d6565b610db861292f565b610dc133612982565b60085460ff1615610dd557610dd5336129eb565b60008111610e255760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e203000000060448201526064016109dc565b33600090815260208190526040902054811115610e845760405162461bcd60e51b815260206004820152601460248201527f496e73756666696369656e742062616c616e636500000000000000000000000060448201526064016109dc565b610e8e33826126be565b6000610e98612274565b905060006204d0d5610eaa8385613b27565b610eb49190613b54565b90506000610ec3826000611ab0565b9050601154811015610ed457506011545b808211610f235760405162461bcd60e51b815260206004820152601d60248201527f4665652065786365656473207769746864726177616c20616d6f756e7400000060448201526064016109dc565b6000610f2f8284613b68565b9050610f656001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016338361262d565b601054610f9f906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811691168461262d565b610fa842612a9c565b610fb185612a9c565b604051602001610fc2929190613b7b565b60408051601f19818403018152918152336000908152600d6020522090610fe99082613c4a565b50604080518281526020810184905233917fdf273cb619d95419a9cd0ec88123a0538c85064229baa6363788f743fff90deb91015b60405180910390a2505050506110346001600755565b50565b60008281526005602052604090206001015461105281612623565b61105c8383612b3c565b505050565b6001600160a01b03811633146110df5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084016109dc565b6110e98282612bde565b5050565b3360008181526001602090815260408083206001600160a01b03871684529091528120549091906109759082908690611127908790613d09565b6124cb565b6001600160a01b0381166000908152600c60205260408120548082036111555750600092915050565b42101592915050565b3360009081527fe3a5955c11d878176a306e8c308ba1ceef9cfa46a3768e3b22365ec256a01e1f602052604090205460ff16806111c957503360009081527f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc602052604090205460ff165b61120c5760405162461bcd60e51b81526020600482015260146024820152732737ba1036b0b730b3b2b91037b91030b236b4b760611b60448201526064016109dc565b611214612c61565b565b600061122181612623565b60095482106112625760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b60448201526064016109dc565b6009805461127290600190613b68565b8154811061128257611282613d1c565b9060005260206000209060040201600983815481106112a3576112a3613d1c565b600091825260209091208254600490920201908155600180830154908201556002808301549082015560039182015491015560098054806112e6576112e6613d32565b60008281526020812060046000199093019283020181815560018101829055600281018290556003015590555050565b3360009081527fe3a5955c11d878176a306e8c308ba1ceef9cfa46a3768e3b22365ec256a01e1f602052604090205460ff168061138157503360009081527f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc602052604090205460ff165b6113c45760405162461bcd60e51b81526020600482015260146024820152732737ba1036b0b730b3b2b91037b91030b236b4b760611b60448201526064016109dc565b6001600160a01b0381166000818152600f6020526040808220805460ff19166001179055517fffa4e6181777692565cf28528fc88fd1516ea86b56da075235fa575af6a4b8559190a250565b3360009081527fe3a5955c11d878176a306e8c308ba1ceef9cfa46a3768e3b22365ec256a01e1f602052604090205460ff168061147b57503360009081527f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc602052604090205460ff165b6114be5760405162461bcd60e51b81526020600482015260146024820152732737ba1036b0b730b3b2b91037b91030b236b4b760611b60448201526064016109dc565b6001600160a01b0381166000818152600f6020526040808220805460ff19169055517f7534c63860313c46c473e4e98328f37017e9674e2162faf1a3ad7a96236c3b7b9190a250565b3360009081527fe3a5955c11d878176a306e8c308ba1ceef9cfa46a3768e3b22365ec256a01e1f602052604090205460ff168061157257503360009081527f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc602052604090205460ff165b6115b55760405162461bcd60e51b81526020600482015260146024820152732737ba1036b0b730b3b2b91037b91030b236b4b760611b60448201526064016109dc565b6001600160a01b03811661160b5760405162461bcd60e51b815260206004820152600f60248201527f496e76616c69642061646472657373000000000000000000000000000000000060448201526064016109dc565b6001600160a01b0381166000908152600c6020526040902054156116715760405162461bcd60e51b815260206004820152601460248201527f416c726561647920696e2077686974656c69737400000000000000000000000060448201526064016109dc565b600061167f61a8c042613d09565b6001600160a01b0383166000818152600c60205260409081902083905551919250907f57f2df100d4ab28ca291e2986ed1c62e7c78cb054257ae2a811ce2a31edf91dc906116d09084815260200190565b60405180910390a25050565b600e60205260009081526040902080546116f590613aae565b80601f016020809104026020016040519081016040528092919081815260200182805461172190613aae565b801561176e5780601f106117435761010080835404028352916020019161176e565b820191906000526020600020905b81548152906001019060200180831161175157829003601f168201915b505050505081565b3360009081527fe3a5955c11d878176a306e8c308ba1ceef9cfa46a3768e3b22365ec256a01e1f602052604090205460ff16806117e157503360009081527f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc602052604090205460ff165b6118245760405162461bcd60e51b81526020600482015260146024820152732737ba1036b0b730b3b2b91037b91030b236b4b760611b60448201526064016109dc565b611214612cb3565b600061183781612623565b60095486106118785760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b60448201526064016109dc565b6101f48311156118d95760405162461bcd60e51b815260206004820152602660248201527f4d696e7420666565206d757374206265206265747765656e203020616e64203560448201526530302062707360d01b60648201526084016109dc565b6101f482111561193a5760405162461bcd60e51b815260206004820152602660248201527f4275726e20666565206d757374206265206265747765656e203020616e64203560448201526530302062707360d01b60648201526084016109dc565b6040518060800160405280868152602001858152602001848152602001838152506009878154811061196e5761196e613d1c565b906000526020600020906004020160008201518160000155602082015181600101556040820151816002015560608201518160030155905050505050505050565b3360009081527fe3a5955c11d878176a306e8c308ba1ceef9cfa46a3768e3b22365ec256a01e1f602052604090205460ff1680611a1a57503360009081527f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc602052604090205460ff165b611a5d5760405162461bcd60e51b81526020600482015260146024820152732737ba1036b0b730b3b2b91037b91030b236b4b760611b60448201526064016109dc565b6001600160a01b0381166000818152600c6020526040808220829055517fde8cf212af7ce38b2840785a2768d97ff2dbf3c21b516961cec0061e134c2a1e9190a250565b6060600480546108e490613aae565b6000805b600954811015611b9c5760098181548110611ad157611ad1613d1c565b9060005260206000209060040201600001548410158015611b16575060098181548110611b0057611b00613d1c565b9060005260206000209060040201600101548411155b15611b9457600083611b4c5760098281548110611b3557611b35613d1c565b906000526020600020906004020160030154611b72565b60098281548110611b5f57611b5f613d1c565b9060005260206000209060040201600201545b9050612710611b818287613b27565b611b8b9190613b54565b925050506108cf565b600101611ab4565b5060405162461bcd60e51b815260206004820152601a60248201527f4e6f206d61746368696e6720666565207469657220666f756e6400000000000060448201526064016109dc565b3360008181526001602090815260408083206001600160a01b038716845290915281205490919083811015611c825760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f00000000000000000000000000000000000000000000000000000060648201526084016109dc565b610d9d82868684036124cb565b6000336109758185856128b9565b611ca56128d6565b611cad61292f565b611cb633612982565b60085460ff1615611cca57611cca336129eb565b60008111611d1a5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e203000000060448201526064016109dc565b611d4f6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333084612cf0565b6000611d5c826001611ab0565b9050601154811015611d6d57506011545b6000611d798284613b68565b905060008111611dcb5760405162461bcd60e51b815260206004820152601360248201527f4665652065786365656473206465706f7369740000000000000000000000000060448201526064016109dc565b6000611dd5612274565b9050600081611de76204d0d585613b27565b611df19190613b54565b9050611dfd3382612d41565b601054611e37906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811691168661262d565b611e4042612a9c565b611e4983612a9c565b604051602001611e5a929190613b7b565b60408051601f19818403018152918152336000908152600e6020522090611e819082613c4a565b50604080518681526020810186905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910161101e565b6000828152600a602052604081205490819003611f8d573360009081527fe3a5955c11d878176a306e8c308ba1ceef9cfa46a3768e3b22365ec256a01e1f602052604090205460ff1680611f3c57503360009081527f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc602052604090205460ff165b611f885760405162461bcd60e51b815260206004820152601960248201527f4e6f7420617574686f72697a656420746f20736574204350490000000000000060448201526064016109dc565b61200b565b3360009081527f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc602052604090205460ff1661200b5760405162461bcd60e51b815260206004820152601c60248201527f4f6e6c792061646d696e2063616e206f7665727772697465204350490000000060448201526064016109dc565b6000838152600a602090815260409182902084905581518581529081018490527ffaae7e9ebff587ddfd1fc7584c25926410fd174a75c5781a0ce1dfe041c0edab9101610d3d565b600d60205260009081526040902080546116f590613aae565b600061207781612623565b506008805460ff19166001179055565b600061209281612623565b6000838152600b602090815260409182902084905581518581529081018490527ff06db0d97fa92002986c2d675db085bd5dd088d2045b49eefdda0454c2ffb9559101610d3d565b60006120e581612623565b6120ef8484612d41565b600080835111612134576040518060400160405280600b81526020017f6d616e75616c206d696e74000000000000000000000000000000000000000000815250612136565b825b9050846001600160a01b03167f20a4aaa30fc904e456b39c9976be3f84769d03af262eb7798744011de9dca7c4858342604051610b4c93929190613ae8565b60008281526005602052604090206001015461219081612623565b61105c8383612bde565b60006121a581612623565b506008805460ff19169055565b60006121bd81612623565b6000821161220d5760405162461bcd60e51b815260206004820152601260248201527f416d6f756e74206d757374206265203e2030000000000000000000000000000060448201526064016109dc565b6122426001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333085612cf0565b60405182815233907f24d9b234ebe2cc8e9888bf66c5e584fb213f0f62863e36f821c16ed40b5cb6d0906020016116d0565b60008061227f612d54565b9050600061228f82600119612db1565b9050600061229f83600219612db1565b6000838152600a6020526040808220548383529120549192509080158015906122c85750600082115b6123145760405162461bcd60e51b815260206004820152601560248201527f4e6f20435049206461746120617661696c61626c65000000000000000000000060448201526064016109dc565b6000858152600b6020819052604082205491908161233189612e96565b8152602001908152602001600020549050814210156123565750909695505050505050565b8042106123695750919695505050505050565b60006123758342613b68565b905060006123838484613b68565b905060008161239a84670de0b6b3a7640000613b27565b6123a49190613b54565b9050670de0b6b3a76400006123b98289613b27565b6123cb83670de0b6b3a7640000613b68565b6123d59089613b27565b6123df9190613d09565b6123e99190613b54565b9a505050505050505050505090565b600061240381612623565b6001600160a01b0382166124595760405162461bcd60e51b815260206004820152601860248201527f496e76616c69642074726561737572792061646472657373000000000000000060448201526064016109dc565b601080546001600160a01b038481167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f8c3aa5f43a388513435861bf27dfad7829cd248696fed367c62d441f629544969101610d3d565b6001600160a01b0383166125465760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f726573730000000000000000000000000000000000000000000000000000000060648201526084016109dc565b6001600160a01b0382166125c25760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f737300000000000000000000000000000000000000000000000000000000000060648201526084016109dc565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6110348133612ef2565b6040516001600160a01b03831660248201526044810182905261105c9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152612f67565b6001600160a01b03821661273a5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f730000000000000000000000000000000000000000000000000000000000000060648201526084016109dc565b6001600160a01b038216600090815260208190526040902054818110156127c95760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f636500000000000000000000000000000000000000000000000000000000000060648201526084016109dc565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6001600160a01b0383811660009081526001602090815260408083209386168352929052205460001981146128b357818110156128a65760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109dc565b6128b384848484036124cb565b50505050565b6128c283612982565b6128cb82612982565b61105c83838361304f565b6002600754036129285760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016109dc565b6002600755565b60065460ff16156112145760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016109dc565b6001600160a01b0381166000908152600f602052604090205460ff16156110345760405162461bcd60e51b815260206004820152600b60248201527f426c61636b6c697374656400000000000000000000000000000000000000000060448201526064016109dc565b6001600160a01b0381166000908152600c602052604090205415801590612a2a57506001600160a01b0381166000908152600c60205260409020544210155b6110345760405162461bcd60e51b815260206004820152602360248201527f4e6f742077686974656c6973746564206f722064656c6179206e6f742070617360448201527f736564000000000000000000000000000000000000000000000000000000000060648201526084016109dc565b60606000612aa98361323c565b600101905060008167ffffffffffffffff811115612ac957612ac9613865565b6040519080825280601f01601f191660200182016040528015612af3576020820181803683370190505b5090508181016020015b600019017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8504945084612afd57509392505050565b60008281526005602090815260408083206001600160a01b038516845290915290205460ff166110e95760008281526005602090815260408083206001600160a01b03851684529091529020805460ff19166001179055612b9a3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526005602090815260408083206001600160a01b038516845290915290205460ff16156110e95760008281526005602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b612c6961331e565b6006805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b612cbb61292f565b6006805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612c963390565b6040516001600160a01b03808516602483015283166044820152606481018290526128b39085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401612672565b612d4a82612982565b6110e98282613370565b6000622819a0612d686301e1338042613d48565b612d729190613b54565b612d806301e1338042613b54565b612d8c906107b2613d09565b612d97906064613b27565b612da19190613d09565b612dac906001613d09565b905090565b6000806000612dbf8561342f565b90925090508181612dd08682613d5c565b90505b600c811315612dfb57612de7600c82613d84565b9050612df4600183613d5c565b9150612dd3565b6001811215612e2357612e0f600c82613d5c565b9050612e1c600183613d84565b9150612dfb565b6107b2821215612e755760405162461bcd60e51b815260206004820152601160248201527f59656172206f7574206f662072616e676500000000000000000000000000000060448201526064016109dc565b80612e81836064613b27565b612e8b9190613d09565b979650505050505050565b6000806000612ea48461342f565b9150915080600c03612ec657612ebb600183613d09565b915060019050612ed4565b612ed1600182613d09565b90505b80612ee0836064613b27565b612eea9190613d09565b949350505050565b60008281526005602090815260408083206001600160a01b038516845290915290205460ff166110e957612f2581613451565b612f30836020613463565b604051602001612f41929190613dab565b60408051601f198184030181529082905262461bcd60e51b82526109dc916004016137d8565b6000612fbc826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661364b9092919063ffffffff16565b9050805160001480612fdd575080806020019051810190612fdd9190613e2c565b61105c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016109dc565b6001600160a01b0383166130cb5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f647265737300000000000000000000000000000000000000000000000000000060648201526084016109dc565b6001600160a01b0382166131475760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f657373000000000000000000000000000000000000000000000000000000000060648201526084016109dc565b6001600160a01b038316600090815260208190526040902054818110156131d65760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e6365000000000000000000000000000000000000000000000000000060648201526084016109dc565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36128b3565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310613285577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef810000000083106132b1576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106132cf57662386f26fc10000830492506010015b6305f5e10083106132e7576305f5e100830492506008015b61271083106132fb57612710830492506004015b6064831061330d576064830492506002015b600a83106108cf5760010192915050565b60065460ff166112145760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016109dc565b6001600160a01b0382166133c65760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109dc565b80600260008282546133d89190613d09565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b60008061343d606484613b54565b915061344a606484613d48565b9050915091565b60606108cf6001600160a01b03831660145b60606000613472836002613b27565b61347d906002613d09565b67ffffffffffffffff81111561349557613495613865565b6040519080825280601f01601f1916602001820160405280156134bf576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000816000815181106134f6576134f6613d1c565b60200101906001600160f81b031916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061354157613541613d1c565b60200101906001600160f81b031916908160001a9053506000613565846002613b27565b613570906001613d09565b90505b60018111156135f5577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106135b1576135b1613d1c565b1a60f81b8282815181106135c7576135c7613d1c565b60200101906001600160f81b031916908160001a90535060049490941c936135ee81613e49565b9050613573565b5083156136445760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016109dc565b9392505050565b6060612eea848460008585600080866001600160a01b031685876040516136729190613e60565b60006040518083038185875af1925050503d80600081146136af576040519150601f19603f3d011682016040523d82523d6000602084013e6136b4565b606091505b5091509150612e8b878383876060831561372f578251600003613728576001600160a01b0385163b6137285760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109dc565b5081612eea565b612eea83838151156137445781518083602001fd5b8060405162461bcd60e51b81526004016109dc91906137d8565b60006020828403121561377057600080fd5b81356001600160e01b03198116811461364457600080fd5b60005b838110156137a357818101518382015260200161378b565b50506000910152565b600081518084526137c4816020860160208601613788565b601f01601f19169290920160200192915050565b60208152600061364460208301846137ac565b80356001600160a01b038116811461380257600080fd5b919050565b6000806040838503121561381a57600080fd5b613823836137eb565b946020939093013593505050565b60006020828403121561384357600080fd5b613644826137eb565b60006020828403121561385e57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561389057600080fd5b613899846137eb565b925060208401359150604084013567ffffffffffffffff8111156138bc57600080fd5b8401601f810186136138cd57600080fd5b803567ffffffffffffffff8111156138e7576138e7613865565b604051601f8201601f19908116603f0116810167ffffffffffffffff8111828210171561391657613916613865565b60405281815282820160200188101561392e57600080fd5b816020840160208301376000602083830101528093505050509250925092565b6000806000806080858703121561396457600080fd5b5050823594602084013594506040840135936060013592509050565b60008060006060848603121561399557600080fd5b61399e846137eb565b92506139ac602085016137eb565b929592945050506040919091013590565b600080604083850312156139d057600080fd5b823591506139e0602084016137eb565b90509250929050565b600080600080600060a08688031215613a0157600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b801515811461103457600080fd5b60008060408385031215613a4557600080fd5b823591506020830135613a5781613a24565b809150509250929050565b60008060408385031215613a7557600080fd5b50508035926020909101359150565b60008060408385031215613a9757600080fd5b613aa0836137eb565b91506139e0602084016137eb565b600181811c90821680613ac257607f821691505b602082108103613ae257634e487b7160e01b600052602260045260246000fd5b50919050565b838152606060208201526000613b0160608301856137ac565b9050826040830152949350505050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176108cf576108cf613b11565b634e487b7160e01b600052601260045260246000fd5b600082613b6357613b63613b3e565b500490565b818103818111156108cf576108cf613b11565b7f74696d657374616d703a20000000000000000000000000000000000000000000815260008351613bb381600b850160208801613788565b7f2c2070726f72617465644350493a200000000000000000000000000000000000600b918401918201528351613bf081601a840160208801613788565b01601a01949350505050565b601f82111561105c57806000526020600020601f840160051c81016020851015613c235750805b601f840160051c820191505b81811015613c435760008155600101613c2f565b5050505050565b815167ffffffffffffffff811115613c6457613c64613865565b613c7881613c728454613aae565b84613bfc565b6020601f821160018114613cac5760008315613c945750848201515b600019600385901b1c1916600184901b178455613c43565b600084815260208120601f198516915b82811015613cdc5787850151825560209485019460019092019101613cbc565b5084821015613cfa5786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b808201808211156108cf576108cf613b11565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b600082613d5757613d57613b3e565b500690565b8082018281126000831280158216821582161715613d7c57613d7c613b11565b505092915050565b8181036000831280158383131683831282161715613da457613da4613b11565b5092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351613de3816017850160208801613788565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351613e20816028840160208801613788565b01602801949350505050565b600060208284031215613e3e57600080fd5b815161364481613a24565b600081613e5857613e58613b11565b506000190190565b60008251613e72818460208701613788565b919091019291505056fea2646970667358221220d4075305891c56f037778efe2bc84f4f08ba11fa62c4d9b648c313f93254bf7664736f6c634300081c0033000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103835760003560e01c806361d027b3116101de578063b6b55f251161010f578063d547741f116100ad578063ec87621c1161007c578063ec87621c14610807578063edddee1a1461082e578063f0f4426014610836578063f9f92be41461084957600080fd5b8063d547741f146107a0578063d6b0f484146107b3578063dd62ed3e146107bb578063e333f146146107f457600080fd5b8063cdfb2b4e116100e9578063cdfb2b4e14610769578063d0262ceb14610771578063d3fc986414610784578063d495ee281461079757600080fd5b8063b6b55f2514610730578063c5461d2114610743578063c64318e81461075657600080fd5b806391d148541161017c5780639c9795b2116101565780639c9795b2146106ef578063a217fddf14610702578063a457c2d71461070a578063a9059cbb1461071d57600080fd5b806391d14854146106a457806394b14f3c146106dd57806395d89b41146106e757600080fd5b806384215a46116101b857806384215a46146106635780638456cb59146106765780638aaf37651461067e5780638ab1d6811461069157600080fd5b806361d027b3146106075780636245af4a1461061a57806370a082311461063a57600080fd5b80632e1a7d4d116102b857806342b53e5f1161025657806351fb012d1161023057806351fb012d146105c9578063537df3b6146105d657806354a30576146105e95780635c975abb146105fc57600080fd5b806342b53e5f1461056457806344337ea11461057757806347e621b71461058a57600080fd5b806336568abe1161029257806336568abe1461052357806339509351146105365780633af32abf146105495780633f4ba83a1461055c57600080fd5b80632e1a7d4d146104ee5780632f2ff15d14610501578063313ce5671461051457600080fd5b806316b54c26116103255780631a7626e7116102ff5780631a7626e71461047c578063230ed44a1461048557806323b872dd146104b8578063248a9ca3146104cb57600080fd5b806316b54c261461044e57806318160ddd14610461578063182a75061461046957600080fd5b80630a4c0ca3116103615780630a4c0ca3146103d85780630d4b40fb1461040657806312f30c751461042657806315f570dc1461043b57600080fd5b806301ffc9a71461038857806306fdde03146103b0578063095ea7b3146103c5575b600080fd5b61039b61039636600461375e565b61086c565b60405190151581526020015b60405180910390f35b6103b86108d5565b6040516103a791906137d8565b61039b6103d3366004613807565b610967565b6103f86103e6366004613831565b600c6020526000908152604090205481565b6040519081526020016103a7565b6103f861041436600461384c565b600b6020526000908152604090205481565b610439610434366004613807565b61097f565b005b61043961044936600461387b565b610ab1565b61043961045c36600461394e565b610b5b565b6002546103f8565b61043961047736600461384c565b610cf8565b6103f860115481565b61049861049336600461384c565b610d4a565b6040805194855260208501939093529183015260608201526080016103a7565b61039b6104c6366004613980565b610d84565b6103f86104d936600461384c565b60009081526005602052604090206001015490565b6104396104fc36600461384c565b610da8565b61043961050f3660046139bd565b611037565b604051600681526020016103a7565b6104396105313660046139bd565b611061565b61039b610544366004613807565b6110ed565b61039b610557366004613831565b61112c565b61043961115e565b61043961057236600461384c565b611216565b610439610585366004613831565b611316565b6105b17f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b6040516001600160a01b0390911681526020016103a7565b60085461039b9060ff1681565b6104396105e4366004613831565b611410565b6104396105f7366004613831565b611507565b60065460ff1661039b565b6010546105b1906001600160a01b031681565b6103f861062836600461384c565b600a6020526000908152604090205481565b6103f8610648366004613831565b6001600160a01b031660009081526020819052604090205490565b6103b8610671366004613831565b6116dc565b610439611776565b61043961068c3660046139e9565b61182c565b61043961069f366004613831565b6119af565b61039b6106b23660046139bd565b60009182526005602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6103f86204d0d581565b6103b8611aa1565b6103f86106fd366004613a32565b611ab0565b6103f8600081565b61039b610718366004613807565b611be5565b61039b61072b366004613807565b611c8f565b61043961073e36600461384c565b611c9d565b610439610751366004613a62565b611eba565b6103b8610764366004613831565b612053565b61043961206c565b61043961077f366004613a62565b612087565b61043961079236600461387b565b6120da565b6103f861a8c081565b6104396107ae3660046139bd565b612175565b61043961219a565b6103f86107c9366004613a84565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b61043961080236600461384c565b6121b2565b6103f87f241ecf16d79d0f8dbfb92cbc07fe17840425976cf0667f022fe9877caa831b0881565b6103f8612274565b610439610844366004613831565b6123f8565b61039b610857366004613831565b600f6020526000908152604090205460ff1681565b60006001600160e01b031982167f7965db0b0000000000000000000000000000000000000000000000000000000014806108cf57507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b92915050565b6060600380546108e490613aae565b80601f016020809104026020016040519081016040528092919081815260200182805461091090613aae565b801561095d5780601f106109325761010080835404028352916020019161095d565b820191906000526020600020905b81548152906001019060200180831161094057829003601f168201915b5050505050905090565b6000336109758185856124cb565b5060019392505050565b600061098a81612623565b6001600160a01b0383166109e55760405162461bcd60e51b815260206004820152601160248201527f496e76616c696420726563697069656e7400000000000000000000000000000060448201526064015b60405180910390fd5b60008211610a355760405162461bcd60e51b815260206004820152601260248201527f416d6f756e74206d757374206265203e2030000000000000000000000000000060448201526064016109dc565b610a696001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816848461262d565b826001600160a01b03167f02d97641906fb7b62434b440b5998869ebf88faae661ffa33f3179b64a1ae71b83604051610aa491815260200190565b60405180910390a2505050565b6000610abc81612623565b610ac684846126be565b600080835111610b0b576040518060400160405280600b81526020017f6d616e75616c206275726e000000000000000000000000000000000000000000815250610b0d565b825b9050846001600160a01b03167f153e4c4bf18e12e4ee1b475b3e2717cf9db66291bc2184246821fe033027febb858342604051610b4c93929190613ae8565b60405180910390a25050505050565b6000610b6681612623565b6101f4831115610bc75760405162461bcd60e51b815260206004820152602660248201527f4d696e7420666565206d757374206265206265747765656e203020616e64203560448201526530302062707360d01b60648201526084016109dc565b6101f4821115610c285760405162461bcd60e51b815260206004820152602660248201527f4275726e20666565206d757374206265206265747765656e203020616e64203560448201526530302062707360d01b60648201526084016109dc565b5060408051608081018252948552602085019384528401918252606084019081526009805460018101825560009190915293517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af60049095029485015591517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b0840155517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b1830155517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b290910155565b6000610d0381612623565b601180549083905560408051828152602081018590527f42af500532a73708ee46cb952e653f5a82c5aede53857b7bfc1ec76d46bc1a5291015b60405180910390a1505050565b60098181548110610d5a57600080fd5b60009182526020909120600490910201805460018201546002830154600390930154919350919084565b600033610d92858285612827565b610d9d8585856128b9565b506001949350505050565b610db06128d6565b610db861292f565b610dc133612982565b60085460ff1615610dd557610dd5336129eb565b60008111610e255760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e203000000060448201526064016109dc565b33600090815260208190526040902054811115610e845760405162461bcd60e51b815260206004820152601460248201527f496e73756666696369656e742062616c616e636500000000000000000000000060448201526064016109dc565b610e8e33826126be565b6000610e98612274565b905060006204d0d5610eaa8385613b27565b610eb49190613b54565b90506000610ec3826000611ab0565b9050601154811015610ed457506011545b808211610f235760405162461bcd60e51b815260206004820152601d60248201527f4665652065786365656473207769746864726177616c20616d6f756e7400000060448201526064016109dc565b6000610f2f8284613b68565b9050610f656001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816338361262d565b601054610f9f906001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48811691168461262d565b610fa842612a9c565b610fb185612a9c565b604051602001610fc2929190613b7b565b60408051601f19818403018152918152336000908152600d6020522090610fe99082613c4a565b50604080518281526020810184905233917fdf273cb619d95419a9cd0ec88123a0538c85064229baa6363788f743fff90deb91015b60405180910390a2505050506110346001600755565b50565b60008281526005602052604090206001015461105281612623565b61105c8383612b3c565b505050565b6001600160a01b03811633146110df5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084016109dc565b6110e98282612bde565b5050565b3360008181526001602090815260408083206001600160a01b03871684529091528120549091906109759082908690611127908790613d09565b6124cb565b6001600160a01b0381166000908152600c60205260408120548082036111555750600092915050565b42101592915050565b3360009081527fe3a5955c11d878176a306e8c308ba1ceef9cfa46a3768e3b22365ec256a01e1f602052604090205460ff16806111c957503360009081527f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc602052604090205460ff165b61120c5760405162461bcd60e51b81526020600482015260146024820152732737ba1036b0b730b3b2b91037b91030b236b4b760611b60448201526064016109dc565b611214612c61565b565b600061122181612623565b60095482106112625760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b60448201526064016109dc565b6009805461127290600190613b68565b8154811061128257611282613d1c565b9060005260206000209060040201600983815481106112a3576112a3613d1c565b600091825260209091208254600490920201908155600180830154908201556002808301549082015560039182015491015560098054806112e6576112e6613d32565b60008281526020812060046000199093019283020181815560018101829055600281018290556003015590555050565b3360009081527fe3a5955c11d878176a306e8c308ba1ceef9cfa46a3768e3b22365ec256a01e1f602052604090205460ff168061138157503360009081527f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc602052604090205460ff165b6113c45760405162461bcd60e51b81526020600482015260146024820152732737ba1036b0b730b3b2b91037b91030b236b4b760611b60448201526064016109dc565b6001600160a01b0381166000818152600f6020526040808220805460ff19166001179055517fffa4e6181777692565cf28528fc88fd1516ea86b56da075235fa575af6a4b8559190a250565b3360009081527fe3a5955c11d878176a306e8c308ba1ceef9cfa46a3768e3b22365ec256a01e1f602052604090205460ff168061147b57503360009081527f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc602052604090205460ff165b6114be5760405162461bcd60e51b81526020600482015260146024820152732737ba1036b0b730b3b2b91037b91030b236b4b760611b60448201526064016109dc565b6001600160a01b0381166000818152600f6020526040808220805460ff19169055517f7534c63860313c46c473e4e98328f37017e9674e2162faf1a3ad7a96236c3b7b9190a250565b3360009081527fe3a5955c11d878176a306e8c308ba1ceef9cfa46a3768e3b22365ec256a01e1f602052604090205460ff168061157257503360009081527f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc602052604090205460ff165b6115b55760405162461bcd60e51b81526020600482015260146024820152732737ba1036b0b730b3b2b91037b91030b236b4b760611b60448201526064016109dc565b6001600160a01b03811661160b5760405162461bcd60e51b815260206004820152600f60248201527f496e76616c69642061646472657373000000000000000000000000000000000060448201526064016109dc565b6001600160a01b0381166000908152600c6020526040902054156116715760405162461bcd60e51b815260206004820152601460248201527f416c726561647920696e2077686974656c69737400000000000000000000000060448201526064016109dc565b600061167f61a8c042613d09565b6001600160a01b0383166000818152600c60205260409081902083905551919250907f57f2df100d4ab28ca291e2986ed1c62e7c78cb054257ae2a811ce2a31edf91dc906116d09084815260200190565b60405180910390a25050565b600e60205260009081526040902080546116f590613aae565b80601f016020809104026020016040519081016040528092919081815260200182805461172190613aae565b801561176e5780601f106117435761010080835404028352916020019161176e565b820191906000526020600020905b81548152906001019060200180831161175157829003601f168201915b505050505081565b3360009081527fe3a5955c11d878176a306e8c308ba1ceef9cfa46a3768e3b22365ec256a01e1f602052604090205460ff16806117e157503360009081527f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc602052604090205460ff165b6118245760405162461bcd60e51b81526020600482015260146024820152732737ba1036b0b730b3b2b91037b91030b236b4b760611b60448201526064016109dc565b611214612cb3565b600061183781612623565b60095486106118785760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b60448201526064016109dc565b6101f48311156118d95760405162461bcd60e51b815260206004820152602660248201527f4d696e7420666565206d757374206265206265747765656e203020616e64203560448201526530302062707360d01b60648201526084016109dc565b6101f482111561193a5760405162461bcd60e51b815260206004820152602660248201527f4275726e20666565206d757374206265206265747765656e203020616e64203560448201526530302062707360d01b60648201526084016109dc565b6040518060800160405280868152602001858152602001848152602001838152506009878154811061196e5761196e613d1c565b906000526020600020906004020160008201518160000155602082015181600101556040820151816002015560608201518160030155905050505050505050565b3360009081527fe3a5955c11d878176a306e8c308ba1ceef9cfa46a3768e3b22365ec256a01e1f602052604090205460ff1680611a1a57503360009081527f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc602052604090205460ff165b611a5d5760405162461bcd60e51b81526020600482015260146024820152732737ba1036b0b730b3b2b91037b91030b236b4b760611b60448201526064016109dc565b6001600160a01b0381166000818152600c6020526040808220829055517fde8cf212af7ce38b2840785a2768d97ff2dbf3c21b516961cec0061e134c2a1e9190a250565b6060600480546108e490613aae565b6000805b600954811015611b9c5760098181548110611ad157611ad1613d1c565b9060005260206000209060040201600001548410158015611b16575060098181548110611b0057611b00613d1c565b9060005260206000209060040201600101548411155b15611b9457600083611b4c5760098281548110611b3557611b35613d1c565b906000526020600020906004020160030154611b72565b60098281548110611b5f57611b5f613d1c565b9060005260206000209060040201600201545b9050612710611b818287613b27565b611b8b9190613b54565b925050506108cf565b600101611ab4565b5060405162461bcd60e51b815260206004820152601a60248201527f4e6f206d61746368696e6720666565207469657220666f756e6400000000000060448201526064016109dc565b3360008181526001602090815260408083206001600160a01b038716845290915281205490919083811015611c825760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f00000000000000000000000000000000000000000000000000000060648201526084016109dc565b610d9d82868684036124cb565b6000336109758185856128b9565b611ca56128d6565b611cad61292f565b611cb633612982565b60085460ff1615611cca57611cca336129eb565b60008111611d1a5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e203000000060448201526064016109dc565b611d4f6001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816333084612cf0565b6000611d5c826001611ab0565b9050601154811015611d6d57506011545b6000611d798284613b68565b905060008111611dcb5760405162461bcd60e51b815260206004820152601360248201527f4665652065786365656473206465706f7369740000000000000000000000000060448201526064016109dc565b6000611dd5612274565b9050600081611de76204d0d585613b27565b611df19190613b54565b9050611dfd3382612d41565b601054611e37906001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48811691168661262d565b611e4042612a9c565b611e4983612a9c565b604051602001611e5a929190613b7b565b60408051601f19818403018152918152336000908152600e6020522090611e819082613c4a565b50604080518681526020810186905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910161101e565b6000828152600a602052604081205490819003611f8d573360009081527fe3a5955c11d878176a306e8c308ba1ceef9cfa46a3768e3b22365ec256a01e1f602052604090205460ff1680611f3c57503360009081527f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc602052604090205460ff165b611f885760405162461bcd60e51b815260206004820152601960248201527f4e6f7420617574686f72697a656420746f20736574204350490000000000000060448201526064016109dc565b61200b565b3360009081527f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc602052604090205460ff1661200b5760405162461bcd60e51b815260206004820152601c60248201527f4f6e6c792061646d696e2063616e206f7665727772697465204350490000000060448201526064016109dc565b6000838152600a602090815260409182902084905581518581529081018490527ffaae7e9ebff587ddfd1fc7584c25926410fd174a75c5781a0ce1dfe041c0edab9101610d3d565b600d60205260009081526040902080546116f590613aae565b600061207781612623565b506008805460ff19166001179055565b600061209281612623565b6000838152600b602090815260409182902084905581518581529081018490527ff06db0d97fa92002986c2d675db085bd5dd088d2045b49eefdda0454c2ffb9559101610d3d565b60006120e581612623565b6120ef8484612d41565b600080835111612134576040518060400160405280600b81526020017f6d616e75616c206d696e74000000000000000000000000000000000000000000815250612136565b825b9050846001600160a01b03167f20a4aaa30fc904e456b39c9976be3f84769d03af262eb7798744011de9dca7c4858342604051610b4c93929190613ae8565b60008281526005602052604090206001015461219081612623565b61105c8383612bde565b60006121a581612623565b506008805460ff19169055565b60006121bd81612623565b6000821161220d5760405162461bcd60e51b815260206004820152601260248201527f416d6f756e74206d757374206265203e2030000000000000000000000000000060448201526064016109dc565b6122426001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816333085612cf0565b60405182815233907f24d9b234ebe2cc8e9888bf66c5e584fb213f0f62863e36f821c16ed40b5cb6d0906020016116d0565b60008061227f612d54565b9050600061228f82600119612db1565b9050600061229f83600219612db1565b6000838152600a6020526040808220548383529120549192509080158015906122c85750600082115b6123145760405162461bcd60e51b815260206004820152601560248201527f4e6f20435049206461746120617661696c61626c65000000000000000000000060448201526064016109dc565b6000858152600b6020819052604082205491908161233189612e96565b8152602001908152602001600020549050814210156123565750909695505050505050565b8042106123695750919695505050505050565b60006123758342613b68565b905060006123838484613b68565b905060008161239a84670de0b6b3a7640000613b27565b6123a49190613b54565b9050670de0b6b3a76400006123b98289613b27565b6123cb83670de0b6b3a7640000613b68565b6123d59089613b27565b6123df9190613d09565b6123e99190613b54565b9a505050505050505050505090565b600061240381612623565b6001600160a01b0382166124595760405162461bcd60e51b815260206004820152601860248201527f496e76616c69642074726561737572792061646472657373000000000000000060448201526064016109dc565b601080546001600160a01b038481167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f8c3aa5f43a388513435861bf27dfad7829cd248696fed367c62d441f629544969101610d3d565b6001600160a01b0383166125465760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f726573730000000000000000000000000000000000000000000000000000000060648201526084016109dc565b6001600160a01b0382166125c25760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f737300000000000000000000000000000000000000000000000000000000000060648201526084016109dc565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6110348133612ef2565b6040516001600160a01b03831660248201526044810182905261105c9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152612f67565b6001600160a01b03821661273a5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f730000000000000000000000000000000000000000000000000000000000000060648201526084016109dc565b6001600160a01b038216600090815260208190526040902054818110156127c95760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f636500000000000000000000000000000000000000000000000000000000000060648201526084016109dc565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6001600160a01b0383811660009081526001602090815260408083209386168352929052205460001981146128b357818110156128a65760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109dc565b6128b384848484036124cb565b50505050565b6128c283612982565b6128cb82612982565b61105c83838361304f565b6002600754036129285760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016109dc565b6002600755565b60065460ff16156112145760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016109dc565b6001600160a01b0381166000908152600f602052604090205460ff16156110345760405162461bcd60e51b815260206004820152600b60248201527f426c61636b6c697374656400000000000000000000000000000000000000000060448201526064016109dc565b6001600160a01b0381166000908152600c602052604090205415801590612a2a57506001600160a01b0381166000908152600c60205260409020544210155b6110345760405162461bcd60e51b815260206004820152602360248201527f4e6f742077686974656c6973746564206f722064656c6179206e6f742070617360448201527f736564000000000000000000000000000000000000000000000000000000000060648201526084016109dc565b60606000612aa98361323c565b600101905060008167ffffffffffffffff811115612ac957612ac9613865565b6040519080825280601f01601f191660200182016040528015612af3576020820181803683370190505b5090508181016020015b600019017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8504945084612afd57509392505050565b60008281526005602090815260408083206001600160a01b038516845290915290205460ff166110e95760008281526005602090815260408083206001600160a01b03851684529091529020805460ff19166001179055612b9a3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526005602090815260408083206001600160a01b038516845290915290205460ff16156110e95760008281526005602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b612c6961331e565b6006805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b612cbb61292f565b6006805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612c963390565b6040516001600160a01b03808516602483015283166044820152606481018290526128b39085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401612672565b612d4a82612982565b6110e98282613370565b6000622819a0612d686301e1338042613d48565b612d729190613b54565b612d806301e1338042613b54565b612d8c906107b2613d09565b612d97906064613b27565b612da19190613d09565b612dac906001613d09565b905090565b6000806000612dbf8561342f565b90925090508181612dd08682613d5c565b90505b600c811315612dfb57612de7600c82613d84565b9050612df4600183613d5c565b9150612dd3565b6001811215612e2357612e0f600c82613d5c565b9050612e1c600183613d84565b9150612dfb565b6107b2821215612e755760405162461bcd60e51b815260206004820152601160248201527f59656172206f7574206f662072616e676500000000000000000000000000000060448201526064016109dc565b80612e81836064613b27565b612e8b9190613d09565b979650505050505050565b6000806000612ea48461342f565b9150915080600c03612ec657612ebb600183613d09565b915060019050612ed4565b612ed1600182613d09565b90505b80612ee0836064613b27565b612eea9190613d09565b949350505050565b60008281526005602090815260408083206001600160a01b038516845290915290205460ff166110e957612f2581613451565b612f30836020613463565b604051602001612f41929190613dab565b60408051601f198184030181529082905262461bcd60e51b82526109dc916004016137d8565b6000612fbc826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661364b9092919063ffffffff16565b9050805160001480612fdd575080806020019051810190612fdd9190613e2c565b61105c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016109dc565b6001600160a01b0383166130cb5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f647265737300000000000000000000000000000000000000000000000000000060648201526084016109dc565b6001600160a01b0382166131475760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f657373000000000000000000000000000000000000000000000000000000000060648201526084016109dc565b6001600160a01b038316600090815260208190526040902054818110156131d65760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e6365000000000000000000000000000000000000000000000000000060648201526084016109dc565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36128b3565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310613285577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef810000000083106132b1576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106132cf57662386f26fc10000830492506010015b6305f5e10083106132e7576305f5e100830492506008015b61271083106132fb57612710830492506004015b6064831061330d576064830492506002015b600a83106108cf5760010192915050565b60065460ff166112145760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016109dc565b6001600160a01b0382166133c65760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109dc565b80600260008282546133d89190613d09565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b60008061343d606484613b54565b915061344a606484613d48565b9050915091565b60606108cf6001600160a01b03831660145b60606000613472836002613b27565b61347d906002613d09565b67ffffffffffffffff81111561349557613495613865565b6040519080825280601f01601f1916602001820160405280156134bf576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000816000815181106134f6576134f6613d1c565b60200101906001600160f81b031916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061354157613541613d1c565b60200101906001600160f81b031916908160001a9053506000613565846002613b27565b613570906001613d09565b90505b60018111156135f5577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106135b1576135b1613d1c565b1a60f81b8282815181106135c7576135c7613d1c565b60200101906001600160f81b031916908160001a90535060049490941c936135ee81613e49565b9050613573565b5083156136445760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016109dc565b9392505050565b6060612eea848460008585600080866001600160a01b031685876040516136729190613e60565b60006040518083038185875af1925050503d80600081146136af576040519150601f19603f3d011682016040523d82523d6000602084013e6136b4565b606091505b5091509150612e8b878383876060831561372f578251600003613728576001600160a01b0385163b6137285760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109dc565b5081612eea565b612eea83838151156137445781518083602001fd5b8060405162461bcd60e51b81526004016109dc91906137d8565b60006020828403121561377057600080fd5b81356001600160e01b03198116811461364457600080fd5b60005b838110156137a357818101518382015260200161378b565b50506000910152565b600081518084526137c4816020860160208601613788565b601f01601f19169290920160200192915050565b60208152600061364460208301846137ac565b80356001600160a01b038116811461380257600080fd5b919050565b6000806040838503121561381a57600080fd5b613823836137eb565b946020939093013593505050565b60006020828403121561384357600080fd5b613644826137eb565b60006020828403121561385e57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561389057600080fd5b613899846137eb565b925060208401359150604084013567ffffffffffffffff8111156138bc57600080fd5b8401601f810186136138cd57600080fd5b803567ffffffffffffffff8111156138e7576138e7613865565b604051601f8201601f19908116603f0116810167ffffffffffffffff8111828210171561391657613916613865565b60405281815282820160200188101561392e57600080fd5b816020840160208301376000602083830101528093505050509250925092565b6000806000806080858703121561396457600080fd5b5050823594602084013594506040840135936060013592509050565b60008060006060848603121561399557600080fd5b61399e846137eb565b92506139ac602085016137eb565b929592945050506040919091013590565b600080604083850312156139d057600080fd5b823591506139e0602084016137eb565b90509250929050565b600080600080600060a08688031215613a0157600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b801515811461103457600080fd5b60008060408385031215613a4557600080fd5b823591506020830135613a5781613a24565b809150509250929050565b60008060408385031215613a7557600080fd5b50508035926020909101359150565b60008060408385031215613a9757600080fd5b613aa0836137eb565b91506139e0602084016137eb565b600181811c90821680613ac257607f821691505b602082108103613ae257634e487b7160e01b600052602260045260246000fd5b50919050565b838152606060208201526000613b0160608301856137ac565b9050826040830152949350505050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176108cf576108cf613b11565b634e487b7160e01b600052601260045260246000fd5b600082613b6357613b63613b3e565b500490565b818103818111156108cf576108cf613b11565b7f74696d657374616d703a20000000000000000000000000000000000000000000815260008351613bb381600b850160208801613788565b7f2c2070726f72617465644350493a200000000000000000000000000000000000600b918401918201528351613bf081601a840160208801613788565b01601a01949350505050565b601f82111561105c57806000526020600020601f840160051c81016020851015613c235750805b601f840160051c820191505b81811015613c435760008155600101613c2f565b5050505050565b815167ffffffffffffffff811115613c6457613c64613865565b613c7881613c728454613aae565b84613bfc565b6020601f821160018114613cac5760008315613c945750848201515b600019600385901b1c1916600184901b178455613c43565b600084815260208120601f198516915b82811015613cdc5787850151825560209485019460019092019101613cbc565b5084821015613cfa5786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b808201808211156108cf576108cf613b11565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b600082613d5757613d57613b3e565b500690565b8082018281126000831280158216821582161715613d7c57613d7c613b11565b505092915050565b8181036000831280158383131683831282161715613da457613da4613b11565b5092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351613de3816017850160208801613788565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351613e20816028840160208801613788565b01602801949350505050565b600060208284031215613e3e57600080fd5b815161364481613a24565b600081613e5857613e58613b11565b506000190190565b60008251613e72818460208701613788565b919091019291505056fea2646970667358221220d4075305891c56f037778efe2bc84f4f08ba11fa62c4d9b648c313f93254bf7664736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
-----Decoded View---------------
Arg [0] : _backingToken (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Loading...
Loading
Loading...
Loading
OVERVIEW
USDi is the first stablecoin backed by real world assets and designed to be a medium of exchange not subject to inflation.Net Worth in USD
$0.34
Net Worth in ETH
0.000182
Token Allocations
USDC
100.00%
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ETH | 100.00% | $1 | 0.3395 | $0.3395 |
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.