Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
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:
WrapperFactorLeverageVaultPT
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
// inheritances
import { Initializable } from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import { ReentrancyGuardUpgradeable } from '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol';
import { FactorGauge } from '../../scale/FactorGauge.sol';
import { ERC721DS } from '../../diamond/token/ERC721DS.sol';
import { ERC20Augmented } from '../../diamond/token/ERC20Augmented.sol';
// libraries
import { SafeERC20 } from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import { TransferHelper } from '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol';
// interfaces
import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import { IERC721 } from '@openzeppelin/contracts/token/ERC721/IERC721.sol';
import { ILeverageStrategy } from '../../interfaces/ILeverageStrategy.sol';
import { ILeverageStrategyReward } from '../../interfaces/ILeverageStrategyReward.sol';
import { IFactorLeverageVault as ILeverageVault } from '../../interfaces/IFactorLeverageVault.sol';
import { FactorBoostReward } from '../../boost/FactorBoostReward.sol';
import { WrapperFactorLeverageVaultLib } from '../../libraries/WrapperFactorLeverageVaultLib..sol';
interface ILeverageStrategyView {
function assetBalance() external view returns (uint256);
function debtBalance() external view returns (uint256);
}
interface IStrategyUpgradeTo {
function upgradeTo(address) external;
}
contract WrapperFactorLeverageVaultPT is
Initializable,
ERC721DS,
ERC20Augmented,
ReentrancyGuardUpgradeable,
FactorGauge,
FactorBoostReward
{
using SafeERC20 for IERC20;
mapping(uint256 => address) public stakedNFT;
mapping(uint256 => uint256) public snapshotBalance;
address public factorLeverageVaultAddress;
address public allowedAsset;
address public allowedDebt;
address immutable additionalToken;
error Unauthorized();
error InvalidAssetOrDebt();
error BalanceNotZero();
error NotOwner();
error NoPosition();
error NotSupportReward();
event LeverageAdded(address positionStrategy, uint256 positionId, uint256 amount, uint256 debt);
event LeverageRemoved(address positionStrategy, uint256 positionId, uint256 debt);
event LeverageClosed(address positionStrategy, uint256 positionId, uint256 assetBalance, uint256 debtBalance);
event Stake(uint256 positionId);
event CreatePosition(uint256 positonId, address vault);
event UnStake(uint256 positionId);
event UpdateAugmentedBalance(address positionStrategy, uint256 positionId, uint256 oldBalance, uint256 newBalance);
event Repay(address positionStrategy, uint256 positionId, uint256 amount);
struct InitParams {
string _name;
string _symbol;
address _allowedAsset;
address _allowedDebt;
address _factorLeverageVaultAddress;
address _veFctr;
address _gaugeController;
address _boostController;
uint256 _rewardDuration;
}
constructor(address _additionalToken) {
additionalToken = _additionalToken;
_disableInitializers();
}
function initialize(InitParams memory initParams) public initializer {
__ERC20AUGMENTED_init(initParams._name, initParams._symbol);
__ERC721_init(initParams._name, initParams._symbol);
__FactorGauge_init(initParams._veFctr, initParams._gaugeController);
__FactorBoostReward_init(initParams._boostController, initParams._rewardDuration);
allowedAsset = initParams._allowedAsset;
allowedDebt = initParams._allowedDebt;
factorLeverageVaultAddress = initParams._factorLeverageVaultAddress;
}
function getAdditionalToken() public view returns (address) {
return additionalToken;
}
function transferFrom(address from, address to, uint256 id) public virtual override {
ERC721DS.transferFrom(from, to, id);
address positionStrategy = ILeverageVault(factorLeverageVaultAddress).positions(id);
ERC20Augmented._transfer(from, to, ILeverageStrategy(positionStrategy).debtBalance());
}
function stakePosition(uint256 positionId) external nonReentrant {
address positionStrategy = ILeverageVault(factorLeverageVaultAddress).positions(positionId);
address asset = ILeverageStrategy(positionStrategy).asset();
address debtToken = ILeverageStrategy(positionStrategy).debtToken();
if (asset != allowedAsset || debtToken != allowedDebt) revert InvalidAssetOrDebt();
if (
!(ILeverageStrategy(positionStrategy).assetBalance() == 0 &&
ILeverageStrategy(positionStrategy).debtBalance() == 0)
) revert BalanceNotZero();
IERC721(factorLeverageVaultAddress).transferFrom(msg.sender, address(this), positionId);
_mint(msg.sender, positionId);
emit Stake(positionId);
}
function createPosition() external nonReentrant returns (uint256, address) {
(uint256 position, address strategy) = ILeverageVault(factorLeverageVaultAddress).createPosition(
allowedAsset,
allowedDebt
);
_mint(msg.sender, position - 1);
emit CreatePosition(position - 1, strategy);
return (position - 1, strategy);
}
function unstakePosition(uint256 positionId) external nonReentrant {
if (ownerOf(positionId) != msg.sender) revert NotOwner();
_burn(positionId);
ERC20Augmented._burnAugmented(msg.sender, snapshotBalance[positionId]);
snapshotBalance[positionId] = 0;
IERC721(factorLeverageVaultAddress).transferFrom(address(this), msg.sender, positionId);
emit UnStake(positionId);
}
function addLeverage(uint256 positionId, uint256 amount, uint256 debt, bytes calldata data) external nonReentrant {
if (ownerOf(positionId) != msg.sender) revert NotOwner();
address positionStrategy = ILeverageVault(factorLeverageVaultAddress).positions(positionId);
uint256 oldBalance = snapshotBalance[positionId];
IERC20(ILeverageStrategy(positionStrategy).asset()).safeTransferFrom(msg.sender, address(this), amount);
TransferHelper.safeApprove(ILeverageStrategy(positionStrategy).asset(), positionStrategy, amount);
ILeverageStrategy(positionStrategy).addLeverage(amount, debt, data);
uint256 newBalance = ILeverageStrategy(positionStrategy).debtBalance();
_operationAugmented(msg.sender, newBalance, oldBalance);
snapshotBalance[positionId] = newBalance;
emit LeverageAdded(positionStrategy, positionId, amount, debt);
}
function supply(uint256 positionId, uint256 amount) external nonReentrant {
if (ownerOf(positionId) != msg.sender) revert NotOwner();
WrapperFactorLeverageVaultLib.supply(factorLeverageVaultAddress, positionId, amount);
}
function removeLeverage(uint256 positionId, uint256 amount, bytes calldata data) external nonReentrant {
if (ownerOf(positionId) != msg.sender) revert NotOwner();
address positionStrategy = ILeverageVault(factorLeverageVaultAddress).positions(positionId);
uint256 oldBalance = snapshotBalance[positionId];
uint256 _assetBalanceBefore = IERC20(ILeverageStrategy(positionStrategy).asset()).balanceOf(address(this));
ILeverageStrategy(positionStrategy).removeLeverage(amount, data);
IERC20(ILeverageStrategy(positionStrategy).asset()).safeTransfer(
msg.sender,
IERC20(ILeverageStrategy(positionStrategy).asset()).balanceOf(address(this)) - _assetBalanceBefore
);
uint256 newBalance = ILeverageStrategy(positionStrategy).debtBalance();
_operationAugmented(msg.sender, newBalance, oldBalance);
snapshotBalance[positionId] = newBalance;
emit LeverageRemoved(positionStrategy, positionId, amount);
}
function _operationAugmented(address user, uint256 newBalance, uint256 oldBalance) internal {
if (newBalance > oldBalance) {
ERC20Augmented._mintAugmented(user, newBalance - oldBalance);
}
if (oldBalance > newBalance) {
ERC20Augmented._burnAugmented(user, oldBalance - newBalance);
}
}
function updateAugmentedBalance(uint256 positionId) external nonReentrant {
address positionStrategy = ILeverageVault(factorLeverageVaultAddress).positions(positionId);
uint256 oldBalance = snapshotBalance[positionId];
uint256 newBalance = ILeverageStrategy(positionStrategy).debtBalance();
address user = ownerOf(positionId);
if (user == address(0)) {
revert NoPosition();
}
_operationAugmented(user, newBalance, oldBalance);
snapshotBalance[positionId] = newBalance;
emit UpdateAugmentedBalance(positionStrategy, positionId, oldBalance, newBalance);
}
function closeLeverage(uint256 positionId, uint256 amount, bytes calldata data) external nonReentrant {
if (ownerOf(positionId) != msg.sender) revert NotOwner();
address positionStrategy = ILeverageVault(factorLeverageVaultAddress).positions(positionId);
uint256 oldBalance = snapshotBalance[positionId];
uint256 _assetBalanceBefore = IERC20(ILeverageStrategy(positionStrategy).asset()).balanceOf(address(this));
uint256 _debtBalanceBefore = IERC20(ILeverageStrategy(positionStrategy).debtToken()).balanceOf(address(this));
uint256 _additionalTokenBalanceBefore = IERC20(additionalToken).balanceOf(address(this));
ILeverageStrategy(positionStrategy).closeLeverage(amount, data);
IERC20(ILeverageStrategy(positionStrategy).asset()).safeTransfer(
msg.sender,
IERC20(ILeverageStrategy(positionStrategy).asset()).balanceOf(address(this)) - _assetBalanceBefore
);
IERC20(ILeverageStrategy(positionStrategy).debtToken()).safeTransfer(
msg.sender,
IERC20(ILeverageStrategy(positionStrategy).debtToken()).balanceOf(address(this)) - _debtBalanceBefore
);
IERC20(additionalToken).safeTransfer(
msg.sender,
IERC20(additionalToken).balanceOf(address(this)) - _additionalTokenBalanceBefore
);
uint256 newBalance = ILeverageStrategy(positionStrategy).debtBalance();
_operationAugmented(msg.sender, newBalance, oldBalance);
uint256 closedAsset = ILeverageStrategy(positionStrategy).assetBalance();
uint256 closedDebt = ILeverageStrategy(positionStrategy).debtBalance();
snapshotBalance[positionId] = newBalance;
emit LeverageClosed(positionStrategy, positionId, closedAsset, closedDebt);
}
function withdraw(uint256 positionId, uint256 amount) external nonReentrant {
if (ownerOf(positionId) != msg.sender) revert NotOwner();
WrapperFactorLeverageVaultLib.withdraw(factorLeverageVaultAddress, positionId, amount);
}
function repay(uint256 positionId, uint256 amount) external nonReentrant {
if (ownerOf(positionId) != msg.sender) revert NotOwner();
address positionStrategy = ILeverageVault(factorLeverageVaultAddress).positions(positionId);
uint256 oldBalance = snapshotBalance[positionId];
IERC20(ILeverageStrategy(positionStrategy).debtToken()).safeTransferFrom(msg.sender, address(this), amount);
TransferHelper.safeApprove(ILeverageStrategy(positionStrategy).debtToken(), positionStrategy, amount);
ILeverageStrategy(positionStrategy).repay(amount);
uint256 newBalance = ILeverageStrategy(positionStrategy).debtBalance();
_operationAugmented(msg.sender, newBalance, oldBalance);
snapshotBalance[positionId] = newBalance;
emit Repay(positionStrategy, positionId, amount);
}
function withdrawTokenInCaseStuck(uint256 positionId, address token, uint256 amount) external nonReentrant {
if (ownerOf(positionId) != msg.sender) revert NotOwner();
WrapperFactorLeverageVaultLib.withdrawTokenInCaseStuck(factorLeverageVaultAddress, positionId, token, amount);
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal override(ERC20Augmented, FactorGauge, FactorBoostReward) {
FactorGauge._beforeTokenTransfer(from, to, amount);
FactorBoostReward._beforeTokenTransfer(from, to, amount);
}
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal override(ERC20Augmented, FactorGauge) {
FactorGauge._afterTokenTransfer(from, to, amount);
}
function _stakedBalance(address user) internal view override(FactorGauge, FactorBoostReward) returns (uint256) {
return ERC20Augmented.balanceOfAugmented(user);
}
function _totalStaked() internal view override(FactorGauge, FactorBoostReward) returns (uint256) {
return ERC20Augmented.totalSupplyAugmented();
}
function tokenURI(uint256 id) public view virtual override returns (string memory) {
return ILeverageVault(factorLeverageVaultAddress).tokenURI(id);
}
/**
* @notice redeems the user's reward
* @return amount of reward token redeemed, in the same order as `getRewardTokens()`
*/
function redeemRewards(address user) public nonReentrant returns (uint256[] memory) {
return _redeemRewards(user);
}
/// @notice returns the list of reward tokens
function getRewardTokens() external view returns (address[] memory) {
return _getRewardTokens();
}
function claimRewards(uint256 positionId, address token) external nonReentrant {
if (ownerOf(positionId) != msg.sender) revert NotOwner();
WrapperFactorLeverageVaultLib.claimRewards(factorLeverageVaultAddress, positionId, token);
}
function upgradeStrategy(uint256 positionId, address upgradeImplementation) public {
if (ownerOf(positionId) != msg.sender) revert NotOwner();
WrapperFactorLeverageVaultLib.upgradeStrategy(factorLeverageVaultAddress, positionId, upgradeImplementation);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// On the first call to nonReentrant, _status will be NOT_ENTERED
if ($._status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
$._status = ENTERED;
}
function _nonReentrantAfter() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
$._status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../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 An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
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);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that 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(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.0;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
library TransferHelper {
/// @notice Transfers tokens from the targeted address to the given destination
/// @notice Errors with 'STF' if transfer fails
/// @param token The contract address of the token to be transferred
/// @param from The originating address from which the tokens will be transferred
/// @param to The destination address of the transfer
/// @param value The amount to be transferred
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) =
token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF');
}
/// @notice Transfers tokens from msg.sender to a recipient
/// @dev Errors with ST if transfer fails
/// @param token The contract address of the token which will be transferred
/// @param to The recipient of the transfer
/// @param value The value of the transfer
function safeTransfer(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST');
}
/// @notice Approves the stipulated contract to spend the given allowance in the given token
/// @dev Errors with 'SA' if transfer fails
/// @param token The contract address of the token to be approved
/// @param to The target of the approval
/// @param value The amount of the given token the target will be allowed to spend
function safeApprove(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA');
}
/// @notice Transfers ETH to the recipient address
/// @dev Fails with `STE`
/// @param to The destination of the transfer
/// @param value The value to be transferred
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'STE');
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol';
import '../interfaces/IFactorBoostController.sol';
/**
* @notice FactorBoostReward.sol is a modified version of Synthetix's StakingRewards.sol:
* https://github.com/Synthetixio/synthetix/blob/develop/contracts/StakingRewards.sol
*
*/
abstract contract FactorBoostReward is ReentrancyGuardUpgradeable {
using SafeERC20 for IERC20;
/* ========== EVENTS ========== */
event RewardAdded(uint256 reward);
event RewardPaid(address indexed user, address indexed rewardsToken, uint256 reward);
error NotSetupRewardTokens();
error NotWhitelisted(address _token);
error LessThanMinAmount();
struct Reward {
uint256 periodFinish;
uint256 rewardRate;
uint256 lastUpdateTime;
uint256 rewardPerTokenStored;
}
struct FactorBoostStorage {
address boostController;
uint256 rewardDuration;
mapping(address => Reward) rewardData;
// user -> reward token -> amount
mapping(address => mapping(address => uint256)) userRewardPerTokenPaid;
mapping(address => mapping(address => uint256)) rewards;
}
bytes32 private constant FACTOR_BOOST_STORAGE = keccak256('factor.boost.storage');
function _getFactorBoostStorage() internal pure returns (FactorBoostStorage storage ds) {
bytes32 slot = FACTOR_BOOST_STORAGE;
assembly {
ds.slot := slot
}
}
modifier updateReward(address account) {
_updateReward(account);
_;
}
function __FactorBoostReward_init(
address _boostController,
uint256 _rewardDuration
) internal onlyInitializing {
__ReentrancyGuard_init();
FactorBoostStorage storage $ = _getFactorBoostStorage();
$.rewardDuration = _rewardDuration;
$.boostController = _boostController;
}
/* ========== VIEWS ========== */
function boostController() external view returns (address) {
return _getFactorBoostStorage().boostController;
}
function rewardDuration() external view returns (uint256) {
return _getFactorBoostStorage().rewardDuration;
}
function userRewardPerTokenPaid(address _user, address _rewardsToken) external view returns (uint256) {
return _getFactorBoostStorage().userRewardPerTokenPaid[_user][_rewardsToken];
}
function rewardData(address _rewardsToken) external view returns (Reward memory) {
return _getFactorBoostStorage().rewardData[_rewardsToken];
}
function lastTimeRewardApplicable(address _rewardsToken) public view returns (uint256) {
FactorBoostStorage storage $ = _getFactorBoostStorage();
uint256 periodFinish = $.rewardData[_rewardsToken].periodFinish;
return block.timestamp < periodFinish ? block.timestamp : periodFinish;
}
function rewardPerToken(address _rewardsToken) public view returns (uint256) {
FactorBoostStorage storage $ = _getFactorBoostStorage();
uint256 totalSupply = _totalStaked();
if (totalSupply == 0) {
return $.rewardData[_rewardsToken].rewardPerTokenStored;
}
return
$.rewardData[_rewardsToken].rewardPerTokenStored +
(((lastTimeRewardApplicable(_rewardsToken) - $.rewardData[_rewardsToken].lastUpdateTime) *
$.rewardData[_rewardsToken].rewardRate *
1e18) / totalSupply);
}
function earned(address account, address _rewardsToken) public view returns (uint256) {
FactorBoostStorage storage $ = _getFactorBoostStorage();
return
(_stakedBalance(account) *
(rewardPerToken(_rewardsToken) - $.userRewardPerTokenPaid[account][_rewardsToken])) /
1e18 +
$.rewards[account][_rewardsToken];
}
function getRewardForDuration(address _rewardsToken) external view returns (uint256) {
FactorBoostStorage storage $ = _getFactorBoostStorage();
return $.rewardData[_rewardsToken].rewardRate * $.rewardDuration;
}
/* ========== MUTATIVE FUNCTIONS ========== */
function redeemBoostRewardAll() public nonReentrant updateReward(msg.sender) {
FactorBoostStorage storage $ = _getFactorBoostStorage();
address[] memory rewardTokens = IFactorBoostController($.boostController).getAllRewardTokens(address(this));
if (rewardTokens.length == 0) revert NotSetupRewardTokens();
for (uint i; i < rewardTokens.length; i++) {
address _rewardsToken = rewardTokens[i];
uint256 reward = $.rewards[msg.sender][_rewardsToken];
if (reward > 0) {
$.rewards[msg.sender][_rewardsToken] = 0;
IERC20(_rewardsToken).safeTransfer(msg.sender, reward);
emit RewardPaid(msg.sender, _rewardsToken, reward);
}
}
}
function redeemBoostReward(
address user,
address[] calldata rewardTokens
) public nonReentrant {
_updateReward(user);
FactorBoostStorage storage $ = _getFactorBoostStorage();
for (uint i; i < rewardTokens.length; i++) {
address _rewardsToken = rewardTokens[i];
uint256 reward = $.rewards[user][_rewardsToken];
if (reward > 0) {
$.rewards[user][_rewardsToken] = 0;
IERC20(_rewardsToken).safeTransfer(user, reward);
emit RewardPaid(user, _rewardsToken, reward);
}
}
}
/* ========== RESTRICTED FUNCTIONS ========== */
function notifyRewardAmount(address _rewardsToken, uint256 reward) external updateReward(address(0)) {
FactorBoostStorage storage $ = _getFactorBoostStorage();
if (!IFactorBoostController($.boostController).whitelisted(address(this), _rewardsToken))
revert NotWhitelisted(_rewardsToken);
if (IFactorBoostController($.boostController).minAmount(_rewardsToken) > reward)
revert LessThanMinAmount();
IERC20(_rewardsToken).safeTransferFrom(msg.sender, address(this), reward);
if (block.timestamp >= $.rewardData[_rewardsToken].periodFinish) {
$.rewardData[_rewardsToken].rewardRate = reward / $.rewardDuration;
} else {
uint256 remaining = $.rewardData[_rewardsToken].periodFinish - block.timestamp;
uint256 leftover = remaining * $.rewardData[_rewardsToken].rewardRate;
$.rewardData[_rewardsToken].rewardRate = (reward + leftover) / $.rewardDuration;
}
$.rewardData[_rewardsToken].lastUpdateTime = block.timestamp;
$.rewardData[_rewardsToken].periodFinish = block.timestamp + $.rewardDuration;
emit RewardAdded(reward);
}
function _updateReward(address _account) internal {
FactorBoostStorage storage $ = _getFactorBoostStorage();
address[] memory rewardTokens = IFactorBoostController($.boostController).getAllRewardTokens(address(this));
for (uint i; i < rewardTokens.length; i++) {
address token = rewardTokens[i];
$.rewardData[token].rewardPerTokenStored = rewardPerToken(token);
$.rewardData[token].lastUpdateTime = lastTimeRewardApplicable(token);
if (_account != address(0)) {
$.rewards[_account][token] = earned(_account, token);
$.userRewardPerTokenPaid[_account][token] = $.rewardData[token].rewardPerTokenStored;
}
}
}
function _beforeTokenTransfer(address from, address to, uint256) internal virtual {
if (from != address(0)) {
_updateReward(from);
}
if (to != address(0) && to != from) {
_updateReward(to);
}
}
function _stakedBalance(address user) internal view virtual returns (uint256);
function _totalStaked() internal view virtual returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import { Initializable } from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
abstract contract ERC20Augmented is Initializable {
mapping(address => uint256) private _balances;
uint248 private _totalSupply;
string private _name;
string private _symbol;
uint8 public decimals;
function __ERC20AUGMENTED_init(string memory name_, string memory symbol_) internal onlyInitializing {
_name = name_;
_symbol = symbol_;
decimals = 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupplyAugmented() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOfAugmented(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev Moves `amount` of tokens from `sender` to `recipient`.
*
* 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');
require(from != to, 'ERC20: transfer to self');
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, 'ERC20: transfer amount exceeds balance');
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[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 _mintAugmented(address account, uint256 amount) internal virtual {
require(account != address(0), 'ERC20: mint to the zero address');
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += toUint248(amount);
_balances[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 _burnAugmented(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;
}
_totalSupply -= toUint248(amount);
_afterTokenTransfer(account, address(0), 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 {}
function toUint248(uint256 x) internal virtual returns (uint248) {
require(x <= type(uint248).max); // signed, lim = bit-1
return uint248(x);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import { Initializable } from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721DS is Initializable {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 indexed id);
event Approval(address indexed owner, address indexed spender, uint256 indexed id);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE/LOGIC
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
function tokenURI(uint256 id) public view virtual returns (string memory);
/*//////////////////////////////////////////////////////////////
ERC721 BALANCE/OWNER STORAGE
//////////////////////////////////////////////////////////////*/
mapping(uint256 => address) internal _ownerOf;
mapping(address => uint256) internal _balanceOf;
function ownerOf(uint256 id) public view virtual returns (address owner) {
require((owner = _ownerOf[id]) != address(0), 'NOT_MINTED');
}
function balanceOf(address owner) public view virtual returns (uint256) {
require(owner != address(0), 'ZERO_ADDRESS');
return _balanceOf[owner];
}
/*//////////////////////////////////////////////////////////////
ERC721 APPROVAL STORAGE
//////////////////////////////////////////////////////////////*/
mapping(uint256 => address) public getApproved;
mapping(address => mapping(address => bool)) public isApprovedForAll;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
function __ERC721_init(string memory _name, string memory _symbol) internal onlyInitializing {
name = _name;
symbol = _symbol;
}
/*//////////////////////////////////////////////////////////////
ERC721 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 id) public virtual {
address owner = _ownerOf[id];
require(msg.sender == owner || isApprovedForAll[owner][msg.sender], 'NOT_AUTHORIZED');
getApproved[id] = spender;
emit Approval(owner, spender, id);
}
function setApprovalForAll(address operator, bool approved) public virtual {
isApprovedForAll[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function transferFrom(address from, address to, uint256 id) public virtual {
require(from == _ownerOf[id], 'WRONG_FROM');
require(to != address(0), 'INVALID_RECIPIENT');
require(
msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
'NOT_AUTHORIZED'
);
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
unchecked {
_balanceOf[from]--;
_balanceOf[to]++;
}
_ownerOf[id] = to;
delete getApproved[id];
emit Transfer(from, to, id);
}
function safeTransferFrom(address from, address to, uint256 id) public virtual {
transferFrom(from, to, id);
require(
to.code.length == 0 ||
ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, '') ==
ERC721TokenReceiver.onERC721Received.selector,
'UNSAFE_RECIPIENT'
);
}
function safeTransferFrom(address from, address to, uint256 id, bytes calldata data) public virtual {
transferFrom(from, to, id);
require(
to.code.length == 0 ||
ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
ERC721TokenReceiver.onERC721Received.selector,
'UNSAFE_RECIPIENT'
);
}
/*//////////////////////////////////////////////////////////////
ERC165 LOGIC
//////////////////////////////////////////////////////////////*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return
interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 id) internal virtual {
require(to != address(0), 'INVALID_RECIPIENT');
require(_ownerOf[id] == address(0), 'ALREADY_MINTED');
// Counter overflow is incredibly unrealistic.
unchecked {
_balanceOf[to]++;
}
_ownerOf[id] = to;
emit Transfer(address(0), to, id);
}
function _burn(uint256 id) internal virtual {
address owner = _ownerOf[id];
require(owner != address(0), 'NOT_MINTED');
// Ownership check above ensures no underflow.
unchecked {
_balanceOf[owner]--;
}
delete _ownerOf[id];
delete getApproved[id];
emit Transfer(owner, address(0), id);
}
/*//////////////////////////////////////////////////////////////
INTERNAL SAFE MINT LOGIC
//////////////////////////////////////////////////////////////*/
function _safeMint(address to, uint256 id) internal virtual {
_mint(to, id);
require(
to.code.length == 0 ||
ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, '') ==
ERC721TokenReceiver.onERC721Received.selector,
'UNSAFE_RECIPIENT'
);
}
function _safeMint(address to, uint256 id, bytes memory data) internal virtual {
_mint(to, id);
require(
to.code.length == 0 ||
ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
ERC721TokenReceiver.onERC721Received.selector,
'UNSAFE_RECIPIENT'
);
}
}
/// @notice A generic interface for a contract which properly accepts ERC721 tokens.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721TokenReceiver {
function onERC721Received(address, address, uint256, bytes calldata) external virtual returns (bytes4) {
return ERC721TokenReceiver.onERC721Received.selector;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface IFactorBoostController {
function whitelisted(address _vault, address _token) external view returns (bool);
function minAmount(address _token) external view returns (uint256);
function getAllRewardTokens(address _vault) external view returns (address[] memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface IFactorGaugeController {
event VaultClaimReward(
address indexed vault,
uint256 amount
);
event ReceiveVotingResults(
uint128 indexed wTime,
address[] vaults,
uint256[] fctrAmounts
);
event UpdateVaultReward(
address indexed vault,
uint256 fctrPerSec,
uint256 incentiveEndsAt
);
event AddVault(address indexed vault);
event RemoveVault(address indexed vault);
function fundEsFctr(uint256 amount) external;
function withdrawEsFctr(uint256 amount) external;
function esFctr() external returns (address);
function redeemVaultReward() external;
function rewardData(
address pool
) external view returns (uint128 fctrPerSec, uint128, uint128, uint128);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IFactorLeverageVault {
function isRegisteredUpgrade(
address baseImplementation,
address upgradeImplementation
) external view returns (bool);
function registerUpgrade(address baseImplementation, address upgradeImplementation) external;
function createPosition(address asset, address debt) external returns (uint256 id, address strategy);
function assets(address) external view returns (address);
function leverageFee() external view returns (uint256);
function debts(address) external view returns (address);
function claimRewardFee() external view returns (uint256);
function version() external pure returns (string memory);
function feeRecipient() external view returns (address);
function FEE_SCALE() external view returns (uint256);
function positions(uint256) external view returns (address);
function tokenURI(uint256 id) external view returns (string memory);
function burnPosition(uint256 positionId) external;
function currentPositionId() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface ILeverageStrategy {
function initialize(uint256, address, address, address, address, address) external;
function vaultManager() external view returns (address);
function positionId() external view returns (uint256);
function asset() external view returns (address);
function debtToken() external view returns (address);
function assetPool() external view returns (address);
function debtPool() external view returns (address);
function assetBalance() external returns (uint256);
function debtBalance() external returns (uint256);
function owner() external view returns (address);
function addLeverage(uint256 amount, uint256 debt, bytes calldata data) external;
function removeLeverage(uint256 amount, bytes calldata data) external;
function closeLeverage(uint256 amount, bytes calldata data) external;
function supply(uint256 withdraw) external;
function borrow(uint256 debt) external;
function repay(uint256 amount) external;
function withdraw(uint256 withdraw) external;
function version() external pure returns (string memory);
function withdrawTokenInCaseStuck(address tokenAddress, uint256 amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface ILeverageStrategyReward {
function claimRewards() external;
function claimRewards(address token) external;
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.20;
interface IVotingEscrow {
// ============= USER INFO =============
function balanceOf(address user) external view returns (uint128);
function balanceOfAt(address user, uint128 timestamp) external view returns (uint128);
function positionData(address user) external view returns (uint128 amount, uint128 expiry);
// ============= META DATA =============
function totalSupplyStored() external view returns (uint128);
function totalSupplyCurrent() external returns (uint128);
function totalSupplyAndBalanceCurrent(address user) external returns (uint128, uint128);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
library ArrayLib {
function sum(uint256[] memory input) internal pure returns (uint256) {
uint256 value = 0;
for (uint256 i = 0; i < input.length; ) {
value += input[i];
unchecked {
i++;
}
}
return value;
}
/// @notice return index of the element if found, else return uint256.max
function find(address[] memory array, address element) internal pure returns (uint256 index) {
uint256 length = array.length;
for (uint256 i = 0; i < length; ) {
if (array[i] == element) return i;
unchecked {
i++;
}
}
return type(uint256).max;
}
function append(
address[] memory inp,
address element
) internal pure returns (address[] memory out) {
uint256 length = inp.length;
out = new address[](length + 1);
for (uint256 i = 0; i < length; ) {
out[i] = inp[i];
unchecked {
i++;
}
}
out[length] = element;
}
/**
* @dev This function assumes a and b each contains unidentical elements
* @param a array of addresses a
* @param b array of addresses b
* @return out Concatenation of a and b containing unidentical elements
*/
function merge(
address[] memory a,
address[] memory b
) internal pure returns (address[] memory out) {
unchecked {
uint256 countUnidenticalB = 0;
bool[] memory isUnidentical = new bool[](b.length);
for(uint256 i = 0; i < b.length; ++i) {
if (!contains(a, b[i])) {
countUnidenticalB++;
isUnidentical[i] = true;
}
}
out = new address[](a.length + countUnidenticalB);
for(uint256 i = 0; i < a.length; ++i) {
out[i] = a[i];
}
uint256 id = a.length;
for(uint256 i = 0; i < b.length; ++i) {
if (isUnidentical[i]) {
out[id++] = b[i];
}
}
}
}
// various version of contains
function contains(address[] memory array, address element) internal pure returns (bool) {
uint256 length = array.length;
for (uint256 i = 0; i < length; ) {
if (array[i] == element) return true;
unchecked {
i++;
}
}
return false;
}
function contains(bytes4[] memory array, bytes4 element) internal pure returns (bool) {
uint256 length = array.length;
for (uint256 i = 0; i < length; ) {
if (array[i] == element) return true;
unchecked {
i++;
}
}
return false;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
/*//////////////////////////////////////////////////////////////
SIMPLIFIED FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
uint256 internal constant MAX_UINT256 = 2**256 - 1;
uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.
function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
}
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
}
function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
}
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
}
/*//////////////////////////////////////////////////////////////
LOW LEVEL FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// Divide x * y by the denominator.
z := div(mul(x, y), denominator)
}
}
function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// If x * y modulo the denominator is strictly greater than 0,
// 1 is added to round up the division of x * y by the denominator.
z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
}
}
function rpow(
uint256 x,
uint256 n,
uint256 scalar
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
switch x
case 0 {
switch n
case 0 {
// 0 ** 0 = 1
z := scalar
}
default {
// 0 ** n = 0
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
// If n is even, store scalar in z for now.
z := scalar
}
default {
// If n is odd, store x in z for now.
z := x
}
// Shifting right by 1 is like dividing by 2.
let half := shr(1, scalar)
for {
// Shift n right by 1 before looping to halve it.
n := shr(1, n)
} n {
// Shift n right by 1 each iteration to halve it.
n := shr(1, n)
} {
// Revert immediately if x ** 2 would overflow.
// Equivalent to iszero(eq(div(xx, x), x)) here.
if shr(128, x) {
revert(0, 0)
}
// Store x squared.
let xx := mul(x, x)
// Round to the nearest number.
let xxRound := add(xx, half)
// Revert if xx + half overflowed.
if lt(xxRound, xx) {
revert(0, 0)
}
// Set x to scaled xxRound.
x := div(xxRound, scalar)
// If n is even:
if mod(n, 2) {
// Compute z * x.
let zx := mul(z, x)
// If z * x overflowed:
if iszero(eq(div(zx, x), z)) {
// Revert if x is non-zero.
if iszero(iszero(x)) {
revert(0, 0)
}
}
// Round to the nearest number.
let zxRound := add(zx, half)
// Revert if zx + half overflowed.
if lt(zxRound, zx) {
revert(0, 0)
}
// Return properly scaled zxRound.
z := div(zxRound, scalar)
}
}
}
}
}
/*//////////////////////////////////////////////////////////////
GENERAL NUMBER UTILITIES
//////////////////////////////////////////////////////////////*/
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let y := x // We start y at x, which will help us make our initial estimate.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// We check y >= 2^(k + 8) but shift right by k bits
// each branch to ensure that if x >= 256, then y >= 256.
if iszero(lt(y, 0x10000000000000000000000000000000000)) {
y := shr(128, y)
z := shl(64, z)
}
if iszero(lt(y, 0x1000000000000000000)) {
y := shr(64, y)
z := shl(32, z)
}
if iszero(lt(y, 0x10000000000)) {
y := shr(32, y)
z := shl(16, z)
}
if iszero(lt(y, 0x1000000)) {
y := shr(16, y)
z := shl(8, z)
}
// Goal was to get z*z*y within a small factor of x. More iterations could
// get y in a tighter range. Currently, we will have y in [256, 256*2^16).
// We ensured y >= 256 so that the relative difference between y and y+1 is small.
// That's not possible if x < 256 but we can just verify those cases exhaustively.
// Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
// Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
// Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.
// For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
// (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.
// Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
// sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.
// There is no overflow risk here since y < 2^136 after the first branch above.
z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If x+1 is a perfect square, the Babylonian method cycles between
// floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
// Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
// If you don't care whether the floor or ceil square root is returned, you can remove this statement.
z := sub(z, lt(div(x, z), z))
}
}
function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Mod x by y. Note this will return
// 0 instead of reverting if y is zero.
z := mod(x, y)
}
}
function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
// Divide x by y. Note this will return
// 0 instead of reverting if y is zero.
r := div(x, y)
}
}
function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Add 1 to x * y if x % y > 0. Note this will
// return 0 instead of reverting if y is zero.
z := add(gt(mod(x, y), 0), div(x, y))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { ILeverageStrategy } from '../interfaces/ILeverageStrategy.sol';
import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import { IFactorLeverageVault as ILeverageVault } from '../interfaces/IFactorLeverageVault.sol';
import { ILeverageStrategyReward } from '../interfaces/ILeverageStrategyReward.sol';
import { ERC20Augmented } from '../diamond/token/ERC20Augmented.sol';
import { SafeERC20 } from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import { TransferHelper } from '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol';
interface IStrategyUpgradeTo {
function upgradeTo(address) external;
}
library WrapperFactorLeverageVaultLib {
using SafeERC20 for IERC20;
error ZeroReward();
error NotSupportReward();
error BalanceNotEnough();
event UpgradeStrategy(address positionStrategy, uint256 positionId, address upgradeImplementation);
event WithdrawTokenInCaseStuck(address positionStrategy, uint256 positionId, address token, uint256 amount);
event Supply(address positionStrategy, uint256 positionId, uint256 amount);
event Withdraw(address positionStrategy, uint256 positionId, uint256 amount);
function claimRewards(address factorLeverageVaultAddressm, uint256 positionId, address token) public {
address strategy = ILeverageVault(factorLeverageVaultAddressm).positions(positionId);
uint256 balanceBefore = IERC20(token).balanceOf(address(this));
try ILeverageStrategyReward(strategy).claimRewards() {
// If successful, nothing more to do
} catch {
// If the call failed, it might be the other type of strategy
// Now try calling `claimRewards(address token)`
try ILeverageStrategyReward(strategy).claimRewards(token) {
// If successful, nothing more to do
} catch {
revert NotSupportReward();
}
}
uint256 balance = IERC20(token).balanceOf(address(this)) - balanceBefore;
if (balance == 0) {
revert ZeroReward();
}
IERC20(token).safeTransfer(msg.sender, balance);
}
function upgradeStrategy(
address factorLeverageVaultAddress,
uint256 positionId,
address upgradeImplementation
) public {
address positionStrategy = ILeverageVault(factorLeverageVaultAddress).positions(positionId);
IStrategyUpgradeTo(positionStrategy).upgradeTo(upgradeImplementation);
emit UpgradeStrategy(positionStrategy, positionId, upgradeImplementation);
}
function withdrawTokenInCaseStuck(
address factorLeverageVaultAddress,
uint256 positionId,
address token,
uint256 amount
) public {
address positionStrategy = ILeverageVault(factorLeverageVaultAddress).positions(positionId);
uint256 balanceBefore = IERC20(token).balanceOf(address(this));
ILeverageStrategy(positionStrategy).withdrawTokenInCaseStuck(token, amount);
uint256 balance = IERC20(token).balanceOf(address(this)) - balanceBefore;
if (amount > balance) {
revert BalanceNotEnough();
}
IERC20(token).safeTransfer(msg.sender, balance);
emit WithdrawTokenInCaseStuck(positionStrategy, positionId, token, balance);
}
function supply(address factorLeverageVaultAddress, uint256 positionId, uint256 amount) public {
address positionStrategy = ILeverageVault(factorLeverageVaultAddress).positions(positionId);
IERC20(ILeverageStrategy(positionStrategy).asset()).safeTransferFrom(msg.sender, address(this), amount);
TransferHelper.safeApprove(ILeverageStrategy(positionStrategy).asset(), positionStrategy, amount);
ILeverageStrategy(positionStrategy).supply(amount);
emit Supply(positionStrategy, positionId, amount);
}
function withdraw(address factorLeverageVaultAddress, uint256 positionId, uint256 amount) public {
address positionStrategy = ILeverageVault(factorLeverageVaultAddress).positions(positionId);
ILeverageStrategy(positionStrategy).withdraw(amount);
IERC20(ILeverageStrategy(positionStrategy).asset()).safeTransfer(msg.sender, amount);
emit Withdraw(positionStrategy, positionId, amount);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { Initializable } from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import { Math } from '@openzeppelin/contracts/utils/math/Math.sol';
import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import { SafeERC20 } from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import { RewardManager } from './RewardManager.sol';
import { IVotingEscrow } from '../interfaces/IVotingEscrow.sol';
import { IFactorGaugeController } from '../interfaces/IFactorGaugeController.sol';
import { ArrayLib } from '../libraries/ArrayLib.sol';
/**
* @dev FactorGauge.sol is a modified version of Pendle's PendleGauge.sol:
* https://github.com/pendle-finance/pendle-core-v2-public/blob/main/contracts/core/Market/PendleGauge.sol
*
* @notice
* This is used with FactorVault.
*/
abstract contract FactorGauge is RewardManager, Initializable {
// =============================================================
// Library
// =============================================================
using SafeERC20 for IERC20;
using Math for uint256;
using ArrayLib for address[];
// =============================================================
// Events
// =============================================================
event RedeemRewards(address indexed user, uint256[] rewardsOut);
uint256 internal constant TOKENLESS_PRODUCTION = 40;
struct FactorGaugeStorage {
address esFctr;
address veFctr;
address gaugeController;
uint256 totalActiveSupply;
mapping(address => uint256) activeBalance;
}
bytes32 private constant FACTOR_GAUGE_STORAGE = keccak256('factor.base.gauge.storage');
function _getFactorGaugeStorage() internal pure returns (FactorGaugeStorage storage $) {
bytes32 slot = FACTOR_GAUGE_STORAGE;
assembly {
$.slot := slot
}
}
function __FactorGauge_init(address _veFctr, address _gaugeController) internal onlyInitializing {
FactorGaugeStorage storage $ = _getFactorGaugeStorage();
$.veFctr = _veFctr;
$.gaugeController = _gaugeController;
$.esFctr = IFactorGaugeController(_gaugeController).esFctr();
}
/**
* @dev Since rewardShares is based on activeBalance, user's activeBalance must be updated AFTER
* rewards is updated.
* It's intended to have user's activeBalance updated when rewards is redeemed
*/
function _redeemRewards(address user) internal virtual returns (uint256[] memory rewardsOut) {
_updateAndDistributeRewards(user);
_updateUserActiveBalance(user);
rewardsOut = _doTransferOutRewards(user, user);
emit RedeemRewards(user, rewardsOut);
}
function _updateUserActiveBalance(address user) internal virtual {
_updateUserActiveBalanceForTwo(user, address(0));
}
function _updateUserActiveBalanceForTwo(address user1, address user2) internal virtual {
if (user1 != address(0) && user1 != address(this)) _updateUserActiveBalancePrivate(user1);
if (user2 != address(0) && user2 != address(this)) _updateUserActiveBalancePrivate(user2);
}
/**
* @dev should only be callable from `_updateUserActiveBalanceForTwo` to
* guarantee user != address(0) && user != address(this)
*/
function _updateUserActiveBalancePrivate(address user) private {
assert(user != address(0) && user != address(this));
uint256 lpBalance = _stakedBalance(user);
uint256 veBoostedLpBalance = _calcVeBoostedLpBalance(user, lpBalance);
uint256 newActiveBalance = Math.min(veBoostedLpBalance, lpBalance);
FactorGaugeStorage storage $ = _getFactorGaugeStorage();
$.totalActiveSupply = $.totalActiveSupply - $.activeBalance[user] + newActiveBalance;
$.activeBalance[user] = newActiveBalance;
}
function _calcVeBoostedLpBalance(address user, uint256 lpBalance) internal virtual returns (uint256) {
FactorGaugeStorage storage $ = _getFactorGaugeStorage();
(uint256 veFctrSupplyCurrent, uint256 veFctrBalanceCurrent) = IVotingEscrow($.veFctr)
.totalSupplyAndBalanceCurrent(user);
// Inspired by Curve's Gauge
uint256 veBoostedLpBalance = (lpBalance * TOKENLESS_PRODUCTION) / 100;
if (veFctrSupplyCurrent > 0) {
veBoostedLpBalance +=
(((_totalStaked() * veFctrBalanceCurrent) / veFctrSupplyCurrent) * (100 - TOKENLESS_PRODUCTION)) /
100;
}
return veBoostedLpBalance;
}
function _redeemExternalReward() internal virtual override {
IFactorGaugeController(_getFactorGaugeStorage().gaugeController).redeemVaultReward();
}
function _stakedBalance(address user) internal view virtual returns (uint256);
function _totalStaked() internal view virtual returns (uint256);
function _getRewardTokens() internal view virtual override returns (address[] memory) {
address[] memory rewardTokens = new address[](0);
return rewardTokens.append(_getFactorGaugeStorage().esFctr);
}
function _rewardSharesTotal() internal view virtual override returns (uint256) {
return _getFactorGaugeStorage().totalActiveSupply;
}
function _rewardSharesUser(address user) internal view virtual override returns (uint256) {
return _getFactorGaugeStorage().activeBalance[user];
}
function _beforeTokenTransfer(address from, address to, uint256) internal virtual {
_updateAndDistributeRewardsForTwo(from, to);
}
function _afterTokenTransfer(address from, address to, uint256) internal virtual {
_updateUserActiveBalanceForTwo(from, to);
}
function totalActiveSupply() public view returns (uint256) {
return _getFactorGaugeStorage().totalActiveSupply;
}
function activeBalance(address user) public view returns (uint256) {
return _getFactorGaugeStorage().activeBalance[user];
}
function _pendingRewards(
address user
) internal view returns (uint256) {
FactorGaugeStorage storage $ = _getFactorGaugeStorage();
address rewardToken = $.esFctr;
(
uint128 fctrPerSec,
uint128 accumulatedFctr,
uint128 lastUpdated,
) = IFactorGaugeController($.gaugeController).rewardData(address(this));
accumulatedFctr += fctrPerSec * (uint128(block.timestamp) - lastUpdated);
return _calculateReward(user, rewardToken, accumulatedFctr);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { SafeCast } from '@openzeppelin/contracts/utils/math/SafeCast.sol';
import { FixedPointMathLib } from '../libraries/uniswap/FixedPointMathLib.sol';
import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import { SafeERC20 } from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
/**
* @dev RewardManager.sol is a modified version of Pendle's RewardManager.sol & RewardManagerAbstract:
* https://github.com/pendle-finance/pendle-core-v2-public/blob/main/contracts/core/RewardManager/RewardManager.sol
*
* @notice
* This is used with FactorGauge. RewardManager must not have duplicated rewardTokens
*/
abstract contract RewardManager {
using FixedPointMathLib for uint256;
using SafeCast for uint256;
using SafeERC20 for IERC20;
struct RewardState {
uint128 index;
uint128 lastBalance;
}
struct UserReward {
uint128 index;
uint128 accrued;
}
struct RewardManagerStorage {
uint256 lastRewardBlock;
/// @dev [token] => [user] => (index, accrued)
mapping(address => mapping(address => UserReward)) userReward;
/// @dev [token] => (index, lastBalance)
mapping(address => RewardState) rewardState;
}
bytes32 private constant REWARD_MANAGER_STORAGE = keccak256('factor.base.RewardManager.storage');
function _getRewardManagerStorage() internal pure returns (RewardManagerStorage storage $) {
bytes32 slot = REWARD_MANAGER_STORAGE;
assembly {
$.slot := slot
}
}
uint256 internal constant INITIAL_REWARD_INDEX = 1;
function _updateAndDistributeRewards(address user) internal virtual {
_updateAndDistributeRewardsForTwo(user, address(0));
}
function _updateAndDistributeRewardsForTwo(address user1, address user2) internal virtual {
(address[] memory tokens, uint256[] memory indexes) = _updateRewardIndex();
if (tokens.length == 0) return;
if (user1 != address(0) && user1 != address(this)) _distributeRewardsPrivate(user1, tokens, indexes);
if (user2 != address(0) && user2 != address(this)) _distributeRewardsPrivate(user2, tokens, indexes);
}
/**
* @dev should only be callable from `_updateAndDistributeRewardsForTwo` to guarantee
* user != address(0) && user != address(this)
*/
function _distributeRewardsPrivate(address user, address[] memory tokens, uint256[] memory indexes) private {
assert(user != address(0) && user != address(this));
RewardManagerStorage storage $ = _getRewardManagerStorage();
uint256 userShares = _rewardSharesUser(user);
for (uint256 i = 0; i < tokens.length; ++i) {
address token = tokens[i];
uint256 index = indexes[i];
uint256 userIndex = $.userReward[token][user].index;
if (userIndex == 0) {
$.userReward[token][user].index = index.toUint128();
continue;
}
if (userIndex == index) continue;
uint256 deltaIndex = index - userIndex;
uint256 rewardDelta = userShares.mulWadDown(deltaIndex);
uint256 rewardAccrued = $.userReward[token][user].accrued + rewardDelta;
$.userReward[token][user] = UserReward({ index: index.toUint128(), accrued: rewardAccrued.toUint128() });
}
}
function _updateRewardIndex() internal virtual returns (address[] memory tokens, uint256[] memory indexes) {
tokens = _getRewardTokens();
indexes = new uint256[](tokens.length);
if (tokens.length == 0) return (tokens, indexes);
RewardManagerStorage storage $ = _getRewardManagerStorage();
if ($.lastRewardBlock != block.number) {
// if we have not yet update the index for this block
$.lastRewardBlock = block.number;
uint256 totalShares = _rewardSharesTotal();
_redeemExternalReward();
for (uint256 i = 0; i < tokens.length; ++i) {
address token = tokens[i];
// the entire token balance of the contract must be the rewards of the contract
uint256 accrued = IERC20(tokens[i]).balanceOf(address(this)) - $.rewardState[token].lastBalance;
uint256 index = $.rewardState[token].index;
if (index == 0) index = INITIAL_REWARD_INDEX;
if (totalShares != 0) index += accrued.divWadDown(totalShares);
$.rewardState[token].index = index.toUint128();
$.rewardState[token].lastBalance += accrued.toUint128();
}
}
for (uint256 i = 0; i < tokens.length; i++) indexes[i] = $.rewardState[tokens[i]].index;
}
/// @dev this function doesn't need redeemExternal since redeemExternal is bundled in updateRewardIndex
/// @dev this function also has to update rewardState.lastBalance
function _doTransferOutRewards(
address user,
address receiver
) internal virtual returns (uint256[] memory rewardAmounts) {
address[] memory tokens = _getRewardTokens();
rewardAmounts = new uint256[](tokens.length);
RewardManagerStorage storage $ = _getRewardManagerStorage();
for (uint256 i = 0; i < tokens.length; i++) {
rewardAmounts[i] = $.userReward[tokens[i]][user].accrued;
if (rewardAmounts[i] != 0) {
$.userReward[tokens[i]][user].accrued = 0;
$.rewardState[tokens[i]].lastBalance -= rewardAmounts[i].toUint128();
IERC20(tokens[i]).safeTransfer(receiver, rewardAmounts[i]);
}
}
}
function _redeemExternalReward() internal virtual;
function _rewardSharesUser(address user) internal view virtual returns (uint256);
function _getRewardTokens() internal view virtual returns (address[] memory);
function _rewardSharesTotal() internal view virtual returns (uint256);
function getLastRewardBlock() external view returns (uint256) {
return _getRewardManagerStorage().lastRewardBlock;
}
function _calculateReward(address user, address token, uint256 accumulatedFctr) internal view returns (uint256) {
RewardManagerStorage storage $ = _getRewardManagerStorage();
uint256 index = $.rewardState[token].index;
if (index == 0) index = INITIAL_REWARD_INDEX;
uint256 totalShares = _rewardSharesTotal();
if (totalShares != 0) index += accumulatedFctr.divWadDown(totalShares);
uint256 userIndex = $.userReward[token][user].index;
uint256 rewardDelta = _rewardSharesUser(user).mulWadDown(index - userIndex);
uint256 rewardAccrued = $.userReward[token][user].accrued + rewardDelta;
return rewardAccrued;
}
}{
"evmVersion": "paris",
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {
"contracts/libraries/WrapperFactorLeverageVaultLib..sol": {
"WrapperFactorLeverageVaultLib": "0xd60ea812166ee52cd3edaebb18465f13c19875c1"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_additionalToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"BalanceNotZero","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidAssetOrDebt","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"LessThanMinAmount","type":"error"},{"inputs":[],"name":"NoPosition","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NotSetupRewardTokens","type":"error"},{"inputs":[],"name":"NotSupportReward","type":"error"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"NotWhitelisted","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"positonId","type":"uint256"},{"indexed":false,"internalType":"address","name":"vault","type":"address"}],"name":"CreatePosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"positionStrategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debt","type":"uint256"}],"name":"LeverageAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"positionStrategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtBalance","type":"uint256"}],"name":"LeverageClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"positionStrategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debt","type":"uint256"}],"name":"LeverageRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"rewardsOut","type":"uint256[]"}],"name":"RedeemRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"positionStrategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Repay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"rewardsToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"UnStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"positionStrategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"UpdateAugmentedBalance","type":"event"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"activeBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"debt","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"addLeverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"allowedAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowedDebt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOfAugmented","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"boostController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"address","name":"token","type":"address"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"closeLeverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"createPosition","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factorLeverageVaultAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAdditionalToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRewardBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"getRewardForDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"address","name":"_allowedAsset","type":"address"},{"internalType":"address","name":"_allowedDebt","type":"address"},{"internalType":"address","name":"_factorLeverageVaultAddress","type":"address"},{"internalType":"address","name":"_veFctr","type":"address"},{"internalType":"address","name":"_gaugeController","type":"address"},{"internalType":"address","name":"_boostController","type":"address"},{"internalType":"uint256","name":"_rewardDuration","type":"uint256"}],"internalType":"struct WrapperFactorLeverageVaultPT.InitParams","name":"initParams","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"lastTimeRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"},{"internalType":"uint256","name":"reward","type":"uint256"}],"name":"notifyRewardAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address[]","name":"rewardTokens","type":"address[]"}],"name":"redeemBoostReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redeemBoostRewardAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"redeemRewards","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"removeLeverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"rewardData","outputs":[{"components":[{"internalType":"uint256","name":"periodFinish","type":"uint256"},{"internalType":"uint256","name":"rewardRate","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTime","type":"uint256"},{"internalType":"uint256","name":"rewardPerTokenStored","type":"uint256"}],"internalType":"struct FactorBoostReward.Reward","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"rewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"snapshotBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"stakePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakedNFT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"supply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalActiveSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupplyAugmented","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"unstakePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"updateAugmentedBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"address","name":"upgradeImplementation","type":"address"}],"name":"upgradeStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"userRewardPerTokenPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawTokenInCaseStuck","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a06040523480156200001157600080fd5b506040516200612f3803806200612f833981016040819052620000349162000106565b6001600160a01b0381166080526200004b62000052565b5062000138565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff1615620000a35760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b0390811614620001035780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b6000602082840312156200011957600080fd5b81516001600160a01b03811681146200013157600080fd5b9392505050565b608051615fc6620001696000396000818161057301528181611efa0152818161225501526122d40152615fc66000f3fe608060405234801561001057600080fd5b506004361061030c5760003560e01c8063720692641161019d578063bf62bee6116100e9578063d3d6850c116100a2578063daecfa6c1161007c578063daecfa6c146107f0578063e985e9c514610803578063f122977714610831578063f520e7e51461084457600080fd5b8063d3d6850c146107b7578063d8ad9cf6146107ca578063d8aed145146107dd57600080fd5b8063bf62bee614610734578063c359770d14610749578063c4f59f9b1461075c578063c85700be14610771578063c87b56dd14610791578063cd729a3d146107a457600080fd5b8063a22cb46511610156578063b351a3cc11610130578063b351a3cc146106e8578063b66503cf146106fb578063b88d4fde1461070e578063bcd110141461072157600080fd5b8063a22cb465146106ba578063a769d542146106cd578063a900ae3d146106d557600080fd5b806372069264146106155780637c8988951461063c5780638bf091c91461065a5780639262187b1461066d57806395d89b411461068d5780639ab89f481461069557600080fd5b806342842e0e1161025c5780636352211e116102155780636bbe3012116101ef5780636bbe3012146105715780636c7b69cb146105975780637035ab98146105aa57806370a082311461060257600080fd5b80636352211e14610522578063638634ee14610535578063653f3cfb1461054857600080fd5b806342842e0e1461047f578063441a3e701461049257806348e5d9f8146104a557806349d305d0146104eb5780634a235eb6146104fe57806351b3b9981461051157600080fd5b80631c1265fb116102c95780632cbeceaf116102a35780632cbeceaf14610427578063313ce5671461043a5780633a8b5e4e146104595780633be762341461046c57600080fd5b80631c1265fb146103d8578063211dc32d1461040157806323b872dd1461041457600080fd5b806301ffc9a71461031157806304305f651461033957806306fdde031461034e578063081812fc146103635780630892cd8b146103a4578063095ea7b3146103c5575b600080fd5b61032461031f36600461534b565b61086b565b60405190151581526020015b60405180910390f35b61034c6103473660046153b0565b6108bd565b005b610356610b9b565b6040516103309190615434565b61038c610371366004615467565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610330565b6103b76103b23660046154a0565b610c29565b604051908152602001610330565b61034c6103d33660046154bd565b610c63565b6103b76103e63660046154a0565b6001600160a01b031660009081526006602052604090205490565b6103b761040f3660046154e9565b610d4a565b61034c610422366004615522565b610e22565b61034c610435366004615563565b610f11565b600a546104479060ff1681565b60405160ff9091168152602001610330565b61034c610467366004615676565b610fdc565b61034c61047a36600461577a565b611175565b61034c61048d366004615522565b61129d565b61034c6104a0366004615801565b611390565b6104b86104b33660046154a0565b61144b565b60405161033091908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b600d5461038c906001600160a01b031681565b61034c61050c366004615467565b6114e3565b6007546001600160f81b03166103b7565b61038c610530366004615467565b6115ff565b6103b76105433660046154a0565b611656565b61038c610556366004615467565b600b602052600090815260409020546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000061038c565b61034c6105a5366004615823565b6116b4565b6103b76105b83660046154e9565b6001600160a01b0391821660009081527f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e76020908152604080832093909416825291909152205490565b6103b76106103660046154a0565b611740565b7f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d5546103b7565b600080516020615f71833981519152546001600160a01b031661038c565b61034c610668366004615467565b6117a3565b61068061067b3660046154a0565b61192f565b6040516103309190615848565b61035661194c565b61069d611959565b604080519283526001600160a01b03909116602083015201610330565b61034c6106c836600461589a565b611a64565b61034c611ad0565b61034c6106e33660046158c8565b611c7d565b600e5461038c906001600160a01b031681565b61034c6107093660046154bd565b61249e565b61034c61071c36600461591a565b612761565b6103b761072f3660046154a0565b612842565b600080516020615f31833981519152546103b7565b61034c6107573660046158c8565b6128c2565b610764612c96565b604051610330919061596f565b6103b761077f366004615467565b600c6020526000908152604090205481565b61035661079f366004615467565b612ca5565b600f5461038c906001600160a01b031681565b61034c6107c5366004615823565b612d17565b61034c6107d8366004615467565b612dc2565b61034c6107eb366004615801565b6130f0565b61034c6107fe366004615801565b613386565b6103246108113660046154e9565b600560209081526000928352604080842090915290825290205460ff1681565b6103b761083f3660046154a0565b613405565b7f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e5546103b7565b60006301ffc9a760e01b6001600160e01b03198316148061089c57506380ac58cd60e01b6001600160e01b03198316145b806108b75750635b5e139f60e01b6001600160e01b03198316145b92915050565b6108c56134d6565b336108cf866115ff565b6001600160a01b0316146108f6576040516330cd747160e01b815260040160405180910390fd5b600d5460405163133f757160e31b8152600481018790526000916001600160a01b0316906399fbab8890602401602060405180830381865afa158015610940573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096491906159b0565b90506000600c60008881526020019081526020016000205490506109f7333088856001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e691906159b0565b6001600160a01b0316929190613520565b610a63826001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a5c91906159b0565b8388613587565b6040516346b869a160e11b81526001600160a01b03831690638d70d34290610a959089908990899089906004016159f6565b600060405180830381600087803b158015610aaf57600080fd5b505af1158015610ac3573d6000803e3d6000fd5b505050506000826001600160a01b031663bf1eb64a6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610b09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2d9190615a16565b9050610b3a338284613680565b6000888152600c602052604090819020829055517fd879d5e7d9b51cf3fa46f67670befeb3a59fcab405350ea4bcb26cc6e7268a5190610b819085908b908b908b90615a2f565b60405180910390a1505050610b946136b6565b5050505050565b60008054610ba890615a55565b80601f0160208091040260200160405190810160405280929190818152602001828054610bd490615a55565b8015610c215780601f10610bf657610100808354040283529160200191610c21565b820191906000526020600020905b815481529060010190602001808311610c0457829003601f168201915b505050505081565b6001600160a01b031660009081527f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d6602052604090205490565b6000818152600260205260409020546001600160a01b031633811480610cac57506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b610cee5760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064015b60405180910390fd5b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b6001600160a01b0382811660008181527f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e860209081526040808320948616808452948252808320549383527f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e7825280832094835293905291822054600080516020615f718339815191529190670de0b6b3a764000090610de986613405565b610df39190615aa5565b610dfc876136dc565b610e069190615ab8565b610e109190615acf565b610e1a9190615af1565b949350505050565b610e2d8383836136fa565b600d5460405163133f757160e31b8152600481018390526000916001600160a01b0316906399fbab8890602401602060405180830381865afa158015610e77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9b91906159b0565b9050610f0b8484836001600160a01b031663bf1eb64a6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610ee2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f069190615a16565b6138c1565b50505050565b610f196134d6565b33610f23846115ff565b6001600160a01b031614610f4a576040516330cd747160e01b815260040160405180910390fd5b600d54604051630aeba61160e31b81526001600160a01b0391821660048201526024810185905290831660448201526064810182905273d60ea812166ee52cd3edaebb18465f13c19875c19063575d30889060840160006040518083038186803b158015610fb757600080fd5b505af4158015610fcb573d6000803e3d6000fd5b50505050610fd76136b6565b505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03166000811580156110215750825b90506000826001600160401b0316600114801561103d5750303b155b90508115801561104b575080155b156110695760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561109357845460ff60401b1916600160401b1785555b6110a586600001518760200151613ab3565b6110b786600001518760200151613ae6565b6110c98660a001518760c00151613b07565b6110dc8660e00151876101000151613c0b565b6040860151600e80546001600160a01b039283166001600160a01b0319918216179091556060880151600f80549184169183169190911790556080880151600d8054919093169116179055831561116d57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b61117d6134d6565b61118683613c6c565b600080516020615f7183398151915260005b828110156112935760008484838181106111b4576111b4615b04565b90506020020160208101906111c991906154a0565b6001600160a01b038088166000908152600486016020908152604080832093851683529290522054909150801561127e576001600160a01b038088166000908152600486016020908152604080832093861680845293909152812055611230908883613de7565b816001600160a01b0316876001600160a01b03167f540798df468d7b23d11f156fdb954cb19ad414d150722a7b6d55ba369dea792e8360405161127591815260200190565b60405180910390a35b5050808061128b90615b1a565b915050611198565b5050610fd76136b6565b6112a8838383610e22565b6001600160a01b0382163b15806113515750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af1158015611321573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113459190615b33565b6001600160e01b031916145b610fd75760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610ce5565b6113986134d6565b336113a2836115ff565b6001600160a01b0316146113c9576040516330cd747160e01b815260040160405180910390fd5b600d54604051635ae2fb3960e11b815273d60ea812166ee52cd3edaebb18465f13c19875c19163b5c5f6729161140f916001600160a01b03169086908690600401615b50565b60006040518083038186803b15801561142757600080fd5b505af415801561143b573d6000803e3d6000fd5b505050506114476136b6565b5050565b6114766040518060800160405280600081526020016000815260200160008152602001600081525090565b506001600160a01b031660009081527f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e66020908152604091829020825160808101845281548152600182015492810192909252600281015492820192909252600390910154606082015290565b6114eb6134d6565b336114f5826115ff565b6001600160a01b03161461151c576040516330cd747160e01b815260040160405180910390fd5b61152581613e18565b6000818152600c602052604090205461153f903390613ee5565b6000818152600c602052604080822091909155600d5490516323b872dd60e01b8152306004820152336024820152604481018390526001600160a01b03909116906323b872dd90606401600060405180830381600087803b1580156115a357600080fd5b505af11580156115b7573d6000803e3d6000fd5b505050507f603af6cb36e852311201ebb828cda2d49c5dc06d9d14a04ecd5e4211308625aa816040516115ec91815260200190565b60405180910390a16115fc6136b6565b50565b6000818152600260205260409020546001600160a01b0316806116515760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610ce5565b919050565b6001600160a01b03811660009081527f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e66020526040812054600080516020615f71833981519152904281116116ab5780610e1a565b42949350505050565b6116bc6134d6565b336116c6836115ff565b6001600160a01b0316146116ed576040516330cd747160e01b815260040160405180910390fd5b600d54604051632300b28360e11b81526001600160a01b03918216600482015260248101849052908216604482015273d60ea812166ee52cd3edaebb18465f13c19875c19063460165069060640161140f565b60006001600160a01b0382166117875760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401610ce5565b506001600160a01b031660009081526003602052604090205490565b6117ab6134d6565b600d5460405163133f757160e31b8152600481018390526000916001600160a01b0316906399fbab8890602401602060405180830381865afa1580156117f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061181991906159b0565b6000838152600c60209081526040808320548151635f8f5b2560e11b81529151949550936001600160a01b0386169263bf1eb64a9260048082019391829003018187875af115801561186f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118939190615a16565b905060006118a0856115ff565b90506001600160a01b0381166118c957604051632afc3c0d60e21b815260040160405180910390fd5b6118d4818385613680565b6000858152600c602052604090819020839055517fe7b71ff10e471529b8ab2bfc3c309129e2e31552017f7073ff90b318fa5f3baa9061191b908690889087908790615a2f565b60405180910390a1505050506115fc6136b6565b60606119396134d6565b61194282614036565b90506116516136b6565b60018054610ba890615a55565b6000806119646134d6565b600d54600e54600f54604051636969e58b60e01b81526001600160a01b039283166004820152908216602482015260009283921690636969e58b9060440160408051808303816000875af11580156119c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e49190615b71565b90925090506119fd336119f8600185615aa5565b61409c565b7f665e422c8352bce9bc2d0eaadb34a203cf7fbe89ffc7bd71d7c7e59510bb2700611a29600184615aa5565b604080519182526001600160a01b03841660208301520160405180910390a1611a53600183615aa5565b9350915050611a606136b6565b9091565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b611ad86134d6565b33611ae281613c6c565b6000600080516020615f718339815191528054604051632b71961d60e11b81523060048201529192506000916001600160a01b03909116906356e32c3a90602401600060405180830381865afa158015611b40573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611b689190810190615b96565b90508051600003611b8c57604051630dad652960e41b815260040160405180910390fd5b60005b8151811015611c6f576000828281518110611bac57611bac615b04565b60209081029190910181015133600090815260048701835260408082206001600160a01b038416835290935291909120549091508015611c5a5733600081815260048701602090815260408083206001600160a01b0387168085529252822091909155611c199183613de7565b6040518181526001600160a01b0383169033907f540798df468d7b23d11f156fdb954cb19ad414d150722a7b6d55ba369dea792e9060200160405180910390a35b50508080611c6790615b1a565b915050611b8f565b50505050611c7b6136b6565b565b611c856134d6565b33611c8f856115ff565b6001600160a01b031614611cb6576040516330cd747160e01b815260040160405180910390fd5b600d5460405163133f757160e31b8152600481018690526000916001600160a01b0316906399fbab8890602401602060405180830381865afa158015611d00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d2491906159b0565b6000868152600c602090815260408083205481516338d52e0f60e01b81529151949550936001600160a01b038616926338d52e0f92600480820193918290030181865afa158015611d79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d9d91906159b0565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015611de3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e079190615a16565b90506000836001600160a01b031663f8d898986040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6d91906159b0565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015611eb3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ed79190615a16565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611f41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f659190615a16565b60405163841f477960e01b81529091506001600160a01b0386169063841f477990611f98908b908b908b90600401615c47565b600060405180830381600087803b158015611fb257600080fd5b505af1158015611fc6573d6000803e3d6000fd5b505050506121173384876001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561200d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203191906159b0565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015612077573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209b9190615a16565b6120a59190615aa5565b876001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210791906159b0565b6001600160a01b03169190613de7565b6122303383876001600160a01b031663f8d898986040518163ffffffff1660e01b8152600401602060405180830381865afa15801561215a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217e91906159b0565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156121c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e89190615a16565b6121f29190615aa5565b876001600160a01b031663f8d898986040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120e3573d6000803e3d6000fd5b6040516370a0823160e01b81523060048201526122fb90339083906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561229c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c09190615a16565b6122ca9190615aa5565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169190613de7565b6000856001600160a01b031663bf1eb64a6040518163ffffffff1660e01b81526004016020604051808303816000875af115801561233d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123619190615a16565b905061236e338287613680565b6000866001600160a01b031663c66f24556040518163ffffffff1660e01b81526004016020604051808303816000875af11580156123b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123d49190615a16565b90506000876001600160a01b031663bf1eb64a6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612418573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243c9190615a16565b60008d8152600c602052604090819020859055519091507f0e62bdb265148e28f778225a0d4dcfa76a6621dcf77db5e1edbc5aac5e5cafaf90612486908a908f9086908690615a2f565b60405180910390a15050505050505050610f0b6136b6565b60006124a981613c6c565b6000600080516020615f71833981519152805460405163bc120fe760e01b81523060048201526001600160a01b03878116602483015292935091169063bc120fe790604401602060405180830381865afa15801561250b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061252f9190615c6a565b61255757604051636f8bf18b60e11b81526001600160a01b0385166004820152602401610ce5565b8054604051634d0a32db60e01b81526001600160a01b03868116600483015285921690634d0a32db90602401602060405180830381865afa1580156125a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c49190615a16565b11156125e357604051630708444160e31b815260040160405180910390fd5b6125f86001600160a01b038516333086613520565b6001600160a01b0384166000908152600282016020526040902054421061264b5760018101546126289084615acf565b6001600160a01b03851660009081526002830160205260409020600101556126da565b6001600160a01b0384166000908152600282016020526040812054612671904290615aa5565b6001600160a01b03861660009081526002840160205260408120600101549192509061269d9083615ab8565b60018401549091506126af8287615af1565b6126b99190615acf565b6001600160a01b038716600090815260028501602052604090206001015550505b6001600160a01b038416600090815260028083016020526040909120429101819055600182015461270a91615af1565b6001600160a01b038516600090815260028301602090815260409182902092909255518481527fde88a922e0d3b88b24e9623efeb464919c6bf9f66857a65e2bfcf2ce87a9433d910160405180910390a150505050565b61276c858585610e22565b6001600160a01b0384163b15806128035750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a02906127b49033908a90899089908990600401615c87565b6020604051808303816000875af11580156127d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127f79190615b33565b6001600160e01b031916145b610b945760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610ce5565b7f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e5546001600160a01b03821660009081527f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e660205260408120600101549091600080516020615f71833981519152916128bb9190615ab8565b9392505050565b6128ca6134d6565b336128d4856115ff565b6001600160a01b0316146128fb576040516330cd747160e01b815260040160405180910390fd5b600d5460405163133f757160e31b8152600481018690526000916001600160a01b0316906399fbab8890602401602060405180830381865afa158015612945573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296991906159b0565b6000868152600c602090815260408083205481516338d52e0f60e01b81529151949550936001600160a01b038616926338d52e0f92600480820193918290030181865afa1580156129be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e291906159b0565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015612a28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a4c9190615a16565b6040516359783fcb60e11b81529091506001600160a01b0384169063b2f07f9690612a7f90899089908990600401615c47565b600060405180830381600087803b158015612a9957600080fd5b505af1158015612aad573d6000803e3d6000fd5b50505050612bca3382856001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612af4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b1891906159b0565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015612b5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b829190615a16565b612b8c9190615aa5565b856001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120e3573d6000803e3d6000fd5b6000836001600160a01b031663bf1eb64a6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612c0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c309190615a16565b9050612c3d338285613680565b6000888152600c602052604090819020829055517fae20c8842eb2c74e1d7d2e3a7548de6ed7c7278e9f603403911aa0174175747190612c829086908b908b90615b50565b60405180910390a150505050610f0b6136b6565b6060612ca06141a7565b905090565b600d5460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd90602401600060405180830381865afa158015612cef573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108b79190810190615cbb565b33612d21836115ff565b6001600160a01b031614612d48576040516330cd747160e01b815260040160405180910390fd5b600d54604051634948b2d960e11b81526001600160a01b03918216600482015260248101849052908216604482015273d60ea812166ee52cd3edaebb18465f13c19875c19063929165b29060640160006040518083038186803b158015612dae57600080fd5b505af415801561116d573d6000803e3d6000fd5b612dca6134d6565b600d5460405163133f757160e31b8152600481018390526000916001600160a01b0316906399fbab8890602401602060405180830381865afa158015612e14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3891906159b0565b90506000816001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9e91906159b0565b90506000826001600160a01b031663f8d898986040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ee0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f0491906159b0565b600e549091506001600160a01b038381169116141580612f325750600f546001600160a01b03828116911614155b15612f4f5760405162774c6560e91b815260040160405180910390fd5b826001600160a01b031663c66f24556040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612f8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fb39190615a16565b1580156130215750826001600160a01b031663bf1eb64a6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612ffb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061301f9190615a16565b155b61303e5760405163493e98f360e11b815260040160405180910390fd5b600d546040516323b872dd60e01b8152336004820152306024820152604481018690526001600160a01b03909116906323b872dd90606401600060405180830381600087803b15801561309057600080fd5b505af11580156130a4573d6000803e3d6000fd5b505050506130b2338561409c565b6040518481527f227a473b70d2f893cc7659219575c030a63b5743024fe1e0c1a680e708b1525a9060200160405180910390a15050506115fc6136b6565b6130f86134d6565b33613102836115ff565b6001600160a01b031614613129576040516330cd747160e01b815260040160405180910390fd5b600d5460405163133f757160e31b8152600481018490526000916001600160a01b0316906399fbab8890602401602060405180830381865afa158015613173573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061319791906159b0565b90506000600c60008581526020019081526020016000205490506131f5333085856001600160a01b031663f8d898986040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109c2573d6000803e3d6000fd5b613261826001600160a01b031663f8d898986040518163ffffffff1660e01b8152600401602060405180830381865afa158015613236573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061325a91906159b0565b8385613587565b604051631b8fec7360e11b8152600481018490526001600160a01b0383169063371fd8e690602401600060405180830381600087803b1580156132a357600080fd5b505af11580156132b7573d6000803e3d6000fd5b505050506000826001600160a01b031663bf1eb64a6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156132fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133219190615a16565b905061332e338284613680565b6000858152600c602052604090819020829055517f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d09061337390859088908890615b50565b60405180910390a15050506114476136b6565b61338e6134d6565b33613398836115ff565b6001600160a01b0316146133bf576040516330cd747160e01b815260040160405180910390fd5b600d54604051637dbca35360e01b815273d60ea812166ee52cd3edaebb18465f13c19875c191637dbca3539161140f916001600160a01b03169086908690600401615b50565b6000600080516020615f718339815191528161341f6141e4565b90508060000361344e57506001600160a01b039092166000908152600290920160205250604090206003015490565b6001600160a01b038416600090815260028084016020526040909120600181015491015482919061347e87611656565b6134889190615aa5565b6134929190615ab8565b6134a490670de0b6b3a7640000615ab8565b6134ae9190615acf565b6001600160a01b0385166000908152600284016020526040902060030154610e1a9190615af1565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0080546001190161351a57604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b6040516001600160a01b038481166024830152838116604483015260648201839052610f0b9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506141f8565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b17905291516000928392908716916135e39190615d28565b6000604051808303816000865af19150503d8060008114613620576040519150601f19603f3d011682016040523d82523d6000602084013e613625565b606091505b509150915081801561364f57508051158061364f57508080602001905181019061364f9190615c6a565b610b945760405162461bcd60e51b8152602060048201526002602482015261534160f01b6044820152606401610ce5565b8082111561369b5761369b836136968385615aa5565b61425b565b81811115610fd757610fd7836136b18484615aa5565b613ee5565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6001600160a01b0381166000908152600660205260408120546108b7565b6000818152600260205260409020546001600160a01b038481169116146137505760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b6044820152606401610ce5565b6001600160a01b03821661379a5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610ce5565b336001600160a01b03841614806137d457506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b806137f557506000818152600460205260409020546001600160a01b031633145b6138325760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610ce5565b6001600160a01b0380841660008181526003602090815260408083208054600019019055938616808352848320805460010190558583526002825284832080546001600160a01b03199081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6001600160a01b0383166139255760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610ce5565b6001600160a01b0382166139875760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610ce5565b816001600160a01b0316836001600160a01b0316036139e85760405162461bcd60e51b815260206004820152601760248201527f45524332303a207472616e7366657220746f2073656c660000000000000000006044820152606401610ce5565b6139f383838361434c565b6001600160a01b03831660009081526006602052604090205481811015613a6b5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610ce5565b6001600160a01b03808516600090815260066020526040808220858503905591851681529081208054849290613aa2908490615af1565b90915550610f0b9050848484614362565b613abb61436d565b6008613ac78382615d8a565b506009613ad48282615d8a565b5050600a805460ff1916601217905550565b613aee61436d565b6000613afa8382615d8a565b506001610fd78282615d8a565b613b0f61436d565b7f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d380546001600160a01b038481166001600160a01b0319928316179092557f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d480549284169290911682179055604080516344bc194960e11b81529051600080516020615f518339815191529291638978329291600480830192602092919082900301816000875af1158015613bc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bec91906159b0565b81546001600160a01b0319166001600160a01b03919091161790555050565b613c1361436d565b613c1b6143b6565b7f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e555600080516020615f7183398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6000600080516020615f718339815191528054604051632b71961d60e11b81523060048201529192506000916001600160a01b03909116906356e32c3a90602401600060405180830381865afa158015613cca573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613cf29190810190615b96565b905060005b8151811015610f0b576000828281518110613d1457613d14615b04565b60200260200101519050613d2781613405565b6001600160a01b0382166000908152600286016020526040902060030155613d4e81611656565b6001600160a01b038083166000908152600280880160205260409091200191909155851615613dd457613d818582610d4a565b6001600160a01b0380871660008181526004880160209081526040808320948716808452948252808320959095556002890181528482206003908101549383528901815284822093825292909252919020555b5080613ddf81615b1a565b915050613cf7565b6040516001600160a01b03838116602483015260448201839052610fd791859182169063a9059cbb90606401613555565b6000818152600260205260409020546001600160a01b031680613e6a5760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610ce5565b6001600160a01b038116600081815260036020908152604080832080546000190190558583526002825280832080546001600160a01b031990811690915560049092528083208054909216909155518492907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6001600160a01b038216613f455760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610ce5565b613f518260008361434c565b6001600160a01b03821660009081526006602052604090205481811015613fc55760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610ce5565b6001600160a01b03831660009081526006602052604090208282039055613feb826143c6565b600780546000906140069084906001600160f81b0316615e49565b92506101000a8154816001600160f81b0302191690836001600160f81b03160217905550610fd783600084614362565b6060614041826143e0565b61404a826143eb565b61405482836143f6565b9050816001600160a01b03167f78d61a0c27b13f43911095f9f356f14daa3cd8b125eea1aa22421245e90e813d8260405161408f9190615848565b60405180910390a2919050565b6001600160a01b0382166140e65760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610ce5565b6000818152600260205260409020546001600160a01b03161561413c5760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b6044820152606401610ce5565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60408051600080825260208201909252606091506141de600080516020615f518339815191525482906001600160a01b03166146c7565b91505090565b6000612ca06007546001600160f81b031690565b600061420d6001600160a01b038416836147ac565b905080516000141580156142325750808060200190518101906142309190615c6a565b155b15610fd757604051635274afe760e01b81526001600160a01b0384166004820152602401610ce5565b6001600160a01b0382166142b15760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610ce5565b6142bd6000838361434c565b6142c6816143c6565b600780546000906142e19084906001600160f81b0316615e70565b92506101000a8154816001600160f81b0302191690836001600160f81b031602179055508060066000846001600160a01b03166001600160a01b03168152602001908152602001600020600082825461433a9190615af1565b90915550611447905060008383614362565b6143578383836147ba565b610fd78383836147c4565b610fd7838383614814565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16611c7b57604051631afcd79f60e31b815260040160405180910390fd5b6143be61436d565b611c7b61481e565b60006001600160f81b038211156143dc57600080fd5b5090565b6115fc816000614826565b6115fc8160006148a6565b606060006144026141a7565b905080516001600160401b0381111561441d5761441d61558a565b604051908082528060200260200182016040528015614446578160200160208202803683370190505b509150600080516020615f3183398151915260005b82518110156146be5781600101600084838151811061447c5761447c615b04565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000876001600160a01b03166001600160a01b0316815260200190815260200160002060000160109054906101000a90046001600160801b03166001600160801b03168482815181106144f9576144f9615b04565b60200260200101818152505083818151811061451757614517615b04565b60200260200101516000146146ac57600082600101600085848151811061454057614540615b04565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000886001600160a01b03166001600160a01b0316815260200190815260200160002060000160106101000a8154816001600160801b0302191690836001600160801b031602179055506145d48482815181106145c7576145c7615b04565b6020026020010151614904565b8260020160008584815181106145ec576145ec615b04565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060000160108282829054906101000a90046001600160801b03166146389190615e90565b92506101000a8154816001600160801b0302191690836001600160801b031602179055506146ac8585838151811061467257614672615b04565b602002602001015185848151811061468c5761468c615b04565b60200260200101516001600160a01b0316613de79092919063ffffffff16565b806146b681615b1a565b91505061445b565b50505092915050565b81516060906146d7816001615af1565b6001600160401b038111156146ee576146ee61558a565b604051908082528060200260200182016040528015614717578160200160208202803683370190505b50915060005b818110156147715784818151811061473757614737615b04565b602002602001015183828151811061475157614751615b04565b6001600160a01b039092166020928302919091019091015260010161471d565b508282828151811061478557614785615b04565b60200260200101906001600160a01b031690816001600160a01b0316815250505092915050565b60606128bb83836000614938565b610fd78383614826565b6001600160a01b038316156147dc576147dc83613c6c565b6001600160a01b038216158015906148065750826001600160a01b0316826001600160a01b031614155b15610fd757610fd782613c6c565b610fd783836148a6565b6136b661436d565b6000806148316149d5565b9150915081516000036148445750505050565b6001600160a01b0384161580159061486557506001600160a01b0384163014155b1561487557614875848383614d0b565b6001600160a01b0383161580159061489657506001600160a01b0383163014155b15610f0b57610f0b838383614d0b565b6001600160a01b038216158015906148c757506001600160a01b0382163014155b156148d5576148d582614fcb565b6001600160a01b038116158015906148f657506001600160a01b0381163014155b156114475761144781614fcb565b60006001600160801b038211156143dc576040516306dfcc6560e41b81526080600482015260248101839052604401610ce5565b60608147101561495d5760405163cd78605960e01b8152306004820152602401610ce5565b600080856001600160a01b031684866040516149799190615d28565b60006040518083038185875af1925050503d80600081146149b6576040519150601f19603f3d011682016040523d82523d6000602084013e6149bb565b606091505b50915091506149cb8683836150cb565b9695505050505050565b6060806149e06141a7565b915081516001600160401b038111156149fb576149fb61558a565b604051908082528060200260200182016040528015614a24578160200160208202803683370190505b5090508151600003614a34579091565b600080516020615f3183398151915280544314614c80574381556000614a787f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d55490565b9050614a82615127565b60005b8451811015614c7d576000858281518110614aa257614aa2615b04565b6020908102919091018101516001600160a01b03811660009081526002870190925260408220548851919350600160801b90046001600160801b031690889085908110614af157614af1615b04565b60209081029190910101516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015614b41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b659190615a16565b614b6f9190615aa5565b6001600160a01b03831660009081526002870160205260408120549192506001600160801b0390911690819003614ba4575060015b8415614bc157614bb482866151a0565b614bbe9082615af1565b90505b614bca81614904565b6001600160a01b0384166000908152600288016020526040902080546001600160801b0319166001600160801b0392909216919091179055614c0b82614904565b6001600160a01b038416600090815260028801602052604090208054601090614c45908490600160801b90046001600160801b0316615eb0565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555050505080614c7690615b1a565b9050614a85565b50505b60005b8351811015614d0557816002016000858381518110614ca457614ca4615b04565b6020908102919091018101516001600160a01b031682528101919091526040016000205483516001600160801b0390911690849083908110614ce857614ce8615b04565b602090810291909101015280614cfd81615b1a565b915050614c83565b50509091565b6001600160a01b03831615801590614d2c57506001600160a01b0383163014155b614d3857614d38615ed0565b600080516020615f318339815191526000614d5285610c29565b905060005b845181101561116d576000858281518110614d7457614d74615b04565b602002602001015190506000858381518110614d9257614d92615b04565b6020908102919091018101516001600160a01b0380851660009081526001890184526040808220928d168252919093528220549092506001600160801b031690819003614e3257614de282614904565b6001600160a01b0393841660009081526001880160209081526040808320968d1683529590529390932080546001600160801b0319166001600160801b039094169390931790925550614fbb9050565b818103614e4157505050614fbb565b6000614e4d8284615aa5565b90506000614e5b87836151b5565b9050600081896001016000886001600160a01b03166001600160a01b0316815260200190815260200160002060008e6001600160a01b03166001600160a01b0316815260200190815260200160002060000160109054906101000a90046001600160801b03166001600160801b0316614ed49190615af1565b90506040518060400160405280614eea87614904565b6001600160801b03168152602001614f0183614904565b6001600160801b0316815250896001016000886001600160a01b03166001600160a01b0316815260200190815260200160002060008e6001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a8154816001600160801b0302191690836001600160801b0316021790555060208201518160000160106101000a8154816001600160801b0302191690836001600160801b031602179055509050505050505050505b614fc481615b1a565b9050614d57565b6001600160a01b03811615801590614fec57506001600160a01b0381163014155b614ff857614ff8615ed0565b6000615003826136dc565b9050600061501183836151ca565b9050600061501f82846152d8565b6001600160a01b03851660009081527f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d660205260409020547f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d554919250600080516020615f5183398151915291839161509791615aa5565b6150a19190615af1565b60038201556001600160a01b03909416600090815260049094016020526040909320929092555050565b6060826150e0576150db826152ee565b6128bb565b81511580156150f757506001600160a01b0384163b155b1561512057604051639996b31560e01b81526001600160a01b0385166004820152602401610ce5565b50806128bb565b7f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d45460408051638113382760e01b815290516001600160a01b039092169163811338279160048082019260009290919082900301818387803b15801561518c57600080fd5b505af1158015610f0b573d6000803e3d6000fd5b60006128bb83670de0b6b3a764000084615317565b60006128bb8383670de0b6b3a7640000615317565b600080600080516020615f51833981519152600181015460405163389a2ce960e21b81526001600160a01b0387811660048301529293506000928392169063e268b3a49060240160408051808303816000875af115801561522f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906152539190615efd565b6001600160801b03918216935016905060006064615272602888615ab8565b61527c9190615acf565b905082156149cb576064615291602882615aa5565b848461529b6141e4565b6152a59190615ab8565b6152af9190615acf565b6152b99190615ab8565b6152c39190615acf565b6152cd9082615af1565b979650505050505050565b60008183106152e757816128bb565b5090919050565b8051156152fe5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b600082600019048411830215820261532e57600080fd5b5091020490565b6001600160e01b0319811681146115fc57600080fd5b60006020828403121561535d57600080fd5b81356128bb81615335565b60008083601f84011261537a57600080fd5b5081356001600160401b0381111561539157600080fd5b6020830191508360208285010111156153a957600080fd5b9250929050565b6000806000806000608086880312156153c857600080fd5b85359450602086013593506040860135925060608601356001600160401b038111156153f357600080fd5b6153ff88828901615368565b969995985093965092949392505050565b60005b8381101561542b578181015183820152602001615413565b50506000910152565b6020815260008251806020840152615453816040850160208701615410565b601f01601f19169190910160400192915050565b60006020828403121561547957600080fd5b5035919050565b6001600160a01b03811681146115fc57600080fd5b803561165181615480565b6000602082840312156154b257600080fd5b81356128bb81615480565b600080604083850312156154d057600080fd5b82356154db81615480565b946020939093013593505050565b600080604083850312156154fc57600080fd5b823561550781615480565b9150602083013561551781615480565b809150509250929050565b60008060006060848603121561553757600080fd5b833561554281615480565b9250602084013561555281615480565b929592945050506040919091013590565b60008060006060848603121561557857600080fd5b83359250602084013561555281615480565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b03811182821017156155c3576155c361558a565b60405290565b604051601f8201601f191681016001600160401b03811182821017156155f1576155f161558a565b604052919050565b60006001600160401b038211156156125761561261558a565b50601f01601f191660200190565b600082601f83011261563157600080fd5b813561564461563f826155f9565b6155c9565b81815284602083860101111561565957600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561568857600080fd5b81356001600160401b038082111561569f57600080fd5b9083019061012082860312156156b457600080fd5b6156bc6155a0565b8235828111156156cb57600080fd5b6156d787828601615620565b8252506020830135828111156156ec57600080fd5b6156f887828601615620565b60208301525061570a60408401615495565b604082015261571b60608401615495565b606082015261572c60808401615495565b608082015261573d60a08401615495565b60a082015261574e60c08401615495565b60c082015261575f60e08401615495565b60e08201526101009283013592810192909252509392505050565b60008060006040848603121561578f57600080fd5b833561579a81615480565b925060208401356001600160401b03808211156157b657600080fd5b818601915086601f8301126157ca57600080fd5b8135818111156157d957600080fd5b8760208260051b85010111156157ee57600080fd5b6020830194508093505050509250925092565b6000806040838503121561581457600080fd5b50508035926020909101359150565b6000806040838503121561583657600080fd5b82359150602083013561551781615480565b6020808252825182820181905260009190848201906040850190845b8181101561588057835183529284019291840191600101615864565b50909695505050505050565b80151581146115fc57600080fd5b600080604083850312156158ad57600080fd5b82356158b881615480565b915060208301356155178161588c565b600080600080606085870312156158de57600080fd5b843593506020850135925060408501356001600160401b0381111561590257600080fd5b61590e87828801615368565b95989497509550505050565b60008060008060006080868803121561593257600080fd5b853561593d81615480565b9450602086013561594d81615480565b93506040860135925060608601356001600160401b038111156153f357600080fd5b6020808252825182820181905260009190848201906040850190845b818110156158805783516001600160a01b03168352928401929184019160010161598b565b6000602082840312156159c257600080fd5b81516128bb81615480565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8481528360208201526060604082015260006149cb6060830184866159cd565b600060208284031215615a2857600080fd5b5051919050565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b600181811c90821680615a6957607f821691505b602082108103615a8957634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b818103818111156108b7576108b7615a8f565b80820281158282048414176108b7576108b7615a8f565b600082615aec57634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156108b7576108b7615a8f565b634e487b7160e01b600052603260045260246000fd5b600060018201615b2c57615b2c615a8f565b5060010190565b600060208284031215615b4557600080fd5b81516128bb81615335565b6001600160a01b039390931683526020830191909152604082015260600190565b60008060408385031215615b8457600080fd5b82519150602083015161551781615480565b60006020808385031215615ba957600080fd5b82516001600160401b0380821115615bc057600080fd5b818501915085601f830112615bd457600080fd5b815181811115615be657615be661558a565b8060051b9150615bf78483016155c9565b8181529183018401918481019088841115615c1157600080fd5b938501935b83851015615c3b5784519250615c2b83615480565b8282529385019390850190615c16565b98975050505050505050565b838152604060208201526000615c616040830184866159cd565b95945050505050565b600060208284031215615c7c57600080fd5b81516128bb8161588c565b6001600160a01b03868116825285166020820152604081018490526080606082018190526000906152cd90830184866159cd565b600060208284031215615ccd57600080fd5b81516001600160401b03811115615ce357600080fd5b8201601f81018413615cf457600080fd5b8051615d0261563f826155f9565b818152856020838501011115615d1757600080fd5b615c61826020830160208601615410565b60008251615d3a818460208701615410565b9190910192915050565b601f821115610fd757600081815260208120601f850160051c81016020861015615d6b5750805b601f850160051c820191505b8181101561116d57828155600101615d77565b81516001600160401b03811115615da357615da361558a565b615db781615db18454615a55565b84615d44565b602080601f831160018114615dec5760008415615dd45750858301515b600019600386901b1c1916600185901b17855561116d565b600085815260208120601f198616915b82811015615e1b57888601518255948401946001909101908401615dfc565b5085821015615e395787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160f81b03828116828216039080821115615e6957615e69615a8f565b5092915050565b6001600160f81b03818116838216019080821115615e6957615e69615a8f565b6001600160801b03828116828216039080821115615e6957615e69615a8f565b6001600160801b03818116838216019080821115615e6957615e69615a8f565b634e487b7160e01b600052600160045260246000fd5b80516001600160801b038116811461165157600080fd5b60008060408385031215615f1057600080fd5b615f1983615ee6565b9150615f2760208401615ee6565b9050925092905056fe42eb16b0bf2565d9a663d4e7253d588f054024f7228c103568322f697f63b61324bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d2911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e4a2646970667358221220303971b95cce04e4a40c3baa51d99a562399f6385acab4a8dd3e7bbf55ac68a464736f6c6343000814003300000000000000000000000035751007a407ca6feffe80b3cb397736d2cf4dbe
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061030c5760003560e01c8063720692641161019d578063bf62bee6116100e9578063d3d6850c116100a2578063daecfa6c1161007c578063daecfa6c146107f0578063e985e9c514610803578063f122977714610831578063f520e7e51461084457600080fd5b8063d3d6850c146107b7578063d8ad9cf6146107ca578063d8aed145146107dd57600080fd5b8063bf62bee614610734578063c359770d14610749578063c4f59f9b1461075c578063c85700be14610771578063c87b56dd14610791578063cd729a3d146107a457600080fd5b8063a22cb46511610156578063b351a3cc11610130578063b351a3cc146106e8578063b66503cf146106fb578063b88d4fde1461070e578063bcd110141461072157600080fd5b8063a22cb465146106ba578063a769d542146106cd578063a900ae3d146106d557600080fd5b806372069264146106155780637c8988951461063c5780638bf091c91461065a5780639262187b1461066d57806395d89b411461068d5780639ab89f481461069557600080fd5b806342842e0e1161025c5780636352211e116102155780636bbe3012116101ef5780636bbe3012146105715780636c7b69cb146105975780637035ab98146105aa57806370a082311461060257600080fd5b80636352211e14610522578063638634ee14610535578063653f3cfb1461054857600080fd5b806342842e0e1461047f578063441a3e701461049257806348e5d9f8146104a557806349d305d0146104eb5780634a235eb6146104fe57806351b3b9981461051157600080fd5b80631c1265fb116102c95780632cbeceaf116102a35780632cbeceaf14610427578063313ce5671461043a5780633a8b5e4e146104595780633be762341461046c57600080fd5b80631c1265fb146103d8578063211dc32d1461040157806323b872dd1461041457600080fd5b806301ffc9a71461031157806304305f651461033957806306fdde031461034e578063081812fc146103635780630892cd8b146103a4578063095ea7b3146103c5575b600080fd5b61032461031f36600461534b565b61086b565b60405190151581526020015b60405180910390f35b61034c6103473660046153b0565b6108bd565b005b610356610b9b565b6040516103309190615434565b61038c610371366004615467565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610330565b6103b76103b23660046154a0565b610c29565b604051908152602001610330565b61034c6103d33660046154bd565b610c63565b6103b76103e63660046154a0565b6001600160a01b031660009081526006602052604090205490565b6103b761040f3660046154e9565b610d4a565b61034c610422366004615522565b610e22565b61034c610435366004615563565b610f11565b600a546104479060ff1681565b60405160ff9091168152602001610330565b61034c610467366004615676565b610fdc565b61034c61047a36600461577a565b611175565b61034c61048d366004615522565b61129d565b61034c6104a0366004615801565b611390565b6104b86104b33660046154a0565b61144b565b60405161033091908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b600d5461038c906001600160a01b031681565b61034c61050c366004615467565b6114e3565b6007546001600160f81b03166103b7565b61038c610530366004615467565b6115ff565b6103b76105433660046154a0565b611656565b61038c610556366004615467565b600b602052600090815260409020546001600160a01b031681565b7f00000000000000000000000035751007a407ca6feffe80b3cb397736d2cf4dbe61038c565b61034c6105a5366004615823565b6116b4565b6103b76105b83660046154e9565b6001600160a01b0391821660009081527f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e76020908152604080832093909416825291909152205490565b6103b76106103660046154a0565b611740565b7f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d5546103b7565b600080516020615f71833981519152546001600160a01b031661038c565b61034c610668366004615467565b6117a3565b61068061067b3660046154a0565b61192f565b6040516103309190615848565b61035661194c565b61069d611959565b604080519283526001600160a01b03909116602083015201610330565b61034c6106c836600461589a565b611a64565b61034c611ad0565b61034c6106e33660046158c8565b611c7d565b600e5461038c906001600160a01b031681565b61034c6107093660046154bd565b61249e565b61034c61071c36600461591a565b612761565b6103b761072f3660046154a0565b612842565b600080516020615f31833981519152546103b7565b61034c6107573660046158c8565b6128c2565b610764612c96565b604051610330919061596f565b6103b761077f366004615467565b600c6020526000908152604090205481565b61035661079f366004615467565b612ca5565b600f5461038c906001600160a01b031681565b61034c6107c5366004615823565b612d17565b61034c6107d8366004615467565b612dc2565b61034c6107eb366004615801565b6130f0565b61034c6107fe366004615801565b613386565b6103246108113660046154e9565b600560209081526000928352604080842090915290825290205460ff1681565b6103b761083f3660046154a0565b613405565b7f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e5546103b7565b60006301ffc9a760e01b6001600160e01b03198316148061089c57506380ac58cd60e01b6001600160e01b03198316145b806108b75750635b5e139f60e01b6001600160e01b03198316145b92915050565b6108c56134d6565b336108cf866115ff565b6001600160a01b0316146108f6576040516330cd747160e01b815260040160405180910390fd5b600d5460405163133f757160e31b8152600481018790526000916001600160a01b0316906399fbab8890602401602060405180830381865afa158015610940573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096491906159b0565b90506000600c60008881526020019081526020016000205490506109f7333088856001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e691906159b0565b6001600160a01b0316929190613520565b610a63826001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a5c91906159b0565b8388613587565b6040516346b869a160e11b81526001600160a01b03831690638d70d34290610a959089908990899089906004016159f6565b600060405180830381600087803b158015610aaf57600080fd5b505af1158015610ac3573d6000803e3d6000fd5b505050506000826001600160a01b031663bf1eb64a6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610b09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2d9190615a16565b9050610b3a338284613680565b6000888152600c602052604090819020829055517fd879d5e7d9b51cf3fa46f67670befeb3a59fcab405350ea4bcb26cc6e7268a5190610b819085908b908b908b90615a2f565b60405180910390a1505050610b946136b6565b5050505050565b60008054610ba890615a55565b80601f0160208091040260200160405190810160405280929190818152602001828054610bd490615a55565b8015610c215780601f10610bf657610100808354040283529160200191610c21565b820191906000526020600020905b815481529060010190602001808311610c0457829003601f168201915b505050505081565b6001600160a01b031660009081527f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d6602052604090205490565b6000818152600260205260409020546001600160a01b031633811480610cac57506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b610cee5760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064015b60405180910390fd5b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b6001600160a01b0382811660008181527f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e860209081526040808320948616808452948252808320549383527f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e7825280832094835293905291822054600080516020615f718339815191529190670de0b6b3a764000090610de986613405565b610df39190615aa5565b610dfc876136dc565b610e069190615ab8565b610e109190615acf565b610e1a9190615af1565b949350505050565b610e2d8383836136fa565b600d5460405163133f757160e31b8152600481018390526000916001600160a01b0316906399fbab8890602401602060405180830381865afa158015610e77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9b91906159b0565b9050610f0b8484836001600160a01b031663bf1eb64a6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610ee2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f069190615a16565b6138c1565b50505050565b610f196134d6565b33610f23846115ff565b6001600160a01b031614610f4a576040516330cd747160e01b815260040160405180910390fd5b600d54604051630aeba61160e31b81526001600160a01b0391821660048201526024810185905290831660448201526064810182905273d60ea812166ee52cd3edaebb18465f13c19875c19063575d30889060840160006040518083038186803b158015610fb757600080fd5b505af4158015610fcb573d6000803e3d6000fd5b50505050610fd76136b6565b505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03166000811580156110215750825b90506000826001600160401b0316600114801561103d5750303b155b90508115801561104b575080155b156110695760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561109357845460ff60401b1916600160401b1785555b6110a586600001518760200151613ab3565b6110b786600001518760200151613ae6565b6110c98660a001518760c00151613b07565b6110dc8660e00151876101000151613c0b565b6040860151600e80546001600160a01b039283166001600160a01b0319918216179091556060880151600f80549184169183169190911790556080880151600d8054919093169116179055831561116d57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b61117d6134d6565b61118683613c6c565b600080516020615f7183398151915260005b828110156112935760008484838181106111b4576111b4615b04565b90506020020160208101906111c991906154a0565b6001600160a01b038088166000908152600486016020908152604080832093851683529290522054909150801561127e576001600160a01b038088166000908152600486016020908152604080832093861680845293909152812055611230908883613de7565b816001600160a01b0316876001600160a01b03167f540798df468d7b23d11f156fdb954cb19ad414d150722a7b6d55ba369dea792e8360405161127591815260200190565b60405180910390a35b5050808061128b90615b1a565b915050611198565b5050610fd76136b6565b6112a8838383610e22565b6001600160a01b0382163b15806113515750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af1158015611321573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113459190615b33565b6001600160e01b031916145b610fd75760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610ce5565b6113986134d6565b336113a2836115ff565b6001600160a01b0316146113c9576040516330cd747160e01b815260040160405180910390fd5b600d54604051635ae2fb3960e11b815273d60ea812166ee52cd3edaebb18465f13c19875c19163b5c5f6729161140f916001600160a01b03169086908690600401615b50565b60006040518083038186803b15801561142757600080fd5b505af415801561143b573d6000803e3d6000fd5b505050506114476136b6565b5050565b6114766040518060800160405280600081526020016000815260200160008152602001600081525090565b506001600160a01b031660009081527f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e66020908152604091829020825160808101845281548152600182015492810192909252600281015492820192909252600390910154606082015290565b6114eb6134d6565b336114f5826115ff565b6001600160a01b03161461151c576040516330cd747160e01b815260040160405180910390fd5b61152581613e18565b6000818152600c602052604090205461153f903390613ee5565b6000818152600c602052604080822091909155600d5490516323b872dd60e01b8152306004820152336024820152604481018390526001600160a01b03909116906323b872dd90606401600060405180830381600087803b1580156115a357600080fd5b505af11580156115b7573d6000803e3d6000fd5b505050507f603af6cb36e852311201ebb828cda2d49c5dc06d9d14a04ecd5e4211308625aa816040516115ec91815260200190565b60405180910390a16115fc6136b6565b50565b6000818152600260205260409020546001600160a01b0316806116515760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610ce5565b919050565b6001600160a01b03811660009081527f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e66020526040812054600080516020615f71833981519152904281116116ab5780610e1a565b42949350505050565b6116bc6134d6565b336116c6836115ff565b6001600160a01b0316146116ed576040516330cd747160e01b815260040160405180910390fd5b600d54604051632300b28360e11b81526001600160a01b03918216600482015260248101849052908216604482015273d60ea812166ee52cd3edaebb18465f13c19875c19063460165069060640161140f565b60006001600160a01b0382166117875760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401610ce5565b506001600160a01b031660009081526003602052604090205490565b6117ab6134d6565b600d5460405163133f757160e31b8152600481018390526000916001600160a01b0316906399fbab8890602401602060405180830381865afa1580156117f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061181991906159b0565b6000838152600c60209081526040808320548151635f8f5b2560e11b81529151949550936001600160a01b0386169263bf1eb64a9260048082019391829003018187875af115801561186f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118939190615a16565b905060006118a0856115ff565b90506001600160a01b0381166118c957604051632afc3c0d60e21b815260040160405180910390fd5b6118d4818385613680565b6000858152600c602052604090819020839055517fe7b71ff10e471529b8ab2bfc3c309129e2e31552017f7073ff90b318fa5f3baa9061191b908690889087908790615a2f565b60405180910390a1505050506115fc6136b6565b60606119396134d6565b61194282614036565b90506116516136b6565b60018054610ba890615a55565b6000806119646134d6565b600d54600e54600f54604051636969e58b60e01b81526001600160a01b039283166004820152908216602482015260009283921690636969e58b9060440160408051808303816000875af11580156119c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e49190615b71565b90925090506119fd336119f8600185615aa5565b61409c565b7f665e422c8352bce9bc2d0eaadb34a203cf7fbe89ffc7bd71d7c7e59510bb2700611a29600184615aa5565b604080519182526001600160a01b03841660208301520160405180910390a1611a53600183615aa5565b9350915050611a606136b6565b9091565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b611ad86134d6565b33611ae281613c6c565b6000600080516020615f718339815191528054604051632b71961d60e11b81523060048201529192506000916001600160a01b03909116906356e32c3a90602401600060405180830381865afa158015611b40573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611b689190810190615b96565b90508051600003611b8c57604051630dad652960e41b815260040160405180910390fd5b60005b8151811015611c6f576000828281518110611bac57611bac615b04565b60209081029190910181015133600090815260048701835260408082206001600160a01b038416835290935291909120549091508015611c5a5733600081815260048701602090815260408083206001600160a01b0387168085529252822091909155611c199183613de7565b6040518181526001600160a01b0383169033907f540798df468d7b23d11f156fdb954cb19ad414d150722a7b6d55ba369dea792e9060200160405180910390a35b50508080611c6790615b1a565b915050611b8f565b50505050611c7b6136b6565b565b611c856134d6565b33611c8f856115ff565b6001600160a01b031614611cb6576040516330cd747160e01b815260040160405180910390fd5b600d5460405163133f757160e31b8152600481018690526000916001600160a01b0316906399fbab8890602401602060405180830381865afa158015611d00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d2491906159b0565b6000868152600c602090815260408083205481516338d52e0f60e01b81529151949550936001600160a01b038616926338d52e0f92600480820193918290030181865afa158015611d79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d9d91906159b0565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015611de3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e079190615a16565b90506000836001600160a01b031663f8d898986040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6d91906159b0565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015611eb3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ed79190615a16565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f00000000000000000000000035751007a407ca6feffe80b3cb397736d2cf4dbe16906370a0823190602401602060405180830381865afa158015611f41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f659190615a16565b60405163841f477960e01b81529091506001600160a01b0386169063841f477990611f98908b908b908b90600401615c47565b600060405180830381600087803b158015611fb257600080fd5b505af1158015611fc6573d6000803e3d6000fd5b505050506121173384876001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561200d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203191906159b0565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015612077573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209b9190615a16565b6120a59190615aa5565b876001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210791906159b0565b6001600160a01b03169190613de7565b6122303383876001600160a01b031663f8d898986040518163ffffffff1660e01b8152600401602060405180830381865afa15801561215a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217e91906159b0565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156121c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e89190615a16565b6121f29190615aa5565b876001600160a01b031663f8d898986040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120e3573d6000803e3d6000fd5b6040516370a0823160e01b81523060048201526122fb90339083906001600160a01b037f00000000000000000000000035751007a407ca6feffe80b3cb397736d2cf4dbe16906370a0823190602401602060405180830381865afa15801561229c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c09190615a16565b6122ca9190615aa5565b6001600160a01b037f00000000000000000000000035751007a407ca6feffe80b3cb397736d2cf4dbe169190613de7565b6000856001600160a01b031663bf1eb64a6040518163ffffffff1660e01b81526004016020604051808303816000875af115801561233d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123619190615a16565b905061236e338287613680565b6000866001600160a01b031663c66f24556040518163ffffffff1660e01b81526004016020604051808303816000875af11580156123b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123d49190615a16565b90506000876001600160a01b031663bf1eb64a6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612418573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243c9190615a16565b60008d8152600c602052604090819020859055519091507f0e62bdb265148e28f778225a0d4dcfa76a6621dcf77db5e1edbc5aac5e5cafaf90612486908a908f9086908690615a2f565b60405180910390a15050505050505050610f0b6136b6565b60006124a981613c6c565b6000600080516020615f71833981519152805460405163bc120fe760e01b81523060048201526001600160a01b03878116602483015292935091169063bc120fe790604401602060405180830381865afa15801561250b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061252f9190615c6a565b61255757604051636f8bf18b60e11b81526001600160a01b0385166004820152602401610ce5565b8054604051634d0a32db60e01b81526001600160a01b03868116600483015285921690634d0a32db90602401602060405180830381865afa1580156125a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c49190615a16565b11156125e357604051630708444160e31b815260040160405180910390fd5b6125f86001600160a01b038516333086613520565b6001600160a01b0384166000908152600282016020526040902054421061264b5760018101546126289084615acf565b6001600160a01b03851660009081526002830160205260409020600101556126da565b6001600160a01b0384166000908152600282016020526040812054612671904290615aa5565b6001600160a01b03861660009081526002840160205260408120600101549192509061269d9083615ab8565b60018401549091506126af8287615af1565b6126b99190615acf565b6001600160a01b038716600090815260028501602052604090206001015550505b6001600160a01b038416600090815260028083016020526040909120429101819055600182015461270a91615af1565b6001600160a01b038516600090815260028301602090815260409182902092909255518481527fde88a922e0d3b88b24e9623efeb464919c6bf9f66857a65e2bfcf2ce87a9433d910160405180910390a150505050565b61276c858585610e22565b6001600160a01b0384163b15806128035750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a02906127b49033908a90899089908990600401615c87565b6020604051808303816000875af11580156127d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127f79190615b33565b6001600160e01b031916145b610b945760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610ce5565b7f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e5546001600160a01b03821660009081527f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e660205260408120600101549091600080516020615f71833981519152916128bb9190615ab8565b9392505050565b6128ca6134d6565b336128d4856115ff565b6001600160a01b0316146128fb576040516330cd747160e01b815260040160405180910390fd5b600d5460405163133f757160e31b8152600481018690526000916001600160a01b0316906399fbab8890602401602060405180830381865afa158015612945573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296991906159b0565b6000868152600c602090815260408083205481516338d52e0f60e01b81529151949550936001600160a01b038616926338d52e0f92600480820193918290030181865afa1580156129be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e291906159b0565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015612a28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a4c9190615a16565b6040516359783fcb60e11b81529091506001600160a01b0384169063b2f07f9690612a7f90899089908990600401615c47565b600060405180830381600087803b158015612a9957600080fd5b505af1158015612aad573d6000803e3d6000fd5b50505050612bca3382856001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612af4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b1891906159b0565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015612b5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b829190615a16565b612b8c9190615aa5565b856001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120e3573d6000803e3d6000fd5b6000836001600160a01b031663bf1eb64a6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612c0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c309190615a16565b9050612c3d338285613680565b6000888152600c602052604090819020829055517fae20c8842eb2c74e1d7d2e3a7548de6ed7c7278e9f603403911aa0174175747190612c829086908b908b90615b50565b60405180910390a150505050610f0b6136b6565b6060612ca06141a7565b905090565b600d5460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd90602401600060405180830381865afa158015612cef573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108b79190810190615cbb565b33612d21836115ff565b6001600160a01b031614612d48576040516330cd747160e01b815260040160405180910390fd5b600d54604051634948b2d960e11b81526001600160a01b03918216600482015260248101849052908216604482015273d60ea812166ee52cd3edaebb18465f13c19875c19063929165b29060640160006040518083038186803b158015612dae57600080fd5b505af415801561116d573d6000803e3d6000fd5b612dca6134d6565b600d5460405163133f757160e31b8152600481018390526000916001600160a01b0316906399fbab8890602401602060405180830381865afa158015612e14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3891906159b0565b90506000816001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9e91906159b0565b90506000826001600160a01b031663f8d898986040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ee0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f0491906159b0565b600e549091506001600160a01b038381169116141580612f325750600f546001600160a01b03828116911614155b15612f4f5760405162774c6560e91b815260040160405180910390fd5b826001600160a01b031663c66f24556040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612f8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fb39190615a16565b1580156130215750826001600160a01b031663bf1eb64a6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612ffb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061301f9190615a16565b155b61303e5760405163493e98f360e11b815260040160405180910390fd5b600d546040516323b872dd60e01b8152336004820152306024820152604481018690526001600160a01b03909116906323b872dd90606401600060405180830381600087803b15801561309057600080fd5b505af11580156130a4573d6000803e3d6000fd5b505050506130b2338561409c565b6040518481527f227a473b70d2f893cc7659219575c030a63b5743024fe1e0c1a680e708b1525a9060200160405180910390a15050506115fc6136b6565b6130f86134d6565b33613102836115ff565b6001600160a01b031614613129576040516330cd747160e01b815260040160405180910390fd5b600d5460405163133f757160e31b8152600481018490526000916001600160a01b0316906399fbab8890602401602060405180830381865afa158015613173573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061319791906159b0565b90506000600c60008581526020019081526020016000205490506131f5333085856001600160a01b031663f8d898986040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109c2573d6000803e3d6000fd5b613261826001600160a01b031663f8d898986040518163ffffffff1660e01b8152600401602060405180830381865afa158015613236573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061325a91906159b0565b8385613587565b604051631b8fec7360e11b8152600481018490526001600160a01b0383169063371fd8e690602401600060405180830381600087803b1580156132a357600080fd5b505af11580156132b7573d6000803e3d6000fd5b505050506000826001600160a01b031663bf1eb64a6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156132fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133219190615a16565b905061332e338284613680565b6000858152600c602052604090819020829055517f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d09061337390859088908890615b50565b60405180910390a15050506114476136b6565b61338e6134d6565b33613398836115ff565b6001600160a01b0316146133bf576040516330cd747160e01b815260040160405180910390fd5b600d54604051637dbca35360e01b815273d60ea812166ee52cd3edaebb18465f13c19875c191637dbca3539161140f916001600160a01b03169086908690600401615b50565b6000600080516020615f718339815191528161341f6141e4565b90508060000361344e57506001600160a01b039092166000908152600290920160205250604090206003015490565b6001600160a01b038416600090815260028084016020526040909120600181015491015482919061347e87611656565b6134889190615aa5565b6134929190615ab8565b6134a490670de0b6b3a7640000615ab8565b6134ae9190615acf565b6001600160a01b0385166000908152600284016020526040902060030154610e1a9190615af1565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0080546001190161351a57604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b6040516001600160a01b038481166024830152838116604483015260648201839052610f0b9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506141f8565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b17905291516000928392908716916135e39190615d28565b6000604051808303816000865af19150503d8060008114613620576040519150601f19603f3d011682016040523d82523d6000602084013e613625565b606091505b509150915081801561364f57508051158061364f57508080602001905181019061364f9190615c6a565b610b945760405162461bcd60e51b8152602060048201526002602482015261534160f01b6044820152606401610ce5565b8082111561369b5761369b836136968385615aa5565b61425b565b81811115610fd757610fd7836136b18484615aa5565b613ee5565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6001600160a01b0381166000908152600660205260408120546108b7565b6000818152600260205260409020546001600160a01b038481169116146137505760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b6044820152606401610ce5565b6001600160a01b03821661379a5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610ce5565b336001600160a01b03841614806137d457506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b806137f557506000818152600460205260409020546001600160a01b031633145b6138325760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610ce5565b6001600160a01b0380841660008181526003602090815260408083208054600019019055938616808352848320805460010190558583526002825284832080546001600160a01b03199081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6001600160a01b0383166139255760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610ce5565b6001600160a01b0382166139875760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610ce5565b816001600160a01b0316836001600160a01b0316036139e85760405162461bcd60e51b815260206004820152601760248201527f45524332303a207472616e7366657220746f2073656c660000000000000000006044820152606401610ce5565b6139f383838361434c565b6001600160a01b03831660009081526006602052604090205481811015613a6b5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610ce5565b6001600160a01b03808516600090815260066020526040808220858503905591851681529081208054849290613aa2908490615af1565b90915550610f0b9050848484614362565b613abb61436d565b6008613ac78382615d8a565b506009613ad48282615d8a565b5050600a805460ff1916601217905550565b613aee61436d565b6000613afa8382615d8a565b506001610fd78282615d8a565b613b0f61436d565b7f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d380546001600160a01b038481166001600160a01b0319928316179092557f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d480549284169290911682179055604080516344bc194960e11b81529051600080516020615f518339815191529291638978329291600480830192602092919082900301816000875af1158015613bc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bec91906159b0565b81546001600160a01b0319166001600160a01b03919091161790555050565b613c1361436d565b613c1b6143b6565b7f911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e555600080516020615f7183398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6000600080516020615f718339815191528054604051632b71961d60e11b81523060048201529192506000916001600160a01b03909116906356e32c3a90602401600060405180830381865afa158015613cca573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613cf29190810190615b96565b905060005b8151811015610f0b576000828281518110613d1457613d14615b04565b60200260200101519050613d2781613405565b6001600160a01b0382166000908152600286016020526040902060030155613d4e81611656565b6001600160a01b038083166000908152600280880160205260409091200191909155851615613dd457613d818582610d4a565b6001600160a01b0380871660008181526004880160209081526040808320948716808452948252808320959095556002890181528482206003908101549383528901815284822093825292909252919020555b5080613ddf81615b1a565b915050613cf7565b6040516001600160a01b03838116602483015260448201839052610fd791859182169063a9059cbb90606401613555565b6000818152600260205260409020546001600160a01b031680613e6a5760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610ce5565b6001600160a01b038116600081815260036020908152604080832080546000190190558583526002825280832080546001600160a01b031990811690915560049092528083208054909216909155518492907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6001600160a01b038216613f455760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610ce5565b613f518260008361434c565b6001600160a01b03821660009081526006602052604090205481811015613fc55760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610ce5565b6001600160a01b03831660009081526006602052604090208282039055613feb826143c6565b600780546000906140069084906001600160f81b0316615e49565b92506101000a8154816001600160f81b0302191690836001600160f81b03160217905550610fd783600084614362565b6060614041826143e0565b61404a826143eb565b61405482836143f6565b9050816001600160a01b03167f78d61a0c27b13f43911095f9f356f14daa3cd8b125eea1aa22421245e90e813d8260405161408f9190615848565b60405180910390a2919050565b6001600160a01b0382166140e65760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610ce5565b6000818152600260205260409020546001600160a01b03161561413c5760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b6044820152606401610ce5565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60408051600080825260208201909252606091506141de600080516020615f518339815191525482906001600160a01b03166146c7565b91505090565b6000612ca06007546001600160f81b031690565b600061420d6001600160a01b038416836147ac565b905080516000141580156142325750808060200190518101906142309190615c6a565b155b15610fd757604051635274afe760e01b81526001600160a01b0384166004820152602401610ce5565b6001600160a01b0382166142b15760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610ce5565b6142bd6000838361434c565b6142c6816143c6565b600780546000906142e19084906001600160f81b0316615e70565b92506101000a8154816001600160f81b0302191690836001600160f81b031602179055508060066000846001600160a01b03166001600160a01b03168152602001908152602001600020600082825461433a9190615af1565b90915550611447905060008383614362565b6143578383836147ba565b610fd78383836147c4565b610fd7838383614814565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16611c7b57604051631afcd79f60e31b815260040160405180910390fd5b6143be61436d565b611c7b61481e565b60006001600160f81b038211156143dc57600080fd5b5090565b6115fc816000614826565b6115fc8160006148a6565b606060006144026141a7565b905080516001600160401b0381111561441d5761441d61558a565b604051908082528060200260200182016040528015614446578160200160208202803683370190505b509150600080516020615f3183398151915260005b82518110156146be5781600101600084838151811061447c5761447c615b04565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000876001600160a01b03166001600160a01b0316815260200190815260200160002060000160109054906101000a90046001600160801b03166001600160801b03168482815181106144f9576144f9615b04565b60200260200101818152505083818151811061451757614517615b04565b60200260200101516000146146ac57600082600101600085848151811061454057614540615b04565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000886001600160a01b03166001600160a01b0316815260200190815260200160002060000160106101000a8154816001600160801b0302191690836001600160801b031602179055506145d48482815181106145c7576145c7615b04565b6020026020010151614904565b8260020160008584815181106145ec576145ec615b04565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060000160108282829054906101000a90046001600160801b03166146389190615e90565b92506101000a8154816001600160801b0302191690836001600160801b031602179055506146ac8585838151811061467257614672615b04565b602002602001015185848151811061468c5761468c615b04565b60200260200101516001600160a01b0316613de79092919063ffffffff16565b806146b681615b1a565b91505061445b565b50505092915050565b81516060906146d7816001615af1565b6001600160401b038111156146ee576146ee61558a565b604051908082528060200260200182016040528015614717578160200160208202803683370190505b50915060005b818110156147715784818151811061473757614737615b04565b602002602001015183828151811061475157614751615b04565b6001600160a01b039092166020928302919091019091015260010161471d565b508282828151811061478557614785615b04565b60200260200101906001600160a01b031690816001600160a01b0316815250505092915050565b60606128bb83836000614938565b610fd78383614826565b6001600160a01b038316156147dc576147dc83613c6c565b6001600160a01b038216158015906148065750826001600160a01b0316826001600160a01b031614155b15610fd757610fd782613c6c565b610fd783836148a6565b6136b661436d565b6000806148316149d5565b9150915081516000036148445750505050565b6001600160a01b0384161580159061486557506001600160a01b0384163014155b1561487557614875848383614d0b565b6001600160a01b0383161580159061489657506001600160a01b0383163014155b15610f0b57610f0b838383614d0b565b6001600160a01b038216158015906148c757506001600160a01b0382163014155b156148d5576148d582614fcb565b6001600160a01b038116158015906148f657506001600160a01b0381163014155b156114475761144781614fcb565b60006001600160801b038211156143dc576040516306dfcc6560e41b81526080600482015260248101839052604401610ce5565b60608147101561495d5760405163cd78605960e01b8152306004820152602401610ce5565b600080856001600160a01b031684866040516149799190615d28565b60006040518083038185875af1925050503d80600081146149b6576040519150601f19603f3d011682016040523d82523d6000602084013e6149bb565b606091505b50915091506149cb8683836150cb565b9695505050505050565b6060806149e06141a7565b915081516001600160401b038111156149fb576149fb61558a565b604051908082528060200260200182016040528015614a24578160200160208202803683370190505b5090508151600003614a34579091565b600080516020615f3183398151915280544314614c80574381556000614a787f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d55490565b9050614a82615127565b60005b8451811015614c7d576000858281518110614aa257614aa2615b04565b6020908102919091018101516001600160a01b03811660009081526002870190925260408220548851919350600160801b90046001600160801b031690889085908110614af157614af1615b04565b60209081029190910101516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015614b41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b659190615a16565b614b6f9190615aa5565b6001600160a01b03831660009081526002870160205260408120549192506001600160801b0390911690819003614ba4575060015b8415614bc157614bb482866151a0565b614bbe9082615af1565b90505b614bca81614904565b6001600160a01b0384166000908152600288016020526040902080546001600160801b0319166001600160801b0392909216919091179055614c0b82614904565b6001600160a01b038416600090815260028801602052604090208054601090614c45908490600160801b90046001600160801b0316615eb0565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555050505080614c7690615b1a565b9050614a85565b50505b60005b8351811015614d0557816002016000858381518110614ca457614ca4615b04565b6020908102919091018101516001600160a01b031682528101919091526040016000205483516001600160801b0390911690849083908110614ce857614ce8615b04565b602090810291909101015280614cfd81615b1a565b915050614c83565b50509091565b6001600160a01b03831615801590614d2c57506001600160a01b0383163014155b614d3857614d38615ed0565b600080516020615f318339815191526000614d5285610c29565b905060005b845181101561116d576000858281518110614d7457614d74615b04565b602002602001015190506000858381518110614d9257614d92615b04565b6020908102919091018101516001600160a01b0380851660009081526001890184526040808220928d168252919093528220549092506001600160801b031690819003614e3257614de282614904565b6001600160a01b0393841660009081526001880160209081526040808320968d1683529590529390932080546001600160801b0319166001600160801b039094169390931790925550614fbb9050565b818103614e4157505050614fbb565b6000614e4d8284615aa5565b90506000614e5b87836151b5565b9050600081896001016000886001600160a01b03166001600160a01b0316815260200190815260200160002060008e6001600160a01b03166001600160a01b0316815260200190815260200160002060000160109054906101000a90046001600160801b03166001600160801b0316614ed49190615af1565b90506040518060400160405280614eea87614904565b6001600160801b03168152602001614f0183614904565b6001600160801b0316815250896001016000886001600160a01b03166001600160a01b0316815260200190815260200160002060008e6001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a8154816001600160801b0302191690836001600160801b0316021790555060208201518160000160106101000a8154816001600160801b0302191690836001600160801b031602179055509050505050505050505b614fc481615b1a565b9050614d57565b6001600160a01b03811615801590614fec57506001600160a01b0381163014155b614ff857614ff8615ed0565b6000615003826136dc565b9050600061501183836151ca565b9050600061501f82846152d8565b6001600160a01b03851660009081527f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d660205260409020547f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d554919250600080516020615f5183398151915291839161509791615aa5565b6150a19190615af1565b60038201556001600160a01b03909416600090815260049094016020526040909320929092555050565b6060826150e0576150db826152ee565b6128bb565b81511580156150f757506001600160a01b0384163b155b1561512057604051639996b31560e01b81526001600160a01b0385166004820152602401610ce5565b50806128bb565b7f24bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d45460408051638113382760e01b815290516001600160a01b039092169163811338279160048082019260009290919082900301818387803b15801561518c57600080fd5b505af1158015610f0b573d6000803e3d6000fd5b60006128bb83670de0b6b3a764000084615317565b60006128bb8383670de0b6b3a7640000615317565b600080600080516020615f51833981519152600181015460405163389a2ce960e21b81526001600160a01b0387811660048301529293506000928392169063e268b3a49060240160408051808303816000875af115801561522f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906152539190615efd565b6001600160801b03918216935016905060006064615272602888615ab8565b61527c9190615acf565b905082156149cb576064615291602882615aa5565b848461529b6141e4565b6152a59190615ab8565b6152af9190615acf565b6152b99190615ab8565b6152c39190615acf565b6152cd9082615af1565b979650505050505050565b60008183106152e757816128bb565b5090919050565b8051156152fe5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b600082600019048411830215820261532e57600080fd5b5091020490565b6001600160e01b0319811681146115fc57600080fd5b60006020828403121561535d57600080fd5b81356128bb81615335565b60008083601f84011261537a57600080fd5b5081356001600160401b0381111561539157600080fd5b6020830191508360208285010111156153a957600080fd5b9250929050565b6000806000806000608086880312156153c857600080fd5b85359450602086013593506040860135925060608601356001600160401b038111156153f357600080fd5b6153ff88828901615368565b969995985093965092949392505050565b60005b8381101561542b578181015183820152602001615413565b50506000910152565b6020815260008251806020840152615453816040850160208701615410565b601f01601f19169190910160400192915050565b60006020828403121561547957600080fd5b5035919050565b6001600160a01b03811681146115fc57600080fd5b803561165181615480565b6000602082840312156154b257600080fd5b81356128bb81615480565b600080604083850312156154d057600080fd5b82356154db81615480565b946020939093013593505050565b600080604083850312156154fc57600080fd5b823561550781615480565b9150602083013561551781615480565b809150509250929050565b60008060006060848603121561553757600080fd5b833561554281615480565b9250602084013561555281615480565b929592945050506040919091013590565b60008060006060848603121561557857600080fd5b83359250602084013561555281615480565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b03811182821017156155c3576155c361558a565b60405290565b604051601f8201601f191681016001600160401b03811182821017156155f1576155f161558a565b604052919050565b60006001600160401b038211156156125761561261558a565b50601f01601f191660200190565b600082601f83011261563157600080fd5b813561564461563f826155f9565b6155c9565b81815284602083860101111561565957600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561568857600080fd5b81356001600160401b038082111561569f57600080fd5b9083019061012082860312156156b457600080fd5b6156bc6155a0565b8235828111156156cb57600080fd5b6156d787828601615620565b8252506020830135828111156156ec57600080fd5b6156f887828601615620565b60208301525061570a60408401615495565b604082015261571b60608401615495565b606082015261572c60808401615495565b608082015261573d60a08401615495565b60a082015261574e60c08401615495565b60c082015261575f60e08401615495565b60e08201526101009283013592810192909252509392505050565b60008060006040848603121561578f57600080fd5b833561579a81615480565b925060208401356001600160401b03808211156157b657600080fd5b818601915086601f8301126157ca57600080fd5b8135818111156157d957600080fd5b8760208260051b85010111156157ee57600080fd5b6020830194508093505050509250925092565b6000806040838503121561581457600080fd5b50508035926020909101359150565b6000806040838503121561583657600080fd5b82359150602083013561551781615480565b6020808252825182820181905260009190848201906040850190845b8181101561588057835183529284019291840191600101615864565b50909695505050505050565b80151581146115fc57600080fd5b600080604083850312156158ad57600080fd5b82356158b881615480565b915060208301356155178161588c565b600080600080606085870312156158de57600080fd5b843593506020850135925060408501356001600160401b0381111561590257600080fd5b61590e87828801615368565b95989497509550505050565b60008060008060006080868803121561593257600080fd5b853561593d81615480565b9450602086013561594d81615480565b93506040860135925060608601356001600160401b038111156153f357600080fd5b6020808252825182820181905260009190848201906040850190845b818110156158805783516001600160a01b03168352928401929184019160010161598b565b6000602082840312156159c257600080fd5b81516128bb81615480565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8481528360208201526060604082015260006149cb6060830184866159cd565b600060208284031215615a2857600080fd5b5051919050565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b600181811c90821680615a6957607f821691505b602082108103615a8957634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b818103818111156108b7576108b7615a8f565b80820281158282048414176108b7576108b7615a8f565b600082615aec57634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156108b7576108b7615a8f565b634e487b7160e01b600052603260045260246000fd5b600060018201615b2c57615b2c615a8f565b5060010190565b600060208284031215615b4557600080fd5b81516128bb81615335565b6001600160a01b039390931683526020830191909152604082015260600190565b60008060408385031215615b8457600080fd5b82519150602083015161551781615480565b60006020808385031215615ba957600080fd5b82516001600160401b0380821115615bc057600080fd5b818501915085601f830112615bd457600080fd5b815181811115615be657615be661558a565b8060051b9150615bf78483016155c9565b8181529183018401918481019088841115615c1157600080fd5b938501935b83851015615c3b5784519250615c2b83615480565b8282529385019390850190615c16565b98975050505050505050565b838152604060208201526000615c616040830184866159cd565b95945050505050565b600060208284031215615c7c57600080fd5b81516128bb8161588c565b6001600160a01b03868116825285166020820152604081018490526080606082018190526000906152cd90830184866159cd565b600060208284031215615ccd57600080fd5b81516001600160401b03811115615ce357600080fd5b8201601f81018413615cf457600080fd5b8051615d0261563f826155f9565b818152856020838501011115615d1757600080fd5b615c61826020830160208601615410565b60008251615d3a818460208701615410565b9190910192915050565b601f821115610fd757600081815260208120601f850160051c81016020861015615d6b5750805b601f850160051c820191505b8181101561116d57828155600101615d77565b81516001600160401b03811115615da357615da361558a565b615db781615db18454615a55565b84615d44565b602080601f831160018114615dec5760008415615dd45750858301515b600019600386901b1c1916600185901b17855561116d565b600085815260208120601f198616915b82811015615e1b57888601518255948401946001909101908401615dfc565b5085821015615e395787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160f81b03828116828216039080821115615e6957615e69615a8f565b5092915050565b6001600160f81b03818116838216019080821115615e6957615e69615a8f565b6001600160801b03828116828216039080821115615e6957615e69615a8f565b6001600160801b03818116838216019080821115615e6957615e69615a8f565b634e487b7160e01b600052600160045260246000fd5b80516001600160801b038116811461165157600080fd5b60008060408385031215615f1057600080fd5b615f1983615ee6565b9150615f2760208401615ee6565b9050925092905056fe42eb16b0bf2565d9a663d4e7253d588f054024f7228c103568322f697f63b61324bc46ff97535a32ac9a9fd00a6caac7641d058373f14d0429bdbb23908d69d2911c9f18e2dcedc0ab129c74f573095a6371b074abf49ebc102126a3251b33e4a2646970667358221220303971b95cce04e4a40c3baa51d99a562399f6385acab4a8dd3e7bbf55ac68a464736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000035751007a407ca6feffe80b3cb397736d2cf4dbe
-----Decoded View---------------
Arg [0] : _additionalToken (address): 0x35751007a407ca6FEFfE80b3cB397736D2cf4dbe
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000035751007a407ca6feffe80b3cb397736d2cf4dbe
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
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.