Source Code
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 7 internal transactions
Advanced mode:
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:
BeefyRevenueBridge
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
// Essential Interfaces
import {IERC20} from "@openzeppelin-4/contracts/token/ERC20/ERC20.sol";
import {SafeERC20} from "@openzeppelin-4/contracts/token/ERC20/utils/SafeERC20.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {Address} from "@openzeppelin-4/contracts/utils/Address.sol";
// Bridge Interfaces
import {IAxelar} from "../interfaces/bridge/IAxelar.sol";
import {ICircle} from "../interfaces/bridge/ICircle.sol";
import {IStargate} from "../interfaces/bridge/IStargate.sol";
import {ISynapse} from "../interfaces/bridge/ISynapse.sol";
import {IzkEVM} from "../interfaces/bridge/IzkEVM.sol";
import {IzkSync} from "../interfaces/bridge/IzkSync.sol";
import {IFraxFerry} from "../interfaces/bridge/IFraxFerry.sol";
import {IBeefySwapper} from "../interfaces/swap/IBeefySwapper.sol";
//Swap Interfaces and Utils
import {IUniswapRouterETH} from "../interfaces/swap/IUniswapRouterETH.sol";
import {ISolidlyRouter} from "../interfaces/swap/ISolidlyRouter.sol";
import {IBalancerVault} from "../interfaces/swap/IBalancerVault.sol";
import {UniV3Actions} from "../utils/UniV3Actions.sol";
import {Path} from '../utils/Path.sol';
import {BeefyBalancerStructs} from "../utils/BeefyBalancerStructs.sol";
import {BalancerActionsLib} from "../utils/BalancerActionsLib.sol";
// Additional Interfaces Needed
import {IWrappedNative} from "../interfaces/IWrappedNative.sol";
import {Events} from "./Events.sol";
import {Errors} from "./Errors.sol";
// Beefy's revenue bridging system
contract BeefyRevenueBridge is
OwnableUpgradeable,
UUPSUpgradeable,
Events,
Errors
{
using SafeERC20 for IERC20;
using Address for address;
using Path for bytes;
IERC20 public stable;
IERC20 public native;
// Set our params
bytes32 public activeBridge;
bytes32 public activeSwap;
Cowllector public cowllector;
BridgeParams public bridgeParams;
SwapParams public swapParams;
DestinationAddress public destinationAddress;
uint256 public minBridgeAmount;
bool private init;
// Mapping our enums to function string
mapping(bytes32 => string) public bridgeToUse;
mapping(bytes32 => string) public swapToUse;
uint256 public lastHarvest;
function initialize() external initializer {
__Ownable_init();
_initBridgeMapping();
_initSwapMapping();
funds = IBalancerVault.FundManagement(address(this), false, payable(address(this)), false);
swapKind = IBalancerVault.SwapKind.GIVEN_IN;
}
modifier onlyThis {
_onlyThis();
_;
}
function _onlyThis() private view {
if (msg.sender != address(this)) revert NotAuthorized();
}
function _initBridgeMapping() private {
bridgeToUse[keccak256(abi.encode("CIRCLE"))] = "bridgeCircle()";
bridgeToUse[keccak256(abi.encode("STARGATE"))] = "bridgeStargate()";
bridgeToUse[keccak256(abi.encode("AXELAR"))] = "bridgeAxelar()";
bridgeToUse[keccak256(abi.encode("SYNAPSE"))] = "bridgeSynapse()";
bridgeToUse[keccak256(abi.encode("zkEVM"))] = "bridgezkEVM()";
bridgeToUse[keccak256(abi.encode("zkSYNC"))] = "bridgezkSync()";
}
function _initSwapMapping() private {
swapToUse[keccak256(abi.encode("UNISWAP_V2"))] = "swapUniV2()";
swapToUse[keccak256(abi.encode("SOLIDLY"))] = "swapSolidly()";
swapToUse[keccak256(abi.encode("UNISWAP_V3"))] = "swapUniV3()";
swapToUse[keccak256(abi.encode("UNISWAP_V3_DEADLINE"))] = "swapUniV3Deadline()";
swapToUse[keccak256(abi.encode("ALGEBRA"))] = "swapAlgebra()";
swapToUse[keccak256(abi.encode("BALANCER"))] = "swapBalancer()";
}
function harvest() external {
// We just wrap the native we have at the start.
_wrapNative();
_sendCowllectorFunds();
emit Harvested(_balanceOfNative());
if (_balanceOfNative() > 0) _bridge();
lastHarvest = block.timestamp;
}
function _swap() private {
address(this).functionCall(
abi.encodeWithSignature(swapToUse[activeSwap])
);
}
function _bridge() private {
address(this).functionCall(
abi.encodeWithSignature(bridgeToUse[activeBridge])
);
}
/**@notice Bridge function called by this contract if it is the the activeBridge */
function bridgeCircle() external onlyThis {
uint32 destinationDomain = abi.decode(bridgeParams.params, (uint32));
_swap();
uint256 bal = _balanceOfStable();
if (bal > minBridgeAmount) {
ICircle(bridgeParams.bridge).depositForBurn(
bal,
destinationDomain,
bytes32(uint256(uint160(destinationAddress.destination))),
address(stable)
);
}
emit Bridged(address(stable), bal);
}
function bridgeStargate() external onlyThis {
(Stargate memory _params) = abi.decode(bridgeParams.params, (Stargate));
IStargate.lzTxObj memory _lzTxObj = IStargate.lzTxObj({
dstGasForCall: _params.gasLimit,
dstNativeAmount: 0,
dstNativeAddr: "0x"
});
uint256 gasAmount = _stargateGasCost(_params.dstChainId, destinationAddress.destinationBytes, _lzTxObj);
_getGas(gasAmount);
_swap();
uint256 bal = _balanceOfStable();
if (bal > minBridgeAmount) {
IStargate(bridgeParams.bridge).swap{ value: gasAmount }(
_params.dstChainId,
_params.srcPoolId,
_params.dstPoolId,
payable(address(this)),
bal,
0,
_lzTxObj,
destinationAddress.destinationBytes,
""
);
}
emit Bridged(address(stable), bal);
}
function _stargateGasCost(uint16 _dstChainId, bytes memory _dstAddress, IStargate.lzTxObj memory _lzTxObj) private view returns (uint256 gasAmount) {
(gasAmount,) = IStargate(bridgeParams.bridge).quoteLayerZeroFee(
_dstChainId,
1, // TYPE_SWAP_REMOTE
_dstAddress,
"",
_lzTxObj
);
}
function bridgeAxelar() external onlyThis {
Axelar memory params = abi.decode(bridgeParams.params, (Axelar));
_swap();
uint256 bal = _balanceOfStable();
if (bal > minBridgeAmount) {
IAxelar(bridgeParams.bridge).sendToken(
params.destinationChain,
destinationAddress.destinationString,
params.symbol,
bal
);
}
emit Bridged(address(stable), bal);
}
function bridgeSynapse() external onlyThis {
(Synapse memory params) = abi.decode(bridgeParams.params, (Synapse));
_swap();
uint256 bal = _balanceOfStable();
if (bal > minBridgeAmount) {
ISynapse(bridgeParams.bridge).swapAndRedeemAndSwap(
destinationAddress.destination,
params.chainId,
params.token,
params.tokenIndexFrom,
params.tokenIndexTo,
bal,
0,
block.timestamp,
params.dstIndexFrom,
params.dstIndexTo,
0,
block.timestamp + 1 hours
);
}
emit Bridged(address(stable), bal);
}
function bridgezkEVM() external onlyThis {
_swap();
uint256 bal = _balanceOfStable();
if (bal > minBridgeAmount) {
IzkEVM(bridgeParams.bridge).bridgeAsset(
0,
destinationAddress.destination,
bal,
address(stable),
true,
""
);
}
emit Bridged(address(stable), bal);
}
function bridgezkSync() external onlyThis {
_swap();
uint256 bal = _balanceOfStable();
if (bal > minBridgeAmount) {
IzkSync(bridgeParams.bridge).withdraw(
destinationAddress.destination,
address(stable),
bal
);
}
emit Bridged(address(stable), bal);
}
function bridgeFraxFerry() external onlyThis {
_swap();
uint256 bal = _balanceOfStable();
if (bal > minBridgeAmount) {
IFraxFerry(bridgeParams.bridge).embarkWithRecipient(
bal,
destinationAddress.destination
);
emit Bridged(address(stable), bal);
}
}
/**@notice Swap functions */
function swapUniV2() external onlyThis {
address[] memory route = abi.decode(swapParams.params, (address[]));
if (route[0] != address(native)) revert IncorrectRoute();
if (route[route.length - 1] != address(stable)) revert IncorrectRoute();
uint256 bal = _balanceOfNative();
IUniswapRouterETH(swapParams.router).swapExactTokensForTokens(
bal, 0, route, address(this), block.timestamp
);
}
function swapSolidly() external onlyThis {
ISolidlyRouter.Routes[] memory routes = abi.decode(swapParams.params, (ISolidlyRouter.Routes[]));
address[] memory route = _solidlyToRoute(routes);
if (route[0] != address(native)) revert IncorrectRoute();
if (route[route.length - 1] != address(stable)) revert IncorrectRoute();
uint256 bal = _balanceOfNative();
ISolidlyRouter(swapParams.router).swapExactTokensForTokens(bal, 0, routes, address(this), block.timestamp);
}
function swapUniV3() external onlyThis {
bytes memory path = abi.decode(swapParams.params, (bytes));
address[] memory route = _pathToRoute(path);
if (route[0] != address(native)) revert IncorrectRoute();
if (route[route.length - 1] != address(stable)) revert IncorrectRoute();
uint256 bal = _balanceOfNative();
UniV3Actions.swapV3(swapParams.router, path, bal);
}
function swapUniV3Deadline() external onlyThis {
bytes memory path = abi.decode(swapParams.params, (bytes));
address[] memory route = _pathToRoute(path);
if (route[0] != address(native)) revert IncorrectRoute();
if (route[route.length - 1] != address(stable)) revert IncorrectRoute();
uint256 bal = _balanceOfNative();
UniV3Actions.swapV3WithDeadline(swapParams.router, path, bal);
}
function swapAlgebra() external onlyThis {
address[] memory route = abi.decode(swapParams.params, (address[]));
if (route[0] != address(native)) revert IncorrectRoute();
if (route[route.length - 1] != address(stable)) revert IncorrectRoute();
bytes memory path = _routeToPath(route);
uint256 bal = _balanceOfNative();
UniV3Actions.swapV3WithDeadline(swapParams.router, path, bal);
}
function swapBalancer() external onlyThis {
(BeefyBalancerStructs.BatchSwapStruct[] memory route, address[] memory assets) = abi.decode(swapParams.params, (BeefyBalancerStructs.BatchSwapStruct[],address[]));
if (assets[0] != address(native)) revert IncorrectRoute();
if (assets[assets.length - 1] != address(stable)) revert IncorrectRoute();
uint256 bal = _balanceOfNative();
IBalancerVault.BatchSwapStep[] memory _swaps = BalancerActionsLib.buildSwapStructArray(route, bal);
BalancerActionsLib.balancerSwap(swapParams.router, swapKind, _swaps, assets, funds, int256(bal));
}
function swapBeefy() external onlyThis {
address[] memory route = abi.decode(swapParams.params, (address[]));
if (route[0] != address(native)) revert IncorrectRoute();
if (route[1] != address(stable)) revert IncorrectRoute();
uint256 bal = _balanceOfNative();
IBeefySwapper(swapParams.router).swap(route[0], route[1], bal);
}
/**@notice View functions */
function _balanceOfStable() private view returns (uint256) {
return stable.balanceOf(address(this));
}
function _balanceOfNative() private view returns (uint256) {
return native.balanceOf(address(this));
}
function findHash(string calldata _variable) external pure returns (bytes32) {
return keccak256(abi.encode(_variable));
}
// Convert encoded path to token route
function _pathToRoute(bytes memory _path) private pure returns (address[] memory) {
uint256 numPools = _path.numPools();
address[] memory route = new address[](numPools + 1);
for (uint256 i; i < numPools; i++) {
(address tokenA, address tokenB,) = _path.decodeFirstPool();
route[i] = tokenA;
route[i + 1] = tokenB;
_path = _path.skipToken();
}
return route;
}
// Convert token route to encoded path
// uint24 type for fees so path is packed tightly
function _routeToPath(address[] memory _route) private pure returns (bytes memory path) {
path = abi.encodePacked(_route[0]);
for (uint256 i = 1; i < _route.length; i++) {
path = abi.encodePacked(path, _route[i]);
}
}
function _solidlyToRoute(ISolidlyRouter.Routes[] memory _route) private pure returns (address[] memory) {
address[] memory route = new address[](_route.length + 1);
route[0] = _route[0].from;
for (uint i; i < _route.length; ++i) {
route[i + 1] = _route[i].to;
}
return route;
}
function _sendCowllectorFunds() private {
if (cowllector.sendFunds) {
uint256 amountOnHand = address(cowllector.cowllector).balance + IERC20(native).balanceOf(cowllector.cowllector);
if (amountOnHand < cowllector.amountCowllectorNeeds) {
uint256 thisBal = _balanceOfNative();
uint256 amountToSend = cowllector.amountCowllectorNeeds - amountOnHand;
amountToSend = amountToSend > thisBal ? thisBal : amountToSend;
IERC20(native).safeTransfer(cowllector.cowllector, amountToSend);
emit CowllectorRefill(amountToSend);
}
}
}
function _getGas(uint256 _gasAmount) private {
uint256 nativeBal = _balanceOfNative();
if (nativeBal >= _gasAmount) {
try IWrappedNative(address(native)).withdraw(_gasAmount) {
// Do nothing. Chains like Metis will fail this.
} catch {
// Do nothing as well.
}
}
}
function _wrapNative() private {
uint256 bal = address(this).balance;
if (bal > 0) {
try IWrappedNative(address(native)).deposit{value: address(this).balance}() {
// Do nothing. Metis needs this try/catch.
} catch {
// Do nothing.
}
}
}
function _approveTokenIfNeeded(address token, address spender) private {
if (IERC20(token).allowance(address(this), spender) == 0) {
IERC20(token).safeApprove(spender, type(uint256).max);
}
}
function _removeApprovalIfNeeded(address token, address spender) private {
if (IERC20(token).allowance(address(this), spender) > 0) {
IERC20(token).safeApprove(spender, 0);
}
}
function _authorizeUpgrade(address) internal override onlyOwner {}
function setSwapHash(string calldata _hash, string calldata _variable) external onlyOwner {
swapToUse[keccak256(abi.encode(_hash))] = _variable;
}
// Setters
function setActiveBridge(bytes32 _bridgeHash, BridgeParams calldata _params) external onlyOwner {
emit SetBridge(_bridgeHash, _params);
_removeApprovalIfNeeded(address(stable), bridgeParams.bridge);
activeBridge = _bridgeHash;
bridgeParams = _params;
_approveTokenIfNeeded(address(stable), _params.bridge);
}
function setActiveSwap(bytes32 _swapHash, SwapParams calldata _params) external onlyOwner {
emit SetSwap(_swapHash, _params);
_removeApprovalIfNeeded(address(native), swapParams.router);
activeSwap = _swapHash;
swapParams = _params;
_approveTokenIfNeeded(address(native), _params.router);
}
function setBridgeMap(bytes32 _bridgeHash, string calldata _function) external onlyOwner {
bridgeToUse[_bridgeHash] = _function;
}
function setCowllector(Cowllector calldata _cowllector) external onlyOwner {
cowllector = _cowllector;
}
function setDestinationAddress(DestinationAddress calldata _destination) external onlyOwner {
emit SetDestinationAddress(_destination);
destinationAddress = _destination;
}
function setMinBridgeAmount(uint256 _amount) external onlyOwner {
emit SetMinBridgeAmount(_amount);
minBridgeAmount = _amount;
}
function setStable(IERC20 _stable, IERC20 _native) external onlyOwner {
if (!init) {
stable = _stable;
native = _native;
init = true;
return;
}
emit SetStable(address(stable), address(_stable));
_removeApprovalIfNeeded(address(stable), bridgeParams.bridge);
stable = _stable;
_approveTokenIfNeeded(address(stable), bridgeParams.bridge);
}
function inCaseTokensGetStuck(address _token, bool _native) external onlyOwner {
if (_native) {
uint256 _nativeAmount = address(this).balance;
(bool sent,) = msg.sender.call{value: _nativeAmount}("");
if(!sent) revert FailedToSendEther();
} else {
uint256 _amount = IERC20(_token).balanceOf(address(this));
IERC20(_token).safeTransfer(msg.sender, _amount);
}
}
receive() external payable {
assert(msg.sender == address(native));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to
* 0 before setting it to a non-zero value.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. 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 {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822ProxiableUpgradeable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
*
* _Available since v4.8.3._
*/
interface IERC1967Upgradeable {
/**
* @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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeaconUpgradeable {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeaconUpgradeable.sol";
import "../../interfaces/IERC1967Upgradeable.sol";
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/StorageSlotUpgradeable.sol";
import "../utils/Initializable.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*/
abstract contract ERC1967UpgradeUpgradeable is Initializable, IERC1967Upgradeable {
function __ERC1967Upgrade_init() internal onlyInitializing {
}
function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
}
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
AddressUpgradeable.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
AddressUpgradeable.functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
}
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```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 Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* 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 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.0;
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*
* _Available since v4.1._
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
address private immutable __self = address(this);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
require(address(this) != __self, "Function must be called through delegatecall");
require(_getImplementation() == __self, "Function must be called through active proxy");
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
_;
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate 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 override notDelegated returns (bytes32) {
return _IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeTo(address newImplementation) public virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data, true);
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeTo} and {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal override onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```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(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlotUpgradeable {
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
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
contract Errors {
/**@notice Errors */
error BridgeError();
error SwapError();
error NotAuthorized();
error IncorrectRoute();
error NotEnoughEth();
error FailedToSendEther();
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {Structs} from "./Structs.sol";
contract Events is Structs {
/**@notice Revenue Bridge Events **/
event SetBridge(bytes32 bridge, BridgeParams params);
event SetSwap(bytes32 swap, SwapParams params);
event SetMinBridgeAmount(uint256 amount);
event SetDestinationAddress(DestinationAddress destinationAddress);
event SetStable(address oldStable, address newStable);
event Bridged(address indexed stable, uint256 stableBridged);
event CowllectorRefill(uint256 amount);
event Harvested(uint256 amount);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {IBalancerVault} from "../interfaces/swap/IBalancerVault.sol";
contract Structs {
// Will be unused if we dont swap with balancer
IBalancerVault.SwapKind public swapKind;
IBalancerVault.FundManagement public funds;
struct Cowllector {
bool sendFunds;
address cowllector;
uint256 amountCowllectorNeeds;
}
struct BridgeParams {
address bridge;
bytes params;
}
struct SwapParams {
address router;
bytes params;
}
struct DestinationAddress {
address destination;
bytes destinationBytes;
string destinationString;
}
struct Stargate {
uint16 dstChainId;
uint256 gasLimit;
uint256 srcPoolId;
uint256 dstPoolId;
}
struct Axelar {
string destinationChain;
string symbol;
}
struct Synapse {
uint256 chainId;
uint8 tokenIndexFrom;
uint8 tokenIndexTo;
address token;
uint8 dstIndexFrom;
uint8 dstIndexTo;
}
struct Across {
uint256 destinationChainId;
uint256 relayFee;
}
struct ReAl {
uint16 dstChainId;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IAxelar {
function sendToken(
string memory destinationChain,
string memory destinationAddress,
string memory symbol,
uint256 amount
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ICircle {
function depositForBurn(
uint256 amount,
uint32 destinationDomain,
bytes32 mintRecipient,
address burnToken
) external returns (uint64 _nonce);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IFraxFerry {
function embarkWithRecipient(
uint256 amount,
address to
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IStargate {
struct lzTxObj {
uint256 dstGasForCall;
uint256 dstNativeAmount;
bytes dstNativeAddr;
}
function addLiquidity(
uint256 _poolId,
uint256 _amountLD,
address _to
) external;
function swap(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
uint256 _amountLD,
uint256 _minAmountLD,
lzTxObj memory _lzTxParams,
bytes calldata _to,
bytes calldata _payload
) external payable;
function redeemRemote(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
uint256 _amountLP,
uint256 _minAmountLD,
bytes calldata _to,
lzTxObj memory _lzTxParams
) external payable;
function instantRedeemLocal(
uint16 _srcPoolId,
uint256 _amountLP,
address _to
) external returns (uint256);
function redeemLocal(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
uint256 _amountLP,
bytes calldata _to,
lzTxObj memory _lzTxParams
) external payable;
function sendCredits(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress
) external payable;
function quoteLayerZeroFee(
uint16 _dstChainId,
uint8 _functionType,
bytes calldata _toAddress,
bytes calldata _transferAndCallPayload,
lzTxObj memory _lzTxParams
) external view returns (uint256, uint256);
struct SendParam {
uint32 dstEid; // Destination endpoint ID.
bytes32 to; // Recipient address.
uint256 amountLD; // Amount to send in local decimals.
uint256 minAmountLD; // Minimum amount to send in local decimals.
bytes extraOptions; // Additional options supplied by the caller to be used in the LayerZero message.
bytes composeMsg; // The composed message for the send() operation.
bytes oftCmd; // The OFT command to be executed, unused in default OFT implementations.
}
/**
* @dev Struct representing OFT limit information.
* @dev These amounts can change dynamically and are up the the specific oft implementation.
*/
struct OFTLimit {
uint256 minAmountLD; // Minimum amount in local decimals that can be sent to the recipient.
uint256 maxAmountLD; // Maximum amount in local decimals that can be sent to the recipient.
}
/**
* @dev Struct representing OFT receipt information.
*/
struct OFTReceipt {
uint256 amountSentLD; // Amount of tokens ACTUALLY debited from the sender in local decimals.
// @dev In non-default implementations, the amountReceivedLD COULD differ from this value.
uint256 amountReceivedLD; // Amount of tokens to be received on the remote side.
}
/**
* @dev Struct representing OFT fee details.
* @dev Future proof mechanism to provide a standardized way to communicate fees to things like a UI.
*/
struct OFTFeeDetail {
int256 feeAmountLD; // Amount of the fee in local decimals.
string description; // Description of the fee.
}
struct MessagingFee {
uint256 nativeFee;
uint256 lzTokenFee;
}
struct MessagingReceipt {
bytes32 guid;
uint64 nonce;
MessagingFee fee;
}
/// @notice Ticket data for bus ride.
struct Ticket {
uint72 ticketId;
bytes passengerBytes;
}
function quoteSend(
SendParam calldata _sendParam,
bool _payInLzToken
) external view returns (MessagingFee memory fee);
function sendToken(
SendParam calldata _sendParam,
MessagingFee calldata _fee,
address _refundAddress
)
external
payable
returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt, Ticket memory ticket);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ISynapse {
function swapAndRedeemAndSwap(
address to,
uint256 chainId,
address token,
uint8 tokenIndexFrom,
uint8 tokenIndexTo,
uint256 dx,
uint256 minDy,
uint256 deadline,
uint8 swapIndexFrom,
uint8 swapIndexTo,
uint256 min,
uint256 swapTime
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IzkEVM {
function bridgeAsset(
uint32 dstChainId,
address receiver,
uint256 amount,
address token,
bool forceUpdate,
bytes memory permitData
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IzkSync {
function withdraw(
address to,
address token,
uint256 amount
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IWrappedNative {
function deposit() external payable;
function withdraw(uint256 wad) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IBalancerVault {
struct SingleSwap {
bytes32 poolId;
SwapKind kind;
address assetIn;
address assetOut;
uint256 amount;
bytes userData;
}
struct BatchSwapStep {
bytes32 poolId;
uint256 assetInIndex;
uint256 assetOutIndex;
uint256 amount;
bytes userData;
}
struct FundManagement {
address sender;
bool fromInternalBalance;
address payable recipient;
bool toInternalBalance;
}
struct JoinPoolRequest {
address[] assets;
uint256[] maxAmountsIn;
bytes userData;
bool fromInternalBalance;
}
enum SwapKind { GIVEN_IN, GIVEN_OUT }
function swap(
SingleSwap memory singleSwap,
FundManagement memory funds,
uint256 limit,
uint256 deadline
) external payable returns (uint256);
function batchSwap(
SwapKind kind,
BatchSwapStep[] memory swaps,
address[] memory assets,
FundManagement memory funds,
int256[] memory limits,
uint256 deadline
) external returns (int256[] memory assetDeltas);
function joinPool(
bytes32 poolId,
address sender,
address recipient,
JoinPoolRequest memory request
) external;
function getPoolTokens(bytes32 poolId)
external
view
returns (
address[] memory tokens,
uint256[] memory balances,
uint256 lastChangeBlock
);
function getPool(bytes32 poolId)
external
view
returns (address, uint8);
function flashLoan(
address recipient,
address[] memory tokens,
uint256[] memory amounts,
bytes memory userData
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IBeefySwapper {
function swap(address from, address to, uint256 amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IKyberElastic {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 minAmountOut;
uint160 limitSqrtP;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another token
/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function swapExactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 minAmountOut;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
/// @return amountOut The amount of the received token
function swapExactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 maxAmountIn;
uint160 limitSqrtP;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another token
/// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
/// @return amountIn The amount of the input token
function swapExactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);
struct ExactOutputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 maxAmountIn;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
/// @return amountIn The amount of the input token
function swapExactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ISolidlyRouter {
// Routes
struct Routes {
address from;
address to;
bool stable;
}
struct Route {
address from;
address to;
bool stable;
address factory;
}
function addLiquidity(
address tokenA,
address tokenB,
bool stable,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
bool stable,
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,
bool stable,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
bool stable,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokensSimple(
uint amountIn,
uint amountOutMin,
address tokenFrom,
address tokenTo,
bool stable,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
Routes[] memory route,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
Route[] memory route,
address to,
uint deadline
) external returns (uint[] memory amounts);
function getAmountOut(uint amountIn, address tokenIn, address tokenOut) external view returns (uint amount, bool stable);
function getAmountsOut(uint amountIn, Routes[] memory routes) external view returns (uint[] memory amounts);
function getAmountsOut(uint amountIn, Route[] memory routes) external view returns (uint[] memory amounts);
function quoteAddLiquidity(
address tokenA,
address tokenB,
bool stable,
uint amountADesired,
uint amountBDesired
) external view returns (uint amountA, uint amountB, uint liquidity);
function quoteAddLiquidity(
address tokenA,
address tokenB,
bool stable,
address _factory,
uint amountADesired,
uint amountBDesired
) external view returns (uint amountA, uint amountB, uint liquidity);
function defaultFactory() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IUniswapRouterETH {
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 swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
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 swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IUniswapRouterV3 {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another token
/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
struct ExactInputParams {
bytes path;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
/// @return amountOut The amount of the received token
function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another token
/// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
/// @return amountIn The amount of the input token
function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);
struct ExactOutputParams {
bytes path;
address recipient;
uint256 amountOut;
uint256 amountInMaximum;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
/// @return amountIn The amount of the input token
function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IUniswapRouterV3WithDeadline {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another token
/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
/// @return amountOut The amount of the received token
function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another token
/// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
/// @return amountIn The amount of the input token
function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);
struct ExactOutputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
/// @return amountIn The amount of the input token
function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../interfaces/swap/IBalancerVault.sol";
import "@openzeppelin-4/contracts/token/ERC20/ERC20.sol";
import "./BeefyBalancerStructs.sol";
library BalancerActionsLib {
function balancerJoin(address _vault, bytes32 _poolId, address _tokenIn, uint256 _amountIn) internal {
(address[] memory lpTokens,,) = IBalancerVault(_vault).getPoolTokens(_poolId);
uint256[] memory amounts = new uint256[](lpTokens.length);
for (uint256 i = 0; i < amounts.length;) {
amounts[i] = lpTokens[i] == _tokenIn ? _amountIn : 0;
unchecked { ++i; }
}
bytes memory userData = abi.encode(1, amounts, 1);
IBalancerVault.JoinPoolRequest memory request = IBalancerVault.JoinPoolRequest(lpTokens, amounts, userData, false);
IBalancerVault(_vault).joinPool(_poolId, address(this), address(this), request);
}
function buildSwapStructArray(BeefyBalancerStructs.BatchSwapStruct[] memory _route, uint256 _amountIn) internal pure returns (IBalancerVault.BatchSwapStep[] memory) {
IBalancerVault.BatchSwapStep[] memory swaps = new IBalancerVault.BatchSwapStep[](_route.length);
for (uint i; i < _route.length;) {
if (i == 0) {
swaps[0] =
IBalancerVault.BatchSwapStep({
poolId: _route[0].poolId,
assetInIndex: _route[0].assetInIndex,
assetOutIndex: _route[0].assetOutIndex,
amount: _amountIn,
userData: ""
});
} else {
swaps[i] =
IBalancerVault.BatchSwapStep({
poolId: _route[i].poolId,
assetInIndex: _route[i].assetInIndex,
assetOutIndex: _route[i].assetOutIndex,
amount: 0,
userData: ""
});
}
unchecked {
++i;
}
}
return swaps;
}
function balancerSwap(address _vault, IBalancerVault.SwapKind _swapKind, IBalancerVault.BatchSwapStep[] memory _swaps, address[] memory _route, IBalancerVault.FundManagement memory _funds, int256 _amountIn) internal returns (int256[] memory) {
int256[] memory limits = new int256[](_route.length);
for (uint i; i < _route.length;) {
if (i == 0) {
limits[0] = _amountIn;
} else if (i == _route.length - 1) {
limits[i] = -1;
}
unchecked { ++i; }
}
return IBalancerVault(_vault).batchSwap(_swapKind, _swaps, _route, _funds, limits, block.timestamp);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library BeefyBalancerStructs {
enum RouterType {
BALANCER,
UNISWAP_V2,
UNISWAP_V3
}
struct BatchSwapStruct {
bytes32 poolId;
uint256 assetInIndex;
uint256 assetOutIndex;
}
struct Reward {
RouterType routerType;
address router;
mapping(uint => BatchSwapStruct) swapInfo;
address[] assets;
bytes routeToNative; // backup route in case there is no Balancer liquidity for reward
uint minAmount; // minimum amount to be swapped to native
}
struct Input {
address input;
bool isComposable;
bool isBeets;
}
}// SPDX-License-Identifier: BUSL-1.1 /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.5.0 <0.9.0; library BytesLib { function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, 'slice_overflow'); require(_start + _length >= _start, 'slice_overflow'); require(_bytes.length >= _start + _length, 'slice_outOfBounds'); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_start + 20 >= _start, 'toAddress_overflow'); require(_bytes.length >= _start + 20, 'toAddress_outOfBounds'); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) { require(_start + 3 >= _start, 'toUint24_overflow'); require(_bytes.length >= _start + 3, 'toUint24_outOfBounds'); uint24 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x3), _start)) } return tempUint; } }
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import './BytesLib.sol';
/// @title Functions for manipulating path data for multihop swaps
library Path {
using BytesLib for bytes;
/// @dev The length of the bytes encoded address
uint256 private constant ADDR_SIZE = 20;
/// @dev The length of the bytes encoded fee
uint256 private constant FEE_SIZE = 3;
/// @dev The offset of a single token address and pool fee
uint256 private constant NEXT_OFFSET = ADDR_SIZE + FEE_SIZE;
/// @dev The offset of an encoded pool key
uint256 private constant POP_OFFSET = NEXT_OFFSET + ADDR_SIZE;
/// @dev The minimum length of an encoding that contains 2 or more pools
uint256 private constant MULTIPLE_POOLS_MIN_LENGTH = POP_OFFSET + NEXT_OFFSET;
/// @notice Returns true iff the path contains two or more pools
/// @param path The encoded swap path
/// @return True if path contains two or more pools, otherwise false
function hasMultiplePools(bytes memory path) internal pure returns (bool) {
return path.length >= MULTIPLE_POOLS_MIN_LENGTH;
}
/// @notice Returns the number of pools in the path
/// @param path The encoded swap path
/// @return The number of pools in the path
function numPools(bytes memory path) internal pure returns (uint256) {
// Ignore the first token address. From then on every fee and token offset indicates a pool.
return ((path.length - ADDR_SIZE) / NEXT_OFFSET);
}
/// @notice Decodes the first pool in path
/// @param path The bytes encoded swap path
/// @return tokenA The first token of the given pool
/// @return tokenB The second token of the given pool
/// @return fee The fee level of the pool
function decodeFirstPool(bytes memory path)
internal
pure
returns (
address tokenA,
address tokenB,
uint24 fee
)
{
tokenA = path.toAddress(0);
fee = path.toUint24(ADDR_SIZE);
tokenB = path.toAddress(NEXT_OFFSET);
}
/// @notice Gets the segment corresponding to the first pool in the path
/// @param path The bytes encoded swap path
/// @return The segment containing all data necessary to target the first pool in the path
function getFirstPool(bytes memory path) internal pure returns (bytes memory) {
return path.slice(0, POP_OFFSET);
}
/// @notice Skips a token + fee element from the buffer and returns the remainder
/// @param path The swap path
/// @return The remaining token + fee elements in the path
function skipToken(bytes memory path) internal pure returns (bytes memory) {
return path.slice(NEXT_OFFSET, path.length - NEXT_OFFSET);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../interfaces/swap/IKyberElastic.sol";
import "../interfaces/swap/IUniswapRouterV3.sol";
import "../interfaces/swap/IUniswapRouterWithDeadline.sol";
library UniV3Actions {
// kyber V3 swap
function kyberSwap(address _router, bytes memory _path, uint256 _amount) internal returns (uint256 amountOut) {
IKyberElastic.ExactInputParams memory swapParams = IKyberElastic.ExactInputParams({
path: _path,
recipient: address(this),
deadline: block.timestamp,
amountIn: _amount,
minAmountOut: 0
});
return IKyberElastic(_router).swapExactInput(swapParams);
}
// Uniswap V3 swap
function swapV3(address _router, bytes memory _path, uint256 _amount) internal returns (uint256 amountOut) {
IUniswapRouterV3.ExactInputParams memory swapParams = IUniswapRouterV3.ExactInputParams({
path: _path,
recipient: address(this),
amountIn: _amount,
amountOutMinimum: 0
});
return IUniswapRouterV3(_router).exactInput(swapParams);
}
// Uniswap V3 swap with deadline
function swapV3WithDeadline(address _router, bytes memory _path, uint256 _amount) internal returns (uint256 amountOut) {
IUniswapRouterV3WithDeadline.ExactInputParams memory swapParams = IUniswapRouterV3WithDeadline.ExactInputParams({
path: _path,
recipient: address(this),
deadline: block.timestamp,
amountIn: _amount,
amountOutMinimum: 0
});
return IUniswapRouterV3WithDeadline(_router).exactInput(swapParams);
}
// Uniswap V3 swap with deadline
function swapV3WithDeadline(address _router, bytes memory _path, uint256 _amount, address _to) internal returns (uint256 amountOut) {
IUniswapRouterV3WithDeadline.ExactInputParams memory swapParams = IUniswapRouterV3WithDeadline.ExactInputParams({
path: _path,
recipient: _to,
deadline: block.timestamp,
amountIn: _amount,
amountOutMinimum: 0
});
return IUniswapRouterV3WithDeadline(_router).exactInput(swapParams);
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": [
"ds-test/=lib/forge-std/lib/ds-test/src/",
"lib/forge-std:ds-test/=lib/forge-std/lib/ds-test/src/"
],
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"BridgeError","type":"error"},{"inputs":[],"name":"FailedToSendEther","type":"error"},{"inputs":[],"name":"IncorrectRoute","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"NotEnoughEth","type":"error"},{"inputs":[],"name":"SwapError","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stable","type":"address"},{"indexed":false,"internalType":"uint256","name":"stableBridged","type":"uint256"}],"name":"Bridged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CowllectorRefill","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Harvested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","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":false,"internalType":"bytes32","name":"bridge","type":"bytes32"},{"components":[{"internalType":"address","name":"bridge","type":"address"},{"internalType":"bytes","name":"params","type":"bytes"}],"indexed":false,"internalType":"struct Structs.BridgeParams","name":"params","type":"tuple"}],"name":"SetBridge","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"destination","type":"address"},{"internalType":"bytes","name":"destinationBytes","type":"bytes"},{"internalType":"string","name":"destinationString","type":"string"}],"indexed":false,"internalType":"struct Structs.DestinationAddress","name":"destinationAddress","type":"tuple"}],"name":"SetDestinationAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SetMinBridgeAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldStable","type":"address"},{"indexed":false,"internalType":"address","name":"newStable","type":"address"}],"name":"SetStable","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"swap","type":"bytes32"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"bytes","name":"params","type":"bytes"}],"indexed":false,"internalType":"struct Structs.SwapParams","name":"params","type":"tuple"}],"name":"SetSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"activeBridge","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activeSwap","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bridgeAxelar","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bridgeCircle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bridgeFraxFerry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bridgeParams","outputs":[{"internalType":"address","name":"bridge","type":"address"},{"internalType":"bytes","name":"params","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bridgeStargate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bridgeSynapse","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeToUse","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bridgezkEVM","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bridgezkSync","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cowllector","outputs":[{"internalType":"bool","name":"sendFunds","type":"bool"},{"internalType":"address","name":"cowllector","type":"address"},{"internalType":"uint256","name":"amountCowllectorNeeds","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"destinationAddress","outputs":[{"internalType":"address","name":"destination","type":"address"},{"internalType":"bytes","name":"destinationBytes","type":"bytes"},{"internalType":"string","name":"destinationString","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_variable","type":"string"}],"name":"findHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"funds","outputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bool","name":"fromInternalBalance","type":"bool"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"bool","name":"toInternalBalance","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"bool","name":"_native","type":"bool"}],"name":"inCaseTokensGetStuck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastHarvest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minBridgeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"native","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_bridgeHash","type":"bytes32"},{"components":[{"internalType":"address","name":"bridge","type":"address"},{"internalType":"bytes","name":"params","type":"bytes"}],"internalType":"struct Structs.BridgeParams","name":"_params","type":"tuple"}],"name":"setActiveBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_swapHash","type":"bytes32"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"bytes","name":"params","type":"bytes"}],"internalType":"struct Structs.SwapParams","name":"_params","type":"tuple"}],"name":"setActiveSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_bridgeHash","type":"bytes32"},{"internalType":"string","name":"_function","type":"string"}],"name":"setBridgeMap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"sendFunds","type":"bool"},{"internalType":"address","name":"cowllector","type":"address"},{"internalType":"uint256","name":"amountCowllectorNeeds","type":"uint256"}],"internalType":"struct Structs.Cowllector","name":"_cowllector","type":"tuple"}],"name":"setCowllector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"destination","type":"address"},{"internalType":"bytes","name":"destinationBytes","type":"bytes"},{"internalType":"string","name":"destinationString","type":"string"}],"internalType":"struct Structs.DestinationAddress","name":"_destination","type":"tuple"}],"name":"setDestinationAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setMinBridgeAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_stable","type":"address"},{"internalType":"contract IERC20","name":"_native","type":"address"}],"name":"setStable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_hash","type":"string"},{"internalType":"string","name":"_variable","type":"string"}],"name":"setSwapHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stable","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapAlgebra","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapBalancer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapBeefy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapKind","outputs":[{"internalType":"enum IBalancerVault.SwapKind","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapParams","outputs":[{"internalType":"address","name":"router","type":"address"},{"internalType":"bytes","name":"params","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapSolidly","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"swapToUse","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapUniV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapUniV3","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapUniV3Deadline","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","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"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60a06040523060805234801561001457600080fd5b50608051615f686200004d60003960008181610ed401528181610f1d0152818161102401528181611064015261137d0152615f686000f3fe6080604052600436106102815760003560e01c80638129fc1c1161014f578063c4b00c4f116100c1578063ee63c1e51161007a578063ee63c1e51461078a578063f1a392da1461079f578063f2fde38b146107b5578063f3f1a71a146107d5578063fe8d1ab0146107f5578063ff33d21f1461080a57600080fd5b8063c4b00c4f1461068b578063c89f2ce4146106ab578063ca3254691461071c578063cc5ea4ef14610740578063d49b640814610755578063d7d66e711461076a57600080fd5b8063a5131aaa11610113578063a5131aaa146105c2578063b54653fb146105d7578063b9f391471461062b578063bac86af514610640578063bce4547a14610660578063c3c224751461067557600080fd5b80638129fc1c14610540578063873d80ec146105555780638da5cb5b14610578578063943f8e96146105965780639c345b9f146105ac57600080fd5b80635066a747116101f35780636ae40711116101ac5780636ae407111461049f5780636d0a6891146104b457806370c75107146104e1578063715018a61461050157806373f1df3314610516578063748b3c051461052b57600080fd5b80635066a747146103eb5780635109d8b61461040b57806352d1902d14610420578063530728d51461044357806364e510a114610458578063671f6a261461047857600080fd5b80631610ee40116102455780631610ee401461034357806322be3de114610363578063284eb663146103835780633659cfe6146103a35780634641257d146103c35780634f1ef286146103d857600080fd5b80630278fb8a146102a7578063057d1ae3146102bc5780630d1f7833146102d157806311b0b42d146102e6578063154085921461032357600080fd5b366102a25760cd546001600160a01b031633146102a0576102a06146f2565b005b600080fd5b3480156102b357600080fd5b506102a061082a565b3480156102c857600080fd5b506102a06109bc565b3480156102dd57600080fd5b506102a0610c21565b3480156102f257600080fd5b5060cd54610306906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561032f57600080fd5b506102a061033e366004614750565b610e06565b34801561034f57600080fd5b506102a061035e3660046147ad565b610e27565b34801561036f57600080fd5b5060cc54610306906001600160a01b031681565b34801561038f57600080fd5b506102a061039e3660046147e1565b610e78565b3480156103af57600080fd5b506102a06103be366004614861565b610eca565b3480156103cf57600080fd5b506102a0610fb2565b6102a06103e6366004614913565b61101a565b3480156103f757600080fd5b506102a06104063660046149b7565b6110ea565b34801561041757600080fd5b506102a061117d565b34801561042c57600080fd5b50610435611370565b60405190815260200161031a565b34801561044f57600080fd5b506102a0611423565b34801561046457600080fd5b506102a06104733660046149b7565b611510565b34801561048457600080fd5b5060c9546104929060ff1681565b60405161031a9190614a1f565b3480156104ab57600080fd5b506102a061159e565b3480156104c057600080fd5b506104d46104cf366004614a2d565b611784565b60405161031a9190614a96565b3480156104ed57600080fd5b506104356104fc366004614aa9565b61181e565b34801561050d57600080fd5b506102a0611852565b34801561052257600080fd5b506102a0611866565b34801561053757600080fd5b506102a06118c7565b34801561054c57600080fd5b506102a0611a37565b34801561056157600080fd5b5061056a611baf565b60405161031a929190614aea565b34801561058457600080fd5b506033546001600160a01b0316610306565b3480156105a257600080fd5b5061043560cf5481565b3480156105b857600080fd5b5061043560ce5481565b3480156105ce57600080fd5b506102a0611c50565b3480156105e357600080fd5b5060d05460d1546106069160ff8116916101009091046001600160a01b03169083565b6040805193151584526001600160a01b0390921660208401529082015260600161031a565b34801561063757600080fd5b506102a0611cbc565b34801561064c57600080fd5b506102a061065b366004614b1c565b611e48565b34801561066c57600080fd5b506102a0611f42565b34801561068157600080fd5b5061043560d95481565b34801561069757600080fd5b506102a06106a6366004614b55565b612156565b3480156106b757600080fd5b5060ca5460cb546106e7916001600160a01b038082169260ff600160a01b93849004811693928216929091041684565b60405161031a94939291906001600160a01b039485168152921515602084015292166040820152901515606082015260800190565b34801561072857600080fd5b5061073161216b565b60405161031a93929190614b71565b34801561074c57600080fd5b506102a061229a565b34801561076157600080fd5b5061056a612435565b34801561077657600080fd5b506102a0610785366004614a2d565b612453565b34801561079657600080fd5b506102a0612493565b3480156107ab57600080fd5b5061043560dd5481565b3480156107c157600080fd5b506102a06107d0366004614861565b61261f565b3480156107e157600080fd5b506104d46107f0366004614a2d565b612695565b34801561080157600080fd5b506102a06126ae565b34801561081657600080fd5b506102a0610825366004614ba7565b612837565b610832612913565b600060d4600101805461084490614bd5565b80601f016020809104026020016040519081016040528092919081815260200182805461087090614bd5565b80156108bd5780601f10610892576101008083540402835291602001916108bd565b820191906000526020600020905b8154815290600101906020018083116108a057829003601f168201915b50505050508060200190518101906108d59190614c9b565b60cd5481519192506001600160a01b03169082906000906108f8576108f8614ccf565b60200260200101516001600160a01b031614610927576040516376c252e160e11b815260040160405180910390fd5b60cc5481516001600160a01b0390911690829061094690600190614cfb565b8151811061095657610956614ccf565b60200260200101516001600160a01b031614610985576040516376c252e160e11b815260040160405180910390fd5b600061099082612933565b9050600061099c6129ec565b60d4549091506109b6906001600160a01b03168383612a5f565b50505050565b6109c4612913565b600060d260010180546109d690614bd5565b80601f0160208091040260200160405190810160405280929190818152602001828054610a0290614bd5565b8015610a4f5780601f10610a2457610100808354040283529160200191610a4f565b820191906000526020600020905b815481529060010190602001808311610a3257829003601f168201915b5050505050806020019051810190610a679190614d0e565b905060006040518060600160405280836020015181526020016000815260200160405180604001604052806002815260200161060f60f31b81525081525090506000610b45836000015160d66001018054610ac190614bd5565b80601f0160208091040260200160405190810160405280929190818152602001828054610aed90614bd5565b8015610b3a5780601f10610b0f57610100808354040283529160200191610b3a565b820191906000526020600020905b815481529060010190602001808311610b1d57829003601f168201915b505050505084612b00565b9050610b5081612b81565b610b58612bf4565b6000610b62612c55565b905060d954811115610beb5760d2548451604080870151606088015191516327efc43f60e21b81526001600160a01b0390941693639fbf10fc938793610bb8939192309089906000908d9060d790600401614e29565b6000604051808303818588803b158015610bd157600080fd5b505af1158015610be5573d6000803e3d6000fd5b50505050505b60cc546040518281526001600160a01b0390911690600080516020615ecc8339815191529060200160405180910390a250505050565b610c29612913565b60008060d46001018054610c3c90614bd5565b80601f0160208091040260200160405190810160405280929190818152602001828054610c6890614bd5565b8015610cb55780601f10610c8a57610100808354040283529160200191610cb5565b820191906000526020600020905b815481529060010190602001808311610c9857829003601f168201915b5050505050806020019051810190610ccd9190614ea3565b60cd5481519294509092506001600160a01b0316908290600090610cf357610cf3614ccf565b60200260200101516001600160a01b031614610d22576040516376c252e160e11b815260040160405180910390fd5b60cc5481516001600160a01b03909116908290610d4190600190614cfb565b81518110610d5157610d51614ccf565b60200260200101516001600160a01b031614610d80576040516376c252e160e11b815260040160405180910390fd5b6000610d8a6129ec565b90506000610d988483612c86565b60d45460c9546040805160808101825260ca546001600160a01b03808216835260ff600160a01b9283900481161515602085015260cb548083169585019590955291909304811615156060830152949550610dff9491909316929116908490879087612e8f565b5050505050565b610e0e612fd9565b600083815260db602052604090206109b6828483614fdc565b610e2f612fd9565b7f518f47fcfba5d9b707c3387a7fa4301136192d8091a43ea13ae8db7275ab5d3a81604051610e5e9190615103565b60405180910390a18060d6610e7382826151d4565b505050565b610e80612fd9565b818160dc60008787604051602001610e999291906152cd565b6040516020818303038152906040528051906020012081526020019081526020016000209182610dff929190614fdc565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610f1b5760405162461bcd60e51b8152600401610f12906152e1565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610f64600080516020615eec833981519152546001600160a01b031690565b6001600160a01b031614610f8a5760405162461bcd60e51b8152600401610f129061532d565b610f9381613033565b60408051600080825260208201909252610faf9183919061303b565b50565b610fba6131a6565b610fc2613217565b7f8e55ccfc9778ff8eba1646d765cf1982537ce0f9257054a17b48aad745250183610feb6129ec565b60405190815260200160405180910390a160006110066129ec565b111561101457611014613350565b4260dd55565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036110625760405162461bcd60e51b8152600401610f12906152e1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166110ab600080516020615eec833981519152546001600160a01b031690565b6001600160a01b0316146110d15760405162461bcd60e51b8152600401610f129061532d565b6110da82613033565b6110e68282600161303b565b5050565b6110f2612fd9565b7f25f7dd6fc737add5174192a11292dfd270c1397f9c4f641fb6336a208b5efbed82826040516111239291906153bc565b60405180910390a160cd5460d454611147916001600160a01b039081169116613380565b60cf8290558060d461115982826154b1565b505060cd546110e6906001600160a01b03166111786020840184614861565b61340f565b611185612913565b600060d4600101805461119790614bd5565b80601f01602080910402602001604051908101604052809291908181526020018280546111c390614bd5565b80156112105780601f106111e557610100808354040283529160200191611210565b820191906000526020600020905b8154815290600101906020018083116111f357829003601f168201915b505050505080602001905181019061122891906154bb565b905060006112358261349c565b60cd5481519192506001600160a01b031690829060009061125857611258614ccf565b60200260200101516001600160a01b031614611287576040516376c252e160e11b815260040160405180910390fd5b60cc5481516001600160a01b039091169082906112a690600190614cfb565b815181106112b6576112b6614ccf565b60200260200101516001600160a01b0316146112e5576040516376c252e160e11b815260040160405180910390fd5b60006112ef6129ec565b60d454604051631e82ecdb60e31b81529192506001600160a01b03169063f41766d890611329908490600090889030904290600401615593565b6000604051808303816000875af1158015611348573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109b69190810190615628565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146114105760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610f12565b50600080516020615eec83398151915290565b61142b612913565b611433612bf4565b600061143d612c55565b905060d9548111156114dd5760d25460d65460cc5460405163cd58657960e01b81526000600482018190526001600160a01b0393841660248301526044820186905291831660648201526001608482015260c060a482015260c481019190915291169063cd5865799060e4015b600060405180830381600087803b1580156114c457600080fd5b505af11580156114d8573d6000803e3d6000fd5b505050505b60cc546040518281526001600160a01b0390911690600080516020615ecc8339815191529060200160405180910390a250565b611518612fd9565b7f5e355369ceaccb04ff615500f99b96912ce9f237ed35ae521487c19064e2318d82826040516115499291906153bc565b60405180910390a160cc5460d25461156d916001600160a01b039081169116613380565b60ce8290558060d261157f82826154b1565b505060cc546110e6906001600160a01b03166111786020840184614861565b6115a6612913565b600060d460010180546115b890614bd5565b80601f01602080910402602001604051908101604052809291908181526020018280546115e490614bd5565b80156116315780601f1061160657610100808354040283529160200191611631565b820191906000526020600020905b81548152906001019060200180831161161457829003601f168201915b50505050508060200190518101906116499190614c9b565b60cd5481519192506001600160a01b031690829060009061166c5761166c614ccf565b60200260200101516001600160a01b03161461169b576040516376c252e160e11b815260040160405180910390fd5b60cc5481516001600160a01b039091169082906116ba90600190614cfb565b815181106116ca576116ca614ccf565b60200260200101516001600160a01b0316146116f9576040516376c252e160e11b815260040160405180910390fd5b60006117036129ec565b60d4546040516338ed173960e01b81529192506001600160a01b0316906338ed17399061173d9084906000908790309042906004016156fc565b6000604051808303816000875af115801561175c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e739190810190615628565b60db602052600090815260409020805461179d90614bd5565b80601f01602080910402602001604051908101604052809291908181526020018280546117c990614bd5565b80156118165780601f106117eb57610100808354040283529160200191611816565b820191906000526020600020905b8154815290600101906020018083116117f957829003601f168201915b505050505081565b600082826040516020016118339291906152cd565b6040516020818303038152906040528051906020012090505b92915050565b61185a612fd9565b61186460006135ba565b565b61186e612913565b611876612bf4565b6000611880612c55565b905060d954811115610faf5760d25460d6546040516302e108e960e11b8152600481018490526001600160a01b0391821660248201529116906305c211d2906044016114aa565b6118cf612913565b600060d260010180546118e190614bd5565b80601f016020809104026020016040519081016040528092919081815260200182805461190d90614bd5565b801561195a5780601f1061192f5761010080835404028352916020019161195a565b820191906000526020600020905b81548152906001019060200180831161193d57829003601f168201915b50505050508060200190518101906119729190615788565b905061197c612bf4565b6000611986612c55565b905060d954811115611a025760d254825160208401516040516326ef699d60e01b81526001600160a01b03909316926326ef699d926119cf92909160d89190879060040161582e565b600060405180830381600087803b1580156119e957600080fd5b505af11580156119fd573d6000803e3d6000fd5b505050505b60cc546040518281526001600160a01b0390911690600080516020615ecc833981519152906020015b60405180910390a25050565b600054610100900460ff1615808015611a575750600054600160ff909116105b80611a715750303b158015611a71575060005460ff166001145b611ad45760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610f12565b6000805460ff191660011790558015611af7576000805461ff0019166101001790555b611aff61360c565b611b0761363b565b611b0f613962565b604080516080810182523080825260006020830181905292820181905260609091019190915260ca805460ff60a01b199092166001600160a81b0319928316811790915560cb805490921617905560c9805460ff191690558015610faf576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b60d4805460d580546001600160a01b039092169291611bcd90614bd5565b80601f0160208091040260200160405190810160405280929190818152602001828054611bf990614bd5565b8015611c465780601f10611c1b57610100808354040283529160200191611c46565b820191906000526020600020905b815481529060010190602001808311611c2957829003601f168201915b5050505050905082565b611c58612913565b611c60612bf4565b6000611c6a612c55565b905060d9548111156114dd5760d25460d65460cc54604051636ce5768960e11b81526001600160a01b03928316600482015290821660248201526044810184905291169063d9caed12906064016114aa565b611cc4612913565b600060d46001018054611cd690614bd5565b80601f0160208091040260200160405190810160405280929190818152602001828054611d0290614bd5565b8015611d4f5780601f10611d2457610100808354040283529160200191611d4f565b820191906000526020600020905b815481529060010190602001808311611d3257829003601f168201915b5050505050806020019051810190611d679190615879565b90506000611d7482613c6b565b60cd5481519192506001600160a01b0316908290600090611d9757611d97614ccf565b60200260200101516001600160a01b031614611dc6576040516376c252e160e11b815260040160405180910390fd5b60cc5481516001600160a01b03909116908290611de590600190614cfb565b81518110611df557611df5614ccf565b60200260200101516001600160a01b031614611e24576040516376c252e160e11b815260040160405180910390fd5b6000611e2e6129ec565b60d4549091506109b6906001600160a01b03168483612a5f565b611e50612fd9565b8015611ec1576040514790600090339083908381818185875af1925050503d8060008114611e9a576040519150601f19603f3d011682016040523d82523d6000602084013e611e9f565b606091505b50509050806109b657604051630dcf35db60e41b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015611f08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2c91906158c1565b9050610e736001600160a01b0384163383613d6e565b611f4a612913565b600060d46001018054611f5c90614bd5565b80601f0160208091040260200160405190810160405280929190818152602001828054611f8890614bd5565b8015611fd55780601f10611faa57610100808354040283529160200191611fd5565b820191906000526020600020905b815481529060010190602001808311611fb857829003601f168201915b5050505050806020019051810190611fed9190614c9b565b60cd5481519192506001600160a01b031690829060009061201057612010614ccf565b60200260200101516001600160a01b03161461203f576040516376c252e160e11b815260040160405180910390fd5b60cc5481516001600160a01b03909116908290600190811061206357612063614ccf565b60200260200101516001600160a01b031614612092576040516376c252e160e11b815260040160405180910390fd5b600061209c6129ec565b60d45483519192506001600160a01b03169063df791e509084906000906120c5576120c5614ccf565b6020026020010151846001815181106120e0576120e0614ccf565b60209081029190910101516040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260448101849052606401600060405180830381600087803b15801561213a57600080fd5b505af115801561214e573d6000803e3d6000fd5b505050505050565b61215e612fd9565b8060d0610e7382826158da565b60d6805460d780546001600160a01b03909216929161218990614bd5565b80601f01602080910402602001604051908101604052809291908181526020018280546121b590614bd5565b80156122025780601f106121d757610100808354040283529160200191612202565b820191906000526020600020905b8154815290600101906020018083116121e557829003601f168201915b50505050509080600201805461221790614bd5565b80601f016020809104026020016040519081016040528092919081815260200182805461224390614bd5565b80156122905780601f1061226557610100808354040283529160200191612290565b820191906000526020600020905b81548152906001019060200180831161227357829003601f168201915b5050505050905083565b6122a2612913565b600060d260010180546122b490614bd5565b80601f01602080910402602001604051908101604052809291908181526020018280546122e090614bd5565b801561232d5780601f106123025761010080835404028352916020019161232d565b820191906000526020600020905b81548152906001019060200180831161231057829003601f168201915b5050505050806020019051810190612345919061594e565b905061234f612bf4565b6000612359612c55565b905060d954811115611a025760d25460d6548351606085015160208601516040870151608088015160a08901516001600160a01b0397881697639f3307279716959493929189916000914291836123b284610e106159e7565b6040516001600160e01b031960e08f901b1681526001600160a01b039c8d166004820152602481019b909b529a90981660448a015260ff96871660648a0152948616608489015260a488019390935260c487019190915260e4860152821661010485015216610124830152610144820152610164810191909152610184016119cf565b60d2805460d380546001600160a01b039092169291611bcd90614bd5565b61245b612fd9565b6040518181527ff4f47d85dc8207b9d9c6dfd289d4f5008b33df899eda3da90658d75c351e54759060200160405180910390a160d955565b61249b612913565b600060d460010180546124ad90614bd5565b80601f01602080910402602001604051908101604052809291908181526020018280546124d990614bd5565b80156125265780601f106124fb57610100808354040283529160200191612526565b820191906000526020600020905b81548152906001019060200180831161250957829003601f168201915b505050505080602001905181019061253e9190615879565b9050600061254b82613c6b565b60cd5481519192506001600160a01b031690829060009061256e5761256e614ccf565b60200260200101516001600160a01b03161461259d576040516376c252e160e11b815260040160405180910390fd5b60cc5481516001600160a01b039091169082906125bc90600190614cfb565b815181106125cc576125cc614ccf565b60200260200101516001600160a01b0316146125fb576040516376c252e160e11b815260040160405180910390fd5b60006126056129ec565b60d4549091506109b6906001600160a01b03168483613dd1565b612627612fd9565b6001600160a01b03811661268c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610f12565b610faf816135ba565b60dc602052600090815260409020805461179d90614bd5565b6126b6612913565b600060d260010180546126c890614bd5565b80601f01602080910402602001604051908101604052809291908181526020018280546126f490614bd5565b80156127415780601f1061271657610100808354040283529160200191612741565b820191906000526020600020905b81548152906001019060200180831161272457829003601f168201915b505050505080602001905181019061275991906159fa565b9050612763612bf4565b600061276d612c55565b905060d954811115611a025760d25460d65460cc546040516337e9a82760e11b81526004810185905263ffffffff861660248201526001600160a01b0392831660448201529082166064820152911690636fd3504e906084016020604051808303816000875af11580156127e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128099190615a20565b5060cc546040518281526001600160a01b0390911690600080516020615ecc83398151915290602001611a2b565b61283f612fd9565b60da5460ff166128845760cc80546001600160a01b039384166001600160a01b03199182161790915560cd805492909316911617905560da805460ff19166001179055565b60cc54604080516001600160a01b03928316815291841660208301527f4239efeca0761c0d170bd15a6e85542dbe0376ba0f5f1551b39c6045866ff735910160405180910390a160cc5460d2546128e7916001600160a01b039081169116613380565b60cc80546001600160a01b0319166001600160a01b0384811691821790925560d2546110e6921661340f565b3330146118645760405163ea8e4eb560e01b815260040160405180910390fd5b60608160008151811061294857612948614ccf565b6020026020010151604051602001612978919060609190911b6bffffffffffffffffffffffff1916815260140190565b60408051601f19818403018152919052905060015b82518110156129e657818382815181106129a9576129a9614ccf565b60200260200101516040516020016129c2929190615a49565b604051602081830303815290604052915080806129de90615a80565b91505061298d565b50919050565b60cd546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a08231906024015b602060405180830381865afa158015612a36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a5a91906158c1565b905090565b6040805160a081018252838152306020820152428183015260608101839052600060808201819052915163c04b8d5960e01b81526001600160a01b0386169063c04b8d5990612ab2908490600401615a99565b6020604051808303816000875af1158015612ad1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612af591906158c1565b9150505b9392505050565b60d254604051630a51236960e01b81526000916001600160a01b031690630a51236990612b3890879060019088908890600401615af1565b6040805180830381865afa158015612b54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b789190615b3b565b50949350505050565b6000612b8b6129ec565b90508181106110e65760cd54604051632e1a7d4d60e01b8152600481018490526001600160a01b0390911690632e1a7d4d90602401600060405180830381600087803b158015612bda57600080fd5b505af1925050508015612beb575060015b156110e6575050565b60cf54600090815260dc6020526040908190208151600481526024810192839052610faf929091612c2491615b5f565b6040519081900390206020820180516001600160e01b03166001600160e01b03199092169190911790523090613e1e565b60cc546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401612a19565b6060600083516001600160401b03811115612ca357612ca361487e565b604051908082528060200260200182016040528015612d0957816020015b612cf66040518060a0016040528060008019168152602001600081526020016000815260200160008152602001606081525090565b815260200190600190039081612cc15790505b50905060005b8451811015612e875780600003612dd3576040518060a0016040528086600081518110612d3e57612d3e614ccf565b602002602001015160000151815260200186600081518110612d6257612d62614ccf565b602002602001015160200151815260200186600081518110612d8657612d86614ccf565b60200260200101516040015181526020018581526020016040518060200160405280600081525081525082600081518110612dc357612dc3614ccf565b6020026020010181905250612e7f565b6040518060a00160405280868381518110612df057612df0614ccf565b6020026020010151600001518152602001868381518110612e1357612e13614ccf565b6020026020010151602001518152602001868381518110612e3657612e36614ccf565b60200260200101516040015181526020016000815260200160405180602001604052806000815250815250828281518110612e7357612e73614ccf565b60200260200101819052505b600101612d0f565b509392505050565b6060600084516001600160401b03811115612eac57612eac61487e565b604051908082528060200260200182016040528015612ed5578160200160208202803683370190505b50905060005b8551811015612f4f5780600003612f11578382600081518110612f0057612f00614ccf565b602002602001018181525050612f47565b60018651612f1f9190614cfb565b8103612f4757600019828281518110612f3a57612f3a614ccf565b6020026020010181815250505b600101612edb565b5060405163945bcec960e01b81526001600160a01b0389169063945bcec990612f86908a908a908a908a9088904290600401615c05565b6000604051808303816000875af1158015612fa5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612fcd9190810190615628565b98975050505050505050565b6033546001600160a01b031633146118645760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610f12565b610faf612fd9565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561306e57610e7383613e62565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156130c8575060408051601f3d908101601f191682019092526130c5918101906158c1565b60015b61312b5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610f12565b600080516020615eec833981519152811461319a5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610f12565b50610e73838383613efe565b478015610faf5760cd60009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156131fd57600080fd5b505af19350505050801561320f575060015b15610faf5750565b60d05460ff16156118645760cd5460d0546040516370a0823160e01b81526101009091046001600160a01b03908116600483015260009216906370a0823190602401602060405180830381865afa158015613276573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061329a91906158c1565b60d0546132b6919061010090046001600160a01b0316316159e7565b60d154909150811015610faf5760006132cd6129ec565b905060008260d0600101546132e29190614cfb565b90508181116132f157806132f3565b815b60d05460cd54919250613318916001600160a01b039081169161010090041683613d6e565b6040518181527feb722ef3dbafc24e43f4627f9b306563a93d546865b49eb1e64fbaffdab73d5c9060200160405180910390a1505050565b60ce54600090815260db6020526040908190208151600481526024810192839052610faf929091612c2491615b5f565b604051636eb1769f60e11b81523060048201526001600160a01b0382811660248301526000919084169063dd62ed3e90604401602060405180830381865afa1580156133d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133f491906158c1565b11156110e6576110e66001600160a01b038316826000613f23565b604051636eb1769f60e11b81523060048201526001600160a01b03828116602483015283169063dd62ed3e90604401602060405180830381865afa15801561345b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061347f91906158c1565b6000036110e6576110e66001600160a01b03831682600019613f23565b60606000825160016134ae91906159e7565b6001600160401b038111156134c5576134c561487e565b6040519080825280602002602001820160405280156134ee578160200160208202803683370190505b5090508260008151811061350457613504614ccf565b6020026020010151600001518160008151811061352357613523614ccf565b60200260200101906001600160a01b031690816001600160a01b03168152505060005b83518110156135b35783818151811061356157613561614ccf565b6020026020010151602001518282600161357b91906159e7565b8151811061358b5761358b614ccf565b6001600160a01b03909216602092830291909101909101526135ac81615a80565b9050613546565b5092915050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166136335760405162461bcd60e51b8152600401610f1290615d1e565b611864614038565b6040518060400160405280600e81526020016d627269646765436972636c65282960901b81525060db600060405160200161369090602080825260069082015265434952434c4560d01b604082015260600190565b60405160208183030381529060405280519060200120815260200190815260200160002090816136c09190615d69565b506040518060400160405280601081526020016f6272696467655374617267617465282960801b81525060db600060405160200161371a90602080825260089082015267535441524741544560c01b604082015260600190565b604051602081830303815290604052805190602001208152602001908152602001600020908161374a9190615d69565b506040518060400160405280600e81526020016d6272696467654178656c6172282960901b81525060db60006040516020016137a09060208082526006908201526520ac22a620a960d11b604082015260600190565b60405160208183030381529060405280519060200120815260200190815260200160002090816137d09190615d69565b506040518060400160405280600f81526020016e62726964676553796e61707365282960881b81525060db60006040516020016138289060208082526007908201526653594e4150534560c81b604082015260600190565b60405160208183030381529060405280519060200120815260200190815260200160002090816138589190615d69565b506040518060400160405280600d81526020016c6272696467657a6b45564d282960981b81525060db60006040516020016138ac906020808252600590820152647a6b45564d60d81b604082015260600190565b60405160208183030381529060405280519060200120815260200190815260200160002090816138dc9190615d69565b506040518060400160405280600e81526020016d6272696467657a6b53796e63282960901b81525060db6000604051602001613932906020808252600690820152657a6b53594e4360d01b604082015260600190565b6040516020818303038152906040528051906020012081526020019081526020016000209081610faf9190615d69565b6040518060400160405280600b81526020016a73776170556e695632282960a81b81525060dc60006040516020016139b8906020808252600a90820152692aa724a9aba0a82fab1960b11b604082015260600190565b60405160208183030381529060405280519060200120815260200190815260200160002090816139e89190615d69565b506040518060400160405280600d81526020016c73776170536f6c69646c79282960981b81525060dc6000604051602001613a3e90602080825260079082015266534f4c49444c5960c81b604082015260600190565b6040516020818303038152906040528051906020012081526020019081526020016000209081613a6e9190615d69565b506040518060400160405280600b81526020016a73776170556e695633282960a81b81525060dc6000604051602001613ac5906020808252600a9082015269554e49535741505f563360b01b604082015260600190565b6040516020818303038152906040528051906020012081526020019081526020016000209081613af59190615d69565b506040518060400160405280601381526020017273776170556e695633446561646c696e65282960681b81525060dc6000604051602001613b5d90602080825260139082015272554e49535741505f56335f444541444c494e4560681b604082015260600190565b6040516020818303038152906040528051906020012081526020019081526020016000209081613b8d9190615d69565b506040518060400160405280600d81526020016c73776170416c6765627261282960981b81525060dc6000604051602001613be390602080825260079082015266414c474542524160c81b604082015260600190565b6040516020818303038152906040528051906020012081526020019081526020016000209081613c139190615d69565b506040518060400160405280600e81526020016d7377617042616c616e636572282960901b81525060dc6000604051602001613932906020808252600890820152672120a620a721a2a960c11b604082015260600190565b60606000613c7883614068565b90506000613c878260016159e7565b6001600160401b03811115613c9e57613c9e61487e565b604051908082528060200260200182016040528015613cc7578160200160208202803683370190505b50905060005b82811015612e8757600080613ce18761408e565b509150915081848481518110613cf957613cf9614ccf565b6001600160a01b03909216602092830291909101909101528084613d1e8560016159e7565b81518110613d2e57613d2e614ccf565b60200260200101906001600160a01b031690816001600160a01b031681525050613d57876140ca565b965050508080613d6690615a80565b915050613ccd565b6040516001600160a01b038316602482015260448101829052610e7390849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526140fb565b60408051608081018252838152306020820152808201839052600060608201819052915163b858183f60e01b81526001600160a01b0386169063b858183f90612ab2908490600401615e22565b6060612af9838360006040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c656400008152506141d0565b6001600160a01b0381163b613ecf5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610f12565b600080516020615eec83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b613f07836142ad565b600082511180613f145750805b15610e73576109b683836142ed565b801580613f9d5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015613f77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f9b91906158c1565b155b6140085760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610f12565b6040516001600160a01b038316602482015260448101829052610e7390849063095ea7b360e01b90606401613d9a565b600054610100900460ff1661405f5760405162461bcd60e51b8152600401610f1290615d1e565b611864336135ba565b6000614076600360146159e7565b601483516140849190614cfb565b61184c9190615e70565b6000808061409c8482614312565b92506140a98460146143c6565b90506140c16140ba600360146159e7565b8590614312565b91509193909250565b606061184c6140db600360146159e7565b6140e7600360146159e7565b84516140f39190614cfb565b849190614471565b6000614150826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166145c89092919063ffffffff16565b90508051600014806141715750808060200190518101906141719190615e92565b610e735760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610f12565b6060824710156142315760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610f12565b600080866001600160a01b0316858760405161424d9190615eaf565b60006040518083038185875af1925050503d806000811461428a576040519150601f19603f3d011682016040523d82523d6000602084013e61428f565b606091505b50915091506142a0878383876145d7565b925050505b949350505050565b6142b681613e62565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060612af98383604051806060016040528060278152602001615f0c60279139614650565b6000816143208160146159e7565b10156143635760405162461bcd60e51b8152602060048201526012602482015271746f416464726573735f6f766572666c6f7760701b6044820152606401610f12565b61436e8260146159e7565b835110156143b65760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b6044820152606401610f12565b500160200151600160601b900490565b6000816143d48160036159e7565b10156144165760405162461bcd60e51b8152602060048201526011602482015270746f55696e7432345f6f766572666c6f7760781b6044820152606401610f12565b6144218260036159e7565b835110156144685760405162461bcd60e51b8152602060048201526014602482015273746f55696e7432345f6f75744f66426f756e647360601b6044820152606401610f12565b50016003015190565b60608161447f81601f6159e7565b10156144be5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610f12565b826144c983826159e7565b10156145085760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610f12565b61451282846159e7565b845110156145565760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610f12565b6060821580156145755760405191506000825260208201604052612b78565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156145ae578051835260209283019201614596565b5050858452601f01601f1916604052505090509392505050565b60606142a584846000856141d0565b6060831561464657825160000361463f576001600160a01b0385163b61463f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610f12565b50816142a5565b6142a583836146c8565b6060600080856001600160a01b03168560405161466d9190615eaf565b600060405180830381855af49150503d80600081146146a8576040519150601f19603f3d011682016040523d82523d6000602084013e6146ad565b606091505b50915091506146be868383876145d7565b9695505050505050565b8151156146d85781518083602001fd5b8060405162461bcd60e51b8152600401610f129190614a96565b634e487b7160e01b600052600160045260246000fd5b60008083601f84011261471a57600080fd5b5081356001600160401b0381111561473157600080fd5b60208301915083602082850101111561474957600080fd5b9250929050565b60008060006040848603121561476557600080fd5b8335925060208401356001600160401b0381111561478257600080fd5b61478e86828701614708565b9497909650939450505050565b6000606082840312156129e657600080fd5b6000602082840312156147bf57600080fd5b81356001600160401b038111156147d557600080fd5b6142a58482850161479b565b600080600080604085870312156147f757600080fd5b84356001600160401b038082111561480e57600080fd5b61481a88838901614708565b9096509450602087013591508082111561483357600080fd5b5061484087828801614708565b95989497509550505050565b6001600160a01b0381168114610faf57600080fd5b60006020828403121561487357600080fd5b8135612af98161484c565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b03811182821017156148b6576148b661487e565b60405290565b604051601f8201601f191681016001600160401b03811182821017156148e4576148e461487e565b604052919050565b60006001600160401b038211156149055761490561487e565b50601f01601f191660200190565b6000806040838503121561492657600080fd5b82356149318161484c565b915060208301356001600160401b0381111561494c57600080fd5b8301601f8101851361495d57600080fd5b803561497061496b826148ec565b6148bc565b81815286602083850101111561498557600080fd5b816020840160208301376000602083830101528093505050509250929050565b6000604082840312156129e657600080fd5b600080604083850312156149ca57600080fd5b8235915060208301356001600160401b038111156149e757600080fd5b6149f3858286016149a5565b9150509250929050565b60028110614a1b57634e487b7160e01b600052602160045260246000fd5b9052565b6020810161184c82846149fd565b600060208284031215614a3f57600080fd5b5035919050565b60005b83811015614a61578181015183820152602001614a49565b50506000910152565b60008151808452614a82816020860160208601614a46565b601f01601f19169290920160200192915050565b602081526000612af96020830184614a6a565b60008060208385031215614abc57600080fd5b82356001600160401b03811115614ad257600080fd5b614ade85828601614708565b90969095509350505050565b6001600160a01b03831681526040602082018190526000906142a590830184614a6a565b8015158114610faf57600080fd5b60008060408385031215614b2f57600080fd5b8235614b3a8161484c565b91506020830135614b4a81614b0e565b809150509250929050565b600060608284031215614b6757600080fd5b612af9838361479b565b6001600160a01b0384168152606060208201819052600090614b9590830185614a6a565b82810360408401526146be8185614a6a565b60008060408385031215614bba57600080fd5b8235614bc58161484c565b91506020830135614b4a8161484c565b600181811c90821680614be957607f821691505b6020821081036129e657634e487b7160e01b600052602260045260246000fd5b60006001600160401b03821115614c2257614c2261487e565b5060051b60200190565b600082601f830112614c3d57600080fd5b81516020614c4d61496b83614c09565b82815260059290921b84018101918181019086841115614c6c57600080fd5b8286015b84811015614c90578051614c838161484c565b8352918301918301614c70565b509695505050505050565b600060208284031215614cad57600080fd5b81516001600160401b03811115614cc357600080fd5b6142a584828501614c2c565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8181038181111561184c5761184c614ce5565b600060808284031215614d2057600080fd5b604051608081018181106001600160401b0382111715614d4257614d4261487e565b604052825161ffff81168114614d5757600080fd5b808252506020830151602082015260408301516040820152606083015160608201528091505092915050565b805182526020810151602083015260006040820151606060408501526142a56060850182614a6a565b60008154614db981614bd5565b808552602060018381168015614dd65760018114614df057614e1e565b60ff1985168884015283151560051b880183019550614e1e565b866000528260002060005b85811015614e165781548a8201860152908301908401614dfb565b890184019650505b505050505092915050565b600061012061ffff8b16835289602084015288604084015260018060a01b03881660608401528660808401528560a08401528060c0840152614e6d81840186614d83565b905082810360e0840152614e818185614dac565b8381036101009094019390935250506000815260200198975050505050505050565b6000806040808486031215614eb757600080fd5b83516001600160401b0380821115614ece57600080fd5b818601915086601f830112614ee257600080fd5b81516020614ef261496b83614c09565b8281526060928302850182019282820191908b851115614f1157600080fd5b958301955b84871015614f595780878d031215614f2e5760008081fd5b614f36614894565b875181528488015185820152888801518982015283529586019591830191614f16565b5091890151919750909450505080831115614f7357600080fd5b50506149f385828601614c2c565b601f821115610e7357600081815260208120601f850160051c81016020861015614fa85750805b601f850160051c820191505b8181101561214e57828155600101614fb4565b600019600383901b1c191660019190911b1790565b6001600160401b03831115614ff357614ff361487e565b615007836150018354614bd5565b83614f81565b6000601f84116001811461503557600085156150235750838201355b61502d8682614fc7565b845550610dff565b600083815260209020601f19861690835b828110156150665786850135825560209485019460019092019101615046565b50868210156150835760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6000808335601e198436030181126150ac57600080fd5b83016020810192503590506001600160401b038111156150cb57600080fd5b80360382131561474957600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60208152600082356151148161484c565b6001600160a01b031660208381019190915261513290840184615095565b606060408501526151476080850182846150da565b9150506151576040850185615095565b848303601f190160608601526146be8382846150da565b80546001600160a01b0319166001600160a01b0392909216919091179055565b6000808335601e198436030181126151a557600080fd5b8301803591506001600160401b038211156151bf57600080fd5b60200191503681900382131561474957600080fd5b81356151df8161484c565b6151e9818361516e565b50600180820160206151fd8186018661518e565b6001600160401b038111156152145761521461487e565b615228816152228654614bd5565b86614f81565b6000601f82116001811461525657600083156152445750838201355b61524e8482614fc7565b8755506152ab565b600086815260209020601f19841690835b828110156152845786850135825593870193908901908701615267565b50848210156152a15760001960f88660031b161c19848701351681555b50508683881b0186555b505050505050506152bf604083018361518e565b6109b6818360028601614fdc565b6020815260006142a56020830184866150da565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600081356153868161484c565b6001600160a01b0316835261539e6020830183615095565b604060208601526153b36040860182846150da565b95945050505050565b8281526040602082015260006142a56040830184615379565b81356153e08161484c565b6153ea818361516e565b50600180820160206153fe8186018661518e565b6001600160401b038111156154155761541561487e565b615423816152228654614bd5565b6000601f821160018114615451576000831561543f5750838201355b6154498482614fc7565b8755506154a6565b600086815260209020601f19841690835b8281101561547f5786850135825593870193908901908701615462565b508482101561549c5760001960f88660031b161c19848701351681555b50508683881b0186555b505050505050505050565b6110e682826153d5565b600060208083850312156154ce57600080fd5b82516001600160401b038111156154e457600080fd5b8301601f810185136154f557600080fd5b805161550361496b82614c09565b8181526060918202830184019184820191908884111561552257600080fd5b938501935b838510156155875780858a03121561553f5760008081fd5b615547614894565b85516155528161484c565b8152858701516155618161484c565b8188015260408681015161557481614b0e565b9082015283529384019391850191615527565b50979650505050505050565b600060a0820187835260208781850152604060a08186015282885180855260c087019150838a01945060005b818110156155fc57855180516001600160a01b039081168552868201511686850152840151151584840152948401946060909201916001016155bf565b50506001600160a01b0388166060870152935061561892505050565b8260808301529695505050505050565b6000602080838503121561563b57600080fd5b82516001600160401b0381111561565157600080fd5b8301601f8101851361566257600080fd5b805161567061496b82614c09565b81815260059190911b8201830190838101908783111561568f57600080fd5b928401925b828410156156ad57835182529284019290840190615694565b979650505050505050565b600081518084526020808501945080840160005b838110156156f15781516001600160a01b0316875295820195908201906001016156cc565b509495945050505050565b85815284602082015260a06040820152600061571b60a08301866156b8565b6001600160a01b0394909416606083015250608001529392505050565b600061574661496b846148ec565b905082815283838301111561575a57600080fd5b612af9836020830184614a46565b600082601f83011261577957600080fd5b612af983835160208501615738565b60006020828403121561579a57600080fd5b81516001600160401b03808211156157b157600080fd5b90830190604082860312156157c557600080fd5b6040516040810181811083821117156157e0576157e061487e565b6040528251828111156157f257600080fd5b6157fe87828601615768565b82525060208301518281111561581357600080fd5b61581f87828601615768565b60208301525095945050505050565b6080815260006158416080830187614a6a565b82810360208401526158538187614dac565b905082810360408401526158678186614a6a565b91505082606083015295945050505050565b60006020828403121561588b57600080fd5b81516001600160401b038111156158a157600080fd5b8201601f810184136158b257600080fd5b6142a584825160208401615738565b6000602082840312156158d357600080fd5b5051919050565b81356158e581614b0e565b815460ff19811691151560ff16918217835560208401356159058161484c565b6001600160a81b03199190911690911760089190911b610100600160a81b03161781556040919091013560019190910155565b805160ff8116811461594957600080fd5b919050565b600060c0828403121561596057600080fd5b60405160c081018181106001600160401b03821117156159825761598261487e565b6040528251815261599560208401615938565b60208201526159a660408401615938565b604082015260608301516159b98161484c565b60608201526159ca60808401615938565b60808201526159db60a08401615938565b60a08201529392505050565b8082018082111561184c5761184c614ce5565b600060208284031215615a0c57600080fd5b815163ffffffff81168114612af957600080fd5b600060208284031215615a3257600080fd5b81516001600160401b0381168114612af957600080fd5b60008351615a5b818460208801614a46565b60609390931b6bffffffffffffffffffffffff19169190920190815260140192915050565b600060018201615a9257615a92614ce5565b5060010190565b602081526000825160a06020840152615ab560c0840182614a6a565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b61ffff8516815260ff8416602082015260a060408201526000615b1760a0830185614a6a565b82810380606085015260008252602081016080850152506156ad6020820185614d83565b60008060408385031215615b4e57600080fd5b505080516020909101519092909150565b6000808354615b6d81614bd5565b60018281168015615b855760018114615b9a57615bc9565b60ff1984168752821515830287019450615bc9565b8760005260208060002060005b85811015615bc05781548a820152908401908201615ba7565b50505082870194505b50929695505050505050565b600081518084526020808501945080840160005b838110156156f157815187529582019590820190600101615be9565b6000610120808301615c17848b6149fd565b60208481019290925288519081905261014080850192600583901b8601909101918a820160005b82811015615ca15787850361013f190186528151805186528481015185870152604080820151908701526060808201519087015260809081015160a091870182905290615c8d81880183614a6a565b978601979650505090830190600101615c3e565b505050508381036040850152615cb781896156b8565b915050615cf7606084018780516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b82810360e0840152615d098186615bd5565b91505082610100830152979650505050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b81516001600160401b03811115615d8257615d8261487e565b615d9681615d908454614bd5565b84614f81565b602080601f831160018114615dc55760008415615db35750858301515b615dbd8582614fc7565b86555061214e565b600085815260208120601f198616915b82811015615df457888601518255948401946001909101908401615dd5565b5085821015615e125787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b602081526000825160806020840152615e3e60a0840182614a6a565b905060018060a01b03602085015116604084015260408401516060840152606084015160808401528091505092915050565b600082615e8d57634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215615ea457600080fd5b8151612af981614b0e565b60008251615ec1818460208701614a46565b919091019291505056fe48b87fc02925b37a6aefac60c14fa9d8e9988d7dfadf262d4bd845872ca40730360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220411dc7abaa48cfcce728fd30bf8164574864f61c87cb31a26517e462bea19e1a64736f6c63430008130033
Deployed Bytecode
0x6080604052600436106102815760003560e01c80638129fc1c1161014f578063c4b00c4f116100c1578063ee63c1e51161007a578063ee63c1e51461078a578063f1a392da1461079f578063f2fde38b146107b5578063f3f1a71a146107d5578063fe8d1ab0146107f5578063ff33d21f1461080a57600080fd5b8063c4b00c4f1461068b578063c89f2ce4146106ab578063ca3254691461071c578063cc5ea4ef14610740578063d49b640814610755578063d7d66e711461076a57600080fd5b8063a5131aaa11610113578063a5131aaa146105c2578063b54653fb146105d7578063b9f391471461062b578063bac86af514610640578063bce4547a14610660578063c3c224751461067557600080fd5b80638129fc1c14610540578063873d80ec146105555780638da5cb5b14610578578063943f8e96146105965780639c345b9f146105ac57600080fd5b80635066a747116101f35780636ae40711116101ac5780636ae407111461049f5780636d0a6891146104b457806370c75107146104e1578063715018a61461050157806373f1df3314610516578063748b3c051461052b57600080fd5b80635066a747146103eb5780635109d8b61461040b57806352d1902d14610420578063530728d51461044357806364e510a114610458578063671f6a261461047857600080fd5b80631610ee40116102455780631610ee401461034357806322be3de114610363578063284eb663146103835780633659cfe6146103a35780634641257d146103c35780634f1ef286146103d857600080fd5b80630278fb8a146102a7578063057d1ae3146102bc5780630d1f7833146102d157806311b0b42d146102e6578063154085921461032357600080fd5b366102a25760cd546001600160a01b031633146102a0576102a06146f2565b005b600080fd5b3480156102b357600080fd5b506102a061082a565b3480156102c857600080fd5b506102a06109bc565b3480156102dd57600080fd5b506102a0610c21565b3480156102f257600080fd5b5060cd54610306906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561032f57600080fd5b506102a061033e366004614750565b610e06565b34801561034f57600080fd5b506102a061035e3660046147ad565b610e27565b34801561036f57600080fd5b5060cc54610306906001600160a01b031681565b34801561038f57600080fd5b506102a061039e3660046147e1565b610e78565b3480156103af57600080fd5b506102a06103be366004614861565b610eca565b3480156103cf57600080fd5b506102a0610fb2565b6102a06103e6366004614913565b61101a565b3480156103f757600080fd5b506102a06104063660046149b7565b6110ea565b34801561041757600080fd5b506102a061117d565b34801561042c57600080fd5b50610435611370565b60405190815260200161031a565b34801561044f57600080fd5b506102a0611423565b34801561046457600080fd5b506102a06104733660046149b7565b611510565b34801561048457600080fd5b5060c9546104929060ff1681565b60405161031a9190614a1f565b3480156104ab57600080fd5b506102a061159e565b3480156104c057600080fd5b506104d46104cf366004614a2d565b611784565b60405161031a9190614a96565b3480156104ed57600080fd5b506104356104fc366004614aa9565b61181e565b34801561050d57600080fd5b506102a0611852565b34801561052257600080fd5b506102a0611866565b34801561053757600080fd5b506102a06118c7565b34801561054c57600080fd5b506102a0611a37565b34801561056157600080fd5b5061056a611baf565b60405161031a929190614aea565b34801561058457600080fd5b506033546001600160a01b0316610306565b3480156105a257600080fd5b5061043560cf5481565b3480156105b857600080fd5b5061043560ce5481565b3480156105ce57600080fd5b506102a0611c50565b3480156105e357600080fd5b5060d05460d1546106069160ff8116916101009091046001600160a01b03169083565b6040805193151584526001600160a01b0390921660208401529082015260600161031a565b34801561063757600080fd5b506102a0611cbc565b34801561064c57600080fd5b506102a061065b366004614b1c565b611e48565b34801561066c57600080fd5b506102a0611f42565b34801561068157600080fd5b5061043560d95481565b34801561069757600080fd5b506102a06106a6366004614b55565b612156565b3480156106b757600080fd5b5060ca5460cb546106e7916001600160a01b038082169260ff600160a01b93849004811693928216929091041684565b60405161031a94939291906001600160a01b039485168152921515602084015292166040820152901515606082015260800190565b34801561072857600080fd5b5061073161216b565b60405161031a93929190614b71565b34801561074c57600080fd5b506102a061229a565b34801561076157600080fd5b5061056a612435565b34801561077657600080fd5b506102a0610785366004614a2d565b612453565b34801561079657600080fd5b506102a0612493565b3480156107ab57600080fd5b5061043560dd5481565b3480156107c157600080fd5b506102a06107d0366004614861565b61261f565b3480156107e157600080fd5b506104d46107f0366004614a2d565b612695565b34801561080157600080fd5b506102a06126ae565b34801561081657600080fd5b506102a0610825366004614ba7565b612837565b610832612913565b600060d4600101805461084490614bd5565b80601f016020809104026020016040519081016040528092919081815260200182805461087090614bd5565b80156108bd5780601f10610892576101008083540402835291602001916108bd565b820191906000526020600020905b8154815290600101906020018083116108a057829003601f168201915b50505050508060200190518101906108d59190614c9b565b60cd5481519192506001600160a01b03169082906000906108f8576108f8614ccf565b60200260200101516001600160a01b031614610927576040516376c252e160e11b815260040160405180910390fd5b60cc5481516001600160a01b0390911690829061094690600190614cfb565b8151811061095657610956614ccf565b60200260200101516001600160a01b031614610985576040516376c252e160e11b815260040160405180910390fd5b600061099082612933565b9050600061099c6129ec565b60d4549091506109b6906001600160a01b03168383612a5f565b50505050565b6109c4612913565b600060d260010180546109d690614bd5565b80601f0160208091040260200160405190810160405280929190818152602001828054610a0290614bd5565b8015610a4f5780601f10610a2457610100808354040283529160200191610a4f565b820191906000526020600020905b815481529060010190602001808311610a3257829003601f168201915b5050505050806020019051810190610a679190614d0e565b905060006040518060600160405280836020015181526020016000815260200160405180604001604052806002815260200161060f60f31b81525081525090506000610b45836000015160d66001018054610ac190614bd5565b80601f0160208091040260200160405190810160405280929190818152602001828054610aed90614bd5565b8015610b3a5780601f10610b0f57610100808354040283529160200191610b3a565b820191906000526020600020905b815481529060010190602001808311610b1d57829003601f168201915b505050505084612b00565b9050610b5081612b81565b610b58612bf4565b6000610b62612c55565b905060d954811115610beb5760d2548451604080870151606088015191516327efc43f60e21b81526001600160a01b0390941693639fbf10fc938793610bb8939192309089906000908d9060d790600401614e29565b6000604051808303818588803b158015610bd157600080fd5b505af1158015610be5573d6000803e3d6000fd5b50505050505b60cc546040518281526001600160a01b0390911690600080516020615ecc8339815191529060200160405180910390a250505050565b610c29612913565b60008060d46001018054610c3c90614bd5565b80601f0160208091040260200160405190810160405280929190818152602001828054610c6890614bd5565b8015610cb55780601f10610c8a57610100808354040283529160200191610cb5565b820191906000526020600020905b815481529060010190602001808311610c9857829003601f168201915b5050505050806020019051810190610ccd9190614ea3565b60cd5481519294509092506001600160a01b0316908290600090610cf357610cf3614ccf565b60200260200101516001600160a01b031614610d22576040516376c252e160e11b815260040160405180910390fd5b60cc5481516001600160a01b03909116908290610d4190600190614cfb565b81518110610d5157610d51614ccf565b60200260200101516001600160a01b031614610d80576040516376c252e160e11b815260040160405180910390fd5b6000610d8a6129ec565b90506000610d988483612c86565b60d45460c9546040805160808101825260ca546001600160a01b03808216835260ff600160a01b9283900481161515602085015260cb548083169585019590955291909304811615156060830152949550610dff9491909316929116908490879087612e8f565b5050505050565b610e0e612fd9565b600083815260db602052604090206109b6828483614fdc565b610e2f612fd9565b7f518f47fcfba5d9b707c3387a7fa4301136192d8091a43ea13ae8db7275ab5d3a81604051610e5e9190615103565b60405180910390a18060d6610e7382826151d4565b505050565b610e80612fd9565b818160dc60008787604051602001610e999291906152cd565b6040516020818303038152906040528051906020012081526020019081526020016000209182610dff929190614fdc565b6001600160a01b037f0000000000000000000000002659b955655b2d94e34a628818e12f1c21110db3163003610f1b5760405162461bcd60e51b8152600401610f12906152e1565b60405180910390fd5b7f0000000000000000000000002659b955655b2d94e34a628818e12f1c21110db36001600160a01b0316610f64600080516020615eec833981519152546001600160a01b031690565b6001600160a01b031614610f8a5760405162461bcd60e51b8152600401610f129061532d565b610f9381613033565b60408051600080825260208201909252610faf9183919061303b565b50565b610fba6131a6565b610fc2613217565b7f8e55ccfc9778ff8eba1646d765cf1982537ce0f9257054a17b48aad745250183610feb6129ec565b60405190815260200160405180910390a160006110066129ec565b111561101457611014613350565b4260dd55565b6001600160a01b037f0000000000000000000000002659b955655b2d94e34a628818e12f1c21110db31630036110625760405162461bcd60e51b8152600401610f12906152e1565b7f0000000000000000000000002659b955655b2d94e34a628818e12f1c21110db36001600160a01b03166110ab600080516020615eec833981519152546001600160a01b031690565b6001600160a01b0316146110d15760405162461bcd60e51b8152600401610f129061532d565b6110da82613033565b6110e68282600161303b565b5050565b6110f2612fd9565b7f25f7dd6fc737add5174192a11292dfd270c1397f9c4f641fb6336a208b5efbed82826040516111239291906153bc565b60405180910390a160cd5460d454611147916001600160a01b039081169116613380565b60cf8290558060d461115982826154b1565b505060cd546110e6906001600160a01b03166111786020840184614861565b61340f565b611185612913565b600060d4600101805461119790614bd5565b80601f01602080910402602001604051908101604052809291908181526020018280546111c390614bd5565b80156112105780601f106111e557610100808354040283529160200191611210565b820191906000526020600020905b8154815290600101906020018083116111f357829003601f168201915b505050505080602001905181019061122891906154bb565b905060006112358261349c565b60cd5481519192506001600160a01b031690829060009061125857611258614ccf565b60200260200101516001600160a01b031614611287576040516376c252e160e11b815260040160405180910390fd5b60cc5481516001600160a01b039091169082906112a690600190614cfb565b815181106112b6576112b6614ccf565b60200260200101516001600160a01b0316146112e5576040516376c252e160e11b815260040160405180910390fd5b60006112ef6129ec565b60d454604051631e82ecdb60e31b81529192506001600160a01b03169063f41766d890611329908490600090889030904290600401615593565b6000604051808303816000875af1158015611348573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109b69190810190615628565b6000306001600160a01b037f0000000000000000000000002659b955655b2d94e34a628818e12f1c21110db316146114105760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610f12565b50600080516020615eec83398151915290565b61142b612913565b611433612bf4565b600061143d612c55565b905060d9548111156114dd5760d25460d65460cc5460405163cd58657960e01b81526000600482018190526001600160a01b0393841660248301526044820186905291831660648201526001608482015260c060a482015260c481019190915291169063cd5865799060e4015b600060405180830381600087803b1580156114c457600080fd5b505af11580156114d8573d6000803e3d6000fd5b505050505b60cc546040518281526001600160a01b0390911690600080516020615ecc8339815191529060200160405180910390a250565b611518612fd9565b7f5e355369ceaccb04ff615500f99b96912ce9f237ed35ae521487c19064e2318d82826040516115499291906153bc565b60405180910390a160cc5460d25461156d916001600160a01b039081169116613380565b60ce8290558060d261157f82826154b1565b505060cc546110e6906001600160a01b03166111786020840184614861565b6115a6612913565b600060d460010180546115b890614bd5565b80601f01602080910402602001604051908101604052809291908181526020018280546115e490614bd5565b80156116315780601f1061160657610100808354040283529160200191611631565b820191906000526020600020905b81548152906001019060200180831161161457829003601f168201915b50505050508060200190518101906116499190614c9b565b60cd5481519192506001600160a01b031690829060009061166c5761166c614ccf565b60200260200101516001600160a01b03161461169b576040516376c252e160e11b815260040160405180910390fd5b60cc5481516001600160a01b039091169082906116ba90600190614cfb565b815181106116ca576116ca614ccf565b60200260200101516001600160a01b0316146116f9576040516376c252e160e11b815260040160405180910390fd5b60006117036129ec565b60d4546040516338ed173960e01b81529192506001600160a01b0316906338ed17399061173d9084906000908790309042906004016156fc565b6000604051808303816000875af115801561175c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e739190810190615628565b60db602052600090815260409020805461179d90614bd5565b80601f01602080910402602001604051908101604052809291908181526020018280546117c990614bd5565b80156118165780601f106117eb57610100808354040283529160200191611816565b820191906000526020600020905b8154815290600101906020018083116117f957829003601f168201915b505050505081565b600082826040516020016118339291906152cd565b6040516020818303038152906040528051906020012090505b92915050565b61185a612fd9565b61186460006135ba565b565b61186e612913565b611876612bf4565b6000611880612c55565b905060d954811115610faf5760d25460d6546040516302e108e960e11b8152600481018490526001600160a01b0391821660248201529116906305c211d2906044016114aa565b6118cf612913565b600060d260010180546118e190614bd5565b80601f016020809104026020016040519081016040528092919081815260200182805461190d90614bd5565b801561195a5780601f1061192f5761010080835404028352916020019161195a565b820191906000526020600020905b81548152906001019060200180831161193d57829003601f168201915b50505050508060200190518101906119729190615788565b905061197c612bf4565b6000611986612c55565b905060d954811115611a025760d254825160208401516040516326ef699d60e01b81526001600160a01b03909316926326ef699d926119cf92909160d89190879060040161582e565b600060405180830381600087803b1580156119e957600080fd5b505af11580156119fd573d6000803e3d6000fd5b505050505b60cc546040518281526001600160a01b0390911690600080516020615ecc833981519152906020015b60405180910390a25050565b600054610100900460ff1615808015611a575750600054600160ff909116105b80611a715750303b158015611a71575060005460ff166001145b611ad45760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610f12565b6000805460ff191660011790558015611af7576000805461ff0019166101001790555b611aff61360c565b611b0761363b565b611b0f613962565b604080516080810182523080825260006020830181905292820181905260609091019190915260ca805460ff60a01b199092166001600160a81b0319928316811790915560cb805490921617905560c9805460ff191690558015610faf576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b60d4805460d580546001600160a01b039092169291611bcd90614bd5565b80601f0160208091040260200160405190810160405280929190818152602001828054611bf990614bd5565b8015611c465780601f10611c1b57610100808354040283529160200191611c46565b820191906000526020600020905b815481529060010190602001808311611c2957829003601f168201915b5050505050905082565b611c58612913565b611c60612bf4565b6000611c6a612c55565b905060d9548111156114dd5760d25460d65460cc54604051636ce5768960e11b81526001600160a01b03928316600482015290821660248201526044810184905291169063d9caed12906064016114aa565b611cc4612913565b600060d46001018054611cd690614bd5565b80601f0160208091040260200160405190810160405280929190818152602001828054611d0290614bd5565b8015611d4f5780601f10611d2457610100808354040283529160200191611d4f565b820191906000526020600020905b815481529060010190602001808311611d3257829003601f168201915b5050505050806020019051810190611d679190615879565b90506000611d7482613c6b565b60cd5481519192506001600160a01b0316908290600090611d9757611d97614ccf565b60200260200101516001600160a01b031614611dc6576040516376c252e160e11b815260040160405180910390fd5b60cc5481516001600160a01b03909116908290611de590600190614cfb565b81518110611df557611df5614ccf565b60200260200101516001600160a01b031614611e24576040516376c252e160e11b815260040160405180910390fd5b6000611e2e6129ec565b60d4549091506109b6906001600160a01b03168483612a5f565b611e50612fd9565b8015611ec1576040514790600090339083908381818185875af1925050503d8060008114611e9a576040519150601f19603f3d011682016040523d82523d6000602084013e611e9f565b606091505b50509050806109b657604051630dcf35db60e41b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015611f08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2c91906158c1565b9050610e736001600160a01b0384163383613d6e565b611f4a612913565b600060d46001018054611f5c90614bd5565b80601f0160208091040260200160405190810160405280929190818152602001828054611f8890614bd5565b8015611fd55780601f10611faa57610100808354040283529160200191611fd5565b820191906000526020600020905b815481529060010190602001808311611fb857829003601f168201915b5050505050806020019051810190611fed9190614c9b565b60cd5481519192506001600160a01b031690829060009061201057612010614ccf565b60200260200101516001600160a01b03161461203f576040516376c252e160e11b815260040160405180910390fd5b60cc5481516001600160a01b03909116908290600190811061206357612063614ccf565b60200260200101516001600160a01b031614612092576040516376c252e160e11b815260040160405180910390fd5b600061209c6129ec565b60d45483519192506001600160a01b03169063df791e509084906000906120c5576120c5614ccf565b6020026020010151846001815181106120e0576120e0614ccf565b60209081029190910101516040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260448101849052606401600060405180830381600087803b15801561213a57600080fd5b505af115801561214e573d6000803e3d6000fd5b505050505050565b61215e612fd9565b8060d0610e7382826158da565b60d6805460d780546001600160a01b03909216929161218990614bd5565b80601f01602080910402602001604051908101604052809291908181526020018280546121b590614bd5565b80156122025780601f106121d757610100808354040283529160200191612202565b820191906000526020600020905b8154815290600101906020018083116121e557829003601f168201915b50505050509080600201805461221790614bd5565b80601f016020809104026020016040519081016040528092919081815260200182805461224390614bd5565b80156122905780601f1061226557610100808354040283529160200191612290565b820191906000526020600020905b81548152906001019060200180831161227357829003601f168201915b5050505050905083565b6122a2612913565b600060d260010180546122b490614bd5565b80601f01602080910402602001604051908101604052809291908181526020018280546122e090614bd5565b801561232d5780601f106123025761010080835404028352916020019161232d565b820191906000526020600020905b81548152906001019060200180831161231057829003601f168201915b5050505050806020019051810190612345919061594e565b905061234f612bf4565b6000612359612c55565b905060d954811115611a025760d25460d6548351606085015160208601516040870151608088015160a08901516001600160a01b0397881697639f3307279716959493929189916000914291836123b284610e106159e7565b6040516001600160e01b031960e08f901b1681526001600160a01b039c8d166004820152602481019b909b529a90981660448a015260ff96871660648a0152948616608489015260a488019390935260c487019190915260e4860152821661010485015216610124830152610144820152610164810191909152610184016119cf565b60d2805460d380546001600160a01b039092169291611bcd90614bd5565b61245b612fd9565b6040518181527ff4f47d85dc8207b9d9c6dfd289d4f5008b33df899eda3da90658d75c351e54759060200160405180910390a160d955565b61249b612913565b600060d460010180546124ad90614bd5565b80601f01602080910402602001604051908101604052809291908181526020018280546124d990614bd5565b80156125265780601f106124fb57610100808354040283529160200191612526565b820191906000526020600020905b81548152906001019060200180831161250957829003601f168201915b505050505080602001905181019061253e9190615879565b9050600061254b82613c6b565b60cd5481519192506001600160a01b031690829060009061256e5761256e614ccf565b60200260200101516001600160a01b03161461259d576040516376c252e160e11b815260040160405180910390fd5b60cc5481516001600160a01b039091169082906125bc90600190614cfb565b815181106125cc576125cc614ccf565b60200260200101516001600160a01b0316146125fb576040516376c252e160e11b815260040160405180910390fd5b60006126056129ec565b60d4549091506109b6906001600160a01b03168483613dd1565b612627612fd9565b6001600160a01b03811661268c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610f12565b610faf816135ba565b60dc602052600090815260409020805461179d90614bd5565b6126b6612913565b600060d260010180546126c890614bd5565b80601f01602080910402602001604051908101604052809291908181526020018280546126f490614bd5565b80156127415780601f1061271657610100808354040283529160200191612741565b820191906000526020600020905b81548152906001019060200180831161272457829003601f168201915b505050505080602001905181019061275991906159fa565b9050612763612bf4565b600061276d612c55565b905060d954811115611a025760d25460d65460cc546040516337e9a82760e11b81526004810185905263ffffffff861660248201526001600160a01b0392831660448201529082166064820152911690636fd3504e906084016020604051808303816000875af11580156127e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128099190615a20565b5060cc546040518281526001600160a01b0390911690600080516020615ecc83398151915290602001611a2b565b61283f612fd9565b60da5460ff166128845760cc80546001600160a01b039384166001600160a01b03199182161790915560cd805492909316911617905560da805460ff19166001179055565b60cc54604080516001600160a01b03928316815291841660208301527f4239efeca0761c0d170bd15a6e85542dbe0376ba0f5f1551b39c6045866ff735910160405180910390a160cc5460d2546128e7916001600160a01b039081169116613380565b60cc80546001600160a01b0319166001600160a01b0384811691821790925560d2546110e6921661340f565b3330146118645760405163ea8e4eb560e01b815260040160405180910390fd5b60608160008151811061294857612948614ccf565b6020026020010151604051602001612978919060609190911b6bffffffffffffffffffffffff1916815260140190565b60408051601f19818403018152919052905060015b82518110156129e657818382815181106129a9576129a9614ccf565b60200260200101516040516020016129c2929190615a49565b604051602081830303815290604052915080806129de90615a80565b91505061298d565b50919050565b60cd546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a08231906024015b602060405180830381865afa158015612a36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a5a91906158c1565b905090565b6040805160a081018252838152306020820152428183015260608101839052600060808201819052915163c04b8d5960e01b81526001600160a01b0386169063c04b8d5990612ab2908490600401615a99565b6020604051808303816000875af1158015612ad1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612af591906158c1565b9150505b9392505050565b60d254604051630a51236960e01b81526000916001600160a01b031690630a51236990612b3890879060019088908890600401615af1565b6040805180830381865afa158015612b54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b789190615b3b565b50949350505050565b6000612b8b6129ec565b90508181106110e65760cd54604051632e1a7d4d60e01b8152600481018490526001600160a01b0390911690632e1a7d4d90602401600060405180830381600087803b158015612bda57600080fd5b505af1925050508015612beb575060015b156110e6575050565b60cf54600090815260dc6020526040908190208151600481526024810192839052610faf929091612c2491615b5f565b6040519081900390206020820180516001600160e01b03166001600160e01b03199092169190911790523090613e1e565b60cc546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401612a19565b6060600083516001600160401b03811115612ca357612ca361487e565b604051908082528060200260200182016040528015612d0957816020015b612cf66040518060a0016040528060008019168152602001600081526020016000815260200160008152602001606081525090565b815260200190600190039081612cc15790505b50905060005b8451811015612e875780600003612dd3576040518060a0016040528086600081518110612d3e57612d3e614ccf565b602002602001015160000151815260200186600081518110612d6257612d62614ccf565b602002602001015160200151815260200186600081518110612d8657612d86614ccf565b60200260200101516040015181526020018581526020016040518060200160405280600081525081525082600081518110612dc357612dc3614ccf565b6020026020010181905250612e7f565b6040518060a00160405280868381518110612df057612df0614ccf565b6020026020010151600001518152602001868381518110612e1357612e13614ccf565b6020026020010151602001518152602001868381518110612e3657612e36614ccf565b60200260200101516040015181526020016000815260200160405180602001604052806000815250815250828281518110612e7357612e73614ccf565b60200260200101819052505b600101612d0f565b509392505050565b6060600084516001600160401b03811115612eac57612eac61487e565b604051908082528060200260200182016040528015612ed5578160200160208202803683370190505b50905060005b8551811015612f4f5780600003612f11578382600081518110612f0057612f00614ccf565b602002602001018181525050612f47565b60018651612f1f9190614cfb565b8103612f4757600019828281518110612f3a57612f3a614ccf565b6020026020010181815250505b600101612edb565b5060405163945bcec960e01b81526001600160a01b0389169063945bcec990612f86908a908a908a908a9088904290600401615c05565b6000604051808303816000875af1158015612fa5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612fcd9190810190615628565b98975050505050505050565b6033546001600160a01b031633146118645760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610f12565b610faf612fd9565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561306e57610e7383613e62565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156130c8575060408051601f3d908101601f191682019092526130c5918101906158c1565b60015b61312b5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610f12565b600080516020615eec833981519152811461319a5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610f12565b50610e73838383613efe565b478015610faf5760cd60009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156131fd57600080fd5b505af19350505050801561320f575060015b15610faf5750565b60d05460ff16156118645760cd5460d0546040516370a0823160e01b81526101009091046001600160a01b03908116600483015260009216906370a0823190602401602060405180830381865afa158015613276573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061329a91906158c1565b60d0546132b6919061010090046001600160a01b0316316159e7565b60d154909150811015610faf5760006132cd6129ec565b905060008260d0600101546132e29190614cfb565b90508181116132f157806132f3565b815b60d05460cd54919250613318916001600160a01b039081169161010090041683613d6e565b6040518181527feb722ef3dbafc24e43f4627f9b306563a93d546865b49eb1e64fbaffdab73d5c9060200160405180910390a1505050565b60ce54600090815260db6020526040908190208151600481526024810192839052610faf929091612c2491615b5f565b604051636eb1769f60e11b81523060048201526001600160a01b0382811660248301526000919084169063dd62ed3e90604401602060405180830381865afa1580156133d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133f491906158c1565b11156110e6576110e66001600160a01b038316826000613f23565b604051636eb1769f60e11b81523060048201526001600160a01b03828116602483015283169063dd62ed3e90604401602060405180830381865afa15801561345b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061347f91906158c1565b6000036110e6576110e66001600160a01b03831682600019613f23565b60606000825160016134ae91906159e7565b6001600160401b038111156134c5576134c561487e565b6040519080825280602002602001820160405280156134ee578160200160208202803683370190505b5090508260008151811061350457613504614ccf565b6020026020010151600001518160008151811061352357613523614ccf565b60200260200101906001600160a01b031690816001600160a01b03168152505060005b83518110156135b35783818151811061356157613561614ccf565b6020026020010151602001518282600161357b91906159e7565b8151811061358b5761358b614ccf565b6001600160a01b03909216602092830291909101909101526135ac81615a80565b9050613546565b5092915050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166136335760405162461bcd60e51b8152600401610f1290615d1e565b611864614038565b6040518060400160405280600e81526020016d627269646765436972636c65282960901b81525060db600060405160200161369090602080825260069082015265434952434c4560d01b604082015260600190565b60405160208183030381529060405280519060200120815260200190815260200160002090816136c09190615d69565b506040518060400160405280601081526020016f6272696467655374617267617465282960801b81525060db600060405160200161371a90602080825260089082015267535441524741544560c01b604082015260600190565b604051602081830303815290604052805190602001208152602001908152602001600020908161374a9190615d69565b506040518060400160405280600e81526020016d6272696467654178656c6172282960901b81525060db60006040516020016137a09060208082526006908201526520ac22a620a960d11b604082015260600190565b60405160208183030381529060405280519060200120815260200190815260200160002090816137d09190615d69565b506040518060400160405280600f81526020016e62726964676553796e61707365282960881b81525060db60006040516020016138289060208082526007908201526653594e4150534560c81b604082015260600190565b60405160208183030381529060405280519060200120815260200190815260200160002090816138589190615d69565b506040518060400160405280600d81526020016c6272696467657a6b45564d282960981b81525060db60006040516020016138ac906020808252600590820152647a6b45564d60d81b604082015260600190565b60405160208183030381529060405280519060200120815260200190815260200160002090816138dc9190615d69565b506040518060400160405280600e81526020016d6272696467657a6b53796e63282960901b81525060db6000604051602001613932906020808252600690820152657a6b53594e4360d01b604082015260600190565b6040516020818303038152906040528051906020012081526020019081526020016000209081610faf9190615d69565b6040518060400160405280600b81526020016a73776170556e695632282960a81b81525060dc60006040516020016139b8906020808252600a90820152692aa724a9aba0a82fab1960b11b604082015260600190565b60405160208183030381529060405280519060200120815260200190815260200160002090816139e89190615d69565b506040518060400160405280600d81526020016c73776170536f6c69646c79282960981b81525060dc6000604051602001613a3e90602080825260079082015266534f4c49444c5960c81b604082015260600190565b6040516020818303038152906040528051906020012081526020019081526020016000209081613a6e9190615d69565b506040518060400160405280600b81526020016a73776170556e695633282960a81b81525060dc6000604051602001613ac5906020808252600a9082015269554e49535741505f563360b01b604082015260600190565b6040516020818303038152906040528051906020012081526020019081526020016000209081613af59190615d69565b506040518060400160405280601381526020017273776170556e695633446561646c696e65282960681b81525060dc6000604051602001613b5d90602080825260139082015272554e49535741505f56335f444541444c494e4560681b604082015260600190565b6040516020818303038152906040528051906020012081526020019081526020016000209081613b8d9190615d69565b506040518060400160405280600d81526020016c73776170416c6765627261282960981b81525060dc6000604051602001613be390602080825260079082015266414c474542524160c81b604082015260600190565b6040516020818303038152906040528051906020012081526020019081526020016000209081613c139190615d69565b506040518060400160405280600e81526020016d7377617042616c616e636572282960901b81525060dc6000604051602001613932906020808252600890820152672120a620a721a2a960c11b604082015260600190565b60606000613c7883614068565b90506000613c878260016159e7565b6001600160401b03811115613c9e57613c9e61487e565b604051908082528060200260200182016040528015613cc7578160200160208202803683370190505b50905060005b82811015612e8757600080613ce18761408e565b509150915081848481518110613cf957613cf9614ccf565b6001600160a01b03909216602092830291909101909101528084613d1e8560016159e7565b81518110613d2e57613d2e614ccf565b60200260200101906001600160a01b031690816001600160a01b031681525050613d57876140ca565b965050508080613d6690615a80565b915050613ccd565b6040516001600160a01b038316602482015260448101829052610e7390849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526140fb565b60408051608081018252838152306020820152808201839052600060608201819052915163b858183f60e01b81526001600160a01b0386169063b858183f90612ab2908490600401615e22565b6060612af9838360006040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c656400008152506141d0565b6001600160a01b0381163b613ecf5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610f12565b600080516020615eec83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b613f07836142ad565b600082511180613f145750805b15610e73576109b683836142ed565b801580613f9d5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015613f77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f9b91906158c1565b155b6140085760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610f12565b6040516001600160a01b038316602482015260448101829052610e7390849063095ea7b360e01b90606401613d9a565b600054610100900460ff1661405f5760405162461bcd60e51b8152600401610f1290615d1e565b611864336135ba565b6000614076600360146159e7565b601483516140849190614cfb565b61184c9190615e70565b6000808061409c8482614312565b92506140a98460146143c6565b90506140c16140ba600360146159e7565b8590614312565b91509193909250565b606061184c6140db600360146159e7565b6140e7600360146159e7565b84516140f39190614cfb565b849190614471565b6000614150826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166145c89092919063ffffffff16565b90508051600014806141715750808060200190518101906141719190615e92565b610e735760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610f12565b6060824710156142315760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610f12565b600080866001600160a01b0316858760405161424d9190615eaf565b60006040518083038185875af1925050503d806000811461428a576040519150601f19603f3d011682016040523d82523d6000602084013e61428f565b606091505b50915091506142a0878383876145d7565b925050505b949350505050565b6142b681613e62565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060612af98383604051806060016040528060278152602001615f0c60279139614650565b6000816143208160146159e7565b10156143635760405162461bcd60e51b8152602060048201526012602482015271746f416464726573735f6f766572666c6f7760701b6044820152606401610f12565b61436e8260146159e7565b835110156143b65760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b6044820152606401610f12565b500160200151600160601b900490565b6000816143d48160036159e7565b10156144165760405162461bcd60e51b8152602060048201526011602482015270746f55696e7432345f6f766572666c6f7760781b6044820152606401610f12565b6144218260036159e7565b835110156144685760405162461bcd60e51b8152602060048201526014602482015273746f55696e7432345f6f75744f66426f756e647360601b6044820152606401610f12565b50016003015190565b60608161447f81601f6159e7565b10156144be5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610f12565b826144c983826159e7565b10156145085760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610f12565b61451282846159e7565b845110156145565760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610f12565b6060821580156145755760405191506000825260208201604052612b78565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156145ae578051835260209283019201614596565b5050858452601f01601f1916604052505090509392505050565b60606142a584846000856141d0565b6060831561464657825160000361463f576001600160a01b0385163b61463f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610f12565b50816142a5565b6142a583836146c8565b6060600080856001600160a01b03168560405161466d9190615eaf565b600060405180830381855af49150503d80600081146146a8576040519150601f19603f3d011682016040523d82523d6000602084013e6146ad565b606091505b50915091506146be868383876145d7565b9695505050505050565b8151156146d85781518083602001fd5b8060405162461bcd60e51b8152600401610f129190614a96565b634e487b7160e01b600052600160045260246000fd5b60008083601f84011261471a57600080fd5b5081356001600160401b0381111561473157600080fd5b60208301915083602082850101111561474957600080fd5b9250929050565b60008060006040848603121561476557600080fd5b8335925060208401356001600160401b0381111561478257600080fd5b61478e86828701614708565b9497909650939450505050565b6000606082840312156129e657600080fd5b6000602082840312156147bf57600080fd5b81356001600160401b038111156147d557600080fd5b6142a58482850161479b565b600080600080604085870312156147f757600080fd5b84356001600160401b038082111561480e57600080fd5b61481a88838901614708565b9096509450602087013591508082111561483357600080fd5b5061484087828801614708565b95989497509550505050565b6001600160a01b0381168114610faf57600080fd5b60006020828403121561487357600080fd5b8135612af98161484c565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b03811182821017156148b6576148b661487e565b60405290565b604051601f8201601f191681016001600160401b03811182821017156148e4576148e461487e565b604052919050565b60006001600160401b038211156149055761490561487e565b50601f01601f191660200190565b6000806040838503121561492657600080fd5b82356149318161484c565b915060208301356001600160401b0381111561494c57600080fd5b8301601f8101851361495d57600080fd5b803561497061496b826148ec565b6148bc565b81815286602083850101111561498557600080fd5b816020840160208301376000602083830101528093505050509250929050565b6000604082840312156129e657600080fd5b600080604083850312156149ca57600080fd5b8235915060208301356001600160401b038111156149e757600080fd5b6149f3858286016149a5565b9150509250929050565b60028110614a1b57634e487b7160e01b600052602160045260246000fd5b9052565b6020810161184c82846149fd565b600060208284031215614a3f57600080fd5b5035919050565b60005b83811015614a61578181015183820152602001614a49565b50506000910152565b60008151808452614a82816020860160208601614a46565b601f01601f19169290920160200192915050565b602081526000612af96020830184614a6a565b60008060208385031215614abc57600080fd5b82356001600160401b03811115614ad257600080fd5b614ade85828601614708565b90969095509350505050565b6001600160a01b03831681526040602082018190526000906142a590830184614a6a565b8015158114610faf57600080fd5b60008060408385031215614b2f57600080fd5b8235614b3a8161484c565b91506020830135614b4a81614b0e565b809150509250929050565b600060608284031215614b6757600080fd5b612af9838361479b565b6001600160a01b0384168152606060208201819052600090614b9590830185614a6a565b82810360408401526146be8185614a6a565b60008060408385031215614bba57600080fd5b8235614bc58161484c565b91506020830135614b4a8161484c565b600181811c90821680614be957607f821691505b6020821081036129e657634e487b7160e01b600052602260045260246000fd5b60006001600160401b03821115614c2257614c2261487e565b5060051b60200190565b600082601f830112614c3d57600080fd5b81516020614c4d61496b83614c09565b82815260059290921b84018101918181019086841115614c6c57600080fd5b8286015b84811015614c90578051614c838161484c565b8352918301918301614c70565b509695505050505050565b600060208284031215614cad57600080fd5b81516001600160401b03811115614cc357600080fd5b6142a584828501614c2c565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8181038181111561184c5761184c614ce5565b600060808284031215614d2057600080fd5b604051608081018181106001600160401b0382111715614d4257614d4261487e565b604052825161ffff81168114614d5757600080fd5b808252506020830151602082015260408301516040820152606083015160608201528091505092915050565b805182526020810151602083015260006040820151606060408501526142a56060850182614a6a565b60008154614db981614bd5565b808552602060018381168015614dd65760018114614df057614e1e565b60ff1985168884015283151560051b880183019550614e1e565b866000528260002060005b85811015614e165781548a8201860152908301908401614dfb565b890184019650505b505050505092915050565b600061012061ffff8b16835289602084015288604084015260018060a01b03881660608401528660808401528560a08401528060c0840152614e6d81840186614d83565b905082810360e0840152614e818185614dac565b8381036101009094019390935250506000815260200198975050505050505050565b6000806040808486031215614eb757600080fd5b83516001600160401b0380821115614ece57600080fd5b818601915086601f830112614ee257600080fd5b81516020614ef261496b83614c09565b8281526060928302850182019282820191908b851115614f1157600080fd5b958301955b84871015614f595780878d031215614f2e5760008081fd5b614f36614894565b875181528488015185820152888801518982015283529586019591830191614f16565b5091890151919750909450505080831115614f7357600080fd5b50506149f385828601614c2c565b601f821115610e7357600081815260208120601f850160051c81016020861015614fa85750805b601f850160051c820191505b8181101561214e57828155600101614fb4565b600019600383901b1c191660019190911b1790565b6001600160401b03831115614ff357614ff361487e565b615007836150018354614bd5565b83614f81565b6000601f84116001811461503557600085156150235750838201355b61502d8682614fc7565b845550610dff565b600083815260209020601f19861690835b828110156150665786850135825560209485019460019092019101615046565b50868210156150835760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6000808335601e198436030181126150ac57600080fd5b83016020810192503590506001600160401b038111156150cb57600080fd5b80360382131561474957600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60208152600082356151148161484c565b6001600160a01b031660208381019190915261513290840184615095565b606060408501526151476080850182846150da565b9150506151576040850185615095565b848303601f190160608601526146be8382846150da565b80546001600160a01b0319166001600160a01b0392909216919091179055565b6000808335601e198436030181126151a557600080fd5b8301803591506001600160401b038211156151bf57600080fd5b60200191503681900382131561474957600080fd5b81356151df8161484c565b6151e9818361516e565b50600180820160206151fd8186018661518e565b6001600160401b038111156152145761521461487e565b615228816152228654614bd5565b86614f81565b6000601f82116001811461525657600083156152445750838201355b61524e8482614fc7565b8755506152ab565b600086815260209020601f19841690835b828110156152845786850135825593870193908901908701615267565b50848210156152a15760001960f88660031b161c19848701351681555b50508683881b0186555b505050505050506152bf604083018361518e565b6109b6818360028601614fdc565b6020815260006142a56020830184866150da565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600081356153868161484c565b6001600160a01b0316835261539e6020830183615095565b604060208601526153b36040860182846150da565b95945050505050565b8281526040602082015260006142a56040830184615379565b81356153e08161484c565b6153ea818361516e565b50600180820160206153fe8186018661518e565b6001600160401b038111156154155761541561487e565b615423816152228654614bd5565b6000601f821160018114615451576000831561543f5750838201355b6154498482614fc7565b8755506154a6565b600086815260209020601f19841690835b8281101561547f5786850135825593870193908901908701615462565b508482101561549c5760001960f88660031b161c19848701351681555b50508683881b0186555b505050505050505050565b6110e682826153d5565b600060208083850312156154ce57600080fd5b82516001600160401b038111156154e457600080fd5b8301601f810185136154f557600080fd5b805161550361496b82614c09565b8181526060918202830184019184820191908884111561552257600080fd5b938501935b838510156155875780858a03121561553f5760008081fd5b615547614894565b85516155528161484c565b8152858701516155618161484c565b8188015260408681015161557481614b0e565b9082015283529384019391850191615527565b50979650505050505050565b600060a0820187835260208781850152604060a08186015282885180855260c087019150838a01945060005b818110156155fc57855180516001600160a01b039081168552868201511686850152840151151584840152948401946060909201916001016155bf565b50506001600160a01b0388166060870152935061561892505050565b8260808301529695505050505050565b6000602080838503121561563b57600080fd5b82516001600160401b0381111561565157600080fd5b8301601f8101851361566257600080fd5b805161567061496b82614c09565b81815260059190911b8201830190838101908783111561568f57600080fd5b928401925b828410156156ad57835182529284019290840190615694565b979650505050505050565b600081518084526020808501945080840160005b838110156156f15781516001600160a01b0316875295820195908201906001016156cc565b509495945050505050565b85815284602082015260a06040820152600061571b60a08301866156b8565b6001600160a01b0394909416606083015250608001529392505050565b600061574661496b846148ec565b905082815283838301111561575a57600080fd5b612af9836020830184614a46565b600082601f83011261577957600080fd5b612af983835160208501615738565b60006020828403121561579a57600080fd5b81516001600160401b03808211156157b157600080fd5b90830190604082860312156157c557600080fd5b6040516040810181811083821117156157e0576157e061487e565b6040528251828111156157f257600080fd5b6157fe87828601615768565b82525060208301518281111561581357600080fd5b61581f87828601615768565b60208301525095945050505050565b6080815260006158416080830187614a6a565b82810360208401526158538187614dac565b905082810360408401526158678186614a6a565b91505082606083015295945050505050565b60006020828403121561588b57600080fd5b81516001600160401b038111156158a157600080fd5b8201601f810184136158b257600080fd5b6142a584825160208401615738565b6000602082840312156158d357600080fd5b5051919050565b81356158e581614b0e565b815460ff19811691151560ff16918217835560208401356159058161484c565b6001600160a81b03199190911690911760089190911b610100600160a81b03161781556040919091013560019190910155565b805160ff8116811461594957600080fd5b919050565b600060c0828403121561596057600080fd5b60405160c081018181106001600160401b03821117156159825761598261487e565b6040528251815261599560208401615938565b60208201526159a660408401615938565b604082015260608301516159b98161484c565b60608201526159ca60808401615938565b60808201526159db60a08401615938565b60a08201529392505050565b8082018082111561184c5761184c614ce5565b600060208284031215615a0c57600080fd5b815163ffffffff81168114612af957600080fd5b600060208284031215615a3257600080fd5b81516001600160401b0381168114612af957600080fd5b60008351615a5b818460208801614a46565b60609390931b6bffffffffffffffffffffffff19169190920190815260140192915050565b600060018201615a9257615a92614ce5565b5060010190565b602081526000825160a06020840152615ab560c0840182614a6a565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b61ffff8516815260ff8416602082015260a060408201526000615b1760a0830185614a6a565b82810380606085015260008252602081016080850152506156ad6020820185614d83565b60008060408385031215615b4e57600080fd5b505080516020909101519092909150565b6000808354615b6d81614bd5565b60018281168015615b855760018114615b9a57615bc9565b60ff1984168752821515830287019450615bc9565b8760005260208060002060005b85811015615bc05781548a820152908401908201615ba7565b50505082870194505b50929695505050505050565b600081518084526020808501945080840160005b838110156156f157815187529582019590820190600101615be9565b6000610120808301615c17848b6149fd565b60208481019290925288519081905261014080850192600583901b8601909101918a820160005b82811015615ca15787850361013f190186528151805186528481015185870152604080820151908701526060808201519087015260809081015160a091870182905290615c8d81880183614a6a565b978601979650505090830190600101615c3e565b505050508381036040850152615cb781896156b8565b915050615cf7606084018780516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b82810360e0840152615d098186615bd5565b91505082610100830152979650505050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b81516001600160401b03811115615d8257615d8261487e565b615d9681615d908454614bd5565b84614f81565b602080601f831160018114615dc55760008415615db35750858301515b615dbd8582614fc7565b86555061214e565b600085815260208120601f198616915b82811015615df457888601518255948401946001909101908401615dd5565b5085821015615e125787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b602081526000825160806020840152615e3e60a0840182614a6a565b905060018060a01b03602085015116604084015260408401516060840152606084015160808401528091505092915050565b600082615e8d57634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215615ea457600080fd5b8151612af981614b0e565b60008251615ec1818460208701614a46565b919091019291505056fe48b87fc02925b37a6aefac60c14fa9d8e9988d7dfadf262d4bd845872ca40730360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220411dc7abaa48cfcce728fd30bf8164574864f61c87cb31a26517e462bea19e1a64736f6c63430008130033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in FRAX
0
Multichain Portfolio | 35 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.