Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
VSCGovernor
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 2000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
/**
* @dev Management contract for the VOW VSC ecosystem.
* Enables the owner to initialise new VSC regions and update the operating parameters of existing VSC regions.
* VSC region token contracts are beacon proxies that can be upgraded simultaneously.
* Acts as a locus enabling conversions between VOW and regional VSC for MVDs, merchants, and whitelisted users.
* Harnesses oracle feeds to determine live exchange rates where available.
* Connects VSC tokens to the VOW token and their voucher settlement layer.
* Proxy upgradeable implementation utilising EIP-1822.
*/
import './interfaces/IVSCGovernor.sol';
import './interfaces/IVOW.sol';
import './interfaces/IVSC.sol';
import './interfaces/IERC777Recipient.sol';
import './interfaces/IChainlinkV3Aggregator.sol';
import '@openzeppelin/contracts/interfaces/IERC1820Registry.sol';
import '@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol';
import '@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol';
import '@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol';
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol';
contract VSCGovernor is
IVSCGovernor,
IERC777Recipient,
Initializable,
UUPSUpgradeable,
Ownable2StepUpgradeable,
ReentrancyGuardUpgradeable
{
IERC1820Registry private constant ERC1820_REGISTRY = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);
bytes32 private constant ERC777_TOKENS_RECIPIENT_HASH = 0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b;
uint256 private constant ONE_18_DP = uint256(10 ** 18);
uint256 private constant ONE_12_DP = uint256(10 ** 12);
uint256 private constant ONE_8_DP = uint256(10 ** 8);
uint256 private constant TOTAL_BASIS_POINTS = 10000;
uint256 private constant CHAINLINK_FIAT_HEARTBEAT = 24 hours;
bool private _ignoreTokensReceived;
mapping(address => mapping(address => uint256[2])) public lockedVOWToVSC;
mapping(address => mapping(address => bool)) public vowToVSCWhitelist;
mapping(address => uint256[2]) public vscMintOnLockRatio;
mapping(address => uint256) public oneUSD;
mapping(address => MVD) public regionMVD;
mapping(address => uint256) public requiredVOWDeposit;
mapping(address => address) public feedContract;
mapping(address => uint256) public internalRate;
mapping(address => uint8) public vscRegion;
mapping(uint8 => address) public vscContract;
uint256 public vowRateRefreshDelta;
uint256 public vowRateTolerance;
uint256 public maxRatesAge;
uint256 public ratesUpdatedAt;
IUniswapV2Router02 public uniswapV2Router;
IUniswapV2Pair public vowUSDTPair;
address public vow;
address public vowBridge;
address public vscBase;
address public internalRateSetter;
uint8 public nextRegionID;
error AddressIsZero();
error EmptyData();
error ExceedsDeposit();
error FeedOrRateOnly();
error HasExistingLock();
error IncorrectAmount();
error InvalidData();
error InvalidRate();
error InvalidRatio();
error InvalidRegion();
error InvalidT2Key();
error MissingString();
error NoExistingLock();
error NoMVDSet();
error NotAuthorized();
error NotUSDApplicable();
error RateIsStale();
error RateOutsideRange();
error RateSetterOnly();
error RegionMVDOnly();
error RemoveMVDFirst();
error SetRateFirst();
error UnknownToken();
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/**
* @dev Initializes the contract and integrates it with the VOW ecosystem. Can be called only once.
* @param _vscBase The address of the VSC base contract.
* @param _vow The address of the VOW token contract.
* @param _vowBridge The address of the VOW bridge contract.
* @param _uniswapV2Router The address of the Uniswap V2 router.
*/
function initialize(
address _vscBase,
address _vow,
address payable _vowBridge,
address _uniswapV2Router,
address _usdt
) external initializer {
__Ownable_init(msg.sender);
__Ownable2Step_init();
__UUPSUpgradeable_init();
__ReentrancyGuard_init();
if (
_vscBase == address(0) ||
_vow == address(0) ||
_vowBridge == address(0) ||
_uniswapV2Router == address(0) ||
_usdt == address(0)
) revert AddressIsZero();
vscBase = _vscBase;
vow = _vow;
vowBridge = _vowBridge;
uniswapV2Router = IUniswapV2Router02(_uniswapV2Router);
vowUSDTPair = IUniswapV2Pair(IUniswapV2Factory(uniswapV2Router.factory()).getPair(vow, _usdt));
nextRegionID = 1;
ERC1820_REGISTRY.setInterfaceImplementer(address(this), ERC777_TOKENS_RECIPIENT_HASH, address(this));
// Initialise config values which can later be updated by the owner if required
internalRateSetter = msg.sender;
maxRatesAge = 24 hours;
vowRateRefreshDelta = 125; // refresh the VOW rate if it changes by more than 1.25%
vowRateTolerance = 250; // tolerate a rate change of up to +/-2.5% from the last observed rate
}
/**
* @dev Disables the renounceOwnership function to prevent relinquishing control over the contract.
*/
function renounceOwnership() public override onlyOwner {}
/**
* @dev Deploys and configures a new VSC region. Callable only by the owner.
* @param name The name of the new VSC token.
* @param symbol The symbol for the new VSC token.
* @param initialSupply The initial supply of the new VSC token.
* @param feed The oracle feed address or zero for an internal rate.
* @param rate The initial internal exchange rate or zero if using an oracle feed.
* @param vscMintOnLock The ratio of VSC to mint on merchant lock.
* @param transferBurn The ratio of VSC to burn on transfers.
* @return newVSC The address of the deployed VSC contract.
*/
function addRegion(
string calldata name,
string calldata symbol,
uint256 initialSupply,
address feed,
uint256 rate,
uint256[2] calldata vscMintOnLock,
uint256[2] calldata transferBurn
) external onlyOwner returns (address newVSC) {
if (bytes(name).length == 0 || bytes(symbol).length == 0) revert MissingString();
uint8 newRegionID = nextRegionID++;
if (_isUSDRegion(newRegionID)) {
if (feed != address(0) || rate != 0) revert NotUSDApplicable();
} else if ((feed == address(0)) == (rate == 0)) revert FeedOrRateOnly();
BeaconProxy vscBeaconProxy = new BeaconProxy(vscBase, abi.encodeWithSelector(IVSC.initialize.selector, name, symbol));
newVSC = address(vscBeaconProxy);
vscContract[newRegionID] = newVSC;
vscRegion[newVSC] = newRegionID;
uint8[] memory regionID = new uint8[](1);
regionID[0] = newRegionID;
IVSC(newVSC).setSkipTransferBurn(address(this), true);
IVSC(newVSC).setSkipTransferBurn(vowBridge, true);
updateTransferBurn(transferBurn, regionID);
updateVSCMintOnLock(vscMintOnLock, regionID);
if (feed == address(0)) {
internalRate[newVSC] = rate;
if (ratesUpdatedAt == 0) ratesUpdatedAt = block.timestamp;
feed = address(this);
}
if (!_isUSDRegion(newRegionID)) updateFeed(feed, newRegionID);
if (initialSupply != 0) IVSC(newVSC).mint(msg.sender, initialSupply);
emit LogRegionAdded(name, newVSC, newRegionID);
}
/**
* @dev Liquidates a defaulted merchant by swapping their locked VOW for VSC and burning the VSC.
* Callable only by the MVD of the merchant's region.
* @param merchant The address of the defaulted merchant.
* @param regionID The ID of the region where the merchant operates.
* @param minVSCAmount The minimum amount of VSC expected (can be determined by calling previewLiquidateMerchant first).
* @param optionalPath An optional swap path to use for the VOW-to-VSC conversion.
*/
function liquidateMerchant(address merchant, uint8 regionID, uint256 minVSCAmount, address[] calldata optionalPath) external {
address vsc = vscContract[regionID];
if (vsc == address(0)) revert InvalidRegion();
if (msg.sender != regionMVD[vsc].t1Address) revert RegionMVDOnly();
uint256 vowAmount = lockedVOWToVSC[vsc][merchant][0];
if (vowAmount == 0) revert NoExistingLock();
delete lockedVOWToVSC[vsc][merchant];
IVOW(vow).approve(address(uniswapV2Router), vowAmount);
address[] memory path = _generateSwapPath(vsc, optionalPath);
_ignoreTokensReceived = true;
uniswapV2Router.swapExactTokensForTokens(vowAmount, minVSCAmount, path, address(this), block.timestamp + 60);
_ignoreTokensReceived = false;
uint256 vscAmount = IVSC(vsc).balanceOf(address(this));
IVSC(vsc).burn(vscAmount, '');
emit LogMerchantLiquidated(merchant, regionID, vowAmount, vscAmount);
}
/**
* @dev Removes the MVD associated with a specific region, applying a forfeiture to the deposit if specified and transferring any remaining deposit back to the MVD.
* @param forfeiture An optional amount to be deducted from the MVD's deposit as decided by the community.
* @param regionID The ID of the region whose MVD is to be removed.
*/
function removeMVD(uint256 forfeiture, uint8 regionID) external onlyOwner {
address vsc = vscContract[regionID];
if (vsc == address(0)) revert InvalidRegion();
address mvdT1Address = regionMVD[vsc].t1Address;
if (mvdT1Address == address(0)) revert NoMVDSet();
uint256 refund = regionMVD[vsc].deposit;
if (forfeiture > refund) revert ExceedsDeposit();
bytes32 mvdT2PublicKey = regionMVD[vsc].t2PublicKey;
delete regionMVD[vsc];
if (forfeiture != 0) {
unchecked {
refund -= forfeiture;
}
IVOW(vow).transfer(owner(), forfeiture);
}
if (refund != 0) IVOW(vow).transfer(mvdT1Address, refund);
emit LogMVDRemoved(mvdT1Address, mvdT2PublicKey, refund, forfeiture, regionID);
}
/**
* @dev Sets the MVD for a specific region (provided no MVD already exists), transferring the required deposit amount from the MVD to the contract.
* @param t1Address The T1 address of the MVD.
* @param t2PublicKey The 32 byte T2 public key of the MVD.
* @param regionID The ID of the region for which the MVD is to be set.
*/
function setMVD(address t1Address, bytes calldata t2PublicKey, uint8 regionID) external onlyOwner {
address vsc = vscContract[regionID];
if (vsc == address(0)) revert InvalidRegion();
if (regionMVD[vsc].t1Address != address(0)) revert RemoveMVDFirst();
if (t1Address == address(0)) revert AddressIsZero();
if (t2PublicKey.length != 32) revert InvalidT2Key();
uint256 deposit = requiredVOWDeposit[vsc];
if (deposit != 0) {
_ignoreTokensReceived = true;
IVOW(vow).transferFrom(t1Address, address(this), deposit);
_ignoreTokensReceived = false;
}
regionMVD[vsc].t1Address = t1Address;
regionMVD[vsc].t2PublicKey = bytes32(t2PublicKey);
regionMVD[vsc].deposit = deposit;
emit LogMVDSet(t1Address, bytes32(t2PublicKey), deposit, regionID);
}
/**
* @dev Allows the owner to selectively update config params
* @param _internalRateSetter The address permitted to update the internal rates (empty if no update)
* @param _maxRatesAge The maximum number of seconds an internal rate remains valid for (zero if no update).
* @param _vowRateRefreshDelta basis points representing the percentage change from the last observed vow rate that should trigger a fresh observation (zero if no update).
* @param _vowRateTolerance basis points representing the maximum acceptable percentage difference between the last observed vow rate and the current rate (zero if no update).
*/
function updateConfig(
address _internalRateSetter,
uint256 _maxRatesAge,
uint256 _vowRateRefreshDelta,
uint256 _vowRateTolerance
) external onlyOwner {
if (_internalRateSetter != address(0)) internalRateSetter = _internalRateSetter;
if (_maxRatesAge != 0) maxRatesAge = _maxRatesAge;
if (_vowRateRefreshDelta > TOTAL_BASIS_POINTS || _vowRateTolerance > TOTAL_BASIS_POINTS) revert InvalidRatio();
if (_vowRateRefreshDelta != 0) vowRateRefreshDelta = _vowRateRefreshDelta;
if (_vowRateTolerance != 0) vowRateTolerance = _vowRateTolerance;
if (vowRateRefreshDelta > vowRateTolerance) revert InvalidRate();
}
/**
* @dev Updates the deposit required to become an MVD for the specified regions or all regions.
* @param vowAmount The amount of VOW required.
* @param regionIDs The array of region IDs to update, or an empty array to update all.
*/
function updateDeposit(uint256 vowAmount, uint8[] calldata regionIDs) external onlyOwner {
(address[] memory selectedVSC, uint8[] memory selectedIDs) = _selectVSCContracts(regionIDs);
for (uint256 i; i < selectedVSC.length; ++i) {
requiredVOWDeposit[selectedVSC[i]] = vowAmount;
}
emit LogDepositUpdated(vowAmount, selectedIDs);
}
/**
* @dev Updates the oracle feed for a specific region. For internal feeds the rate must be set prior to calling this function.
* @param feed The address of the oracle feed (or the address of this contract for an internal feed).
* @param regionID The ID of the region to update.
*/
function updateFeed(address feed, uint8 regionID) public onlyOwner {
if (feed == address(0)) revert AddressIsZero();
address vsc = vscContract[regionID];
if (vsc == address(0)) revert InvalidRegion();
if (_isUSDRegion(regionID)) revert NotUSDApplicable();
if (feed == address(this)) {
if (internalRate[vsc] == 0) revert SetRateFirst();
oneUSD[vsc] = ONE_8_DP;
} else {
oneUSD[vsc] = 10 ** IChainlinkV3Aggregator(feed).decimals();
}
feedContract[vsc] = feed;
emit LogFeedUpdated(feed, regionID);
}
/**
* @dev Updates the owner of the VSC contracts for specified regions or all regions.
* @param newOwner The address of the new owner.
* @param regionIDs The array of region IDs to update, or an empty array to update all.
*/
function updateOwner(address newOwner, uint8[] calldata regionIDs) external onlyOwner {
if (newOwner == address(0)) revert AddressIsZero();
(address[] memory selectedVSC, uint8[] memory selectedIDs) = _selectVSCContracts(regionIDs);
for (uint256 i; i < selectedVSC.length; ++i) {
IVSC(selectedVSC[i]).setOwner(newOwner);
}
emit LogOwnerUpdated(newOwner, selectedIDs);
}
/**
* @dev Pauses or unpauses token transfers and burns for specified regions or all regions.
* @param pause True to pause, false to unpause.
* @param regionIDs The array of region IDs to update, or an empty array to update all.
*/
function updatePauseTransfers(bool pause, uint8[] calldata regionIDs) external onlyOwner {
(address[] memory selectedVSC, uint8[] memory selectedIDs) = _selectVSCContracts(regionIDs);
for (uint256 i; i < selectedVSC.length; ++i) {
IVSC(selectedVSC[i]).setPauseTransfers(pause);
}
emit LogPauseTransfersUpdated(pause, selectedIDs);
}
/**
* @dev Updates internal exchange rates for VSC regions without Chainlink feeds.
* @param Rates An array of {vsc, rate} pairs specifying the new rates.
*/
function updateRates(Rate[] calldata Rates) external {
if (msg.sender != internalRateSetter) revert RateSetterOnly();
for (uint256 i; i < Rates.length; ++i) {
if (Rates[i].vsc == address(0)) revert AddressIsZero();
if (Rates[i].rate == 0) revert InvalidRate();
internalRate[Rates[i].vsc] = Rates[i].rate;
}
ratesUpdatedAt = block.timestamp;
}
/**
* @dev Updates the VSC transfer burn ratio for specified regions or all regions or all regions.
* Example: passing a ratio of [16,1000] will burn 1.6% of every VSC transfer made by non-whitelisted addresses.
* @param ratio The [numVSCToBurn, numVSCTransferred] ratio.
* @param regionIDs The array of region IDs to update, or an empty array to update all.
*/
function updateTransferBurn(uint256[2] memory ratio, uint8[] memory regionIDs) public onlyOwner {
if (ratio[1] == 0 || ratio[0] > ratio[1]) revert InvalidRatio();
(address[] memory selectedVSC, uint8[] memory selectedIDs) = _selectVSCContracts(regionIDs);
for (uint256 i; i < selectedVSC.length; ++i) {
IVSC(selectedVSC[i]).setTransferBurn(ratio[0], ratio[1]);
}
emit LogTransferBurnUpdated(ratio, selectedIDs);
}
/**
* @dev Updates the transfer burn whitelist for specified regions or all regions.
* Addresses on this whitelist will not incur burn fees when sending or receiving tokens.
* @param target The address to add or remove from the whitelist.
* @param whitelist True to add to the whitelist, false to remove.
* @param regionIDs The array of region IDs to update, or an empty array to update all.
*/
function updateTransferBurnWhitelist(address target, bool whitelist, uint8[] calldata regionIDs) external onlyOwner {
if (target == address(0)) revert AddressIsZero();
(address[] memory selectedVSC, uint8[] memory selectedIDs) = _selectVSCContracts(regionIDs);
for (uint256 i; i < selectedVSC.length; ++i) {
IVSC(selectedVSC[i]).setSkipTransferBurn(target, whitelist);
}
emit LogTransferBurnWhitelistUpdated(target, whitelist, selectedIDs);
}
/**
* @dev Updates the whitelist for VOW to VSC conversion for specified regions or all regions.
* @param target The address to whitelist or remove from the whitelist.
* @param whitelist True to add to the whitelist, false to remove.
* @param regionIDs The array of region IDs to update, or an empty array to update all.
*/
function updateVOWToVSCWhitelist(address target, bool whitelist, uint8[] calldata regionIDs) external onlyOwner {
if (target == address(0)) revert AddressIsZero();
(address[] memory selectedVSC, uint8[] memory selectedIDs) = _selectVSCContracts(regionIDs);
for (uint256 i; i < selectedVSC.length; ++i) {
vowToVSCWhitelist[selectedVSC[i]][target] = whitelist;
}
emit LogVOWToVSCWhitelistUpdated(target, whitelist, selectedIDs);
}
/**
* @dev Updates the Merchant Lock mint multiplier for specified regions or all regions.
* Example: passing a ratio of [5,2] will mint 2.5x the standard amount of VSC
* @param ratio The [multiplierNumerator, multiplierDivisor] ratio.
* @param regionIDs The array of region IDs to update, or an empty array to update all.
*/
function updateVSCMintOnLock(uint256[2] memory ratio, uint8[] memory regionIDs) public onlyOwner {
if (ratio[1] == 0 || ratio[1] > ratio[0]) revert InvalidRatio();
(address[] memory selectedVSC, uint8[] memory selectedIDs) = _selectVSCContracts(regionIDs);
for (uint256 i; i < selectedVSC.length; ++i) {
vscMintOnLockRatio[selectedVSC[i]] = ratio;
}
emit LogVSCMintOnLockUpdated(ratio, selectedIDs);
}
/**
* @dev Handles the receipt of VOW or VSC tokens by this contract.
* - VOW from a registered MVD address is locked against the merchant address provided in the data payload. A mutliplied amount of VSC is then minted and lifted to the MVD's illiquid wallet on the settlement layer.
* - VOW from whitelisted addresses is burned and the VSC specified in the data payload is minted at the current exchange rate (provided the rate lies within the tolerance threshold).
* - VSC from any address unlocks VOW to the merchant specified in the data payload.
* Reverts for all non-VOW or VSC tokens or if the data payload is invalid or missing.
*/
function tokensReceived(
address,
address from,
address,
uint256 amount,
bytes calldata data,
bytes calldata
) external nonReentrant {
if (_ignoreTokensReceived) return;
address token = msg.sender;
if (vscRegion[token] != 0) return _merchantUnlock(token, from, amount, data);
if (token != vow) revert UnknownToken();
if (data.length == 0) revert EmptyData();
address vsc;
address merchant;
(vsc, merchant) = data.length > 32 ? abi.decode(data, (address, address)) : (abi.decode(data, (address)), address(0));
if (vscRegion[vsc] == 0) revert InvalidRegion();
if (from == regionMVD[vsc].t1Address && merchant != address(0)) {
return _merchantLock(vsc, amount, merchant);
} else if (merchant == address(0)) {
return _burnVOWMintVSC(from, amount, vsc);
}
revert InvalidData();
}
/**
* @dev Previews liquidiation of a defaulted merchant, returning the VOW to be unlocked and sold and the minimum VSC to be recovered and burned.
* @param merchant The address of the defaulted merchant.
* @param regionID The ID of the region where the merchant operates.
* @param slippageBP The slippage tolerance in basis points (1 BPS = 0.01%).
* @param optionalPath An optional swap path to use for the VOW-to-VSC conversion.
* @return vowAmount The total amount of VOW locked against the merchant.
* @return minVSCAmount The minimum amount of VSC expected to be received after accounting for slippage.
*/
function previewLiquidateMerchant(
address merchant,
uint8 regionID,
uint256 slippageBP,
address[] calldata optionalPath
) external view returns (uint256 vowAmount, uint256 minVSCAmount) {
address vsc = vscContract[regionID];
vowAmount = lockedVOWToVSC[vsc][merchant][0];
minVSCAmount = _calculateMinVSC(vowAmount, slippageBP, _generateSwapPath(vsc, optionalPath));
}
/**
* @dev Returns the IDs, names, and addresses of all existing VSC regions.
* @return An array of RegionData structs containing the region information.
*/
function regions() external view returns (RegionData[] memory) {
uint8 numRegions = nextRegionID - 1;
RegionData[] memory regionsData = new RegionData[](numRegions);
address vsc;
uint8 regionID;
for (uint8 i = 0; i < numRegions; ++i) {
regionID = i + 1;
vsc = vscContract[regionID];
regionsData[i] = RegionData(regionID, IVSC(vsc).name(), IVSC(vsc).symbol(), vsc);
}
return regionsData;
}
/**
* @dev Returns the current exchange rate of VSC per VOW for a specified region.
* @param regionID The ID of the region.
* @return The number of VSC tokens per VOW.
*/
function vscPerVOW(uint8 regionID) external view returns (uint256) {
address vsc = vscContract[regionID];
if (vsc == address(0)) revert InvalidRegion();
uint256[2] memory vowVSC = _getVOWToVSC(_getVOWToUSD(), vsc);
return (ONE_18_DP * vowVSC[0]) / vowVSC[1];
}
function _authorizeUpgrade(address) internal override onlyOwner {}
function _burnVOWMintVSC(address from, uint256 vowAmount, address vsc) private {
if (!vowToVSCWhitelist[vsc][from]) revert NotAuthorized();
IVOW(vow).burn(vowAmount, '');
uint256[2] memory vowVSC = _getVOWToVSC(_getVOWToUSD(), vsc);
IVSC(vsc).mint(from, (vowAmount * vowVSC[0]) / vowVSC[1]);
}
function _bytes32ToBytes(bytes32 value) private pure returns (bytes memory) {
bytes memory valueAsBytes = new bytes(32);
assembly {
mstore(add(valueAsBytes, 32), value)
}
return valueAsBytes;
}
function _calculateMinVSC(uint256 vowAmount, uint256 slippageBP, address[] memory path) private view returns (uint256) {
uint256[] memory amountsOut = uniswapV2Router.getAmountsOut(vowAmount, path);
uint256 minVSCAmount = amountsOut[amountsOut.length - 1];
uint256 slippageAmount = (minVSCAmount * slippageBP) / TOTAL_BASIS_POINTS;
return minVSCAmount - slippageAmount;
}
function _generateSwapPath(address vsc, address[] calldata optionalPath) private view returns (address[] memory path) {
uint256 pathLength = optionalPath.length + 2;
path = new address[](pathLength);
path[0] = vow;
for (uint256 i; i < optionalPath.length; ++i) {
path[i + 1] = optionalPath[i];
}
path[pathLength - 1] = vsc;
}
function _getMerchant(address vsc, address from, bytes calldata data) private view returns (address) {
if (lockedVOWToVSC[vsc][from][0] != 0) return from;
else if (data.length == 0) revert EmptyData();
else return abi.decode(data, (address));
}
function _getVOWToVSC(uint256[2] memory vowUSD, address vsc) private view returns (uint256[2] memory) {
uint256[2] memory vscUSD = _getVSCToUSD(vsc);
return [vscUSD[0] * vowUSD[1], vscUSD[1] * vowUSD[0]];
}
function _getVOWToUSD() private view returns (uint256[2] memory vowUSD) {
(uint112 vowReserve, uint112 usdtReserve, ) = vowUSDTPair.getReserves();
vowUSD[0] = uint256(vowReserve);
vowUSD[1] = uint256(usdtReserve) * ONE_12_DP; // Scale USDT to match VOW decimals
if (!_rateIsWithinExpectedRange(vowUSD)) revert RateOutsideRange();
}
function _getVSCToUSD(address vsc) private view returns (uint256[2] memory) {
if (_isUSDRegion(vscRegion[vsc])) return [ONE_8_DP, ONE_8_DP]; // USD Region so 1:1
uint256 numVSC = oneUSD[vsc];
address feed = feedContract[vsc];
uint256 numUSD;
if (feed == address(this)) {
if (block.timestamp > ratesUpdatedAt + maxRatesAge) revert RateIsStale();
numUSD = internalRate[vsc];
} else numUSD = _getChainlinkRate(feed);
return [numVSC, numUSD];
}
function _getChainlinkRate(address feed) private view returns (uint256) {
(uint80 roundId, int256 answer, , uint256 updatedAt, uint80 answeredRound) = IChainlinkV3Aggregator(feed).latestRoundData();
if (block.timestamp > updatedAt + CHAINLINK_FIAT_HEARTBEAT) revert RateIsStale();
if (answer < 0 || roundId != answeredRound) revert InvalidRate();
return uint256(answer);
}
function _isUSDRegion(uint8 regionID) private pure returns (bool) {
return regionID == 1;
}
function _merchantLock(address vsc, uint256 vowToLock, address merchant) private {
if (lockedVOWToVSC[vsc][merchant][0] != 0) revert HasExistingLock();
uint256[2] memory vscMintRatio = vscMintOnLockRatio[vsc];
uint256[2] memory vowVSC = _getVOWToVSC(_getVOWToUSD(), vsc);
uint256 vscToMint = (vowToLock * vowVSC[0] * vscMintRatio[0]) / (vscMintRatio[1] * vowVSC[1]);
lockedVOWToVSC[vsc][merchant][0] = vowToLock;
lockedVOWToVSC[vsc][merchant][1] = vscToMint;
IVSC(vsc).mint(regionMVD[vsc].t1Address, vscToMint);
// Automatically lift the new VSC Tokens from the MVD to their T2 illiquid wallet
IVSC(vsc).operatorSend(regionMVD[vsc].t1Address, vowBridge, vscToMint, _bytes32ToBytes(regionMVD[vsc].t2PublicKey), '');
emit LogMerchantLocked(merchant, vscRegion[vsc], vowToLock, vscToMint);
}
function _merchantUnlock(address vsc, address from, uint256 vscReceived, bytes calldata data) private {
address merchant = _getMerchant(vsc, from, data);
uint256[2] storage lockInfo = lockedVOWToVSC[vsc][merchant];
if (lockInfo[0] == 0) revert NoExistingLock();
if (lockInfo[1] != vscReceived) revert IncorrectAmount();
uint256 vowToUnlock = lockInfo[0];
delete lockedVOWToVSC[vsc][merchant];
IVSC(vsc).burn(vscReceived, '');
IVOW(vow).send(merchant, vowToUnlock, '');
emit LogMerchantUnlocked(merchant, vscRegion[vsc], vowToUnlock, vscReceived);
}
function _rateIsWithinExpectedRange(uint256[2] memory currentRate) private view returns (bool) {
uint256 normalizedLast = IVOW(vow).usdRate(0) * currentRate[1];
uint256 normalizedCurrent = currentRate[0] * IVOW(vow).usdRate(1);
uint256 absoluteDiff = normalizedCurrent > normalizedLast
? normalizedCurrent - normalizedLast
: normalizedLast - normalizedCurrent;
uint256 percentageChange = (absoluteDiff * TOTAL_BASIS_POINTS) / normalizedLast;
return percentageChange <= vowRateTolerance;
}
function _selectVSCContracts(uint8[] memory regionIDs) private view returns (address[] memory, uint8[] memory) {
uint8 numRegions = regionIDs.length == 0 ? nextRegionID - 1 : uint8(regionIDs.length);
address[] memory selectedVSC = new address[](numRegions);
uint8[] memory selectedIDs = new uint8[](numRegions);
for (uint8 i = 1; i <= numRegions; ++i) {
uint8 regionIndex = regionIDs.length == 0 ? i : regionIDs[i - 1];
address vsc = vscContract[regionIndex];
if (vsc == address(0)) revert InvalidRegion();
selectedVSC[i - 1] = vsc;
selectedIDs[i - 1] = regionIndex;
}
return (selectedVSC, selectedIDs);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.20;
import {OwnableUpgradeable} from "./OwnableUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is specified at deployment time in the constructor for `Ownable`. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable2Step
struct Ownable2StepStorage {
address _pendingOwner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable2Step")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant Ownable2StepStorageLocation = 0x237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00;
function _getOwnable2StepStorage() private pure returns (Ownable2StepStorage storage $) {
assembly {
$.slot := Ownable2StepStorageLocation
}
}
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
function __Ownable2Step_init() internal onlyInitializing {
}
function __Ownable2Step_init_unchained() internal onlyInitializing {
}
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
Ownable2StepStorage storage $ = _getOwnable2StepStorage();
return $._pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
Ownable2StepStorage storage $ = _getOwnable2StepStorage();
$._pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
Ownable2StepStorage storage $ = _getOwnable2StepStorage();
delete $._pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
function __Ownable_init(address initialOwner) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
OwnableStorage storage $ = _getOwnableStorage();
return $._owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.20;
import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Initializable} from "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable __self = address(this);
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
* and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev The call is from an unauthorized context.
*/
error UUPSUnauthorizedCallContext();
/**
* @dev The storage `slot` is unsupported as a UUID.
*/
error UUPSUnsupportedProxiableUUID(bytes32 slot);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_checkProxy();
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
_checkNotDelegated();
_;
}
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual notDelegated returns (bytes32) {
return ERC1967Utils.IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data);
}
/**
* @dev Reverts if the execution is not performed via delegatecall or the execution
* context is not of a proxy with an ERC1967-compliant implementation pointing to self.
* See {_onlyProxy}.
*/
function _checkProxy() internal view virtual {
if (
address(this) == __self || // Must be called through delegatecall
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Reverts if the execution is performed via delegatecall.
* See {notDelegated}.
*/
function _checkNotDelegated() internal view virtual {
if (address(this) != __self) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
*
* As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
* is expected to be the implementation slot in ERC1967.
*
* Emits an {IERC1967-Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
revert UUPSUnsupportedProxiableUUID(slot);
}
ERC1967Utils.upgradeToAndCall(newImplementation, data);
} catch {
// The implementation is not UUPS
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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 ReentrancyGuardUpgradeable is Initializable {
// 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;
/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._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 {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// On the first call to nonReentrant, _status will be NOT_ENTERED
if ($._status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
$._status = ENTERED;
}
function _nonReentrantAfter() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// 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) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1820Registry.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the global ERC1820 Registry, as defined in the
* https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register
* implementers for interfaces in this registry, as well as query support.
*
* Implementers may be shared by multiple accounts, and can also implement more
* than a single interface for each account. Contracts can implement interfaces
* for themselves, but externally-owned accounts (EOA) must delegate this to a
* contract.
*
* {IERC165} interfaces can also be queried via the registry.
*
* For an in-depth explanation and source code analysis, see the EIP text.
*/
interface IERC1820Registry {
event InterfaceImplementerSet(address indexed account, bytes32 indexed interfaceHash, address indexed implementer);
event ManagerChanged(address indexed account, address indexed newManager);
/**
* @dev Sets `newManager` as the manager for `account`. A manager of an
* account is able to set interface implementers for it.
*
* By default, each account is its own manager. Passing a value of `0x0` in
* `newManager` will reset the manager to this initial state.
*
* Emits a {ManagerChanged} event.
*
* Requirements:
*
* - the caller must be the current manager for `account`.
*/
function setManager(address account, address newManager) external;
/**
* @dev Returns the manager for `account`.
*
* See {setManager}.
*/
function getManager(address account) external view returns (address);
/**
* @dev Sets the `implementer` contract as ``account``'s implementer for
* `interfaceHash`.
*
* `account` being the zero address is an alias for the caller's address.
* The zero address can also be used in `implementer` to remove an old one.
*
* See {interfaceHash} to learn how these are created.
*
* Emits an {InterfaceImplementerSet} event.
*
* Requirements:
*
* - the caller must be the current manager for `account`.
* - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not
* end in 28 zeroes).
* - `implementer` must implement {IERC1820Implementer} and return true when
* queried for support, unless `implementer` is the caller. See
* {IERC1820Implementer-canImplementInterfaceForAddress}.
*/
function setInterfaceImplementer(address account, bytes32 _interfaceHash, address implementer) external;
/**
* @dev Returns the implementer of `interfaceHash` for `account`. If no such
* implementer is registered, returns the zero address.
*
* If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28
* zeroes), `account` will be queried for support of it.
*
* `account` being the zero address is an alias for the caller's address.
*/
function getInterfaceImplementer(address account, bytes32 _interfaceHash) external view returns (address);
/**
* @dev Returns the interface hash for an `interfaceName`, as defined in the
* corresponding
* https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP].
*/
function interfaceHash(string calldata interfaceName) external pure returns (bytes32);
/**
* @notice Updates the cache with whether the contract implements an ERC165 interface or not.
* @param account Address of the contract for which to update the cache.
* @param interfaceId ERC165 interface for which to update the cache.
*/
function updateERC165Cache(address account, bytes4 interfaceId) external;
/**
* @notice Checks whether a contract implements an ERC165 interface or not.
* If the result is not cached a direct lookup on the contract address is performed.
* If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling
* {updateERC165Cache} with the contract address.
* @param account Address of the contract to check.
* @param interfaceId ERC165 interface to check.
* @return True if `account` implements `interfaceId`, false otherwise.
*/
function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool);
/**
* @notice Checks whether a contract implements an ERC165 interface or not without using or updating the cache.
* @param account Address of the contract to check.
* @param interfaceId ERC165 interface to check.
* @return True if `account` implements `interfaceId`, false otherwise.
*/
function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/BeaconProxy.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "./IBeacon.sol";
import {Proxy} from "../Proxy.sol";
import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";
/**
* @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.
*
* The beacon address can only be set once during construction, and cannot be changed afterwards. It is stored in an
* immutable variable to avoid unnecessary storage reads, and also in the beacon storage slot specified by
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] so that it can be accessed externally.
*
* CAUTION: Since the beacon address can never be changed, you must ensure that you either control the beacon, or trust
* the beacon to not upgrade the implementation maliciously.
*
* IMPORTANT: Do not use the implementation logic to modify the beacon storage slot. Doing so would leave the proxy in
* an inconsistent state where the beacon storage slot does not match the beacon address.
*/
contract BeaconProxy is Proxy {
// An immutable address for the beacon to avoid unnecessary SLOADs before each delegate call.
address private immutable _beacon;
/**
* @dev Initializes the proxy with `beacon`.
*
* If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
* will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity
* constructor.
*
* Requirements:
*
* - `beacon` must be a contract with the interface {IBeacon}.
* - If `data` is empty, `msg.value` must be zero.
*/
constructor(address beacon, bytes memory data) payable {
ERC1967Utils.upgradeBeaconToAndCall(beacon, data);
_beacon = beacon;
}
/**
* @dev Returns the current implementation address of the associated beacon.
*/
function _implementation() internal view virtual override returns (address) {
return IBeacon(_getBeacon()).implementation();
}
/**
* @dev Returns the beacon.
*/
function _getBeacon() internal view virtual returns (address) {
return _beacon;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.20;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {UpgradeableBeacon} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*/
library ERC1967Utils {
// We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
// This will be fixed in Solidity 0.8.21. At that point we should remove these events.
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev The `implementation` of the proxy is invalid.
*/
error ERC1967InvalidImplementation(address implementation);
/**
* @dev The `admin` of the proxy is invalid.
*/
error ERC1967InvalidAdmin(address admin);
/**
* @dev The `beacon` of the proxy is invalid.
*/
error ERC1967InvalidBeacon(address beacon);
/**
* @dev An upgrade function sees `msg.value > 0` that may be lost.
*/
error ERC1967NonPayable();
/**
* @dev Returns the current implementation address.
*/
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {IERC1967-AdminChanged} event.
*/
function changeAdmin(address newAdmin) internal {
emit AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
/**
* @dev Change the beacon and trigger a setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-BeaconUpgraded} event.
*
* CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
* it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
* efficiency.
*/
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
/**
* @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
* if an upgrade doesn't perform an initialization call.
*/
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol)
pragma solidity ^0.8.20;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev This is a virtual function that should be overridden so it returns the address to which the fallback
* function and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback() external payable virtual {
_fallback();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @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 or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* 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.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @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`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) 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 FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}pragma solidity >=0.5.0;
interface IUniswapV2Factory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}pragma solidity >=0.5.0;
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}pragma solidity >=0.6.2;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}pragma solidity >=0.6.2;
import './IUniswapV2Router01.sol';
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface IChainlinkV3Aggregator {
function decimals() external view returns (uint8);
function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import './IERC20.sol';
interface IERC777 is IERC20 {
event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData);
event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData);
event AuthorizedOperator(address indexed operator, address indexed holder);
event RevokedOperator(address indexed operator, address indexed holder);
event Sent(
address indexed operator,
address indexed from,
address indexed to,
uint256 amount,
bytes data,
bytes operatorData
);
function granularity() external view returns (uint256);
function defaultOperators() external view returns (address[] memory);
function isOperatorFor(address operator, address holder) external view returns (bool);
function authorizeOperator(address operator) external;
function revokeOperator(address operator) external;
function send(address to, uint256 amount, bytes calldata data) external;
function operatorSend(address from, address to, uint256 amount, bytes calldata data, bytes calldata operatorData) external;
function burn(uint256 amount, bytes calldata) external;
function operatorBurn(address from, uint256 amount, bytes calldata data, bytes calldata operatorData) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface IERC777Recipient {
function tokensReceived(
address operator,
address from,
address to,
uint256 amount,
bytes calldata userData,
bytes calldata operatorData
) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import './IVSC.sol';
interface IVOW is IVSC {
function usdRate(uint256 index) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import './IERC777.sol';
interface IVSC is IERC777 {
event LogOwnershipTransferred(address indexed oldOwner, address indexed newOwner);
event LogSkipTransferBurnSet(address indexed target, bool skipsBurn);
event LogTransferBurnSet(uint256 numVSCBurned, uint256 numVSCSent);
event LogTransferBurnApplied();
function initialize(string calldata _name, string calldata _symbol) external;
function mint(address to, uint256 amount) external;
function setOwner(address _owner) external;
function setPauseTransfers(bool pause) external;
function setSkipTransferBurn(address target, bool skipsBurn) external;
function setTransferBurn(uint256 numVSCBurned, uint256 numVSCSent) external;
function owner() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface IVSCGovernor {
struct MVD {
address t1Address;
bytes32 t2PublicKey;
uint256 deposit;
}
struct RegionData {
uint8 id;
string name;
string symbol;
address vsc;
}
struct Rate {
address vsc;
uint256 rate;
}
event LogDepositUpdated(uint256 vowAmount, uint8[] regionIDs);
event LogFeedUpdated(address indexed feed, uint8 regionID);
event LogMerchantLiquidated(address indexed merchant, uint8 regionID, uint256 vowSold, uint256 vscBurned);
event LogMerchantLocked(address indexed merchant, uint8 regionID, uint256 vowLocked, uint256 vscMinted);
event LogMerchantUnlocked(address indexed merchant, uint8 regionID, uint256 vowUnlocked, uint256 vscBurned);
event LogMVDRemoved(
address indexed t1Address,
bytes32 indexed t2PublicKey,
uint256 refunded,
uint256 forfeit,
uint8 regionID
);
event LogMVDSet(address indexed t1Address, bytes32 indexed t2PublicKey, uint256 deposit, uint8 regionID);
event LogOwnerUpdated(address indexed owner, uint8[] regionIDs);
event LogRegionAdded(string name, address indexed vscContract, uint8 regionID);
event LogPauseTransfersUpdated(bool isPaused, uint8[] regionIDs);
event LogTransferBurnUpdated(uint256[2] ratio, uint8[] regionIDs);
event LogTransferBurnWhitelistUpdated(address indexed target, bool isWhitelisted, uint8[] regionIDs);
event LogVOWToVSCWhitelistUpdated(address indexed target, bool isWhitelisted, uint8[] regionIDs);
event LogVSCMintOnLockUpdated(uint256[2] ratio, uint8[] regionIDs);
function addRegion(
string calldata name,
string calldata symbol,
uint256 initialSupply,
address feed,
uint256 rate,
uint256[2] calldata vscMintOnLock,
uint256[2] calldata transferBurn
) external returns (address vscContract);
function liquidateMerchant(address merchant, uint8 regionID, uint256 minVSCAmount, address[] calldata optionalPath) external;
function removeMVD(uint256 forfeiture, uint8 regionID) external;
function setMVD(address t1Address, bytes calldata t2PublicKey, uint8 regionID) external;
function updateConfig(
address _internalRateSetter,
uint256 _maxRatesAge,
uint256 _vowRateRefreshDelta,
uint256 _vowRateTolerance
) external;
function updateFeed(address feed, uint8 regionID) external;
function updateDeposit(uint256 vowAmount, uint8[] memory regionIDs) external;
function updateOwner(address newOwner, uint8[] calldata regionIDs) external;
function updatePauseTransfers(bool pause, uint8[] calldata regionIDs) external;
function updateRates(Rate[] calldata Rates) external;
function updateTransferBurn(uint256[2] memory ratio, uint8[] memory regionIDs) external;
function updateTransferBurnWhitelist(address target, bool whitelist, uint8[] calldata regionIDs) external;
function updateVOWToVSCWhitelist(address target, bool whitelist, uint8[] calldata regionIDs) external;
function updateVSCMintOnLock(uint256[2] memory ratio, uint8[] memory regionIDs) external;
function previewLiquidateMerchant(
address merchant,
uint8 regionID,
uint256 slippageBP,
address[] calldata optionalPath
) external view returns (uint256 vowAmount, uint256 minVSCAmount);
function regions() external view returns (RegionData[] memory);
function vscPerVOW(uint8 regionID) external view returns (uint256 amount);
}{
"optimizer": {
"enabled": true,
"runs": 2000,
"details": {
"yul": true
}
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"AddressIsZero","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"EmptyData","type":"error"},{"inputs":[],"name":"ExceedsDeposit","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"FeedOrRateOnly","type":"error"},{"inputs":[],"name":"HasExistingLock","type":"error"},{"inputs":[],"name":"IncorrectAmount","type":"error"},{"inputs":[],"name":"InvalidData","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidRate","type":"error"},{"inputs":[],"name":"InvalidRatio","type":"error"},{"inputs":[],"name":"InvalidRegion","type":"error"},{"inputs":[],"name":"InvalidT2Key","type":"error"},{"inputs":[],"name":"MissingString","type":"error"},{"inputs":[],"name":"NoExistingLock","type":"error"},{"inputs":[],"name":"NoMVDSet","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"NotUSDApplicable","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"RateIsStale","type":"error"},{"inputs":[],"name":"RateOutsideRange","type":"error"},{"inputs":[],"name":"RateSetterOnly","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"RegionMVDOnly","type":"error"},{"inputs":[],"name":"RemoveMVDFirst","type":"error"},{"inputs":[],"name":"SetRateFirst","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"inputs":[],"name":"UnknownToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"vowAmount","type":"uint256"},{"indexed":false,"internalType":"uint8[]","name":"regionIDs","type":"uint8[]"}],"name":"LogDepositUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"feed","type":"address"},{"indexed":false,"internalType":"uint8","name":"regionID","type":"uint8"}],"name":"LogFeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"t1Address","type":"address"},{"indexed":true,"internalType":"bytes32","name":"t2PublicKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"refunded","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"forfeit","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"regionID","type":"uint8"}],"name":"LogMVDRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"t1Address","type":"address"},{"indexed":true,"internalType":"bytes32","name":"t2PublicKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"deposit","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"regionID","type":"uint8"}],"name":"LogMVDSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"merchant","type":"address"},{"indexed":false,"internalType":"uint8","name":"regionID","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"vowSold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vscBurned","type":"uint256"}],"name":"LogMerchantLiquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"merchant","type":"address"},{"indexed":false,"internalType":"uint8","name":"regionID","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"vowLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vscMinted","type":"uint256"}],"name":"LogMerchantLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"merchant","type":"address"},{"indexed":false,"internalType":"uint8","name":"regionID","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"vowUnlocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vscBurned","type":"uint256"}],"name":"LogMerchantUnlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint8[]","name":"regionIDs","type":"uint8[]"}],"name":"LogOwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isPaused","type":"bool"},{"indexed":false,"internalType":"uint8[]","name":"regionIDs","type":"uint8[]"}],"name":"LogPauseTransfersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":true,"internalType":"address","name":"vscContract","type":"address"},{"indexed":false,"internalType":"uint8","name":"regionID","type":"uint8"}],"name":"LogRegionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[2]","name":"ratio","type":"uint256[2]"},{"indexed":false,"internalType":"uint8[]","name":"regionIDs","type":"uint8[]"}],"name":"LogTransferBurnUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"isWhitelisted","type":"bool"},{"indexed":false,"internalType":"uint8[]","name":"regionIDs","type":"uint8[]"}],"name":"LogTransferBurnWhitelistUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"isWhitelisted","type":"bool"},{"indexed":false,"internalType":"uint8[]","name":"regionIDs","type":"uint8[]"}],"name":"LogVOWToVSCWhitelistUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[2]","name":"ratio","type":"uint256[2]"},{"indexed":false,"internalType":"uint8[]","name":"regionIDs","type":"uint8[]"}],"name":"LogVSCMintOnLockUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"initialSupply","type":"uint256"},{"internalType":"address","name":"feed","type":"address"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256[2]","name":"vscMintOnLock","type":"uint256[2]"},{"internalType":"uint256[2]","name":"transferBurn","type":"uint256[2]"}],"name":"addRegion","outputs":[{"internalType":"address","name":"newVSC","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"feedContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vscBase","type":"address"},{"internalType":"address","name":"_vow","type":"address"},{"internalType":"address payable","name":"_vowBridge","type":"address"},{"internalType":"address","name":"_uniswapV2Router","type":"address"},{"internalType":"address","name":"_usdt","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"internalRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"internalRateSetter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"merchant","type":"address"},{"internalType":"uint8","name":"regionID","type":"uint8"},{"internalType":"uint256","name":"minVSCAmount","type":"uint256"},{"internalType":"address[]","name":"optionalPath","type":"address[]"}],"name":"liquidateMerchant","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"lockedVOWToVSC","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxRatesAge","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextRegionID","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"oneUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"merchant","type":"address"},{"internalType":"uint8","name":"regionID","type":"uint8"},{"internalType":"uint256","name":"slippageBP","type":"uint256"},{"internalType":"address[]","name":"optionalPath","type":"address[]"}],"name":"previewLiquidateMerchant","outputs":[{"internalType":"uint256","name":"vowAmount","type":"uint256"},{"internalType":"uint256","name":"minVSCAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ratesUpdatedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"regionMVD","outputs":[{"internalType":"address","name":"t1Address","type":"address"},{"internalType":"bytes32","name":"t2PublicKey","type":"bytes32"},{"internalType":"uint256","name":"deposit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"regions","outputs":[{"components":[{"internalType":"uint8","name":"id","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"address","name":"vsc","type":"address"}],"internalType":"struct IVSCGovernor.RegionData[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"forfeiture","type":"uint256"},{"internalType":"uint8","name":"regionID","type":"uint8"}],"name":"removeMVD","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"requiredVOWDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"t1Address","type":"address"},{"internalType":"bytes","name":"t2PublicKey","type":"bytes"},{"internalType":"uint8","name":"regionID","type":"uint8"}],"name":"setMVD","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"tokensReceived","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniswapV2Router","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_internalRateSetter","type":"address"},{"internalType":"uint256","name":"_maxRatesAge","type":"uint256"},{"internalType":"uint256","name":"_vowRateRefreshDelta","type":"uint256"},{"internalType":"uint256","name":"_vowRateTolerance","type":"uint256"}],"name":"updateConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vowAmount","type":"uint256"},{"internalType":"uint8[]","name":"regionIDs","type":"uint8[]"}],"name":"updateDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feed","type":"address"},{"internalType":"uint8","name":"regionID","type":"uint8"}],"name":"updateFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"},{"internalType":"uint8[]","name":"regionIDs","type":"uint8[]"}],"name":"updateOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"pause","type":"bool"},{"internalType":"uint8[]","name":"regionIDs","type":"uint8[]"}],"name":"updatePauseTransfers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"vsc","type":"address"},{"internalType":"uint256","name":"rate","type":"uint256"}],"internalType":"struct IVSCGovernor.Rate[]","name":"Rates","type":"tuple[]"}],"name":"updateRates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[2]","name":"ratio","type":"uint256[2]"},{"internalType":"uint8[]","name":"regionIDs","type":"uint8[]"}],"name":"updateTransferBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"whitelist","type":"bool"},{"internalType":"uint8[]","name":"regionIDs","type":"uint8[]"}],"name":"updateTransferBurnWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"whitelist","type":"bool"},{"internalType":"uint8[]","name":"regionIDs","type":"uint8[]"}],"name":"updateVOWToVSCWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[2]","name":"ratio","type":"uint256[2]"},{"internalType":"uint8[]","name":"regionIDs","type":"uint8[]"}],"name":"updateVSCMintOnLock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"vow","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vowBridge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vowRateRefreshDelta","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vowRateTolerance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"vowToVSCWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vowUSDTPair","outputs":[{"internalType":"contract IUniswapV2Pair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vscBase","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"vscContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"vscMintOnLockRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"regionID","type":"uint8"}],"name":"vscPerVOW","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"vscRegion","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60a06040523060805234801561001457600080fd5b5061001d610022565b6100d4565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff16156100725760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146100d15780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b608051615d3f6100fd6000396000818161384b015281816138740152613a290152615d3f6000f3fe6080604052600436106103125760003560e01c80636588fcb01161019a578063ad3cb1cc116100e1578063e4459dcf1161008a578063f2fde38b11610064578063f2fde38b146109b1578063f3b8212b146109d1578063f7c0b612146109f157600080fd5b8063e4459dcf14610943578063e5753f6a14610970578063f23a617c1461099057600080fd5b8063d8c0869d116100bb578063d8c0869d146108df578063ddf2438314610901578063e30c39781461092e57600080fd5b8063ad3cb1cc14610833578063b6e22a1414610889578063d19172a8146108bf57600080fd5b80637a36b249116101435780638da5cb5b1161011d5780638da5cb5b146107c95780639187e15a146107de5780639abca73b1461081357600080fd5b80637a36b2491461073e5780638abaed96146107895780638c8087b2146107a957600080fd5b8063715018a611610174578063715018a6146106f457806379ba50971461070957806379d48e441461071e57600080fd5b80636588fcb01461069e578063674b5098146106be57806370a21439146106d457600080fd5b8063319aab031161025e5780635174f359116102075780635dd84c97116101e15780635dd84c971461063e57806360b250231461065e578063626cb3c51461067e57600080fd5b80635174f359146105f357806352d1902d1461061357806355bdcc9b1461062857600080fd5b806344ce1c151161023857806344ce1c151461058a57806345bb4b3e146105aa5780634f1ef286146105e057600080fd5b8063319aab031461051d57806334f16d961461053d5780633f98fc071461056a57600080fd5b8063157f5c26116102c05780632019e14f1161029a5780632019e14f146104bd578063265dcefb146104dd5780632bf5909c146104fd57600080fd5b8063157f5c26146104455780631694505e1461047d5780631f25a2d81461049d57600080fd5b80631179561d116102f15780631179561d146103cd5780631459457a1461040f5780631509fe9d1461042f57600080fd5b806223de291461031757806307002dd7146103395780630755be73146103a9575b600080fd5b34801561032357600080fd5b506103376103323660046146e4565b610a11565b005b34801561034557600080fd5b5061037f61035436600461479a565b6005602052600090815260409020805460018201546002909201546001600160a01b03909116919083565b604080516001600160a01b0390941684526020840192909252908201526060015b60405180910390f35b3480156103b557600080fd5b506103bf600b5481565b6040519081526020016103a0565b3480156103d957600080fd5b506103fd6103e836600461479a565b60096020526000908152604090205460ff1681565b60405160ff90911681526020016103a0565b34801561041b57600080fd5b5061033761042a3660046147b7565b610c07565b34801561043b57600080fd5b506103bf600e5481565b34801561045157600080fd5b50610465610460366004614839565b611053565b6040516001600160a01b0390911681526020016103a0565b34801561048957600080fd5b50600f54610465906001600160a01b031681565b3480156104a957600080fd5b506103376104b83660046148f6565b611533565b3480156104c957600080fd5b506103376104d8366004614984565b6115e4565b3480156104e957600080fd5b506103376104f83660046149d9565b611702565b34801561050957600080fd5b50610337610518366004614a50565b611851565b34801561052957600080fd5b506103bf610538366004614a70565b6119b5565b34801561054957600080fd5b506103bf61055836600461479a565b60086020526000908152604090205481565b34801561057657600080fd5b50610337610585366004614a9c565b6119da565b34801561059657600080fd5b50601454610465906001600160a01b031681565b3480156105b657600080fd5b506104656105c536600461479a565b6007602052600090815260409020546001600160a01b031681565b6103376105ee366004614b3e565b611aa6565b3480156105ff57600080fd5b506103bf61060e366004614bd1565b611ac5565b34801561061f57600080fd5b506103bf611af7565b34801561063457600080fd5b506103bf600c5481565b34801561064a57600080fd5b50610337610659366004614cb6565b611b26565b34801561066a57600080fd5b50610337610679366004614d5d565b611c7e565b34801561068a57600080fd5b50601154610465906001600160a01b031681565b3480156106aa57600080fd5b506103376106b9366004614d96565b611e99565b3480156106ca57600080fd5b506103bf600d5481565b3480156106e057600080fd5b506103bf6106ef366004614e09565b612240565b34801561070057600080fd5b506103376122bc565b34801561071557600080fd5b506103376122c6565b34801561072a57600080fd5b50610337610739366004614e26565b61232c565b34801561074a57600080fd5b50610779610759366004614e4b565b600260209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016103a0565b34801561079557600080fd5b50601354610465906001600160a01b031681565b3480156107b557600080fd5b50601254610465906001600160a01b031681565b3480156107d557600080fd5b506104656125f2565b3480156107ea57600080fd5b506107fe6107f9366004614d96565b612627565b604080519283526020830191909152016103a0565b34801561081f57600080fd5b5061033761082e366004614e79565b612680565b34801561083f57600080fd5b5061087c6040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516103a09190614f2e565b34801561089557600080fd5b506104656108a4366004614e09565b600a602052600090815260409020546001600160a01b031681565b3480156108cb57600080fd5b506103376108da366004614cb6565b6127d6565b3480156108eb57600080fd5b506108f46128b5565b6040516103a09190614f41565b34801561090d57600080fd5b506103bf61091c36600461479a565b60066020526000908152604090205481565b34801561093a57600080fd5b50610465612ad9565b34801561094f57600080fd5b506103bf61095e36600461479a565b60046020526000908152604090205481565b34801561097c57600080fd5b5061033761098b36600461500c565b612b02565b34801561099c57600080fd5b506014546103fd90600160a01b900460ff1681565b3480156109bd57600080fd5b506103376109cc36600461479a565b612d70565b3480156109dd57600080fd5b506103376109ec366004614e79565b612df5565b3480156109fd57600080fd5b50601054610465906001600160a01b031681565b610a19612f11565b60005460ff16610bd4573360008181526009602052604090205460ff1615610a4e57610a488189888888612f92565b50610bd4565b6011546001600160a01b03828116911614610a95576040517f8698bf3700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000849003610ad0576040517f99d8fec900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060208611610aee57610ae78688018861479a565b6000610afa565b610afa86880188614e4b565b6001600160a01b03821660009081526009602052604081205492945090925060ff9091169003610b3d576040516397fa436960e01b815260040160405180910390fd5b6001600160a01b038083166000908152600560205260409020548b82169116148015610b7157506001600160a01b03811615155b15610b8957610b818289836131ca565b505050610bd4565b6001600160a01b038116610ba257610b818a8984613454565b6040517f5cb045db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bfd60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050505050505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff16600081158015610c525750825b905060008267ffffffffffffffff166001148015610c6f5750303b155b905081158015610c7d575080155b15610cb4576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315610cff57845468ff00000000000000001916680100000000000000001785555b610d08336135f7565b610d10613608565b610d18613608565b610d20613610565b6001600160a01b038a161580610d3d57506001600160a01b038916155b80610d4f57506001600160a01b038816155b80610d6157506001600160a01b038716155b80610d7357506001600160a01b038616155b15610d915760405163867915ab60e01b815260040160405180910390fd5b601380546001600160a01b03808d166001600160a01b031992831617909255601180548c8416908316179055601280548b8416908316179055600f8054928a169290911682179055604080517fc45a0155000000000000000000000000000000000000000000000000000000008152905163c45a0155916004818101926020929091908290030181865afa158015610e2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e519190615074565b6011546040517fe6a439050000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152888216602482015291169063e6a4390590604401602060405180830381865afa158015610ebb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610edf9190615074565b601080546001600160a01b0319166001600160a01b039290921691909117905560148054600160a01b7fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff9091161790556040517f29965a1d00000000000000000000000000000000000000000000000000000000815230600482018190527fb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b60248301526044820152731820a4b7618bde71dce8cdc73aab6c95905fad24906329965a1d90606401600060405180830381600087803b158015610fc157600080fd5b505af1158015610fd5573d6000803e3d6000fd5b5050601480546001600160a01b03191633179055505062015180600d55607d600b5560fa600c55831561104757845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050565b600061105d613620565b881580611068575086155b1561109f576040517fbd442c0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60148054600091600160a01b90910460ff1690806110bc836150a7565b91906101000a81548160ff021916908360ff16021790555090506110e581600160ff9091161490565b1561113c576001600160a01b03861615158061110057508415155b15611137576040517f22d01ec500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611180565b84156001600160a01b0387161503611180576040517f1c206bd500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6013546040516000916001600160a01b0316907f4cd88b7600000000000000000000000000000000000000000000000000000000906111c9908f908f908f908f906024016150f1565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161123390614608565b61123e929190615123565b604051809103906000f08015801561125a573d6000803e3d6000fd5b5060ff83166000818152600a6020908152604080832080546001600160a01b0319166001600160a01b038716908117909155835260098252808320805460ff19169094179093558251600180825281850190945293965086945090929190828101908036833701905050905082816000815181106112da576112da615145565b60ff9290921660209283029190910190910152604051637ed81ccf60e11b8152306004820152600160248201526001600160a01b0385169063fdb0399e90604401600060405180830381600087803b15801561133557600080fd5b505af1158015611349573d6000803e3d6000fd5b5050601254604051637ed81ccf60e11b81526001600160a01b03918216600482015260016024820152908716925063fdb0399e9150604401600060405180830381600087803b15801561139b57600080fd5b505af11580156113af573d6000803e3d6000fd5b50506040805180820182526113e19350915087906002908390839080828437600092019190915250849150611b269050565b60408051808201825261140e91889060029083908390808284376000920191909152508491506127d69050565b6001600160a01b038816611449576001600160a01b0384166000908152600860205260408120889055600e5490036114455742600e555b3097505b60ff831660011461145e5761145e8884611c7e565b88156114de576040517f40c10f19000000000000000000000000000000000000000000000000000000008152336004820152602481018a90526001600160a01b038516906340c10f1990604401600060405180830381600087803b1580156114c557600080fd5b505af11580156114d9573d6000803e3d6000fd5b505050505b836001600160a01b03167f527bb35a63311a579e081d540028e25768c0825da90cefe051b27e1625bbeb438e8e8660405161151b9392919061515b565b60405180910390a25050509998505050505050505050565b61153b613620565b6001600160a01b0384161561156657601480546001600160a01b0319166001600160a01b0386161790555b821561157257600d8390555b612710821180611583575061271081115b156115a15760405163648564d360e01b815260040160405180910390fd5b81156115ad57600b8290555b80156115b957600c8190555b600c54600b5411156115de57604051636a43f8d160e01b815260040160405180910390fd5b50505050565b6115ec613620565b60008061162b84848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061366b92505050565b9150915060005b82518110156116c15782818151811061164d5761164d615145565b60200260200101516001600160a01b031663ec95ca00876040518263ffffffff1660e01b8152600401611684911515815260200190565b600060405180830381600087803b15801561169e57600080fd5b505af11580156116b2573d6000803e3d6000fd5b50505050806001019050611632565b507f3352c669dce7afa6b0290db8b2b7ab31a285d07af4bfcfc8d03c431046517ced85826040516116f39291906151c1565b60405180910390a15050505050565b6014546001600160a01b03163314611746576040517fbbfa05da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8181101561184857600083838381811061176557611765615145565b61177b926020604090920201908101915061479a565b6001600160a01b0316036117a25760405163867915ab60e01b815260040160405180910390fd5b8282828181106117b4576117b4615145565b905060400201602001356000036117de57604051636a43f8d160e01b815260040160405180910390fd5b8282828181106117f0576117f0615145565b905060400201602001356008600085858581811061181057611810615145565b611826926020604090920201908101915061479a565b6001600160a01b03168152602081019190915260400160002055600101611749565b505042600e5550565b611859613620565b6001600160a01b0383166118805760405163867915ab60e01b815260040160405180910390fd5b6000806118bf84848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061366b92505050565b9150915060005b825181101561196c578281815181106118e1576118e1615145565b60209081029190910101516040517f13af40350000000000000000000000000000000000000000000000000000000081526001600160a01b038881166004830152909116906313af403590602401600060405180830381600087803b15801561194957600080fd5b505af115801561195d573d6000803e3d6000fd5b505050508060010190506118c6565b50846001600160a01b03167fc049d66516b85609e058a9427e73d12f66ae3c2bc5e1c7060ba6b1ddd06e8fc8826040516119a691906151dc565b60405180910390a25050505050565b600360205281600052604060002081600281106119d157600080fd5b01549150829050565b6119e2613620565b600080611a2184848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061366b92505050565b9150915060005b8251811015611a74578560066000858481518110611a4857611a48615145565b6020908102919091018101516001600160a01b0316825281019190915260400160002055600101611a28565b507fe6076479bcacbd9563f9b52d33095130e54c4df7d6b9be809607f0ebc9f71b9985826040516116f39291906151ef565b611aae613840565b611ab782613910565b611ac18282613918565b5050565b60016020528260005260406000206020528160005260406000208160028110611aed57600080fd5b0154925083915050565b6000611b01613a1e565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b611b2e613620565b60208201511580611b43575060208201518251115b15611b615760405163648564d360e01b815260040160405180910390fd5b600080611b6d8361366b565b9150915060005b8251811015611c3e57828181518110611b8f57611b8f615145565b60200260200101516001600160a01b03166335cd5b8f86600060028110611bb857611bb8615145565b602002015187600160200201516040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815260048101929092526024820152604401600060405180830381600087803b158015611c1b57600080fd5b505af1158015611c2f573d6000803e3d6000fd5b50505050806001019050611b74565b507f35ce4f39b55b486963f90530939380436949efccee28e59c3e9199ae8603870e8482604051611c70929190615208565b60405180910390a150505050565b611c86613620565b6001600160a01b038216611cad5760405163867915ab60e01b815260040160405180910390fd5b60ff81166000908152600a60205260409020546001600160a01b031680611ce7576040516397fa436960e01b815260040160405180910390fd5b60ff8216600103611d24576040517f22d01ec500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b306001600160a01b03841603611da9576001600160a01b0381166000908152600860205260408120549003611d85576040517f539a7b4a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03811660009081526004602052604090206305f5e1009055611e30565b826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611de7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e0b9190615244565b611e1690600a615348565b6001600160a01b0382166000908152600460205260409020555b6001600160a01b0381811660009081526007602090815260409182902080546001600160a01b0319169387169384179055905160ff851681527f0965bd7b617d4cd98408a68f5c8ef655b8161502769cabd6832b4a584eb57edb910160405180910390a2505050565b60ff84166000908152600a60205260409020546001600160a01b031680611ed3576040516397fa436960e01b815260040160405180910390fd5b6001600160a01b03818116600090815260056020526040902054163314611f26576040517faae19bbd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038181166000908152600160209081526040808320938a1683529290529081205490819003611f88576040517fad9f423f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038083166000908152600160208181526040808420948c16845293905291812081815590910155601154600f546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526024810184905291169063095ea7b3906044016020604051808303816000875af1158015612024573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120489190615357565b506000612056838686613a80565b6000805460ff19166001179055600f549091506001600160a01b03166338ed17398388843061208642603c615374565b6040518663ffffffff1660e01b81526004016120a69594939291906153c2565b6000604051808303816000875af11580156120c5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120ed91908101906153fe565b506000805460ff191681556040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038516906370a0823190602401602060405180830381865afa158015612155573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121799190615494565b6040805163fe9d930360e01b8152600481018390526024810191909152600060448201529091506001600160a01b0385169063fe9d930390606401600060405180830381600087803b1580156121ce57600080fd5b505af11580156121e2573d6000803e3d6000fd5b50506040805160ff8c168152602081018790529081018490526001600160a01b038c1692507f863f92abaf7349d98b537d0e73acaf4faff5b548a2c1ff5e4026a5445577b22c915060600160405180910390a2505050505050505050565b60ff81166000908152600a60205260408120546001600160a01b03168061227a576040516397fa436960e01b815260040160405180910390fd5b600061228d612287613bcb565b83613cc2565b60208101518151919250906122aa90670de0b6b3a76400006154ad565b6122b491906154c4565b949350505050565b6122c4613620565b565b33806122d0612ad9565b6001600160a01b031614612320576040517f118cdaa70000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024015b60405180910390fd5b61232981613d29565b50565b612334613620565b60ff81166000908152600a60205260409020546001600160a01b03168061236e576040516397fa436960e01b815260040160405180910390fd5b6001600160a01b0380821660009081526005602052604090205416806123c0576040517f8109696c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03821660009081526005602052604090206002015480851115612416576040517f9290475f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316600090815260056020526040812060018101805482546001600160a01b03191683559083905560029091019190915585156124fe5760115491869003916001600160a01b031663a9059cbb6124736125f2565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602481018990526044016020604051808303816000875af11580156124d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124fc9190615357565b505b8115612596576011546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038581166004830152602482018590529091169063a9059cbb906044016020604051808303816000875af1158015612570573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125949190615357565b505b604080518381526020810188905260ff87169181019190915281906001600160a01b038516907f6e94ba4ab6e2cda709fb3b448470e7c53427d9416531ec3b4053db13825e6298906060015b60405180910390a3505050505050565b6000807f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005b546001600160a01b031692915050565b60ff84166000908152600a60209081526040808320546001600160a01b0390811680855260018452828520918a16855292528220549190612673838761266e848989613a80565b613d61565b9150509550959350505050565b612688613620565b6001600160a01b0384166126af5760405163867915ab60e01b815260040160405180910390fd5b6000806126ee84848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061366b92505050565b9150915060005b825181101561278a5782818151811061271057612710615145565b6020908102919091010151604051637ed81ccf60e11b81526001600160a01b03898116600483015288151560248301529091169063fdb0399e90604401600060405180830381600087803b15801561276757600080fd5b505af115801561277b573d6000803e3d6000fd5b505050508060010190506126f5565b50856001600160a01b03167f72f3a174b41131b9c154d829a90b99db5577f6929eb580257255278632884b5e86836040516127c69291906151c1565b60405180910390a2505050505050565b6127de613620565b602082015115806127f3575081516020830151115b156128115760405163648564d360e01b815260040160405180910390fd5b60008061281d8361366b565b9150915060005b825181101561288357846003600085848151811061284457612844615145565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002090600261287a929190614615565b50600101612824565b507ff7924680f54e75bd67fade3ebebc8fbca96a2bc00c83df1bd970c33df97a63b98482604051611c70929190615208565b60606000600160148054906101000a900460ff166128d391906154e6565b905060008160ff1667ffffffffffffffff8111156128f3576128f3614acf565b60405190808252806020026020018201604052801561295b57816020015b6129486040518060800160405280600060ff168152602001606081526020016060815260200160006001600160a01b031681525090565b8152602001906001900390816129115790505b50905060008060005b8460ff168160ff161015612acf5761297d8160016154ff565b60ff81166000818152600a6020908152604080832054815160808101835294855281517f06fdde0300000000000000000000000000000000000000000000000000000000815291516001600160a01b03909116985094965092939084019287926306fdde03926004808401938290030181865afa158015612a02573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612a2a9190810190615518565b8152602001846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612a6d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612a959190810190615518565b8152602001846001600160a01b0316815250848260ff1681518110612abc57612abc615145565b6020908102919091010152600101612964565b5091949350505050565b6000807f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00612617565b612b0a613620565b60ff81166000908152600a60205260409020546001600160a01b031680612b44576040516397fa436960e01b815260040160405180910390fd5b6001600160a01b038181166000908152600560205260409020541615612b96576040517fc8483e4c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038516612bbd5760405163867915ab60e01b815260040160405180910390fd5b60208314612bf7576040517ff4fc87a400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0381166000908152600660205260409020548015612cc5576000805460ff191660011790556011546040517f23b872dd0000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015230602483015260448201849052909116906323b872dd906064016020604051808303816000875af1158015612c95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cb99190615357565b506000805460ff191690555b6001600160a01b03828116600090815260056020526040902080546001600160a01b031916918816919091179055612cfd8486615586565b6001600160a01b03831660009081526005602052604090206001810191909155600201819055612d2d8486615586565b6040805183815260ff861660208201526001600160a01b038916917fae1336e1e0ec5d0d50d43727edbe2012a896a76f9664678e56b7dcfe30b0448891016125e2565b612d78613620565b7f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c0080546001600160a01b0319166001600160a01b0383169081178255612dbc6125f2565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a35050565b612dfd613620565b6001600160a01b038416612e245760405163867915ab60e01b815260040160405180910390fd5b600080612e6384848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061366b92505050565b9150915060005b8251811015612ed5578560026000858481518110612e8a57612e8a615145565b6020908102919091018101516001600160a01b0390811683528282019390935260409182016000908120938c1681529290529020805460ff1916911515919091179055600101612e6a565b50856001600160a01b03167f3bff0fe9289946d0ecd18435d733b69a8f4dfd3ef86cf915f5c127f01f9a343986836040516127c69291906151c1565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0080547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01612f8c576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60029055565b6000612fa086868585613e57565b6001600160a01b0380881660009081526001602090815260408083209385168352929052908120919250810154600003613006576040517fad9f423f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84816001015414613043576040517f69640e7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038881166000818152600160208181526040808420958916845294905283822082815501819055825163fe9d930360e01b8152600481018a9052602481019390935260448301529063fe9d930390606401600060405180830381600087803b1580156130b757600080fd5b505af11580156130cb573d6000803e3d6000fd5b50506011546040517f9bd9bbc60000000000000000000000000000000000000000000000000000000081526001600160a01b0387811660048301526024820186905260606044830152600060648301529091169250639bd9bbc69150608401600060405180830381600087803b15801561314457600080fd5b505af1158015613158573d6000803e3d6000fd5b505050506001600160a01b0388811660009081526009602090815260409182902054825160ff9091168152908101849052908101889052908416907f4d50a22e3094438c1381f48fe67a298bb630ed8cdc7bbdf4d569c31dcd6f6b9f9060600160405180910390a25050505050505050565b6001600160a01b0383811660009081526001602090815260408083209385168352929052205415613227576040517f4e8feca700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0383166000908152600360205260408082208151808301928390529160029082845b8154815260200190600101908083116132505750505050509050600061327d613277613bcb565b86613cc2565b6020808201519084015191925060009161329791906154ad565b835183516132a590886154ad565b6132af91906154ad565b6132b991906154c4565b6001600160a01b0387811660008181526001602081815260408084208b8716855282528084208c815590920186905583835260059052908190205490517f40c10f1900000000000000000000000000000000000000000000000000000000815292166004830152602482018390529192506340c10f1990604401600060405180830381600087803b15801561334d57600080fd5b505af1158015613361573d6000803e3d6000fd5b505050506001600160a01b038681166000818152600560205260409020805460125460019092015492936362ad1b839391811692169085906133a290613edb565b6040518563ffffffff1660e01b81526004016133c194939291906155a4565b600060405180830381600087803b1580156133db57600080fd5b505af11580156133ef573d6000803e3d6000fd5b505050506001600160a01b0386811660009081526009602090815260409182902054825160ff9091168152908101889052908101839052908516907f7e400ef539cd0a4d6440201d8de383e56d7007ca2986d6d33b458ce2ae03d0f4906060016127c6565b6001600160a01b0380821660009081526002602090815260408083209387168352929052205460ff166134b3576040517fea8e4eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011546040805163fe9d930360e01b8152600481018590526024810191909152600060448201526001600160a01b039091169063fe9d930390606401600060405180830381600087803b15801561350957600080fd5b505af115801561351d573d6000803e3d6000fd5b50505050600061352e612287613bcb565b602081015181519192506001600160a01b038416916340c10f1991879161355590886154ad565b61355f91906154c4565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156135bd57600080fd5b505af1158015610bfd573d6000803e3d6000fd5b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6135ff613f0c565b61232981613f73565b6122c4613f0c565b613618613f0c565b6122c4613fbe565b336136296125f2565b6001600160a01b0316146122c4576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401612317565b60608060008351600014613680578351613699565b60145461369990600190600160a01b900460ff166154e6565b905060008160ff1667ffffffffffffffff8111156136b9576136b9614acf565b6040519080825280602002602001820160405280156136e2578160200160208202803683370190505b50905060008260ff1667ffffffffffffffff81111561370357613703614acf565b60405190808252806020026020018201604052801561372c578160200160208202803683370190505b50905060015b8360ff168160ff1611613834576000875160001461377657876137566001846154e6565b60ff168151811061376957613769615145565b6020026020010151613778565b815b60ff81166000908152600a60205260409020549091506001600160a01b0316806137b5576040516397fa436960e01b815260040160405180910390fd5b80856137c26001866154e6565b60ff16815181106137d5576137d5615145565b6001600160a01b039092166020928302919091019091015281846137fa6001866154e6565b60ff168151811061380d5761380d615145565b602002602001019060ff16908160ff168152505050508061382d906150a7565b9050613732565b50909590945092505050565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806138d957507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166138cd7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6001600160a01b031614155b156122c4576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612329613620565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015613972575060408051601f3d908101601f1916820190925261396f91810190615494565b60015b6139b3576040517f4c9c8ce30000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401612317565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114613a0f576040517faa1d49a400000000000000000000000000000000000000000000000000000000815260048101829052602401612317565b613a198383613fc6565b505050565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146122c4576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60606000613a8f836002615374565b90508067ffffffffffffffff811115613aaa57613aaa614acf565b604051908082528060200260200182016040528015613ad3578160200160208202803683370190505b5060115481519193506001600160a01b0316908390600090613af757613af7615145565b60200260200101906001600160a01b031690816001600160a01b03168152505060005b83811015613b8557848482818110613b3457613b34615145565b9050602002016020810190613b49919061479a565b83613b55836001615374565b81518110613b6557613b65615145565b6001600160a01b0390921660209283029190910190910152600101613b1a565b508482613b936001846155f7565b81518110613ba357613ba3615145565b60200260200101906001600160a01b031690816001600160a01b031681525050509392505050565b613bd3614653565b600080601060009054906101000a90046001600160a01b03166001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015613c29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4d919061562d565b506dffffffffffffffffffffffffffff80831686529193509150613c799064e8d4a510009083166154ad565b6020840152613c878361401c565b613cbd576040517f418dc4df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505090565b613cca614653565b6000613cd58361419d565b9050604051806040016040528085600160028110613cf557613cf5615145565b60200201518351613d0691906154ad565b81528551602084810151920191613d1d91906154ad565b90529150505b92915050565b7f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c0080546001600160a01b0319168155611ac1826142a1565b600f546040517fd06ca61f00000000000000000000000000000000000000000000000000000000815260009182916001600160a01b039091169063d06ca61f90613db1908890879060040161567d565b600060405180830381865afa158015613dce573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613df691908101906153fe565b905060008160018351613e0991906155f7565b81518110613e1957613e19615145565b6020026020010151905060006127108683613e3491906154ad565b613e3e91906154c4565b9050613e4a81836155f7565b93505050505b9392505050565b6001600160a01b03848116600090815260016020908152604080832093871683529290529081205415613e8b5750826122b4565b6000829003613ec6576040517f99d8fec900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613ed28284018461479a565b95945050505050565b6040805160208082528183019092526060916000919060208201818036833750505060208101939093525090919050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff166122c4576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613f7b613f0c565b6001600160a01b038116612320576040517f1e4fbdf700000000000000000000000000000000000000000000000000000000815260006004820152602401612317565b6135d1613f0c565b613fcf82614312565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a280511561401457613a1982826143a2565b611ac161440f565b60008082600160200201516011546040517f6f54ed75000000000000000000000000000000000000000000000000000000008152600060048201526001600160a01b0390911690636f54ed7590602401602060405180830381865afa158015614089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140ad9190615494565b6140b791906154ad565b6011546040517f6f54ed75000000000000000000000000000000000000000000000000000000008152600160048201529192506000916001600160a01b0390911690636f54ed7590602401602060405180830381865afa15801561411f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141439190615494565b845161414f91906154ad565b905060008282116141695761416482846155f7565b614173565b61417383836155f7565b9050600083614184612710846154ad565b61418e91906154c4565b600c5410159695505050505050565b6141a5614653565b6001600160a01b03821660009081526009602052604090205460ff166001036141e4575050604080518082019091526305f5e100808252602082015290565b6001600160a01b0380831660009081526004602090815260408083205460079092528220549092169030820361427c57600d54600e546142249190615374565b42111561425d576040517f4fbd1cb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506001600160a01b038416600090815260086020526040902054614288565b61428582614447565b90505b6040805180820190915292835260208301525092915050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b806001600160a01b03163b600003614361576040517f4c9c8ce30000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401612317565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b0316846040516143bf9190615696565b600060405180830381855af49150503d80600081146143fa576040519150601f19603f3d011682016040523d82523d6000602084013e6143ff565b606091505b5091509150613ed2858383614551565b34156122c4576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000806000856001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561448d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144b191906156cc565b94509450509350935062015180826144c99190615374565b421115614502576040517f4fbd1cb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083128061452957508069ffffffffffffffffffff168469ffffffffffffffffffff1614155b1561454757604051636a43f8d160e01b815260040160405180910390fd5b5090949350505050565b60608261456657614561826145c6565b613e50565b815115801561457d57506001600160a01b0384163b155b156145bf576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401612317565b5080613e50565b8051156145d65780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105eb8061571f83390190565b8260028101928215614643579160200282015b82811115614643578251825591602001919060010190614628565b5061464f929150614671565b5090565b60405180604001604052806002906020820280368337509192915050565b5b8082111561464f5760008155600101614672565b6001600160a01b038116811461232957600080fd5b60008083601f8401126146ad57600080fd5b50813567ffffffffffffffff8111156146c557600080fd5b6020830191508360208285010111156146dd57600080fd5b9250929050565b60008060008060008060008060c0898b03121561470057600080fd5b883561470b81614686565b9750602089013561471b81614686565b9650604089013561472b81614686565b955060608901359450608089013567ffffffffffffffff81111561474e57600080fd5b61475a8b828c0161469b565b90955093505060a089013567ffffffffffffffff81111561477a57600080fd5b6147868b828c0161469b565b999c989b5096995094979396929594505050565b6000602082840312156147ac57600080fd5b8135613e5081614686565b600080600080600060a086880312156147cf57600080fd5b85356147da81614686565b945060208601356147ea81614686565b935060408601356147fa81614686565b9250606086013561480a81614686565b9150608086013561481a81614686565b809150509295509295909350565b8060408101831015613d2357600080fd5b60008060008060008060008060006101208a8c03121561485857600080fd5b893567ffffffffffffffff81111561486f57600080fd5b61487b8c828d0161469b565b909a5098505060208a013567ffffffffffffffff81111561489b57600080fd5b6148a78c828d0161469b565b90985096505060408a0135945060608a01356148c281614686565b935060808a013592506148d88b60a08c01614828565b91506148e78b60e08c01614828565b90509295985092959850929598565b6000806000806080858703121561490c57600080fd5b843561491781614686565b966020860135965060408601359560600135945092505050565b801515811461232957600080fd5b60008083601f84011261495157600080fd5b50813567ffffffffffffffff81111561496957600080fd5b6020830191508360208260051b85010111156146dd57600080fd5b60008060006040848603121561499957600080fd5b83356149a481614931565b9250602084013567ffffffffffffffff8111156149c057600080fd5b6149cc8682870161493f565b9497909650939450505050565b600080602083850312156149ec57600080fd5b823567ffffffffffffffff811115614a0357600080fd5b8301601f81018513614a1457600080fd5b803567ffffffffffffffff811115614a2b57600080fd5b8560208260061b8401011115614a4057600080fd5b6020919091019590945092505050565b600080600060408486031215614a6557600080fd5b83356149a481614686565b60008060408385031215614a8357600080fd5b8235614a8e81614686565b946020939093013593505050565b600080600060408486031215614ab157600080fd5b83359250602084013567ffffffffffffffff8111156149c057600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614b0e57614b0e614acf565b604052919050565b600067ffffffffffffffff821115614b3057614b30614acf565b50601f01601f191660200190565b60008060408385031215614b5157600080fd5b8235614b5c81614686565b9150602083013567ffffffffffffffff811115614b7857600080fd5b8301601f81018513614b8957600080fd5b8035614b9c614b9782614b16565b614ae5565b818152866020838501011115614bb157600080fd5b816020840160208301376000602083830101528093505050509250929050565b600080600060608486031215614be657600080fd5b8335614bf181614686565b92506020840135614c0181614686565b929592945050506040919091013590565b600067ffffffffffffffff821115614c2c57614c2c614acf565b5060051b60200190565b60ff8116811461232957600080fd5b600082601f830112614c5657600080fd5b8135614c64614b9782614c12565b8082825260208201915060208360051b860101925085831115614c8657600080fd5b602085015b83811015614cac578035614c9e81614c36565b835260209283019201614c8b565b5095945050505050565b60008060608385031215614cc957600080fd5b83601f840112614cd857600080fd5b6040805190810167ffffffffffffffff81118282101715614cfb57614cfb614acf565b8060405250806040850186811115614d1257600080fd5b855b81811015614d2c578035835260209283019201614d14565b50919350503567ffffffffffffffff811115614d4757600080fd5b614d5385828601614c45565b9150509250929050565b60008060408385031215614d7057600080fd5b8235614d7b81614686565b91506020830135614d8b81614c36565b809150509250929050565b600080600080600060808688031215614dae57600080fd5b8535614db981614686565b94506020860135614dc981614c36565b935060408601359250606086013567ffffffffffffffff811115614dec57600080fd5b614df88882890161493f565b969995985093965092949392505050565b600060208284031215614e1b57600080fd5b8135613e5081614c36565b60008060408385031215614e3957600080fd5b823591506020830135614d8b81614c36565b60008060408385031215614e5e57600080fd5b8235614e6981614686565b91506020830135614d8b81614686565b60008060008060608587031215614e8f57600080fd5b8435614e9a81614686565b93506020850135614eaa81614931565b9250604085013567ffffffffffffffff811115614ec657600080fd5b614ed28782880161493f565b95989497509550505050565b60005b83811015614ef9578181015183820152602001614ee1565b50506000910152565b60008151808452614f1a816020860160208601614ede565b601f01601f19169290920160200192915050565b602081526000613e506020830184614f02565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015615000577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0878603018452815160ff8151168652602081015160806020880152614fba6080880182614f02565b905060408201518782036040890152614fd38282614f02565b6060938401516001600160a01b031698909301979097525094506020938401939190910190600101614f69565b50929695505050505050565b6000806000806060858703121561502257600080fd5b843561502d81614686565b9350602085013567ffffffffffffffff81111561504957600080fd5b6150558782880161469b565b909450925050604085013561506981614c36565b939692955090935050565b60006020828403121561508657600080fd5b8151613e5081614686565b634e487b7160e01b600052601160045260246000fd5b600060ff821660ff81036150bd576150bd615091565b60010192915050565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b6040815260006151056040830186886150c6565b82810360208401526151188185876150c6565b979650505050505050565b6001600160a01b03831681526040602082015260006122b46040830184614f02565b634e487b7160e01b600052603260045260246000fd5b60408152600061516f6040830185876150c6565b905060ff83166020830152949350505050565b600081518084526020840193506020830160005b828110156151b757815160ff16865260209586019590910190600101615196565b5093949350505050565b82151581526040602082015260006122b46040830184615182565b602081526000613e506020830184615182565b8281526040602082015260006122b46040830184615182565b60008184825b600281101561522d57815183526020928301929091019060010161520e565b505050606060408301526122b46060830184615182565b60006020828403121561525657600080fd5b8151613e5081614c36565b6001815b600184111561529c5780850481111561528057615280615091565b600184161561528e57908102905b60019390931c928002615265565b935093915050565b6000826152b357506001613d23565b816152c057506000613d23565b81600181146152d657600281146152e0576152fc565b6001915050613d23565b60ff8411156152f1576152f1615091565b50506001821b613d23565b5060208310610133831016604e8410600b841016171561531f575081810a613d23565b61532c6000198484615261565b806000190482111561534057615340615091565b029392505050565b6000613e5060ff8416836152a4565b60006020828403121561536957600080fd5b8151613e5081614931565b80820180821115613d2357613d23615091565b600081518084526020840193506020830160005b828110156151b75781516001600160a01b031686526020958601959091019060010161539b565b85815284602082015260a0604082015260006153e160a0830186615387565b6001600160a01b0394909416606083015250608001529392505050565b60006020828403121561541057600080fd5b815167ffffffffffffffff81111561542757600080fd5b8201601f8101841361543857600080fd5b8051615446614b9782614c12565b8082825260208201915060208360051b85010192508683111561546857600080fd5b6020840193505b8284101561548a57835182526020938401939091019061546f565b9695505050505050565b6000602082840312156154a657600080fd5b5051919050565b8082028115828204841417613d2357613d23615091565b6000826154e157634e487b7160e01b600052601260045260246000fd5b500490565b60ff8281168282160390811115613d2357613d23615091565b60ff8181168382160190811115613d2357613d23615091565b60006020828403121561552a57600080fd5b815167ffffffffffffffff81111561554157600080fd5b8201601f8101841361555257600080fd5b8051615560614b9782614b16565b81815285602083850101111561557557600080fd5b613ed2826020830160208601614ede565b80356020831015613d2357600019602084900360031b1b1692915050565b6001600160a01b03851681526001600160a01b038416602082015282604082015260a0606082015260006155db60a0830184614f02565b8281036080840152600081526020810191505095945050505050565b81810381811115613d2357613d23615091565b80516dffffffffffffffffffffffffffff8116811461562857600080fd5b919050565b60008060006060848603121561564257600080fd5b61564b8461560a565b92506156596020850161560a565b9150604084015163ffffffff8116811461567257600080fd5b809150509250925092565b8281526040602082015260006122b46040830184615387565b600082516156a8818460208701614ede565b9190910192915050565b805169ffffffffffffffffffff8116811461562857600080fd5b600080600080600060a086880312156156e457600080fd5b6156ed866156b2565b60208701516040880151606089015192975090955093509150615712608087016156b2565b9050929550929590935056fe60a06040526040516105eb3803806105eb83398101604081905261002291610387565b61002c828261003e565b506001600160a01b0316608052610484565b610047826100fe565b6040516001600160a01b038316907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a28051156100f2576100ed826001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e7919061044d565b82610211565b505050565b6100fa610288565b5050565b806001600160a01b03163b60000361013957604051631933b43b60e21b81526001600160a01b03821660048201526024015b60405180910390fd5b807fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b0392831617905560408051635c60da1b60e01b81529051600092841691635c60da1b9160048083019260209291908290030181865afa1580156101b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d9919061044d565b9050806001600160a01b03163b6000036100fa57604051634c9c8ce360e01b81526001600160a01b0382166004820152602401610130565b6060600080846001600160a01b03168460405161022e9190610468565b600060405180830381855af49150503d8060008114610269576040519150601f19603f3d011682016040523d82523d6000602084013e61026e565b606091505b50909250905061027f8583836102a9565b95945050505050565b34156102a75760405163b398979f60e01b815260040160405180910390fd5b565b6060826102be576102b982610308565b610301565b81511580156102d557506001600160a01b0384163b155b156102fe57604051639996b31560e01b81526001600160a01b0385166004820152602401610130565b50805b9392505050565b8051156103185780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b80516001600160a01b038116811461034857600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561037e578181015183820152602001610366565b50506000910152565b6000806040838503121561039a57600080fd5b6103a383610331565b60208401519092506001600160401b038111156103bf57600080fd5b8301601f810185136103d057600080fd5b80516001600160401b038111156103e9576103e961034d565b604051601f8201601f19908116603f011681016001600160401b03811182821017156104175761041761034d565b60405281815282820160200187101561042f57600080fd5b610440826020830160208601610363565b8093505050509250929050565b60006020828403121561045f57600080fd5b61030182610331565b6000825161047a818460208701610363565b9190910192915050565b60805161014d61049e60003960006024015261014d6000f3fe608060405261000c61000e565b005b61001e610019610020565b6100b6565b565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561008d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100b191906100da565b905090565b3660008037600080366000845af43d6000803e8080156100d5573d6000f35b3d6000fd5b6000602082840312156100ec57600080fd5b815173ffffffffffffffffffffffffffffffffffffffff8116811461011057600080fd5b939250505056fea26469706673582212203655e5f8a14c566fbe01c38988a7026f24809f164afca809325e3e63d0afa56f64736f6c634300081a0033a264697066735822122066e0ffc0c6f898fa8371849a75ba98a26ac73fce7871e0e88d73622ed024321664736f6c634300081a0033
Deployed Bytecode
0x6080604052600436106103125760003560e01c80636588fcb01161019a578063ad3cb1cc116100e1578063e4459dcf1161008a578063f2fde38b11610064578063f2fde38b146109b1578063f3b8212b146109d1578063f7c0b612146109f157600080fd5b8063e4459dcf14610943578063e5753f6a14610970578063f23a617c1461099057600080fd5b8063d8c0869d116100bb578063d8c0869d146108df578063ddf2438314610901578063e30c39781461092e57600080fd5b8063ad3cb1cc14610833578063b6e22a1414610889578063d19172a8146108bf57600080fd5b80637a36b249116101435780638da5cb5b1161011d5780638da5cb5b146107c95780639187e15a146107de5780639abca73b1461081357600080fd5b80637a36b2491461073e5780638abaed96146107895780638c8087b2146107a957600080fd5b8063715018a611610174578063715018a6146106f457806379ba50971461070957806379d48e441461071e57600080fd5b80636588fcb01461069e578063674b5098146106be57806370a21439146106d457600080fd5b8063319aab031161025e5780635174f359116102075780635dd84c97116101e15780635dd84c971461063e57806360b250231461065e578063626cb3c51461067e57600080fd5b80635174f359146105f357806352d1902d1461061357806355bdcc9b1461062857600080fd5b806344ce1c151161023857806344ce1c151461058a57806345bb4b3e146105aa5780634f1ef286146105e057600080fd5b8063319aab031461051d57806334f16d961461053d5780633f98fc071461056a57600080fd5b8063157f5c26116102c05780632019e14f1161029a5780632019e14f146104bd578063265dcefb146104dd5780632bf5909c146104fd57600080fd5b8063157f5c26146104455780631694505e1461047d5780631f25a2d81461049d57600080fd5b80631179561d116102f15780631179561d146103cd5780631459457a1461040f5780631509fe9d1461042f57600080fd5b806223de291461031757806307002dd7146103395780630755be73146103a9575b600080fd5b34801561032357600080fd5b506103376103323660046146e4565b610a11565b005b34801561034557600080fd5b5061037f61035436600461479a565b6005602052600090815260409020805460018201546002909201546001600160a01b03909116919083565b604080516001600160a01b0390941684526020840192909252908201526060015b60405180910390f35b3480156103b557600080fd5b506103bf600b5481565b6040519081526020016103a0565b3480156103d957600080fd5b506103fd6103e836600461479a565b60096020526000908152604090205460ff1681565b60405160ff90911681526020016103a0565b34801561041b57600080fd5b5061033761042a3660046147b7565b610c07565b34801561043b57600080fd5b506103bf600e5481565b34801561045157600080fd5b50610465610460366004614839565b611053565b6040516001600160a01b0390911681526020016103a0565b34801561048957600080fd5b50600f54610465906001600160a01b031681565b3480156104a957600080fd5b506103376104b83660046148f6565b611533565b3480156104c957600080fd5b506103376104d8366004614984565b6115e4565b3480156104e957600080fd5b506103376104f83660046149d9565b611702565b34801561050957600080fd5b50610337610518366004614a50565b611851565b34801561052957600080fd5b506103bf610538366004614a70565b6119b5565b34801561054957600080fd5b506103bf61055836600461479a565b60086020526000908152604090205481565b34801561057657600080fd5b50610337610585366004614a9c565b6119da565b34801561059657600080fd5b50601454610465906001600160a01b031681565b3480156105b657600080fd5b506104656105c536600461479a565b6007602052600090815260409020546001600160a01b031681565b6103376105ee366004614b3e565b611aa6565b3480156105ff57600080fd5b506103bf61060e366004614bd1565b611ac5565b34801561061f57600080fd5b506103bf611af7565b34801561063457600080fd5b506103bf600c5481565b34801561064a57600080fd5b50610337610659366004614cb6565b611b26565b34801561066a57600080fd5b50610337610679366004614d5d565b611c7e565b34801561068a57600080fd5b50601154610465906001600160a01b031681565b3480156106aa57600080fd5b506103376106b9366004614d96565b611e99565b3480156106ca57600080fd5b506103bf600d5481565b3480156106e057600080fd5b506103bf6106ef366004614e09565b612240565b34801561070057600080fd5b506103376122bc565b34801561071557600080fd5b506103376122c6565b34801561072a57600080fd5b50610337610739366004614e26565b61232c565b34801561074a57600080fd5b50610779610759366004614e4b565b600260209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016103a0565b34801561079557600080fd5b50601354610465906001600160a01b031681565b3480156107b557600080fd5b50601254610465906001600160a01b031681565b3480156107d557600080fd5b506104656125f2565b3480156107ea57600080fd5b506107fe6107f9366004614d96565b612627565b604080519283526020830191909152016103a0565b34801561081f57600080fd5b5061033761082e366004614e79565b612680565b34801561083f57600080fd5b5061087c6040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516103a09190614f2e565b34801561089557600080fd5b506104656108a4366004614e09565b600a602052600090815260409020546001600160a01b031681565b3480156108cb57600080fd5b506103376108da366004614cb6565b6127d6565b3480156108eb57600080fd5b506108f46128b5565b6040516103a09190614f41565b34801561090d57600080fd5b506103bf61091c36600461479a565b60066020526000908152604090205481565b34801561093a57600080fd5b50610465612ad9565b34801561094f57600080fd5b506103bf61095e36600461479a565b60046020526000908152604090205481565b34801561097c57600080fd5b5061033761098b36600461500c565b612b02565b34801561099c57600080fd5b506014546103fd90600160a01b900460ff1681565b3480156109bd57600080fd5b506103376109cc36600461479a565b612d70565b3480156109dd57600080fd5b506103376109ec366004614e79565b612df5565b3480156109fd57600080fd5b50601054610465906001600160a01b031681565b610a19612f11565b60005460ff16610bd4573360008181526009602052604090205460ff1615610a4e57610a488189888888612f92565b50610bd4565b6011546001600160a01b03828116911614610a95576040517f8698bf3700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000849003610ad0576040517f99d8fec900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060208611610aee57610ae78688018861479a565b6000610afa565b610afa86880188614e4b565b6001600160a01b03821660009081526009602052604081205492945090925060ff9091169003610b3d576040516397fa436960e01b815260040160405180910390fd5b6001600160a01b038083166000908152600560205260409020548b82169116148015610b7157506001600160a01b03811615155b15610b8957610b818289836131ca565b505050610bd4565b6001600160a01b038116610ba257610b818a8984613454565b6040517f5cb045db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bfd60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050505050505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff16600081158015610c525750825b905060008267ffffffffffffffff166001148015610c6f5750303b155b905081158015610c7d575080155b15610cb4576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315610cff57845468ff00000000000000001916680100000000000000001785555b610d08336135f7565b610d10613608565b610d18613608565b610d20613610565b6001600160a01b038a161580610d3d57506001600160a01b038916155b80610d4f57506001600160a01b038816155b80610d6157506001600160a01b038716155b80610d7357506001600160a01b038616155b15610d915760405163867915ab60e01b815260040160405180910390fd5b601380546001600160a01b03808d166001600160a01b031992831617909255601180548c8416908316179055601280548b8416908316179055600f8054928a169290911682179055604080517fc45a0155000000000000000000000000000000000000000000000000000000008152905163c45a0155916004818101926020929091908290030181865afa158015610e2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e519190615074565b6011546040517fe6a439050000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152888216602482015291169063e6a4390590604401602060405180830381865afa158015610ebb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610edf9190615074565b601080546001600160a01b0319166001600160a01b039290921691909117905560148054600160a01b7fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff9091161790556040517f29965a1d00000000000000000000000000000000000000000000000000000000815230600482018190527fb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b60248301526044820152731820a4b7618bde71dce8cdc73aab6c95905fad24906329965a1d90606401600060405180830381600087803b158015610fc157600080fd5b505af1158015610fd5573d6000803e3d6000fd5b5050601480546001600160a01b03191633179055505062015180600d55607d600b5560fa600c55831561104757845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050565b600061105d613620565b881580611068575086155b1561109f576040517fbd442c0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60148054600091600160a01b90910460ff1690806110bc836150a7565b91906101000a81548160ff021916908360ff16021790555090506110e581600160ff9091161490565b1561113c576001600160a01b03861615158061110057508415155b15611137576040517f22d01ec500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611180565b84156001600160a01b0387161503611180576040517f1c206bd500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6013546040516000916001600160a01b0316907f4cd88b7600000000000000000000000000000000000000000000000000000000906111c9908f908f908f908f906024016150f1565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161123390614608565b61123e929190615123565b604051809103906000f08015801561125a573d6000803e3d6000fd5b5060ff83166000818152600a6020908152604080832080546001600160a01b0319166001600160a01b038716908117909155835260098252808320805460ff19169094179093558251600180825281850190945293965086945090929190828101908036833701905050905082816000815181106112da576112da615145565b60ff9290921660209283029190910190910152604051637ed81ccf60e11b8152306004820152600160248201526001600160a01b0385169063fdb0399e90604401600060405180830381600087803b15801561133557600080fd5b505af1158015611349573d6000803e3d6000fd5b5050601254604051637ed81ccf60e11b81526001600160a01b03918216600482015260016024820152908716925063fdb0399e9150604401600060405180830381600087803b15801561139b57600080fd5b505af11580156113af573d6000803e3d6000fd5b50506040805180820182526113e19350915087906002908390839080828437600092019190915250849150611b269050565b60408051808201825261140e91889060029083908390808284376000920191909152508491506127d69050565b6001600160a01b038816611449576001600160a01b0384166000908152600860205260408120889055600e5490036114455742600e555b3097505b60ff831660011461145e5761145e8884611c7e565b88156114de576040517f40c10f19000000000000000000000000000000000000000000000000000000008152336004820152602481018a90526001600160a01b038516906340c10f1990604401600060405180830381600087803b1580156114c557600080fd5b505af11580156114d9573d6000803e3d6000fd5b505050505b836001600160a01b03167f527bb35a63311a579e081d540028e25768c0825da90cefe051b27e1625bbeb438e8e8660405161151b9392919061515b565b60405180910390a25050509998505050505050505050565b61153b613620565b6001600160a01b0384161561156657601480546001600160a01b0319166001600160a01b0386161790555b821561157257600d8390555b612710821180611583575061271081115b156115a15760405163648564d360e01b815260040160405180910390fd5b81156115ad57600b8290555b80156115b957600c8190555b600c54600b5411156115de57604051636a43f8d160e01b815260040160405180910390fd5b50505050565b6115ec613620565b60008061162b84848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061366b92505050565b9150915060005b82518110156116c15782818151811061164d5761164d615145565b60200260200101516001600160a01b031663ec95ca00876040518263ffffffff1660e01b8152600401611684911515815260200190565b600060405180830381600087803b15801561169e57600080fd5b505af11580156116b2573d6000803e3d6000fd5b50505050806001019050611632565b507f3352c669dce7afa6b0290db8b2b7ab31a285d07af4bfcfc8d03c431046517ced85826040516116f39291906151c1565b60405180910390a15050505050565b6014546001600160a01b03163314611746576040517fbbfa05da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8181101561184857600083838381811061176557611765615145565b61177b926020604090920201908101915061479a565b6001600160a01b0316036117a25760405163867915ab60e01b815260040160405180910390fd5b8282828181106117b4576117b4615145565b905060400201602001356000036117de57604051636a43f8d160e01b815260040160405180910390fd5b8282828181106117f0576117f0615145565b905060400201602001356008600085858581811061181057611810615145565b611826926020604090920201908101915061479a565b6001600160a01b03168152602081019190915260400160002055600101611749565b505042600e5550565b611859613620565b6001600160a01b0383166118805760405163867915ab60e01b815260040160405180910390fd5b6000806118bf84848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061366b92505050565b9150915060005b825181101561196c578281815181106118e1576118e1615145565b60209081029190910101516040517f13af40350000000000000000000000000000000000000000000000000000000081526001600160a01b038881166004830152909116906313af403590602401600060405180830381600087803b15801561194957600080fd5b505af115801561195d573d6000803e3d6000fd5b505050508060010190506118c6565b50846001600160a01b03167fc049d66516b85609e058a9427e73d12f66ae3c2bc5e1c7060ba6b1ddd06e8fc8826040516119a691906151dc565b60405180910390a25050505050565b600360205281600052604060002081600281106119d157600080fd5b01549150829050565b6119e2613620565b600080611a2184848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061366b92505050565b9150915060005b8251811015611a74578560066000858481518110611a4857611a48615145565b6020908102919091018101516001600160a01b0316825281019190915260400160002055600101611a28565b507fe6076479bcacbd9563f9b52d33095130e54c4df7d6b9be809607f0ebc9f71b9985826040516116f39291906151ef565b611aae613840565b611ab782613910565b611ac18282613918565b5050565b60016020528260005260406000206020528160005260406000208160028110611aed57600080fd5b0154925083915050565b6000611b01613a1e565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b611b2e613620565b60208201511580611b43575060208201518251115b15611b615760405163648564d360e01b815260040160405180910390fd5b600080611b6d8361366b565b9150915060005b8251811015611c3e57828181518110611b8f57611b8f615145565b60200260200101516001600160a01b03166335cd5b8f86600060028110611bb857611bb8615145565b602002015187600160200201516040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815260048101929092526024820152604401600060405180830381600087803b158015611c1b57600080fd5b505af1158015611c2f573d6000803e3d6000fd5b50505050806001019050611b74565b507f35ce4f39b55b486963f90530939380436949efccee28e59c3e9199ae8603870e8482604051611c70929190615208565b60405180910390a150505050565b611c86613620565b6001600160a01b038216611cad5760405163867915ab60e01b815260040160405180910390fd5b60ff81166000908152600a60205260409020546001600160a01b031680611ce7576040516397fa436960e01b815260040160405180910390fd5b60ff8216600103611d24576040517f22d01ec500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b306001600160a01b03841603611da9576001600160a01b0381166000908152600860205260408120549003611d85576040517f539a7b4a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03811660009081526004602052604090206305f5e1009055611e30565b826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611de7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e0b9190615244565b611e1690600a615348565b6001600160a01b0382166000908152600460205260409020555b6001600160a01b0381811660009081526007602090815260409182902080546001600160a01b0319169387169384179055905160ff851681527f0965bd7b617d4cd98408a68f5c8ef655b8161502769cabd6832b4a584eb57edb910160405180910390a2505050565b60ff84166000908152600a60205260409020546001600160a01b031680611ed3576040516397fa436960e01b815260040160405180910390fd5b6001600160a01b03818116600090815260056020526040902054163314611f26576040517faae19bbd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038181166000908152600160209081526040808320938a1683529290529081205490819003611f88576040517fad9f423f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038083166000908152600160208181526040808420948c16845293905291812081815590910155601154600f546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526024810184905291169063095ea7b3906044016020604051808303816000875af1158015612024573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120489190615357565b506000612056838686613a80565b6000805460ff19166001179055600f549091506001600160a01b03166338ed17398388843061208642603c615374565b6040518663ffffffff1660e01b81526004016120a69594939291906153c2565b6000604051808303816000875af11580156120c5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120ed91908101906153fe565b506000805460ff191681556040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038516906370a0823190602401602060405180830381865afa158015612155573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121799190615494565b6040805163fe9d930360e01b8152600481018390526024810191909152600060448201529091506001600160a01b0385169063fe9d930390606401600060405180830381600087803b1580156121ce57600080fd5b505af11580156121e2573d6000803e3d6000fd5b50506040805160ff8c168152602081018790529081018490526001600160a01b038c1692507f863f92abaf7349d98b537d0e73acaf4faff5b548a2c1ff5e4026a5445577b22c915060600160405180910390a2505050505050505050565b60ff81166000908152600a60205260408120546001600160a01b03168061227a576040516397fa436960e01b815260040160405180910390fd5b600061228d612287613bcb565b83613cc2565b60208101518151919250906122aa90670de0b6b3a76400006154ad565b6122b491906154c4565b949350505050565b6122c4613620565b565b33806122d0612ad9565b6001600160a01b031614612320576040517f118cdaa70000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024015b60405180910390fd5b61232981613d29565b50565b612334613620565b60ff81166000908152600a60205260409020546001600160a01b03168061236e576040516397fa436960e01b815260040160405180910390fd5b6001600160a01b0380821660009081526005602052604090205416806123c0576040517f8109696c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03821660009081526005602052604090206002015480851115612416576040517f9290475f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316600090815260056020526040812060018101805482546001600160a01b03191683559083905560029091019190915585156124fe5760115491869003916001600160a01b031663a9059cbb6124736125f2565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602481018990526044016020604051808303816000875af11580156124d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124fc9190615357565b505b8115612596576011546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038581166004830152602482018590529091169063a9059cbb906044016020604051808303816000875af1158015612570573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125949190615357565b505b604080518381526020810188905260ff87169181019190915281906001600160a01b038516907f6e94ba4ab6e2cda709fb3b448470e7c53427d9416531ec3b4053db13825e6298906060015b60405180910390a3505050505050565b6000807f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005b546001600160a01b031692915050565b60ff84166000908152600a60209081526040808320546001600160a01b0390811680855260018452828520918a16855292528220549190612673838761266e848989613a80565b613d61565b9150509550959350505050565b612688613620565b6001600160a01b0384166126af5760405163867915ab60e01b815260040160405180910390fd5b6000806126ee84848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061366b92505050565b9150915060005b825181101561278a5782818151811061271057612710615145565b6020908102919091010151604051637ed81ccf60e11b81526001600160a01b03898116600483015288151560248301529091169063fdb0399e90604401600060405180830381600087803b15801561276757600080fd5b505af115801561277b573d6000803e3d6000fd5b505050508060010190506126f5565b50856001600160a01b03167f72f3a174b41131b9c154d829a90b99db5577f6929eb580257255278632884b5e86836040516127c69291906151c1565b60405180910390a2505050505050565b6127de613620565b602082015115806127f3575081516020830151115b156128115760405163648564d360e01b815260040160405180910390fd5b60008061281d8361366b565b9150915060005b825181101561288357846003600085848151811061284457612844615145565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002090600261287a929190614615565b50600101612824565b507ff7924680f54e75bd67fade3ebebc8fbca96a2bc00c83df1bd970c33df97a63b98482604051611c70929190615208565b60606000600160148054906101000a900460ff166128d391906154e6565b905060008160ff1667ffffffffffffffff8111156128f3576128f3614acf565b60405190808252806020026020018201604052801561295b57816020015b6129486040518060800160405280600060ff168152602001606081526020016060815260200160006001600160a01b031681525090565b8152602001906001900390816129115790505b50905060008060005b8460ff168160ff161015612acf5761297d8160016154ff565b60ff81166000818152600a6020908152604080832054815160808101835294855281517f06fdde0300000000000000000000000000000000000000000000000000000000815291516001600160a01b03909116985094965092939084019287926306fdde03926004808401938290030181865afa158015612a02573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612a2a9190810190615518565b8152602001846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612a6d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612a959190810190615518565b8152602001846001600160a01b0316815250848260ff1681518110612abc57612abc615145565b6020908102919091010152600101612964565b5091949350505050565b6000807f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00612617565b612b0a613620565b60ff81166000908152600a60205260409020546001600160a01b031680612b44576040516397fa436960e01b815260040160405180910390fd5b6001600160a01b038181166000908152600560205260409020541615612b96576040517fc8483e4c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038516612bbd5760405163867915ab60e01b815260040160405180910390fd5b60208314612bf7576040517ff4fc87a400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0381166000908152600660205260409020548015612cc5576000805460ff191660011790556011546040517f23b872dd0000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015230602483015260448201849052909116906323b872dd906064016020604051808303816000875af1158015612c95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cb99190615357565b506000805460ff191690555b6001600160a01b03828116600090815260056020526040902080546001600160a01b031916918816919091179055612cfd8486615586565b6001600160a01b03831660009081526005602052604090206001810191909155600201819055612d2d8486615586565b6040805183815260ff861660208201526001600160a01b038916917fae1336e1e0ec5d0d50d43727edbe2012a896a76f9664678e56b7dcfe30b0448891016125e2565b612d78613620565b7f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c0080546001600160a01b0319166001600160a01b0383169081178255612dbc6125f2565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a35050565b612dfd613620565b6001600160a01b038416612e245760405163867915ab60e01b815260040160405180910390fd5b600080612e6384848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061366b92505050565b9150915060005b8251811015612ed5578560026000858481518110612e8a57612e8a615145565b6020908102919091018101516001600160a01b0390811683528282019390935260409182016000908120938c1681529290529020805460ff1916911515919091179055600101612e6a565b50856001600160a01b03167f3bff0fe9289946d0ecd18435d733b69a8f4dfd3ef86cf915f5c127f01f9a343986836040516127c69291906151c1565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0080547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01612f8c576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60029055565b6000612fa086868585613e57565b6001600160a01b0380881660009081526001602090815260408083209385168352929052908120919250810154600003613006576040517fad9f423f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84816001015414613043576040517f69640e7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038881166000818152600160208181526040808420958916845294905283822082815501819055825163fe9d930360e01b8152600481018a9052602481019390935260448301529063fe9d930390606401600060405180830381600087803b1580156130b757600080fd5b505af11580156130cb573d6000803e3d6000fd5b50506011546040517f9bd9bbc60000000000000000000000000000000000000000000000000000000081526001600160a01b0387811660048301526024820186905260606044830152600060648301529091169250639bd9bbc69150608401600060405180830381600087803b15801561314457600080fd5b505af1158015613158573d6000803e3d6000fd5b505050506001600160a01b0388811660009081526009602090815260409182902054825160ff9091168152908101849052908101889052908416907f4d50a22e3094438c1381f48fe67a298bb630ed8cdc7bbdf4d569c31dcd6f6b9f9060600160405180910390a25050505050505050565b6001600160a01b0383811660009081526001602090815260408083209385168352929052205415613227576040517f4e8feca700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0383166000908152600360205260408082208151808301928390529160029082845b8154815260200190600101908083116132505750505050509050600061327d613277613bcb565b86613cc2565b6020808201519084015191925060009161329791906154ad565b835183516132a590886154ad565b6132af91906154ad565b6132b991906154c4565b6001600160a01b0387811660008181526001602081815260408084208b8716855282528084208c815590920186905583835260059052908190205490517f40c10f1900000000000000000000000000000000000000000000000000000000815292166004830152602482018390529192506340c10f1990604401600060405180830381600087803b15801561334d57600080fd5b505af1158015613361573d6000803e3d6000fd5b505050506001600160a01b038681166000818152600560205260409020805460125460019092015492936362ad1b839391811692169085906133a290613edb565b6040518563ffffffff1660e01b81526004016133c194939291906155a4565b600060405180830381600087803b1580156133db57600080fd5b505af11580156133ef573d6000803e3d6000fd5b505050506001600160a01b0386811660009081526009602090815260409182902054825160ff9091168152908101889052908101839052908516907f7e400ef539cd0a4d6440201d8de383e56d7007ca2986d6d33b458ce2ae03d0f4906060016127c6565b6001600160a01b0380821660009081526002602090815260408083209387168352929052205460ff166134b3576040517fea8e4eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011546040805163fe9d930360e01b8152600481018590526024810191909152600060448201526001600160a01b039091169063fe9d930390606401600060405180830381600087803b15801561350957600080fd5b505af115801561351d573d6000803e3d6000fd5b50505050600061352e612287613bcb565b602081015181519192506001600160a01b038416916340c10f1991879161355590886154ad565b61355f91906154c4565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156135bd57600080fd5b505af1158015610bfd573d6000803e3d6000fd5b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6135ff613f0c565b61232981613f73565b6122c4613f0c565b613618613f0c565b6122c4613fbe565b336136296125f2565b6001600160a01b0316146122c4576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401612317565b60608060008351600014613680578351613699565b60145461369990600190600160a01b900460ff166154e6565b905060008160ff1667ffffffffffffffff8111156136b9576136b9614acf565b6040519080825280602002602001820160405280156136e2578160200160208202803683370190505b50905060008260ff1667ffffffffffffffff81111561370357613703614acf565b60405190808252806020026020018201604052801561372c578160200160208202803683370190505b50905060015b8360ff168160ff1611613834576000875160001461377657876137566001846154e6565b60ff168151811061376957613769615145565b6020026020010151613778565b815b60ff81166000908152600a60205260409020549091506001600160a01b0316806137b5576040516397fa436960e01b815260040160405180910390fd5b80856137c26001866154e6565b60ff16815181106137d5576137d5615145565b6001600160a01b039092166020928302919091019091015281846137fa6001866154e6565b60ff168151811061380d5761380d615145565b602002602001019060ff16908160ff168152505050508061382d906150a7565b9050613732565b50909590945092505050565b306001600160a01b037f000000000000000000000000fb580268f9bbda106bc43fe9c12bdcd5394dca441614806138d957507f000000000000000000000000fb580268f9bbda106bc43fe9c12bdcd5394dca446001600160a01b03166138cd7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6001600160a01b031614155b156122c4576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612329613620565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015613972575060408051601f3d908101601f1916820190925261396f91810190615494565b60015b6139b3576040517f4c9c8ce30000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401612317565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114613a0f576040517faa1d49a400000000000000000000000000000000000000000000000000000000815260048101829052602401612317565b613a198383613fc6565b505050565b306001600160a01b037f000000000000000000000000fb580268f9bbda106bc43fe9c12bdcd5394dca4416146122c4576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60606000613a8f836002615374565b90508067ffffffffffffffff811115613aaa57613aaa614acf565b604051908082528060200260200182016040528015613ad3578160200160208202803683370190505b5060115481519193506001600160a01b0316908390600090613af757613af7615145565b60200260200101906001600160a01b031690816001600160a01b03168152505060005b83811015613b8557848482818110613b3457613b34615145565b9050602002016020810190613b49919061479a565b83613b55836001615374565b81518110613b6557613b65615145565b6001600160a01b0390921660209283029190910190910152600101613b1a565b508482613b936001846155f7565b81518110613ba357613ba3615145565b60200260200101906001600160a01b031690816001600160a01b031681525050509392505050565b613bd3614653565b600080601060009054906101000a90046001600160a01b03166001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015613c29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4d919061562d565b506dffffffffffffffffffffffffffff80831686529193509150613c799064e8d4a510009083166154ad565b6020840152613c878361401c565b613cbd576040517f418dc4df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505090565b613cca614653565b6000613cd58361419d565b9050604051806040016040528085600160028110613cf557613cf5615145565b60200201518351613d0691906154ad565b81528551602084810151920191613d1d91906154ad565b90529150505b92915050565b7f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c0080546001600160a01b0319168155611ac1826142a1565b600f546040517fd06ca61f00000000000000000000000000000000000000000000000000000000815260009182916001600160a01b039091169063d06ca61f90613db1908890879060040161567d565b600060405180830381865afa158015613dce573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613df691908101906153fe565b905060008160018351613e0991906155f7565b81518110613e1957613e19615145565b6020026020010151905060006127108683613e3491906154ad565b613e3e91906154c4565b9050613e4a81836155f7565b93505050505b9392505050565b6001600160a01b03848116600090815260016020908152604080832093871683529290529081205415613e8b5750826122b4565b6000829003613ec6576040517f99d8fec900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613ed28284018461479a565b95945050505050565b6040805160208082528183019092526060916000919060208201818036833750505060208101939093525090919050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff166122c4576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613f7b613f0c565b6001600160a01b038116612320576040517f1e4fbdf700000000000000000000000000000000000000000000000000000000815260006004820152602401612317565b6135d1613f0c565b613fcf82614312565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a280511561401457613a1982826143a2565b611ac161440f565b60008082600160200201516011546040517f6f54ed75000000000000000000000000000000000000000000000000000000008152600060048201526001600160a01b0390911690636f54ed7590602401602060405180830381865afa158015614089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140ad9190615494565b6140b791906154ad565b6011546040517f6f54ed75000000000000000000000000000000000000000000000000000000008152600160048201529192506000916001600160a01b0390911690636f54ed7590602401602060405180830381865afa15801561411f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141439190615494565b845161414f91906154ad565b905060008282116141695761416482846155f7565b614173565b61417383836155f7565b9050600083614184612710846154ad565b61418e91906154c4565b600c5410159695505050505050565b6141a5614653565b6001600160a01b03821660009081526009602052604090205460ff166001036141e4575050604080518082019091526305f5e100808252602082015290565b6001600160a01b0380831660009081526004602090815260408083205460079092528220549092169030820361427c57600d54600e546142249190615374565b42111561425d576040517f4fbd1cb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506001600160a01b038416600090815260086020526040902054614288565b61428582614447565b90505b6040805180820190915292835260208301525092915050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b806001600160a01b03163b600003614361576040517f4c9c8ce30000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401612317565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b0316846040516143bf9190615696565b600060405180830381855af49150503d80600081146143fa576040519150601f19603f3d011682016040523d82523d6000602084013e6143ff565b606091505b5091509150613ed2858383614551565b34156122c4576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000806000856001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561448d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144b191906156cc565b94509450509350935062015180826144c99190615374565b421115614502576040517f4fbd1cb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083128061452957508069ffffffffffffffffffff168469ffffffffffffffffffff1614155b1561454757604051636a43f8d160e01b815260040160405180910390fd5b5090949350505050565b60608261456657614561826145c6565b613e50565b815115801561457d57506001600160a01b0384163b155b156145bf576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401612317565b5080613e50565b8051156145d65780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105eb8061571f83390190565b8260028101928215614643579160200282015b82811115614643578251825591602001919060010190614628565b5061464f929150614671565b5090565b60405180604001604052806002906020820280368337509192915050565b5b8082111561464f5760008155600101614672565b6001600160a01b038116811461232957600080fd5b60008083601f8401126146ad57600080fd5b50813567ffffffffffffffff8111156146c557600080fd5b6020830191508360208285010111156146dd57600080fd5b9250929050565b60008060008060008060008060c0898b03121561470057600080fd5b883561470b81614686565b9750602089013561471b81614686565b9650604089013561472b81614686565b955060608901359450608089013567ffffffffffffffff81111561474e57600080fd5b61475a8b828c0161469b565b90955093505060a089013567ffffffffffffffff81111561477a57600080fd5b6147868b828c0161469b565b999c989b5096995094979396929594505050565b6000602082840312156147ac57600080fd5b8135613e5081614686565b600080600080600060a086880312156147cf57600080fd5b85356147da81614686565b945060208601356147ea81614686565b935060408601356147fa81614686565b9250606086013561480a81614686565b9150608086013561481a81614686565b809150509295509295909350565b8060408101831015613d2357600080fd5b60008060008060008060008060006101208a8c03121561485857600080fd5b893567ffffffffffffffff81111561486f57600080fd5b61487b8c828d0161469b565b909a5098505060208a013567ffffffffffffffff81111561489b57600080fd5b6148a78c828d0161469b565b90985096505060408a0135945060608a01356148c281614686565b935060808a013592506148d88b60a08c01614828565b91506148e78b60e08c01614828565b90509295985092959850929598565b6000806000806080858703121561490c57600080fd5b843561491781614686565b966020860135965060408601359560600135945092505050565b801515811461232957600080fd5b60008083601f84011261495157600080fd5b50813567ffffffffffffffff81111561496957600080fd5b6020830191508360208260051b85010111156146dd57600080fd5b60008060006040848603121561499957600080fd5b83356149a481614931565b9250602084013567ffffffffffffffff8111156149c057600080fd5b6149cc8682870161493f565b9497909650939450505050565b600080602083850312156149ec57600080fd5b823567ffffffffffffffff811115614a0357600080fd5b8301601f81018513614a1457600080fd5b803567ffffffffffffffff811115614a2b57600080fd5b8560208260061b8401011115614a4057600080fd5b6020919091019590945092505050565b600080600060408486031215614a6557600080fd5b83356149a481614686565b60008060408385031215614a8357600080fd5b8235614a8e81614686565b946020939093013593505050565b600080600060408486031215614ab157600080fd5b83359250602084013567ffffffffffffffff8111156149c057600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614b0e57614b0e614acf565b604052919050565b600067ffffffffffffffff821115614b3057614b30614acf565b50601f01601f191660200190565b60008060408385031215614b5157600080fd5b8235614b5c81614686565b9150602083013567ffffffffffffffff811115614b7857600080fd5b8301601f81018513614b8957600080fd5b8035614b9c614b9782614b16565b614ae5565b818152866020838501011115614bb157600080fd5b816020840160208301376000602083830101528093505050509250929050565b600080600060608486031215614be657600080fd5b8335614bf181614686565b92506020840135614c0181614686565b929592945050506040919091013590565b600067ffffffffffffffff821115614c2c57614c2c614acf565b5060051b60200190565b60ff8116811461232957600080fd5b600082601f830112614c5657600080fd5b8135614c64614b9782614c12565b8082825260208201915060208360051b860101925085831115614c8657600080fd5b602085015b83811015614cac578035614c9e81614c36565b835260209283019201614c8b565b5095945050505050565b60008060608385031215614cc957600080fd5b83601f840112614cd857600080fd5b6040805190810167ffffffffffffffff81118282101715614cfb57614cfb614acf565b8060405250806040850186811115614d1257600080fd5b855b81811015614d2c578035835260209283019201614d14565b50919350503567ffffffffffffffff811115614d4757600080fd5b614d5385828601614c45565b9150509250929050565b60008060408385031215614d7057600080fd5b8235614d7b81614686565b91506020830135614d8b81614c36565b809150509250929050565b600080600080600060808688031215614dae57600080fd5b8535614db981614686565b94506020860135614dc981614c36565b935060408601359250606086013567ffffffffffffffff811115614dec57600080fd5b614df88882890161493f565b969995985093965092949392505050565b600060208284031215614e1b57600080fd5b8135613e5081614c36565b60008060408385031215614e3957600080fd5b823591506020830135614d8b81614c36565b60008060408385031215614e5e57600080fd5b8235614e6981614686565b91506020830135614d8b81614686565b60008060008060608587031215614e8f57600080fd5b8435614e9a81614686565b93506020850135614eaa81614931565b9250604085013567ffffffffffffffff811115614ec657600080fd5b614ed28782880161493f565b95989497509550505050565b60005b83811015614ef9578181015183820152602001614ee1565b50506000910152565b60008151808452614f1a816020860160208601614ede565b601f01601f19169290920160200192915050565b602081526000613e506020830184614f02565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015615000577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0878603018452815160ff8151168652602081015160806020880152614fba6080880182614f02565b905060408201518782036040890152614fd38282614f02565b6060938401516001600160a01b031698909301979097525094506020938401939190910190600101614f69565b50929695505050505050565b6000806000806060858703121561502257600080fd5b843561502d81614686565b9350602085013567ffffffffffffffff81111561504957600080fd5b6150558782880161469b565b909450925050604085013561506981614c36565b939692955090935050565b60006020828403121561508657600080fd5b8151613e5081614686565b634e487b7160e01b600052601160045260246000fd5b600060ff821660ff81036150bd576150bd615091565b60010192915050565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b6040815260006151056040830186886150c6565b82810360208401526151188185876150c6565b979650505050505050565b6001600160a01b03831681526040602082015260006122b46040830184614f02565b634e487b7160e01b600052603260045260246000fd5b60408152600061516f6040830185876150c6565b905060ff83166020830152949350505050565b600081518084526020840193506020830160005b828110156151b757815160ff16865260209586019590910190600101615196565b5093949350505050565b82151581526040602082015260006122b46040830184615182565b602081526000613e506020830184615182565b8281526040602082015260006122b46040830184615182565b60008184825b600281101561522d57815183526020928301929091019060010161520e565b505050606060408301526122b46060830184615182565b60006020828403121561525657600080fd5b8151613e5081614c36565b6001815b600184111561529c5780850481111561528057615280615091565b600184161561528e57908102905b60019390931c928002615265565b935093915050565b6000826152b357506001613d23565b816152c057506000613d23565b81600181146152d657600281146152e0576152fc565b6001915050613d23565b60ff8411156152f1576152f1615091565b50506001821b613d23565b5060208310610133831016604e8410600b841016171561531f575081810a613d23565b61532c6000198484615261565b806000190482111561534057615340615091565b029392505050565b6000613e5060ff8416836152a4565b60006020828403121561536957600080fd5b8151613e5081614931565b80820180821115613d2357613d23615091565b600081518084526020840193506020830160005b828110156151b75781516001600160a01b031686526020958601959091019060010161539b565b85815284602082015260a0604082015260006153e160a0830186615387565b6001600160a01b0394909416606083015250608001529392505050565b60006020828403121561541057600080fd5b815167ffffffffffffffff81111561542757600080fd5b8201601f8101841361543857600080fd5b8051615446614b9782614c12565b8082825260208201915060208360051b85010192508683111561546857600080fd5b6020840193505b8284101561548a57835182526020938401939091019061546f565b9695505050505050565b6000602082840312156154a657600080fd5b5051919050565b8082028115828204841417613d2357613d23615091565b6000826154e157634e487b7160e01b600052601260045260246000fd5b500490565b60ff8281168282160390811115613d2357613d23615091565b60ff8181168382160190811115613d2357613d23615091565b60006020828403121561552a57600080fd5b815167ffffffffffffffff81111561554157600080fd5b8201601f8101841361555257600080fd5b8051615560614b9782614b16565b81815285602083850101111561557557600080fd5b613ed2826020830160208601614ede565b80356020831015613d2357600019602084900360031b1b1692915050565b6001600160a01b03851681526001600160a01b038416602082015282604082015260a0606082015260006155db60a0830184614f02565b8281036080840152600081526020810191505095945050505050565b81810381811115613d2357613d23615091565b80516dffffffffffffffffffffffffffff8116811461562857600080fd5b919050565b60008060006060848603121561564257600080fd5b61564b8461560a565b92506156596020850161560a565b9150604084015163ffffffff8116811461567257600080fd5b809150509250925092565b8281526040602082015260006122b46040830184615387565b600082516156a8818460208701614ede565b9190910192915050565b805169ffffffffffffffffffff8116811461562857600080fd5b600080600080600060a086880312156156e457600080fd5b6156ed866156b2565b60208701516040880151606089015192975090955093509150615712608087016156b2565b9050929550929590935056fe60a06040526040516105eb3803806105eb83398101604081905261002291610387565b61002c828261003e565b506001600160a01b0316608052610484565b610047826100fe565b6040516001600160a01b038316907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a28051156100f2576100ed826001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e7919061044d565b82610211565b505050565b6100fa610288565b5050565b806001600160a01b03163b60000361013957604051631933b43b60e21b81526001600160a01b03821660048201526024015b60405180910390fd5b807fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b0392831617905560408051635c60da1b60e01b81529051600092841691635c60da1b9160048083019260209291908290030181865afa1580156101b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d9919061044d565b9050806001600160a01b03163b6000036100fa57604051634c9c8ce360e01b81526001600160a01b0382166004820152602401610130565b6060600080846001600160a01b03168460405161022e9190610468565b600060405180830381855af49150503d8060008114610269576040519150601f19603f3d011682016040523d82523d6000602084013e61026e565b606091505b50909250905061027f8583836102a9565b95945050505050565b34156102a75760405163b398979f60e01b815260040160405180910390fd5b565b6060826102be576102b982610308565b610301565b81511580156102d557506001600160a01b0384163b155b156102fe57604051639996b31560e01b81526001600160a01b0385166004820152602401610130565b50805b9392505050565b8051156103185780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b80516001600160a01b038116811461034857600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561037e578181015183820152602001610366565b50506000910152565b6000806040838503121561039a57600080fd5b6103a383610331565b60208401519092506001600160401b038111156103bf57600080fd5b8301601f810185136103d057600080fd5b80516001600160401b038111156103e9576103e961034d565b604051601f8201601f19908116603f011681016001600160401b03811182821017156104175761041761034d565b60405281815282820160200187101561042f57600080fd5b610440826020830160208601610363565b8093505050509250929050565b60006020828403121561045f57600080fd5b61030182610331565b6000825161047a818460208701610363565b9190910192915050565b60805161014d61049e60003960006024015261014d6000f3fe608060405261000c61000e565b005b61001e610019610020565b6100b6565b565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561008d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100b191906100da565b905090565b3660008037600080366000845af43d6000803e8080156100d5573d6000f35b3d6000fd5b6000602082840312156100ec57600080fd5b815173ffffffffffffffffffffffffffffffffffffffff8116811461011057600080fd5b939250505056fea26469706673582212203655e5f8a14c566fbe01c38988a7026f24809f164afca809325e3e63d0afa56f64736f6c634300081a0033a264697066735822122066e0ffc0c6f898fa8371849a75ba98a26ac73fce7871e0e88d73622ed024321664736f6c634300081a0033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.