More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 1,003 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Log Claim | 21370902 | 31 days ago | IN | 0 ETH | 0.00035736 | ||||
Log Claim | 21014858 | 81 days ago | IN | 0 ETH | 0.00039229 | ||||
Log Claim | 20984505 | 85 days ago | IN | 0 ETH | 0.0004237 | ||||
Log Claim | 20966240 | 87 days ago | IN | 0 ETH | 0.0004315 | ||||
Log Claim | 20905233 | 96 days ago | IN | 0 ETH | 0.00015295 | ||||
Log Claim | 20898375 | 97 days ago | IN | 0 ETH | 0.00012359 | ||||
Log Claim | 20891547 | 98 days ago | IN | 0 ETH | 0.0001291 | ||||
Log Claim | 20776442 | 114 days ago | IN | 0 ETH | 0.00019898 | ||||
Log Claim | 20744291 | 118 days ago | IN | 0 ETH | 0.00015709 | ||||
Log Claim | 20579239 | 141 days ago | IN | 0 ETH | 0.0000739 | ||||
Log Claim | 20522452 | 149 days ago | IN | 0 ETH | 0.00008319 | ||||
Log Claim | 20389412 | 168 days ago | IN | 0 ETH | 0.00005709 | ||||
Log Claim | 20386638 | 168 days ago | IN | 0 ETH | 0.0000674 | ||||
Log Claim | 20381755 | 169 days ago | IN | 0 ETH | 0.00010476 | ||||
Log Claim | 20372651 | 170 days ago | IN | 0 ETH | 0.00006511 | ||||
Log Claim | 20350763 | 173 days ago | IN | 0 ETH | 0.00008471 | ||||
Log Claim | 20305954 | 180 days ago | IN | 0 ETH | 0.00013391 | ||||
Log Claim | 20226663 | 191 days ago | IN | 0 ETH | 0.00037145 | ||||
Log Claim | 20218593 | 192 days ago | IN | 0 ETH | 0.00014753 | ||||
Log Claim | 20217724 | 192 days ago | IN | 0 ETH | 0.00010694 | ||||
Log Claim | 20211276 | 193 days ago | IN | 0 ETH | 0.00016061 | ||||
Log Claim | 20196844 | 195 days ago | IN | 0 ETH | 0.00005658 | ||||
Log Claim | 20191292 | 196 days ago | IN | 0 ETH | 0.00019365 | ||||
Log Claim | 20142999 | 202 days ago | IN | 0 ETH | 0.00010528 | ||||
Log Claim | 20140825 | 203 days ago | IN | 0 ETH | 0.00025674 |
Latest 25 internal transactions (View All)
Advanced mode:
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:
HATVaultsRegistry
Compiler Version
v0.8.16+commit.07a7930e
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT // Disclaimer https://github.com/hats-finance/hats-contracts/blob/main/DISCLAIMER.md pragma solidity 0.8.16; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/proxy/Clones.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; import "./tokenlock/TokenLockFactory.sol"; import "./interfaces/IHATVaultsRegistry.sol"; import "./HATVault.sol"; /** @title Registry to deploy Hats.finance vaults and manage shared parameters * @author Hats.finance * @notice Hats.finance is a proactive bounty protocol for white hat hackers and * security experts, where projects, community members, and stakeholders * incentivize protocol security and responsible disclosure. * Hats create scalable vaults using the project’s own token. The value of the * bounty increases with the success of the token and project. * * The owner of the registry has the permission to set time limits and bounty * parameters and change vaults' info, and to set the other registry roles - * fee setter and arbitrator. * The arbitrator can challenge submitted claims for bounty payouts made by * vaults' committees, approve them with a different bounty percentage or * dismiss them. * The fee setter can set the fee on withdrawals on all vaults. * * This project is open-source and can be found at: * https://github.com/hats-finance/hats-contracts * * @dev New hats.finance vaults should be created through a call to {createVault} * so that they are linked to the registry */ contract HATVaultsRegistry is IHATVaultsRegistry, Ownable { using SafeERC20 for IERC20; using Math for uint256; // Used in {swapAndSend} to avoid a "stack too deep" error struct SwapData { uint256 amount; uint256 amountUnused; uint256 hatsReceived; uint256 totalHackerReward; uint256 governanceAmountSwapped; uint256[] hackerRewards; uint256 governanceHatReward; uint256 usedPart; } uint16 public constant HUNDRED_PERCENT = 10000; // the maximum percentage of the bounty that will be converted in HATs uint16 public constant MAX_HAT_SPLIT = 2000; address public immutable hatVaultImplementation; address[] public hatVaults; // vault address => is visible mapping(address => bool) public isVaultVisible; // asset => hacker address => amount mapping(address => mapping(address => uint256)) public hackersHatReward; // asset => amount mapping(address => uint256) public governanceHatReward; // PARAMETERS FOR ALL VAULTS IHATVaultsRegistry.GeneralParameters public generalParameters; ITokenLockFactory public immutable tokenLockFactory; // the token into which a part of the the bounty will be swapped into IERC20 public HAT; // feeSetter sets the withdrawal fee address public feeSetter; // How the bountyGovernanceHAT and bountyHackerHATVested set how to divide the hats // bounties of the vault, in percentages (out of `HUNDRED_PERCENT`) // The precentages are taken from the total bounty // the default percentage of the total bounty to be swapped to HATs and sent to governance uint16 public defaultBountyGovernanceHAT; // the default percentage of the total bounty to be swapped to HATs and sent to the hacker via vesting contract uint16 public defaultBountyHackerHATVested; address public defaultArbitrator; bool public defaultArbitratorCanChangeBounty; bool public isEmergencyPaused; uint32 public defaultChallengePeriod; uint32 public defaultChallengeTimeOutPeriod; /** * @notice initialize - * @param _hatVaultImplementation The hat vault implementation address. * @param _hatGovernance The governance address. * @param _HAT the HAT token address * @param _bountyGovernanceHAT The default percentage of a claim's total * bounty to be swapped for HAT and sent to the governance * @param _bountyHackerHATVested The default percentage of a claim's total * bounty to be swapped for HAT and sent to a vesting contract for the hacker * _bountyGovernanceHAT + _bountyHackerHATVested must be less * than `HUNDRED_PERCENT`. * @param _tokenLockFactory Address of the token lock factory to be used * to create a vesting contract for the approved claim reporter. */ constructor( address _hatVaultImplementation, address _hatGovernance, address _defaultArbitrator, address _HAT, uint16 _bountyGovernanceHAT, uint16 _bountyHackerHATVested, ITokenLockFactory _tokenLockFactory ) { _transferOwnership(_hatGovernance); hatVaultImplementation = _hatVaultImplementation; HAT = IERC20(_HAT); validateHATSplit(_bountyGovernanceHAT, _bountyHackerHATVested); tokenLockFactory = _tokenLockFactory; generalParameters = IHATVaultsRegistry.GeneralParameters({ hatVestingDuration: 90 days, hatVestingPeriods: 90, withdrawPeriod: 11 hours, safetyPeriod: 1 hours, setMaxBountyDelay: 2 days, withdrawRequestEnablePeriod: 7 days, withdrawRequestPendingPeriod: 7 days, claimFee: 0 }); defaultBountyGovernanceHAT = _bountyGovernanceHAT; defaultBountyHackerHATVested = _bountyHackerHATVested; defaultArbitrator = _defaultArbitrator; defaultChallengePeriod = 3 days; defaultChallengeTimeOutPeriod = 5 weeks; defaultArbitratorCanChangeBounty = true; emit RegistryCreated( _hatVaultImplementation, _HAT, address(_tokenLockFactory), generalParameters, _bountyGovernanceHAT, _bountyHackerHATVested, _hatGovernance, _defaultArbitrator, defaultChallengePeriod, defaultChallengeTimeOutPeriod, defaultArbitratorCanChangeBounty ); } /** @notice See {IHATVaultsRegistry-setSwapToken}. */ function setSwapToken(address _swapToken) external onlyOwner { HAT = IERC20(_swapToken); emit SetSwapToken(_swapToken); } /** @notice See {IHATVaultsRegistry-setEmergencyPaused}. */ function setEmergencyPaused(bool _isEmergencyPaused) external onlyOwner { isEmergencyPaused = _isEmergencyPaused; emit SetEmergencyPaused(_isEmergencyPaused); } /** @notice See {IHATVaultsRegistry-logClaim}. */ function logClaim(string calldata _descriptionHash) external payable { uint256 _claimFee = generalParameters.claimFee; if (_claimFee > 0) { if (msg.value < _claimFee) revert NotEnoughFeePaid(); // solhint-disable-next-line avoid-low-level-calls (bool success,) = payable(owner()).call{value: msg.value}(""); if (!success) revert ClaimFeeTransferFailed(); } emit LogClaim(msg.sender, _descriptionHash); } /** @notice See {IHATVaultsRegistry-setDefaultHATBountySplit}. */ function setDefaultHATBountySplit( uint16 _defaultBountyGovernanceHAT, uint16 _defaultBountyHackerHATVested ) external onlyOwner { validateHATSplit(_defaultBountyGovernanceHAT, _defaultBountyHackerHATVested); defaultBountyGovernanceHAT = _defaultBountyGovernanceHAT; defaultBountyHackerHATVested = _defaultBountyHackerHATVested; emit SetDefaultHATBountySplit(_defaultBountyGovernanceHAT, _defaultBountyHackerHATVested); } /** @notice See {IHATVaultsRegistry-setDefaultArbitrator}. */ function setDefaultArbitrator(address _defaultArbitrator) external onlyOwner { defaultArbitrator = _defaultArbitrator; emit SetDefaultArbitrator(_defaultArbitrator); } /** @notice See {IHATVaultsRegistry-setDefaultChallengePeriod}. */ function setDefaultChallengePeriod(uint32 _defaultChallengePeriod) external onlyOwner { validateChallengePeriod(_defaultChallengePeriod); defaultChallengePeriod = _defaultChallengePeriod; emit SetDefaultChallengePeriod(_defaultChallengePeriod); } /** @notice See {IHATVaultsRegistry-setDefaultChallengeTimeOutPeriod}. */ function setDefaultChallengeTimeOutPeriod(uint32 _defaultChallengeTimeOutPeriod) external onlyOwner { validateChallengeTimeOutPeriod(_defaultChallengeTimeOutPeriod); defaultChallengeTimeOutPeriod = _defaultChallengeTimeOutPeriod; emit SetDefaultChallengeTimeOutPeriod(_defaultChallengeTimeOutPeriod); } /** @notice See {IHATVaultsRegistry-setDefaultArbitratorCanChangeBounty}. */ function setDefaultArbitratorCanChangeBounty(bool _defaultArbitratorCanChangeBounty) external onlyOwner { defaultArbitratorCanChangeBounty = _defaultArbitratorCanChangeBounty; emit SetDefaultArbitratorCanChangeBounty(_defaultArbitratorCanChangeBounty); } /** @notice See {IHATVaultsRegistry-setFeeSetter}. */ function setFeeSetter(address _feeSetter) external onlyOwner { feeSetter = _feeSetter; emit SetFeeSetter(_feeSetter); } /** @notice See {IHATVaultsRegistry-setWithdrawRequestParams}. */ function setWithdrawRequestParams(uint32 _withdrawRequestPendingPeriod, uint32 _withdrawRequestEnablePeriod) external onlyOwner { if (_withdrawRequestPendingPeriod > 90 days) revert WithdrawRequestPendingPeriodTooLong(); if (_withdrawRequestEnablePeriod < 6 hours) revert WithdrawRequestEnabledPeriodTooShort(); if (_withdrawRequestEnablePeriod > 100 days) revert WithdrawRequestEnabledPeriodTooLong(); generalParameters.withdrawRequestPendingPeriod = _withdrawRequestPendingPeriod; generalParameters.withdrawRequestEnablePeriod = _withdrawRequestEnablePeriod; emit SetWithdrawRequestParams(_withdrawRequestPendingPeriod, _withdrawRequestEnablePeriod); } /** @notice See {IHATVaultsRegistry-setClaimFee}. */ function setClaimFee(uint256 _fee) external onlyOwner { generalParameters.claimFee = _fee; emit SetClaimFee(_fee); } /** @notice See {IHATVaultsRegistry-setWithdrawSafetyPeriod}. */ function setWithdrawSafetyPeriod(uint32 _withdrawPeriod, uint32 _safetyPeriod) external onlyOwner { if (_withdrawPeriod < 1 hours) revert WithdrawPeriodTooShort(); if (_safetyPeriod > 6 hours) revert SafetyPeriodTooLong(); generalParameters.withdrawPeriod = _withdrawPeriod; generalParameters.safetyPeriod = _safetyPeriod; emit SetWithdrawSafetyPeriod(_withdrawPeriod, _safetyPeriod); } /** @notice See {IHATVaultsRegistry-setHatVestingParams}. */ function setHatVestingParams(uint32 _duration, uint32 _periods) external onlyOwner { if (_duration >= 180 days) revert HatVestingDurationTooLong(); if (_periods == 0) revert HatVestingPeriodsCannotBeZero(); if (_duration < _periods) revert HatVestingDurationSmallerThanPeriods(); generalParameters.hatVestingDuration = _duration; generalParameters.hatVestingPeriods = _periods; emit SetHatVestingParams(_duration, _periods); } /** @notice See {IHATVaultsRegistry-setMaxBountyDelay}. */ function setMaxBountyDelay(uint32 _delay) external onlyOwner { if (_delay < 2 days) revert DelayTooShort(); generalParameters.setMaxBountyDelay = _delay; emit SetMaxBountyDelay(_delay); } /** @notice See {IHATVaultsRegistry-createVault}. */ function createVault(IHATVault.VaultInitParams calldata _params) external returns(address vault) { vault = Clones.clone(hatVaultImplementation); HATVault(vault).initialize(_params); hatVaults.push(vault); emit VaultCreated(vault, _params); } /** @notice See {IHATVaultsRegistry-setVaultVisibility}. */ function setVaultVisibility(address _vault, bool _visible) external onlyOwner { isVaultVisible[_vault] = _visible; emit SetVaultVisibility(_vault, _visible); } /** @notice See {IHATVaultsRegistry-addTokensToSwap}. */ function addTokensToSwap( IERC20 _asset, address _hacker, uint256 _hackersHatReward, uint256 _governanceHatReward ) external { hackersHatReward[address(_asset)][_hacker] += _hackersHatReward; governanceHatReward[address(_asset)] += _governanceHatReward; _asset.safeTransferFrom(msg.sender, address(this), _hackersHatReward + _governanceHatReward); } /** @notice See {IHATVaultsRegistry-swapAndSend}. */ function swapAndSend( address _asset, address[] calldata _beneficiaries, uint256 _amountOutMinimum, address _routingContract, bytes calldata _routingPayload ) external onlyOwner { // Needed to avoid a "stack too deep" error SwapData memory _swapData; _swapData.hackerRewards = new uint256[](_beneficiaries.length); _swapData.governanceHatReward = governanceHatReward[_asset]; _swapData.amount = _swapData.governanceHatReward; for (uint256 i = 0; i < _beneficiaries.length;) { _swapData.hackerRewards[i] = hackersHatReward[_asset][_beneficiaries[i]]; hackersHatReward[_asset][_beneficiaries[i]] = 0; _swapData.amount += _swapData.hackerRewards[i]; unchecked { ++i; } } if (_swapData.amount == 0) revert AmountToSwapIsZero(); IERC20 _HAT = HAT; (_swapData.hatsReceived, _swapData.amountUnused) = _swapTokenForHAT(IERC20(_asset), _swapData.amount, _amountOutMinimum, _routingContract, _routingPayload); _swapData.usedPart = (_swapData.amount - _swapData.amountUnused); _swapData.governanceAmountSwapped = _swapData.usedPart.mulDiv(_swapData.governanceHatReward, _swapData.amount); governanceHatReward[_asset] = _swapData.amountUnused.mulDiv(_swapData.governanceHatReward, _swapData.amount); for (uint256 i = 0; i < _beneficiaries.length;) { uint256 _hackerReward = _swapData.hatsReceived.mulDiv(_swapData.hackerRewards[i], _swapData.amount); uint256 _hackerAmountSwapped = _swapData.usedPart.mulDiv(_swapData.hackerRewards[i], _swapData.amount); _swapData.totalHackerReward += _hackerReward; hackersHatReward[_asset][_beneficiaries[i]] = _swapData.amountUnused.mulDiv(_swapData.hackerRewards[i], _swapData.amount); address _tokenLock; if (_hackerReward > 0) { // hacker gets her reward via vesting contract _tokenLock = tokenLockFactory.createTokenLock( address(_HAT), 0x0000000000000000000000000000000000000000, //this address as owner, so it can do nothing. _beneficiaries[i], _hackerReward, // solhint-disable-next-line not-rely-on-time block.timestamp, //start // solhint-disable-next-line not-rely-on-time block.timestamp + generalParameters.hatVestingDuration, //end generalParameters.hatVestingPeriods, 0, // no release start 0, // no cliff ITokenLock.Revocability.Disabled, true ); _HAT.safeTransfer(_tokenLock, _hackerReward); } emit SwapAndSend(_beneficiaries[i], _hackerAmountSwapped, _hackerReward, _tokenLock); unchecked { ++i; } } address _owner = owner(); uint256 _amountToOwner = _swapData.hatsReceived - _swapData.totalHackerReward; _HAT.safeTransfer(_owner, _amountToOwner); emit SwapAndSend(_owner, _swapData.governanceAmountSwapped, _amountToOwner, address(0)); } /** @notice See {IHATVaultsRegistry-getWithdrawPeriod}. */ function getWithdrawPeriod() external view returns (uint256) { return generalParameters.withdrawPeriod; } /** @notice See {IHATVaultsRegistry-getSafetyPeriod}. */ function getSafetyPeriod() external view returns (uint256) { return generalParameters.safetyPeriod; } /** @notice See {IHATVaultsRegistry-getWithdrawRequestEnablePeriod}. */ function getWithdrawRequestEnablePeriod() external view returns (uint256) { return generalParameters.withdrawRequestEnablePeriod; } /** @notice See {IHATVaultsRegistry-getWithdrawRequestPendingPeriod}. */ function getWithdrawRequestPendingPeriod() external view returns (uint256) { return generalParameters.withdrawRequestPendingPeriod; } /** @notice See {IHATVaultsRegistry-getSetMaxBountyDelay}. */ function getSetMaxBountyDelay() external view returns (uint256) { return generalParameters.setMaxBountyDelay; } /** @notice See {IHATVaultsRegistry-getNumberOfVaults}. */ function getNumberOfVaults() external view returns(uint256) { return hatVaults.length; } /** @notice See {IHATVaultsRegistry-validateHATSplit}. */ function validateHATSplit(uint16 _bountyGovernanceHAT, uint16 _bountyHackerHATVested) public pure { if (_bountyGovernanceHAT + _bountyHackerHATVested > MAX_HAT_SPLIT) revert TotalHatsSplitPercentageShouldBeUpToMaxHATSplit(); } /** @notice See {IHATVaultsRegistry-validateChallengePeriod}. */ function validateChallengePeriod(uint32 _challengePeriod) public pure { if (_challengePeriod < 1 days) revert ChallengePeriodTooShort(); if (_challengePeriod > 5 days) revert ChallengePeriodTooLong(); } /** @notice See {IHATVaultsRegistry-validateChallengeTimeOutPeriod}. */ function validateChallengeTimeOutPeriod(uint32 _challengeTimeOutPeriod) public pure { if (_challengeTimeOutPeriod < 2 days) revert ChallengeTimeOutPeriodTooShort(); if (_challengeTimeOutPeriod > 85 days) revert ChallengeTimeOutPeriodTooLong(); } /** * @dev Use the given routing contract to swap the given token to HAT token * @param _asset The token to swap * @param _amount Amount of token to swap * @param _amountOutMinimum Minimum amount of HAT tokens at swap * @param _routingContract Routing contract to call for the swap * @param _routingPayload Payload to send to the _routingContract for the * swap */ function _swapTokenForHAT( IERC20 _asset, uint256 _amount, uint256 _amountOutMinimum, address _routingContract, bytes calldata _routingPayload) internal returns (uint256 hatsReceived, uint256 amountUnused) { IERC20 _HAT = HAT; if (_asset == _HAT) { return (_amount, 0); } IERC20(_asset).safeApprove(_routingContract, _amount); uint256 _balanceBefore = _HAT.balanceOf(address(this)); uint256 _assetBalanceBefore = _asset.balanceOf(address(this)); // solhint-disable-next-line avoid-low-level-calls (bool success,) = _routingContract.call(_routingPayload); if (!success) revert SwapFailed(); hatsReceived = _HAT.balanceOf(address(this)) - _balanceBefore; amountUnused = _amount - (_assetBalanceBefore - _asset.balanceOf(address(this))); if (hatsReceived < _amountOutMinimum) revert AmountSwappedLessThanMinimum(); IERC20(_asset).safeApprove(address(_routingContract), 0); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (interfaces/IERC4626.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20Upgradeable.sol"; import "../token/ERC20/extensions/IERC20MetadataUpgradeable.sol"; /** * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. * * _Available since v4.7._ */ interface IERC4626Upgradeable is IERC20Upgradeable, IERC20MetadataUpgradeable { event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); event Withdraw( address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /** * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. * * - MUST be an ERC-20 token contract. * - MUST NOT revert. */ function asset() external view returns (address assetTokenAddress); /** * @dev Returns the total amount of the underlying asset that is “managed” by Vault. * * - SHOULD include any compounding that occurs from yield. * - MUST be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT revert. */ function totalAssets() external view returns (uint256 totalManagedAssets); /** * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToShares(uint256 assets) external view returns (uint256 shares); /** * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToAssets(uint256 shares) external view returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, * through a deposit call. * * - MUST return a limited value if receiver is subject to some deposit limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. * - MUST NOT revert. */ function maxDeposit(address receiver) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given * current on-chain conditions. * * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called * in the same transaction. * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the * deposit would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewDeposit(uint256 assets) external view returns (uint256 shares); /** * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * deposit execution, and are accounted for during deposit. * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function deposit(uint256 assets, address receiver) external returns (uint256 shares); /** * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. * - MUST return a limited value if receiver is subject to some mint limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. * - MUST NOT revert. */ function maxMint(address receiver) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given * current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the * same transaction. * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint * would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by minting. */ function previewMint(uint256 shares) external view returns (uint256 assets); /** * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint * execution, and are accounted for during mint. * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function mint(uint256 shares, address receiver) external returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the * Vault, through a withdraw call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST NOT revert. */ function maxWithdraw(address owner) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, * given current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if * called * in the same transaction. * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though * the withdrawal would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewWithdraw(uint256 assets) external view returns (uint256 shares); /** * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * withdraw execution, and are accounted for during withdraw. * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function withdraw( uint256 assets, address receiver, address owner ) external returns (uint256 shares); /** * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, * through a redeem call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. * - MUST NOT revert. */ function maxRedeem(address owner) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, * given current on-chain conditions. * * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the * same transaction. * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the * redemption would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by redeeming. */ function previewRedeem(uint256 shares) external view returns (uint256 assets); /** * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * redeem execution, and are accounted for during redeem. * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function redeem( uint256 shares, address receiver, address owner ) external returns (uint256 assets); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../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; uint256 private _status; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20Upgradeable.sol"; import "./extensions/IERC20MetadataUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer( address from, address to, uint256 amount ) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[45] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.1) (token/ERC20/extensions/ERC4626.sol) pragma solidity ^0.8.0; import "../ERC20Upgradeable.sol"; import "../utils/SafeERC20Upgradeable.sol"; import "../../../interfaces/IERC4626Upgradeable.sol"; import "../../../utils/math/MathUpgradeable.sol"; import "../../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the ERC4626 "Tokenized Vault Standard" as defined in * https://eips.ethereum.org/EIPS/eip-4626[EIP-4626]. * * This extension allows the minting and burning of "shares" (represented using the ERC20 inheritance) in exchange for * underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends * the ERC20 standard. Any additional extensions included along it would affect the "shares" token represented by this * contract and not the "assets" token which is an independent contract. * * CAUTION: When the vault is empty or nearly empty, deposits are at high risk of being stolen through frontrunning with * a "donation" to the vault that inflates the price of a share. This is variously known as a donation or inflation * attack and is essentially a problem of slippage. Vault deployers can protect against this attack by making an initial * deposit of a non-trivial amount of the asset, such that price manipulation becomes infeasible. Withdrawals may * similarly be affected by slippage. Users can protect against this attack as well unexpected slippage in general by * verifying the amount received is as expected, using a wrapper that performs these checks such as * https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router]. * * _Available since v4.7._ */ abstract contract ERC4626Upgradeable is Initializable, ERC20Upgradeable, IERC4626Upgradeable { using MathUpgradeable for uint256; IERC20Upgradeable private _asset; uint8 private _decimals; /** * @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC20 or ERC777). */ function __ERC4626_init(IERC20Upgradeable asset_) internal onlyInitializing { __ERC4626_init_unchained(asset_); } function __ERC4626_init_unchained(IERC20Upgradeable asset_) internal onlyInitializing { (bool success, uint8 assetDecimals) = _tryGetAssetDecimals(asset_); _decimals = success ? assetDecimals : super.decimals(); _asset = asset_; } /** * @dev Attempts to fetch the asset decimals. A return value of false indicates that the attempt failed in some way. */ function _tryGetAssetDecimals(IERC20Upgradeable asset_) private view returns (bool, uint8) { (bool success, bytes memory encodedDecimals) = address(asset_).staticcall( abi.encodeWithSelector(IERC20MetadataUpgradeable.decimals.selector) ); if (success && encodedDecimals.length >= 32) { uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256)); if (returnedDecimals <= type(uint8).max) { return (true, uint8(returnedDecimals)); } } return (false, 0); } /** * @dev Decimals are read from the underlying asset in the constructor and cached. If this fails (e.g., the asset * has not been created yet), the cached value is set to a default obtained by `super.decimals()` (which depends on * inheritance but is most likely 18). Override this function in order to set a guaranteed hardcoded value. * See {IERC20Metadata-decimals}. */ function decimals() public view virtual override(IERC20MetadataUpgradeable, ERC20Upgradeable) returns (uint8) { return _decimals; } /** @dev See {IERC4626-asset}. */ function asset() public view virtual override returns (address) { return address(_asset); } /** @dev See {IERC4626-totalAssets}. */ function totalAssets() public view virtual override returns (uint256) { return _asset.balanceOf(address(this)); } /** @dev See {IERC4626-convertToShares}. */ function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) { return _convertToShares(assets, MathUpgradeable.Rounding.Down); } /** @dev See {IERC4626-convertToAssets}. */ function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) { return _convertToAssets(shares, MathUpgradeable.Rounding.Down); } /** @dev See {IERC4626-maxDeposit}. */ function maxDeposit(address) public view virtual override returns (uint256) { return _isVaultCollateralized() ? type(uint256).max : 0; } /** @dev See {IERC4626-maxMint}. */ function maxMint(address) public view virtual override returns (uint256) { return type(uint256).max; } /** @dev See {IERC4626-maxWithdraw}. */ function maxWithdraw(address owner) public view virtual override returns (uint256) { return _convertToAssets(balanceOf(owner), MathUpgradeable.Rounding.Down); } /** @dev See {IERC4626-maxRedeem}. */ function maxRedeem(address owner) public view virtual override returns (uint256) { return balanceOf(owner); } /** @dev See {IERC4626-previewDeposit}. */ function previewDeposit(uint256 assets) public view virtual override returns (uint256) { return _convertToShares(assets, MathUpgradeable.Rounding.Down); } /** @dev See {IERC4626-previewMint}. */ function previewMint(uint256 shares) public view virtual override returns (uint256) { return _convertToAssets(shares, MathUpgradeable.Rounding.Up); } /** @dev See {IERC4626-previewWithdraw}. */ function previewWithdraw(uint256 assets) public view virtual override returns (uint256) { return _convertToShares(assets, MathUpgradeable.Rounding.Up); } /** @dev See {IERC4626-previewRedeem}. */ function previewRedeem(uint256 shares) public view virtual override returns (uint256) { return _convertToAssets(shares, MathUpgradeable.Rounding.Down); } /** @dev See {IERC4626-deposit}. */ function deposit(uint256 assets, address receiver) public virtual override returns (uint256) { require(assets <= maxDeposit(receiver), "ERC4626: deposit more than max"); uint256 shares = previewDeposit(assets); _deposit(_msgSender(), receiver, assets, shares); return shares; } /** @dev See {IERC4626-mint}. * * As opposed to {deposit}, minting is allowed even if the vault is in a state where the price of a share is zero. * In this case, the shares will be minted without requiring any assets to be deposited. */ function mint(uint256 shares, address receiver) public virtual override returns (uint256) { require(shares <= maxMint(receiver), "ERC4626: mint more than max"); uint256 assets = previewMint(shares); _deposit(_msgSender(), receiver, assets, shares); return assets; } /** @dev See {IERC4626-withdraw}. */ function withdraw( uint256 assets, address receiver, address owner ) public virtual override returns (uint256) { require(assets <= maxWithdraw(owner), "ERC4626: withdraw more than max"); uint256 shares = previewWithdraw(assets); _withdraw(_msgSender(), receiver, owner, assets, shares); return shares; } /** @dev See {IERC4626-redeem}. */ function redeem( uint256 shares, address receiver, address owner ) public virtual override returns (uint256) { require(shares <= maxRedeem(owner), "ERC4626: redeem more than max"); uint256 assets = previewRedeem(shares); _withdraw(_msgSender(), receiver, owner, assets, shares); return assets; } /** * @dev Internal conversion function (from assets to shares) with support for rounding direction. * * Will revert if assets > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset * would represent an infinite amount of shares. */ function _convertToShares(uint256 assets, MathUpgradeable.Rounding rounding) internal view virtual returns (uint256 shares) { uint256 supply = totalSupply(); return (assets == 0 || supply == 0) ? _initialConvertToShares(assets, rounding) : assets.mulDiv(supply, totalAssets(), rounding); } /** * @dev Internal conversion function (from assets to shares) to apply when the vault is empty. * * NOTE: Make sure to keep this function consistent with {_initialConvertToAssets} when overriding it. */ function _initialConvertToShares( uint256 assets, MathUpgradeable.Rounding /*rounding*/ ) internal view virtual returns (uint256 shares) { return assets; } /** * @dev Internal conversion function (from shares to assets) with support for rounding direction. */ function _convertToAssets(uint256 shares, MathUpgradeable.Rounding rounding) internal view virtual returns (uint256 assets) { uint256 supply = totalSupply(); return (supply == 0) ? _initialConvertToAssets(shares, rounding) : shares.mulDiv(totalAssets(), supply, rounding); } /** * @dev Internal conversion function (from shares to assets) to apply when the vault is empty. * * NOTE: Make sure to keep this function consistent with {_initialConvertToShares} when overriding it. */ function _initialConvertToAssets( uint256 shares, MathUpgradeable.Rounding /*rounding*/ ) internal view virtual returns (uint256 assets) { return shares; } /** * @dev Deposit/mint common workflow. */ function _deposit( address caller, address receiver, uint256 assets, uint256 shares ) internal virtual { // If _asset is ERC777, `transferFrom` can trigger a reenterancy BEFORE the transfer happens through the // `tokensToSend` hook. On the other hand, the `tokenReceived` hook, that is triggered after the transfer, // calls the vault, which is assumed not malicious. // // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the // assets are transferred and before the shares are minted, which is a valid state. // slither-disable-next-line reentrancy-no-eth SafeERC20Upgradeable.safeTransferFrom(_asset, caller, address(this), assets); _mint(receiver, shares); emit Deposit(caller, receiver, assets, shares); } /** * @dev Withdraw/redeem common workflow. */ function _withdraw( address caller, address receiver, address owner, uint256 assets, uint256 shares ) internal virtual { if (caller != owner) { _spendAllowance(owner, caller, shares); } // If _asset is ERC777, `transfer` can trigger a reentrancy AFTER the transfer happens through the // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer, // calls the vault, which is assumed not malicious. // // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the // shares are burned and after the assets are transferred, which is a valid state. _burn(owner, shares); SafeERC20Upgradeable.safeTransfer(_asset, receiver, assets); emit Withdraw(caller, receiver, owner, assets, shares); } /** * @dev Checks if vault is "healthy" in the sense of having assets backing the circulating shares. */ function _isVaultCollateralized() private view returns (bool) { return totalAssets() > 0 || totalSupply() == 0; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20MetadataUpgradeable is IERC20Upgradeable { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20PermitUpgradeable { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; import "../extensions/draft-IERC20PermitUpgradeable.sol"; import "../../../utils/AddressUpgradeable.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 SafeERC20Upgradeable { using AddressUpgradeable for address; function safeTransfer( IERC20Upgradeable token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20Upgradeable token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20Upgradeable token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20Upgradeable token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20Upgradeable token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20PermitUpgradeable token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (proxy/Clones.sol) pragma solidity ^0.8.0; /** * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for * deploying minimal proxy contracts, also known as "clones". * * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies * > a minimal bytecode implementation that delegates all calls to a known, fixed address. * * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the * deterministic method. * * _Available since v3.4._ */ library Clones { /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create opcode, which should never revert. */ function clone(address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes // of the `implementation` address with the bytecode before the address. mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) instance := create(0, 0x09, 0x37) } require(instance != address(0), "ERC1167: create failed"); } /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create2 opcode and a `salt` to deterministically deploy * the clone. Using the same `implementation` and `salt` multiple time will revert, since * the clones cannot be deployed twice at the same address. */ function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes // of the `implementation` address with the bytecode before the address. mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) instance := create2(0, 0x09, 0x37, salt) } require(instance != address(0), "ERC1167: create2 failed"); } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(add(ptr, 0x38), deployer) mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff) mstore(add(ptr, 0x14), implementation) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73) mstore(add(ptr, 0x58), salt) mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37)) predicted := keccak256(add(ptr, 0x43), 0x55) } } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress(address implementation, bytes32 salt) internal view returns (address predicted) { return predictDeterministicAddress(implementation, salt, address(this)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // Disclaimer https://github.com/hats-finance/hats-contracts/blob/main/DISCLAIMER.md pragma solidity 0.8.16; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./tokenlock/TokenLockFactory.sol"; import "./interfaces/IHATVault.sol"; import "./interfaces/IRewardController.sol"; import "./HATVaultsRegistry.sol"; /** @title A Hats.finance vault which holds the funds for a specific project's * bug bounties * @author Hats.finance * @notice The HATVault can be deposited into in a permissionless manner using * the vault’s native token. When a bug is submitted and approved, the bounty * is paid out using the funds in the vault. Bounties are paid out as a * percentage of the vault. The percentage is set according to the severity of * the bug. Vaults have regular safety periods (typically for an hour twice a * day) which are time for the committee to make decisions. * * In addition to the roles defined in the HATVaultsRegistry, every HATVault * has the roles: * Committee - The only address which can submit a claim for a bounty payout * and set the maximum bounty. * User - Anyone can deposit the vault's native token into the vault and * recieve shares for it. Shares represent the user's relative part in the * vault, and when a bounty is paid out, users lose part of their deposits * (based on percentage paid), but keep their share of the vault. * Users also receive rewards for their deposits, which can be claimed at any * time. * To withdraw previously deposited tokens, a user must first send a withdraw * request, and the withdrawal will be made available after a pending period. * Withdrawals are not permitted during safety periods or while there is an * active claim for a bounty payout. * * Bounties are payed out distributed between a few channels, and that * distribution is set upon creation (the hacker gets part in direct transfer, * part in vested reward and part in vested HAT token, part gets rewarded to * the committee, part gets swapped to HAT token and burned and/or sent to Hats * governance). * * This project is open-source and can be found at: * https://github.com/hats-finance/hats-contracts */ contract HATVault is IHATVault, ERC4626Upgradeable, OwnableUpgradeable, ReentrancyGuardUpgradeable { using SafeERC20 for IERC20; using MathUpgradeable for uint256; struct Claim { bytes32 claimId; address beneficiary; uint16 bountyPercentage; // the address of the committee at the time of the submission, so that this committee will // be paid their share of the bounty in case the committee changes before claim approval address committee; uint32 createdAt; uint32 challengedAt; uint256 bountyGovernanceHAT; uint256 bountyHackerHATVested; address arbitrator; uint32 challengePeriod; uint32 challengeTimeOutPeriod; bool arbitratorCanChangeBounty; } struct PendingMaxBounty { uint16 maxBounty; uint32 timestamp; } uint256 public constant MAX_UINT = type(uint256).max; uint16 public constant NULL_UINT16 = type(uint16).max; uint32 public constant NULL_UINT32 = type(uint32).max; address public constant NULL_ADDRESS = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF; uint256 public constant HUNDRED_PERCENT = 1e4; uint256 public constant HUNDRED_PERCENT_SQRD = 1e8; uint256 public constant MAX_BOUNTY_LIMIT = 90e2; // Max bounty can be up to 90% uint256 public constant MAX_WITHDRAWAL_FEE = 2e2; // Max fee is 2% uint256 public constant MAX_COMMITTEE_BOUNTY = 10e2; // Max committee bounty can be up to 10% uint256 public constant MINIMAL_AMOUNT_OF_SHARES = 1e3; // to reduce rounding errors, the number of shares is either 0, or > than this number HATVaultsRegistry public registry; ITokenLockFactory public tokenLockFactory; Claim public activeClaim; IRewardController[] public rewardControllers; IHATVault.BountySplit public bountySplit; uint16 public maxBounty; uint32 public vestingDuration; uint32 public vestingPeriods; address public committee; bool public committeeCheckedIn; bool public depositPause; uint256 public withdrawalFee; uint256 internal nonce; PendingMaxBounty public pendingMaxBounty; // Time of when withdrawal period starts for every user that has an // active withdraw request. (time when last withdraw request pending // period ended, or 0 if last action was deposit or withdraw) mapping(address => uint256) public withdrawEnableStartTime; // the percentage of the total bounty to be swapped to HATs and sent to governance (out of {HUNDRED_PERCENT}) uint16 internal bountyGovernanceHAT; // the percentage of the total bounty to be swapped to HATs and sent to the hacker via vesting contract (out of {HUNDRED_PERCENT}) uint16 internal bountyHackerHATVested; // address of the arbitrator - which can dispute claims and override the committee's decisions address internal arbitrator; // time during which a claim can be challenged by the arbitrator uint32 internal challengePeriod; // time after which a challenged claim is automatically dismissed uint32 internal challengeTimeOutPeriod; // whether the arbitrator can change bounty of claims ArbitratorCanChangeBounty internal arbitratorCanChangeBounty; bool private _isEmergencyWithdraw; modifier onlyRegistryOwner() { if (registry.owner() != msg.sender) revert OnlyRegistryOwner(); _; } modifier onlyFeeSetter() { if (registry.feeSetter() != msg.sender) revert OnlyFeeSetter(); _; } modifier onlyCommittee() { if (committee != msg.sender) revert OnlyCommittee(); _; } modifier notEmergencyPaused() { if (registry.isEmergencyPaused()) revert SystemInEmergencyPause(); _; } modifier noSafetyPeriod() { uint256 _withdrawPeriod = registry.getWithdrawPeriod(); // disable withdraw for safetyPeriod (e.g 1 hour) after each withdrawPeriod(e.g 11 hours) // solhint-disable-next-line not-rely-on-time if (block.timestamp % (_withdrawPeriod + registry.getSafetyPeriod()) >= _withdrawPeriod) revert SafetyPeriod(); _; } modifier noActiveClaim() { if (activeClaim.createdAt != 0) revert ActiveClaimExists(); _; } modifier isActiveClaim(bytes32 _claimId) { if (activeClaim.createdAt == 0) revert NoActiveClaimExists(); if (activeClaim.claimId != _claimId) revert ClaimIdIsNotActive(); _; } /** @notice See {IHATVault-initialize}. */ function initialize(IHATVault.VaultInitParams calldata _params) external initializer { if (_params.maxBounty > MAX_BOUNTY_LIMIT) revert MaxBountyCannotBeMoreThanMaxBountyLimit(); _validateSplit(_params.bountySplit); __ERC20_init(string.concat("Hats Vault ", _params.name), string.concat("HAT", _params.symbol)); __ERC4626_init(IERC20MetadataUpgradeable(address(_params.asset))); rewardControllers = _params.rewardControllers; _setVestingParams(_params.vestingDuration, _params.vestingPeriods); HATVaultsRegistry _registry = HATVaultsRegistry(msg.sender); maxBounty = _params.maxBounty; bountySplit = _params.bountySplit; committee = _params.committee; depositPause = _params.isPaused; registry = _registry; __ReentrancyGuard_init(); _transferOwnership(_params.owner); tokenLockFactory = _registry.tokenLockFactory(); // Set vault to use default registry values where applicable arbitrator = NULL_ADDRESS; bountyGovernanceHAT = NULL_UINT16; bountyHackerHATVested = NULL_UINT16; arbitratorCanChangeBounty = ArbitratorCanChangeBounty.DEFAULT; challengePeriod = NULL_UINT32; challengeTimeOutPeriod = NULL_UINT32; emit SetVaultDescription(_params.descriptionHash); } /* ---------------------------------- Claim --------------------------------------- */ /** @notice See {IHATVault-submitClaim}. */ function submitClaim(address _beneficiary, uint16 _bountyPercentage, string calldata _descriptionHash) external onlyCommittee noActiveClaim notEmergencyPaused returns (bytes32 claimId) { HATVaultsRegistry _registry = registry; uint256 withdrawPeriod = _registry.getWithdrawPeriod(); // require we are in safetyPeriod // solhint-disable-next-line not-rely-on-time if (block.timestamp % (withdrawPeriod + _registry.getSafetyPeriod()) < withdrawPeriod) revert NotSafetyPeriod(); if (_bountyPercentage > maxBounty) revert BountyPercentageHigherThanMaxBounty(); claimId = keccak256(abi.encodePacked(address(this), ++nonce)); activeClaim = Claim({ claimId: claimId, beneficiary: _beneficiary, bountyPercentage: _bountyPercentage, committee: msg.sender, // solhint-disable-next-line not-rely-on-time createdAt: uint32(block.timestamp), challengedAt: 0, bountyGovernanceHAT: getBountyGovernanceHAT(), bountyHackerHATVested: getBountyHackerHATVested(), arbitrator: getArbitrator(), challengePeriod: getChallengePeriod(), challengeTimeOutPeriod: getChallengeTimeOutPeriod(), arbitratorCanChangeBounty: getArbitratorCanChangeBounty() }); emit SubmitClaim( claimId, msg.sender, _beneficiary, _bountyPercentage, _descriptionHash ); } function challengeClaim(bytes32 _claimId) external isActiveClaim(_claimId) { if (msg.sender != activeClaim.arbitrator && msg.sender != registry.owner()) revert OnlyArbitratorOrRegistryOwner(); // solhint-disable-next-line not-rely-on-time if (block.timestamp >= activeClaim.createdAt + activeClaim.challengePeriod) revert ChallengePeriodEnded(); if (activeClaim.challengedAt != 0) { revert ClaimAlreadyChallenged(); } // solhint-disable-next-line not-rely-on-time activeClaim.challengedAt = uint32(block.timestamp); emit ChallengeClaim(_claimId); } /** @notice See {IHATVault-approveClaim}. */ function approveClaim(bytes32 _claimId, uint16 _bountyPercentage) external nonReentrant isActiveClaim(_claimId) { Claim memory _claim = activeClaim; delete activeClaim; // solhint-disable-next-line not-rely-on-time if (block.timestamp >= _claim.createdAt + _claim.challengePeriod + _claim.challengeTimeOutPeriod) { // cannot approve an expired claim revert ClaimExpired(); } if (_claim.challengedAt != 0) { // the claim was challenged, and only the arbitrator can approve it, within the timeout period if ( msg.sender != _claim.arbitrator || // solhint-disable-next-line not-rely-on-time block.timestamp >= _claim.challengedAt + _claim.challengeTimeOutPeriod ) revert ChallengedClaimCanOnlyBeApprovedByArbitratorUntilChallengeTimeoutPeriod(); // the arbitrator can update the bounty if needed if (_claim.arbitratorCanChangeBounty && _bountyPercentage != 0) { _claim.bountyPercentage = _bountyPercentage; } } else { // the claim can be approved by anyone if the challengePeriod passed without a challenge if ( // solhint-disable-next-line not-rely-on-time block.timestamp <= _claim.createdAt + _claim.challengePeriod ) revert UnchallengedClaimCanOnlyBeApprovedAfterChallengePeriod(); } address tokenLock; IHATVault.ClaimBounty memory claimBounty = _calcClaimBounty( _claim.bountyPercentage, _claim.bountyGovernanceHAT, _claim.bountyHackerHATVested ); IERC20 _asset = IERC20(asset()); if (claimBounty.hackerVested > 0) { //hacker gets part of bounty to a vesting contract tokenLock = tokenLockFactory.createTokenLock( address(_asset), 0x0000000000000000000000000000000000000000, //this address as owner, so it can do nothing. _claim.beneficiary, claimBounty.hackerVested, // solhint-disable-next-line not-rely-on-time block.timestamp, //start // solhint-disable-next-line not-rely-on-time block.timestamp + vestingDuration, //end vestingPeriods, 0, //no release start 0, //no cliff ITokenLock.Revocability.Disabled, false ); _asset.safeTransfer(tokenLock, claimBounty.hackerVested); } _asset.safeTransfer(_claim.beneficiary, claimBounty.hacker); _asset.safeTransfer(_claim.committee, claimBounty.committee); // send to the registry the amount of tokens which should be swapped // to HAT so it could call swapAndSend in a separate tx. HATVaultsRegistry _registry = registry; _asset.safeApprove(address(_registry), claimBounty.hackerHatVested + claimBounty.governanceHat); _registry.addTokensToSwap( _asset, _claim.beneficiary, claimBounty.hackerHatVested, claimBounty.governanceHat ); // make sure to reset approval _asset.safeApprove(address(_registry), 0); emit ApproveClaim( _claimId, msg.sender, _claim.beneficiary, _claim.bountyPercentage, tokenLock, claimBounty ); } /** @notice See {IHATVault-dismissClaim}. */ function dismissClaim(bytes32 _claimId) external isActiveClaim(_claimId) { uint256 _challengeTimeOutPeriod = activeClaim.challengeTimeOutPeriod; uint256 _challengedAt = activeClaim.challengedAt; // solhint-disable-next-line not-rely-on-time if (block.timestamp <= activeClaim.createdAt + activeClaim.challengePeriod + _challengeTimeOutPeriod) { if (_challengedAt == 0) revert OnlyCallableIfChallenged(); if ( // solhint-disable-next-line not-rely-on-time block.timestamp <= _challengedAt + _challengeTimeOutPeriod && msg.sender != activeClaim.arbitrator ) revert OnlyCallableByArbitratorOrAfterChallengeTimeOutPeriod(); } // else the claim is expired and should be dismissed delete activeClaim; emit DismissClaim(_claimId); } /* -------------------------------------------------------------------------------- */ /* ---------------------------------- Params -------------------------------------- */ /** @notice See {IHATVault-setCommittee}. */ function setCommittee(address _committee) external { // vault owner can update committee only if committee was not checked in yet. if (msg.sender == owner() && committee != msg.sender) { if (committeeCheckedIn) revert CommitteeAlreadyCheckedIn(); } else { if (committee != msg.sender) revert OnlyCommittee(); } committee = _committee; emit SetCommittee(_committee); } /** @notice See {IHATVault-setVestingParams}. */ function setVestingParams(uint32 _duration, uint32 _periods) external onlyOwner { _setVestingParams(_duration, _periods); } /** @notice See {IHATVault-setBountySplit}. */ function setBountySplit(IHATVault.BountySplit calldata _bountySplit) external onlyOwner noActiveClaim noSafetyPeriod { _validateSplit(_bountySplit); bountySplit = _bountySplit; emit SetBountySplit(_bountySplit); } /** @notice See {IHATVault-setWithdrawalFee}. */ function setWithdrawalFee(uint256 _fee) external onlyFeeSetter { if (_fee > MAX_WITHDRAWAL_FEE) revert WithdrawalFeeTooBig(); withdrawalFee = _fee; emit SetWithdrawalFee(_fee); } /** @notice See {IHATVault-committeeCheckIn}. */ function committeeCheckIn() external onlyCommittee { committeeCheckedIn = true; emit CommitteeCheckedIn(); } /** @notice See {IHATVault-setPendingMaxBounty}. */ function setPendingMaxBounty(uint16 _maxBounty) external onlyOwner noActiveClaim { if (_maxBounty > MAX_BOUNTY_LIMIT) revert MaxBountyCannotBeMoreThanMaxBountyLimit(); pendingMaxBounty.maxBounty = _maxBounty; // solhint-disable-next-line not-rely-on-time pendingMaxBounty.timestamp = uint32(block.timestamp); emit SetPendingMaxBounty(_maxBounty); } /** @notice See {IHATVault-setMaxBounty}. */ function setMaxBounty() external onlyOwner noActiveClaim { PendingMaxBounty memory _pendingMaxBounty = pendingMaxBounty; if (_pendingMaxBounty.timestamp == 0) revert NoPendingMaxBounty(); // solhint-disable-next-line not-rely-on-time if (block.timestamp - _pendingMaxBounty.timestamp < registry.getSetMaxBountyDelay()) revert DelayPeriodForSettingMaxBountyHadNotPassed(); uint16 _maxBounty = pendingMaxBounty.maxBounty; maxBounty = _maxBounty; delete pendingMaxBounty; emit SetMaxBounty(_maxBounty); } /** @notice See {IHATVault-setDepositPause}. */ function setDepositPause(bool _depositPause) external onlyOwner { depositPause = _depositPause; emit SetDepositPause(_depositPause); } /** @notice See {IHATVault-setVaultDescription}. */ function setVaultDescription(string calldata _descriptionHash) external onlyRegistryOwner { emit SetVaultDescription(_descriptionHash); } /** @notice See {IHATVault-addRewardController}. */ function addRewardController(IRewardController _rewardController) external onlyRegistryOwner noActiveClaim { for (uint256 i = 0; i < rewardControllers.length;) { if (_rewardController == rewardControllers[i]) revert DuplicatedRewardController(); unchecked { ++i; } } rewardControllers.push(_rewardController); emit AddRewardController(_rewardController); } /** @notice See {IHATVault-setHATBountySplit}. */ function setHATBountySplit(uint16 _bountyGovernanceHAT, uint16 _bountyHackerHATVested) external onlyRegistryOwner { bountyGovernanceHAT = _bountyGovernanceHAT; bountyHackerHATVested = _bountyHackerHATVested; registry.validateHATSplit(getBountyGovernanceHAT(), getBountyHackerHATVested()); emit SetHATBountySplit(_bountyGovernanceHAT, _bountyHackerHATVested); } /** @notice See {IHATVault-setArbitrator}. */ function setArbitrator(address _arbitrator) external onlyRegistryOwner { arbitrator = _arbitrator; emit SetArbitrator(_arbitrator); } /** @notice See {IHATVault-setChallengePeriod}. */ function setChallengePeriod(uint32 _challengePeriod) external onlyRegistryOwner { if (_challengePeriod != NULL_UINT32) { registry.validateChallengePeriod(_challengePeriod); } challengePeriod = _challengePeriod; emit SetChallengePeriod(_challengePeriod); } /** @notice See {IHATVault-setChallengeTimeOutPeriod}. */ function setChallengeTimeOutPeriod(uint32 _challengeTimeOutPeriod) external onlyRegistryOwner { if (_challengeTimeOutPeriod != NULL_UINT32) { registry.validateChallengeTimeOutPeriod(_challengeTimeOutPeriod); } challengeTimeOutPeriod = _challengeTimeOutPeriod; emit SetChallengeTimeOutPeriod(_challengeTimeOutPeriod); } /** @notice See {IHATVault-setArbitratorCanChangeBounty}. */ function setArbitratorCanChangeBounty(ArbitratorCanChangeBounty _arbitratorCanChangeBounty) external onlyRegistryOwner { arbitratorCanChangeBounty = _arbitratorCanChangeBounty; emit SetArbitratorCanChangeBounty(_arbitratorCanChangeBounty); } /* -------------------------------------------------------------------------------- */ /* ---------------------------------- Vault --------------------------------------- */ /** @notice See {IHATVault-withdrawRequest}. */ function withdrawRequest() external nonReentrant { // set the withdrawEnableStartTime time to be withdrawRequestPendingPeriod from now // solhint-disable-next-line not-rely-on-time uint256 _withdrawEnableStartTime = block.timestamp + registry.getWithdrawRequestPendingPeriod(); address msgSender = _msgSender(); withdrawEnableStartTime[msgSender] = _withdrawEnableStartTime; emit WithdrawRequest(msgSender, _withdrawEnableStartTime); } /** @notice See {IHATVault-withdrawAndClaim}. */ function withdrawAndClaim(uint256 assets, address receiver, address owner) external returns (uint256 shares) { shares = withdraw(assets, receiver, owner); for (uint256 i = 0; i < rewardControllers.length;) { rewardControllers[i].claimReward(address(this), owner); unchecked { ++i; } } } /** @notice See {IHATVault-redeemAndClaim}. */ function redeemAndClaim(uint256 shares, address receiver, address owner) external returns (uint256 assets) { assets = redeem(shares, receiver, owner); for (uint256 i = 0; i < rewardControllers.length;) { rewardControllers[i].claimReward(address(this), owner); unchecked { ++i; } } } /** @notice See {IHATVault-emergencyWithdraw}. */ function emergencyWithdraw(address receiver) external returns (uint256 assets) { _isEmergencyWithdraw = true; address msgSender = _msgSender(); assets = redeem(balanceOf(msgSender), receiver, msgSender); _isEmergencyWithdraw = false; } /** @notice See {IHATVault-withdraw}. */ function withdraw(uint256 assets, address receiver, address owner) public override(IHATVault, ERC4626Upgradeable) virtual returns (uint256) { (uint256 _shares, uint256 _fee) = previewWithdrawAndFee(assets); _withdraw(_msgSender(), receiver, owner, assets, _shares, _fee); return _shares; } /** @notice See {IHATVault-redeem}. */ function redeem(uint256 shares, address receiver, address owner) public override(IHATVault, ERC4626Upgradeable) virtual returns (uint256) { (uint256 _assets, uint256 _fee) = previewRedeemAndFee(shares); _withdraw(_msgSender(), receiver, owner, _assets, shares, _fee); return _assets; } /** @notice See {IHATVault-deposit}. */ function deposit(uint256 assets, address receiver) public override(IHATVault, ERC4626Upgradeable) virtual returns (uint256) { return super.deposit(assets, receiver); } /** @notice See {IHATVault-withdraw}. */ function withdraw(uint256 assets, address receiver, address owner, uint256 maxShares) public virtual returns (uint256) { uint256 shares = withdraw(assets, receiver, owner); if (shares > maxShares) revert WithdrawSlippageProtection(); return shares; } /** @notice See {IHATVault-redeem}. */ function redeem(uint256 shares, address receiver, address owner, uint256 minAssets) public virtual returns (uint256) { uint256 assets = redeem(shares, receiver, owner); if (assets < minAssets) revert RedeemSlippageProtection(); return assets; } /** @notice See {IHATVault-withdrawAndClaim}. */ function withdrawAndClaim(uint256 assets, address receiver, address owner, uint256 maxShares) external returns (uint256 shares) { shares = withdraw(assets, receiver, owner, maxShares); for (uint256 i = 0; i < rewardControllers.length;) { rewardControllers[i].claimReward(address(this), owner); unchecked { ++i; } } } /** @notice See {IHATVault-redeemAndClaim}. */ function redeemAndClaim(uint256 shares, address receiver, address owner, uint256 minAssets) external returns (uint256 assets) { assets = redeem(shares, receiver, owner, minAssets); for (uint256 i = 0; i < rewardControllers.length;) { rewardControllers[i].claimReward(address(this), owner); unchecked { ++i; } } } /** @notice See {IHATVault-deposit}. */ function deposit(uint256 assets, address receiver, uint256 minShares) external virtual returns (uint256) { uint256 shares = deposit(assets, receiver); if (shares < minShares) revert DepositSlippageProtection(); return shares; } /** @notice See {IHATVault-mint}. */ function mint(uint256 shares, address receiver, uint256 maxAssets) external virtual returns (uint256) { uint256 assets = mint(shares, receiver); if (assets > maxAssets) revert MintSlippageProtection(); return assets; } /** @notice See {IERC4626Upgradeable-maxDeposit}. */ function maxDeposit(address) public view virtual override(IERC4626Upgradeable, ERC4626Upgradeable) returns (uint256) { return depositPause ? 0 : MAX_UINT; } /** @notice See {IERC4626Upgradeable-maxMint}. */ function maxMint(address) public view virtual override(IERC4626Upgradeable, ERC4626Upgradeable) returns (uint256) { return depositPause ? 0 : MAX_UINT; } /** @notice See {IERC4626Upgradeable-maxWithdraw}. */ function maxWithdraw(address owner) public view virtual override(IERC4626Upgradeable, ERC4626Upgradeable) returns (uint256) { if (activeClaim.createdAt != 0 || !_isWithdrawEnabledForUser(owner)) return 0; return previewRedeem(balanceOf(owner)); } /** @notice See {IERC4626Upgradeable-maxRedeem}. */ function maxRedeem(address owner) public view virtual override(IERC4626Upgradeable, ERC4626Upgradeable) returns (uint256) { if (activeClaim.createdAt != 0 || !_isWithdrawEnabledForUser(owner)) return 0; return balanceOf(owner); } /** @notice See {IERC4626Upgradeable-previewWithdraw}. */ function previewWithdraw(uint256 assets) public view virtual override(IERC4626Upgradeable, ERC4626Upgradeable) returns (uint256 shares) { (shares,) = previewWithdrawAndFee(assets); } /** @notice See {IERC4626Upgradeable-previewRedeem}. */ function previewRedeem(uint256 shares) public view virtual override(IERC4626Upgradeable, ERC4626Upgradeable) returns (uint256 assets) { (assets,) = previewRedeemAndFee(shares); } /** @notice See {IHATVault-previewWithdrawAndFee}. */ function previewWithdrawAndFee(uint256 assets) public view returns (uint256 shares, uint256 fee) { uint256 _withdrawalFee = withdrawalFee; fee = assets.mulDiv(_withdrawalFee, (HUNDRED_PERCENT - _withdrawalFee)); shares = _convertToShares(assets + fee, MathUpgradeable.Rounding.Up); } /** @notice See {IHATVault-previewRedeemAndFee}. */ function previewRedeemAndFee(uint256 shares) public view returns (uint256 assets, uint256 fee) { uint256 _assetsPlusFee = _convertToAssets(shares, MathUpgradeable.Rounding.Down); fee = _assetsPlusFee.mulDiv(withdrawalFee, HUNDRED_PERCENT); unchecked { // fee will always be maximun 20% of _assetsPlusFee assets = _assetsPlusFee - fee; } } /* -------------------------------------------------------------------------------- */ /* --------------------------------- Getters -------------------------------------- */ /** @notice See {IHATVault-getBountyGovernanceHAT}. */ function getBountyGovernanceHAT() public view returns(uint16) { uint16 _bountyGovernanceHAT = bountyGovernanceHAT; if (_bountyGovernanceHAT != NULL_UINT16) { return _bountyGovernanceHAT; } else { return registry.defaultBountyGovernanceHAT(); } } /** @notice See {IHATVault-getBountyHackerHATVested}. */ function getBountyHackerHATVested() public view returns(uint16) { uint16 _bountyHackerHATVested = bountyHackerHATVested; if (_bountyHackerHATVested != NULL_UINT16) { return _bountyHackerHATVested; } else { return registry.defaultBountyHackerHATVested(); } } /** @notice See {IHATVault-getArbitrator}. */ function getArbitrator() public view returns(address) { address _arbitrator = arbitrator; if (_arbitrator != NULL_ADDRESS) { return _arbitrator; } else { return registry.defaultArbitrator(); } } /** @notice See {IHATVault-getChallengePeriod}. */ function getChallengePeriod() public view returns(uint32) { uint32 _challengePeriod = challengePeriod; if (_challengePeriod != NULL_UINT32) { return _challengePeriod; } else { return registry.defaultChallengePeriod(); } } /** @notice See {IHATVault-getChallengeTimeOutPeriod}. */ function getChallengeTimeOutPeriod() public view returns(uint32) { uint32 _challengeTimeOutPeriod = challengeTimeOutPeriod; if (_challengeTimeOutPeriod != NULL_UINT32) { return _challengeTimeOutPeriod; } else { return registry.defaultChallengeTimeOutPeriod(); } } /** @notice See {IHATVault-getArbitratorCanChangeBounty}. */ function getArbitratorCanChangeBounty() public view returns(bool) { ArbitratorCanChangeBounty _arbitratorCanChangeBounty = arbitratorCanChangeBounty; if (_arbitratorCanChangeBounty != ArbitratorCanChangeBounty.DEFAULT) { return _arbitratorCanChangeBounty == ArbitratorCanChangeBounty.YES; } else { return registry.defaultArbitratorCanChangeBounty(); } } /* -------------------------------------------------------------------------------- */ /* --------------------------------- Helpers -------------------------------------- */ /** * @dev Deposit funds to the vault. Can only be called if the committee had * checked in and deposits are not paused. * @param caller Caller of the action (msg.sender) * @param receiver Reciever of the shares from the deposit * @param assets Amount of vault's native token to deposit * @param shares Respective amount of shares to be received */ function _deposit( address caller, address receiver, uint256 assets, uint256 shares ) internal override virtual nonReentrant { if (!committeeCheckedIn) revert CommitteeNotCheckedInYet(); if (receiver == caller && withdrawEnableStartTime[receiver] != 0 ) { // clear withdraw request if caller deposits in her own account withdrawEnableStartTime[receiver] = 0; } super._deposit(caller, receiver, assets, shares); } // amount of shares correspond with assets + fee function _withdraw( address _caller, address _receiver, address _owner, uint256 _assets, uint256 _shares, uint256 _fee ) internal nonReentrant { if (_assets == 0) revert WithdrawMustBeGreaterThanZero(); if (_caller != _owner) { _spendAllowance(_owner, _caller, _shares); } _burn(_owner, _shares); IERC20 _asset = IERC20(asset()); if (_fee > 0) { _asset.safeTransfer(registry.owner(), _fee); } _asset.safeTransfer(_receiver, _assets); emit Withdraw(_caller, _receiver, _owner, _assets, _shares); } function _beforeTokenTransfer( address _from, address _to, uint256 _amount ) internal virtual override { if (_amount == 0) revert AmountCannotBeZero(); if (_from == _to) revert CannotTransferToSelf(); // deposit/mint/transfer if (_to != address(0)) { HATVaultsRegistry _registry = registry; if (_registry.isEmergencyPaused()) revert SystemInEmergencyPause(); // Cannot transfer or mint tokens to a user for which an active withdraw request exists // because then we would need to reset their withdraw request uint256 _withdrawEnableStartTime = withdrawEnableStartTime[_to]; if (_withdrawEnableStartTime != 0) { // solhint-disable-next-line not-rely-on-time if (block.timestamp <= _withdrawEnableStartTime + _registry.getWithdrawRequestEnablePeriod()) revert CannotTransferToAnotherUserWithActiveWithdrawRequest(); } for (uint256 i = 0; i < rewardControllers.length;) { rewardControllers[i].commitUserBalance(_to, _amount, true); unchecked { ++i; } } } // withdraw/redeem/transfer if (_from != address(0)) { if (_amount > maxRedeem(_from)) revert RedeemMoreThanMax(); // if all is ok and withdrawal can be made - // reset withdrawRequests[_pid][msg.sender] so that another withdrawRequest // will have to be made before next withdrawal withdrawEnableStartTime[_from] = 0; if (!_isEmergencyWithdraw) { for (uint256 i = 0; i < rewardControllers.length;) { rewardControllers[i].commitUserBalance(_from, _amount, false); unchecked { ++i; } } } } } function _afterTokenTransfer(address, address, uint256) internal virtual override { if (totalSupply() > 0 && totalSupply() < MINIMAL_AMOUNT_OF_SHARES) { revert AmountOfSharesMustBeMoreThanMinimalAmount(); } } function _setVestingParams(uint32 _duration, uint32 _periods) internal { if (_duration > 120 days) revert VestingDurationTooLong(); if (_periods == 0) revert VestingPeriodsCannotBeZero(); if (_duration < _periods) revert VestingDurationSmallerThanPeriods(); vestingDuration = _duration; vestingPeriods = _periods; emit SetVestingParams(_duration, _periods); } /** * @dev Checks that the given user can perform a withdraw at this time * @param _user Address of the user to check */ function _isWithdrawEnabledForUser(address _user) internal view returns(bool) { HATVaultsRegistry _registry = registry; uint256 _withdrawPeriod = _registry.getWithdrawPeriod(); // disable withdraw for safetyPeriod (e.g 1 hour) after each withdrawPeriod (e.g 11 hours) // solhint-disable-next-line not-rely-on-time if (block.timestamp % (_withdrawPeriod + _registry.getSafetyPeriod()) >= _withdrawPeriod) return false; // check that withdrawRequestPendingPeriod had passed uint256 _withdrawEnableStartTime = withdrawEnableStartTime[_user]; // solhint-disable-next-line not-rely-on-time return (block.timestamp >= _withdrawEnableStartTime && // check that withdrawRequestEnablePeriod had not passed and that the // last action was withdrawRequest (and not deposit or withdraw, which // reset withdrawRequests[_user] to 0) // solhint-disable-next-line not-rely-on-time block.timestamp <= _withdrawEnableStartTime + _registry.getWithdrawRequestEnablePeriod()); } /** * @dev calculate the specific bounty payout distribution, according to the * predefined bounty split and the given bounty percentage * @param _bountyPercentage The percentage of the vault's funds to be paid * out as bounty * @param _bountyGovernanceHAT The bountyGovernanceHAT at the time the claim was submitted * @param _bountyHackerHATVested The bountyHackerHATVested at the time the claim was submitted * @return claimBounty The bounty distribution for this specific claim */ function _calcClaimBounty( uint256 _bountyPercentage, uint256 _bountyGovernanceHAT, uint256 _bountyHackerHATVested ) internal view returns(IHATVault.ClaimBounty memory claimBounty) { uint256 _totalAssets = totalAssets(); if (_totalAssets == 0) { return claimBounty; } if (_bountyPercentage > maxBounty) revert BountyPercentageHigherThanMaxBounty(); uint256 _totalBountyAmount = _totalAssets * _bountyPercentage; uint256 _governanceHatAmount = _totalBountyAmount.mulDiv(_bountyGovernanceHAT, HUNDRED_PERCENT_SQRD); uint256 _hackerHatVestedAmount = _totalBountyAmount.mulDiv(_bountyHackerHATVested, HUNDRED_PERCENT_SQRD); _totalBountyAmount -= (_governanceHatAmount + _hackerHatVestedAmount) * HUNDRED_PERCENT; claimBounty.governanceHat = _governanceHatAmount; claimBounty.hackerHatVested = _hackerHatVestedAmount; uint256 _hackerVestedAmount = _totalBountyAmount.mulDiv(bountySplit.hackerVested, HUNDRED_PERCENT_SQRD); uint256 _hackerAmount = _totalBountyAmount.mulDiv(bountySplit.hacker, HUNDRED_PERCENT_SQRD); _totalBountyAmount -= (_hackerVestedAmount + _hackerAmount) * HUNDRED_PERCENT; claimBounty.hackerVested = _hackerVestedAmount; claimBounty.hacker = _hackerAmount; // give all the tokens left to the committee to avoid rounding errors claimBounty.committee = _totalBountyAmount / HUNDRED_PERCENT; } /** * @dev Check that a given bounty split is legal, meaning that: * Each entry is a number between 0 and `HUNDRED_PERCENT`. * Except committee part which is capped at maximum of * `MAX_COMMITTEE_BOUNTY`. * Total splits should be equal to `HUNDRED_PERCENT`. * function will revert in case the bounty split is not legal. * @param _bountySplit The bounty split to check */ function _validateSplit(IHATVault.BountySplit calldata _bountySplit) internal pure { if (_bountySplit.committee > MAX_COMMITTEE_BOUNTY) revert CommitteeBountyCannotBeMoreThanMax(); if (_bountySplit.hackerVested + _bountySplit.hacker + _bountySplit.committee != HUNDRED_PERCENT) revert TotalSplitPercentageShouldBeHundredPercent(); } /* -------------------------------------------------------------------------------- */ }
// SPDX-License-Identifier: MIT // Disclaimer https://github.com/hats-finance/hats-contracts/blob/main/DISCLAIMER.md pragma solidity 0.8.16; import "./IRewardController.sol"; import "@openzeppelin/contracts-upgradeable/interfaces/IERC4626Upgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** @title Interface for Hats.finance Vaults * @author Hats.finance * @notice A HATVault holds the funds for a specific project's bug bounties. * Anyone can permissionlessly deposit into the HATVault using * the vault’s native token. When a bug is submitted and approved, the bounty * is paid out using the funds in the vault. Bounties are paid out as a * percentage of the vault. The percentage is set according to the severity of * the bug. Vaults have regular safety periods (typically for an hour twice a * day) which are time for the committee to make decisions. * * In addition to the roles defined in the HATVaultsRegistry, every HATVault * has the roles: * Committee - The only address which can submit a claim for a bounty payout * and set the maximum bounty. * User - Anyone can deposit the vault's native token into the vault and * recieve shares for it. Shares represent the user's relative part in the * vault, and when a bounty is paid out, users lose part of their deposits * (based on percentage paid), but keep their share of the vault. * Users also receive rewards for their deposits, which can be claimed at any * time. * To withdraw previously deposited tokens, a user must first send a withdraw * request, and the withdrawal will be made available after a pending period. * Withdrawals are not permitted during safety periods or while there is an * active claim for a bounty payout. * * Bounties are payed out distributed between a few channels, and that * distribution is set upon creation (the hacker gets part in direct transfer, * part in vested reward and part in vested HAT token, part gets rewarded to * the committee, part gets swapped to HAT token and burned and/or sent to Hats * governance). * * NOTE: Vaults should not use tokens which do not guarantee that the amount * specified is the amount transferred * * This project is open-source and can be found at: * https://github.com/hats-finance/hats-contracts */ interface IHATVault is IERC4626Upgradeable { enum ArbitratorCanChangeBounty{ NO, YES, DEFAULT } // How to divide the bounty - after deducting the part that is swapped to // HAT tokens (and then sent to governance and vested to the hacker) // values are in percentages and should add up to 100% (defined as 10000) struct BountySplit { // the percentage of reward sent to the hacker via vesting contract uint16 hackerVested; // the percentage of tokens that are sent directly to the hacker uint16 hacker; // the percentage sent to the committee uint16 committee; } // How to divide a bounty for a claim that has been approved // used to keep track of payouts, amounts are in vault's native token struct ClaimBounty { uint256 hacker; uint256 hackerVested; uint256 committee; uint256 hackerHatVested; uint256 governanceHat; } /** * @notice Initialization parameters for the vault * @param name The vault's name (concatenated as "Hats Vault " + name) * @param symbol The vault's symbol (concatenated as "HAT" + symbol) * @param rewardController The reward controller for the vault * @param vestingDuration Duration of the vesting period of the vault's * token vested part of the bounty * @param vestingPeriods The number of vesting periods of the vault's token * vested part of the bounty * @param maxBounty The maximum percentage of the vault that can be paid * out as a bounty * @param bountySplit The way to split the bounty between the hacker, * hacker vested, and committee. * Each entry is a number between 0 and `HUNDRED_PERCENT`. * Total splits should be equal to `HUNDRED_PERCENT`. * @param asset The vault's native token * @param owner The address of the vault's owner * @param committee The address of the vault's committee * @param isPaused Whether to initialize the vault with deposits disabled * @dev Needed to avoid a "stack too deep" error */ struct VaultInitParams { string name; string symbol; IRewardController[] rewardControllers; uint32 vestingDuration; uint32 vestingPeriods; uint16 maxBounty; IHATVault.BountySplit bountySplit; IERC20 asset; address owner; address committee; bool isPaused; string descriptionHash; } // Only committee error OnlyCommittee(); // Active claim exists error ActiveClaimExists(); // Safety period error SafetyPeriod(); // Not safety period error NotSafetyPeriod(); // Bounty percentage is higher than the max bounty error BountyPercentageHigherThanMaxBounty(); // Only callable by arbitrator or after challenge timeout period error OnlyCallableByArbitratorOrAfterChallengeTimeOutPeriod(); // No active claim exists error NoActiveClaimExists(); // Claim Id specified is not the active claim Id error ClaimIdIsNotActive(); // Not enough fee paid error NotEnoughFeePaid(); // No pending max bounty error NoPendingMaxBounty(); // Delay period for setting max bounty had not passed error DelayPeriodForSettingMaxBountyHadNotPassed(); // Committee already checked in error CommitteeAlreadyCheckedIn(); // Total bounty split % should be `HUNDRED_PERCENT` error TotalSplitPercentageShouldBeHundredPercent(); // Vesting duration is too long error VestingDurationTooLong(); // Vesting periods cannot be zero error VestingPeriodsCannotBeZero(); // Vesting duration smaller than periods error VestingDurationSmallerThanPeriods(); // Max bounty cannot be more than `MAX_BOUNTY_LIMIT` error MaxBountyCannotBeMoreThanMaxBountyLimit(); // Committee bounty split cannot be more than `MAX_COMMITTEE_BOUNTY` error CommitteeBountyCannotBeMoreThanMax(); // Only registry owner error OnlyRegistryOwner(); // Only fee setter error OnlyFeeSetter(); // Fee must be less than or equal to 2% error WithdrawalFeeTooBig(); // Set shares arrays must have same length error SetSharesArraysMustHaveSameLength(); // Committee not checked in yet error CommitteeNotCheckedInYet(); // Not enough user balance error NotEnoughUserBalance(); // Only arbitrator or registry owner error OnlyArbitratorOrRegistryOwner(); // Unchalleged claim can only be approved if challenge period is over error UnchallengedClaimCanOnlyBeApprovedAfterChallengePeriod(); // Challenged claim can only be approved by arbitrator before the challenge timeout period error ChallengedClaimCanOnlyBeApprovedByArbitratorUntilChallengeTimeoutPeriod(); // Claim has expired error ClaimExpired(); // Challenge period is over error ChallengePeriodEnded(); // Claim can be challenged only once error ClaimAlreadyChallenged(); // Only callable if challenged error OnlyCallableIfChallenged(); // Cannot deposit to another user with withdraw request error CannotTransferToAnotherUserWithActiveWithdrawRequest(); // Withdraw amount must be greater than zero error WithdrawMustBeGreaterThanZero(); // Redeem amount cannot be more than maximum for user error RedeemMoreThanMax(); // System is in an emergency pause error SystemInEmergencyPause(); // Cannot set a reward controller that was already used in the past error CannotSetToPerviousRewardController(); // Cannot mint burn or transfer 0 amount of shares error AmountCannotBeZero(); // Cannot transfer shares to self error CannotTransferToSelf(); // First deposit must return at least MINIMAL_AMOUNT_OF_SHARES error AmountOfSharesMustBeMoreThanMinimalAmount(); // Deposit passed max slippage error DepositSlippageProtection(); // Mint passed max slippage error MintSlippageProtection(); // Withdraw passed max slippage error WithdrawSlippageProtection(); // Redeem passed max slippage error RedeemSlippageProtection(); // Cannot add the same reward controller more than once error DuplicatedRewardController(); event SubmitClaim( bytes32 indexed _claimId, address indexed _committee, address indexed _beneficiary, uint256 _bountyPercentage, string _descriptionHash ); event ChallengeClaim(bytes32 indexed _claimId); event ApproveClaim( bytes32 indexed _claimId, address indexed _committee, address indexed _beneficiary, uint256 _bountyPercentage, address _tokenLock, ClaimBounty _claimBounty ); event DismissClaim(bytes32 indexed _claimId); event SetCommittee(address indexed _committee); event SetVestingParams( uint256 _duration, uint256 _periods ); event SetBountySplit(BountySplit _bountySplit); event SetWithdrawalFee(uint256 _newFee); event CommitteeCheckedIn(); event SetPendingMaxBounty(uint256 _maxBounty); event SetMaxBounty(uint256 _maxBounty); event AddRewardController(IRewardController indexed _newRewardController); event SetDepositPause(bool _depositPause); event SetVaultDescription(string _descriptionHash); event SetHATBountySplit(uint256 _bountyGovernanceHAT, uint256 _bountyHackerHATVested); event SetArbitrator(address indexed _arbitrator); event SetChallengePeriod(uint256 _challengePeriod); event SetChallengeTimeOutPeriod(uint256 _challengeTimeOutPeriod); event SetArbitratorCanChangeBounty(ArbitratorCanChangeBounty _arbitratorCanChangeBounty); event WithdrawRequest( address indexed _beneficiary, uint256 _withdrawEnableTime ); /** * @notice Initialize a vault instance * @param _params The vault initialization parameters * @dev See {IHATVault-VaultInitParams} for more details * @dev Called when the vault is created in {IHATVaultsRegistry-createVault} */ function initialize(VaultInitParams calldata _params) external; /* -------------------------------------------------------------------------------- */ /* ---------------------------------- Claim --------------------------------------- */ /** * @notice Called by the committee to submit a claim for a bounty payout. * This function should be called only on a safety period, when withdrawals * are disabled, and while there's no other active claim. Cannot be called * when the registry is in an emergency pause. * Upon a call to this function by the committee the vault's withdrawals * will be disabled until the claim is approved or dismissed. Also from the * time of this call the arbitrator will have a period of * {HATVaultsRegistry.challengePeriod} to challenge the claim. * @param _beneficiary The submitted claim's beneficiary * @param _bountyPercentage The submitted claim's bug requested reward percentage */ function submitClaim( address _beneficiary, uint16 _bountyPercentage, string calldata _descriptionHash ) external returns (bytes32 claimId); /** * @notice Called by the arbitrator or governance to challenge a claim for a bounty * payout that had been previously submitted by the committee. * Can only be called during the challenge period after submission of the * claim. * @param _claimId The claim ID */ function challengeClaim(bytes32 _claimId) external; /** * @notice Approve a claim for a bounty submitted by a committee, and * pay out bounty to hacker and committee. Also transfer to the * HATVaultsRegistry the part of the bounty that will be swapped to HAT * tokens. * If the claim had been previously challenged, this is only callable by * the arbitrator. Otherwise, callable by anyone after challengePeriod had * passed. * @param _claimId The claim ID * @param _bountyPercentage The percentage of the vault's balance that will * be sent as a bounty. This value will be ignored if the caller is not the * arbitrator. */ function approveClaim(bytes32 _claimId, uint16 _bountyPercentage) external; /** * @notice Dismiss the active claim for bounty payout submitted by the * committee. * Called either by the arbitrator, or by anyone if the claim has timed out. * @param _claimId The claim ID */ function dismissClaim(bytes32 _claimId) external; /* -------------------------------------------------------------------------------- */ /* ---------------------------------- Params -------------------------------------- */ /** * @notice Set new committee address. Can be called by existing committee, * or by the the vault's owner in the case that the committee hadn't checked in * yet. * @param _committee The address of the new committee */ function setCommittee(address _committee) external; /** * @notice Called by the vault's owner to set the vesting params for the * part of the bounty that the hacker gets vested in the vault's native * token * @param _duration Duration of the vesting period. Must be smaller than * 120 days and bigger than `_periods` * @param _periods Number of vesting periods. Cannot be 0. */ function setVestingParams(uint32 _duration, uint32 _periods) external; /** * @notice Called by the vault's owner to set the vault token bounty split * upon an approval. * Can only be called if is no active claim and not during safety periods. * @param _bountySplit The bounty split */ function setBountySplit(BountySplit calldata _bountySplit) external; /** * @notice Called by the registry's fee setter to set the fee for * withdrawals from the vault. * @param _fee The new fee. Must be smaller than or equal to `MAX_WITHDRAWAL_FEE` */ function setWithdrawalFee(uint256 _fee) external; /** * @notice Called by the vault's committee to claim it's role. * Deposits are enabled only after committee check in. */ function committeeCheckIn() external; /** * @notice Called by the vault's owner to set a pending request for the * maximum percentage of the vault that can be paid out as a bounty. * Cannot be called if there is an active claim that has been submitted. * Max bounty should be less than or equal to 90% (defined as 9000). * The pending value can be set by the owner after the time delay (of * {HATVaultsRegistry.generalParameters.setMaxBountyDelay}) had passed. * @param _maxBounty The maximum bounty percentage that can be paid out */ function setPendingMaxBounty(uint16 _maxBounty) external; /** * @notice Called by the vault's owner to set the vault's max bounty to * the already pending max bounty. * Cannot be called if there are active claims that have been submitted. * Can only be called if there is a max bounty pending approval, and the * time delay since setting the pending max bounty had passed. */ function setMaxBounty() external; /** * @notice Called by the vault's owner to disable all deposits to the vault * @param _depositPause Are deposits paused */ function setDepositPause(bool _depositPause) external; /** * @notice Called by the registry's owner to change the description of the * vault in the Hats.finance UI * @param _descriptionHash the hash of the vault's description */ function setVaultDescription(string calldata _descriptionHash) external; /** * @notice Called by the registry's owner to add a reward controller to the vault * @param _newRewardController The new reward controller to add */ function addRewardController(IRewardController _newRewardController) external; /** * @notice Called by the registry's owner to set the vault HAT token bounty * split upon an approval. * If the value passed is the special "null" value the vault will use the * registry's default value. * @param _bountyGovernanceHAT The HAT bounty for governance * @param _bountyHackerHATVested The HAT bounty vested for the hacker */ function setHATBountySplit( uint16 _bountyGovernanceHAT, uint16 _bountyHackerHATVested ) external; /** * @notice Called by the registry's owner to set the vault arbitrator * If the value passed is the special "null" value the vault will use the * registry's default value. * @param _arbitrator The address of vault's arbitrator */ function setArbitrator(address _arbitrator) external; /** * @notice Called by the registry's owner to set the period of time after * a claim for a bounty payout has been submitted that it can be challenged * by the arbitrator. * If the value passed is the special "null" value the vault will use the * registry's default value. * @param _challengePeriod The vault's challenge period */ function setChallengePeriod(uint32 _challengePeriod) external; /** * @notice Called by the registry's owner to set the period of time after * which a claim for a bounty payout can be dismissed by anyone. * If the value passed is the special "null" value the vault will use the * registry's default value. * @param _challengeTimeOutPeriod The vault's challenge timeout period */ function setChallengeTimeOutPeriod(uint32 _challengeTimeOutPeriod) external; /** * @notice Called by the registry's owner to set whether the arbitrator * can change a claim bounty percentage * If the value passed is the special "null" value the vault will use the * registry's default value. * @param _arbitratorCanChangeBounty Whether the arbitrator can change a claim bounty percentage */ function setArbitratorCanChangeBounty(ArbitratorCanChangeBounty _arbitratorCanChangeBounty) external; /* -------------------------------------------------------------------------------- */ /* ---------------------------------- Vault --------------------------------------- */ /** * @notice Submit a request to withdraw funds from the vault. * The request will only be approved if there is no previous active * withdraw request. * The request will be pending for a period of * {HATVaultsRegistry.generalParameters.withdrawRequestPendingPeriod}, * after which a withdraw will be possible for a duration of * {HATVaultsRegistry.generalParameters.withdrawRequestEnablePeriod} */ function withdrawRequest() external; /** * @notice Withdraw previously deposited funds from the vault and claim * the HAT reward that the user has earned. * Can only be performed if a withdraw request has been previously * submitted, and the pending period had passed, and while the withdraw * enabled timeout had not passed. Withdrawals are not permitted during * safety periods or while there is an active claim for a bounty payout. * @param assets Amount of tokens to withdraw * @param receiver Address of receiver of the funds * @param owner Address of owner of the funds * @dev See {IERC4626-withdraw}. */ function withdrawAndClaim(uint256 assets, address receiver, address owner) external returns (uint256 shares); /** * @notice Redeem shares in the vault for the respective amount * of underlying assets and claim the HAT reward that the user has earned. * Can only be performed if a withdraw request has been previously * submitted, and the pending period had passed, and while the withdraw * enabled timeout had not passed. Withdrawals are not permitted during * safety periods or while there is an active claim for a bounty payout. * @param shares Amount of shares to redeem * @param receiver Address of receiver of the funds * @param owner Address of owner of the funds * @dev See {IERC4626-redeem}. */ function redeemAndClaim(uint256 shares, address receiver, address owner) external returns (uint256 assets); /** * @notice Redeem all of the user's shares in the vault for the respective amount * of underlying assets without calling the reward controller, meaning user renounces * their uncommited part of the reward. * Can only be performed if a withdraw request has been previously * submitted, and the pending period had passed, and while the withdraw * enabled timeout had not passed. Withdrawals are not permitted during * safety periods or while there is an active claim for a bounty payout. * @param receiver Address of receiver of the funds */ function emergencyWithdraw(address receiver) external returns (uint256 assets); /** * @notice Withdraw previously deposited funds from the vault, without * transferring the accumulated rewards. * Can only be performed if a withdraw request has been previously * submitted, and the pending period had passed, and while the withdraw * enabled timeout had not passed. Withdrawals are not permitted during * safety periods or while there is an active claim for a bounty payout. * @param assets Amount of tokens to withdraw * @param receiver Address of receiver of the funds * @param owner Address of owner of the funds * @dev See {IERC4626-withdraw}. */ function withdraw(uint256 assets, address receiver, address owner) external returns (uint256); /** * @notice Redeem shares in the vault for the respective amount * of underlying assets, without transferring the accumulated reward. * Can only be performed if a withdraw request has been previously * submitted, and the pending period had passed, and while the withdraw * enabled timeout had not passed. Withdrawals are not permitted during * safety periods or while there is an active claim for a bounty payout. * @param shares Amount of shares to redeem * @param receiver Address of receiver of the funds * @param owner Address of owner of the funds * @dev See {IERC4626-redeem}. */ function redeem(uint256 shares, address receiver, address owner) external returns (uint256); /** * @dev Deposit funds to the vault. Can only be called if the committee had * checked in and deposits are not paused, and the registry is not in an emergency pause. * @param receiver Reciever of the shares from the deposit * @param assets Amount of vault's native token to deposit * @dev See {IERC4626-deposit}. */ function deposit(uint256 assets, address receiver) external returns (uint256); /** * @dev Deposit funds to the vault. Can only be called if the committee had * checked in and deposits are not paused, and the registry is not in an emergency pause. * Allows to specify minimum shares to be minted for slippage protection. * @param receiver Reciever of the shares from the deposit * @param assets Amount of vault's native token to deposit * @param minShares Minimum amount of shares to minted for the assets */ function deposit(uint256 assets, address receiver, uint256 minShares) external returns (uint256); /** * @dev Deposit funds to the vault based on the amount of shares to mint specified. * Can only be called if the committee had checked in and deposits are not paused, * and the registry is not in an emergency pause. * Allows to specify maximum assets to be deposited for slippage protection. * @param receiver Reciever of the shares from the deposit * @param shares Amount of vault's shares to mint * @param maxAssets Maximum amount of assets to deposit for the shares */ function mint(uint256 shares, address receiver, uint256 maxAssets) external returns (uint256); /** * @notice Withdraw previously deposited funds from the vault, without * transferring the accumulated HAT reward. * Can only be performed if a withdraw request has been previously * submitted, and the pending period had passed, and while the withdraw * enabled timeout had not passed. Withdrawals are not permitted during * safety periods or while there is an active claim for a bounty payout. * Allows to specify maximum shares to be burnt for slippage protection. * @param assets Amount of tokens to withdraw * @param receiver Address of receiver of the funds * @param owner Address of owner of the funds * @param maxShares Maximum amount of shares to burn for the assets */ function withdraw(uint256 assets, address receiver, address owner, uint256 maxShares) external returns (uint256); /** * @notice Redeem shares in the vault for the respective amount * of underlying assets, without transferring the accumulated reward. * Can only be performed if a withdraw request has been previously * submitted, and the pending period had passed, and while the withdraw * enabled timeout had not passed. Withdrawals are not permitted during * safety periods or while there is an active claim for a bounty payout. * Allows to specify minimum assets to be received for slippage protection. * @param shares Amount of shares to redeem * @param receiver Address of receiver of the funds * @param owner Address of owner of the funds * @param minAssets Minimum amount of assets to receive for the shares */ function redeem(uint256 shares, address receiver, address owner, uint256 minAssets) external returns (uint256); /** * @notice Withdraw previously deposited funds from the vault and claim * the HAT reward that the user has earned. * Can only be performed if a withdraw request has been previously * submitted, and the pending period had passed, and while the withdraw * enabled timeout had not passed. Withdrawals are not permitted during * safety periods or while there is an active claim for a bounty payout. * Allows to specify maximum shares to be burnt for slippage protection. * @param assets Amount of tokens to withdraw * @param receiver Address of receiver of the funds * @param owner Address of owner of the funds * @param maxShares Maximum amount of shares to burn for the assets * @dev See {IERC4626-withdraw}. */ function withdrawAndClaim(uint256 assets, address receiver, address owner, uint256 maxShares) external returns (uint256 shares); /** * @notice Redeem shares in the vault for the respective amount * of underlying assets and claim the HAT reward that the user has earned. * Can only be performed if a withdraw request has been previously * submitted, and the pending period had passed, and while the withdraw * enabled timeout had not passed. Withdrawals are not permitted during * safety periods or while there is an active claim for a bounty payout. * Allows to specify minimum assets to be received for slippage protection. * @param shares Amount of shares to redeem * @param receiver Address of receiver of the funds * @param owner Address of owner of the funds * @param minAssets Minimum amount of assets to receive for the shares * @dev See {IERC4626-redeem}. */ function redeemAndClaim(uint256 shares, address receiver, address owner, uint256 minAssets) external returns (uint256 assets); /* -------------------------------------------------------------------------------- */ /* --------------------------------- Getters -------------------------------------- */ /** * @notice Returns the vault HAT bounty split part that goes to the governance * If no specific value for this vault has been set, the registry's default * value will be returned. * @return The vault's HAT bounty split part that goes to the governance */ function getBountyGovernanceHAT() external view returns(uint16); /** * @notice Returns the vault HAT bounty split part that is vested for the hacker * If no specific value for this vault has been set, the registry's default * value will be returned. * @return The vault's HAT bounty split part that is vested for the hacker */ function getBountyHackerHATVested() external view returns(uint16); /** * @notice Returns the address of the vault's arbitrator * If no specific value for this vault has been set, the registry's default * value will be returned. * @return The address of the vault's arbitrator */ function getArbitrator() external view returns(address); /** * @notice Returns the period of time after a claim for a bounty payout has * been submitted that it can be challenged by the arbitrator. * If no specific value for this vault has been set, the registry's default * value will be returned. * @return The vault's challenge period */ function getChallengePeriod() external view returns(uint32); /** * @notice Returns the period of time after which a claim for a bounty * payout can be dismissed by anyone. * If no specific value for this vault has been set, the registry's default * value will be returned. * @return The vault's challenge timeout period */ function getChallengeTimeOutPeriod() external view returns(uint32); /** * @notice Returns the amount of shares to be burned to give the user the exact * amount of assets requested plus cover for the fee. Also returns the amount assets * to be paid as fee. * @return shares The amount of shares to be burned to get the requested amount of assets * @return fee The amount of assets that will be paid as fee */ function previewWithdrawAndFee(uint256 assets) external view returns (uint256 shares, uint256 fee); /** * @notice Returns the amount of assets to be sent to the user for the exact * amount of shares to redeem. Also returns the amount assets to be paid as fee. * @return assets amount of assets to be sent in exchange for the amount of shares specified * @return fee The amount of assets that will be paid as fee */ function previewRedeemAndFee(uint256 shares) external view returns (uint256 assets, uint256 fee); }
// SPDX-License-Identifier: MIT // Disclaimer https://github.com/hats-finance/hats-contracts/blob/main/DISCLAIMER.md pragma solidity 0.8.16; import "./IHATVault.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** @title Interface for the Hats.finance Vault Registry * @author hats.finance * @notice The Hats.finance Vault Registry is used to deploy Hats.finance * vaults and manage shared parameters. * * Hats.finance is a proactive bounty protocol for white hat hackers and * security experts, where projects, community members, and stakeholders * incentivize protocol security and responsible disclosure. * Hats create scalable vaults using the project’s own token. The value of the * bounty increases with the success of the token and project. * * The owner of the registry has the permission to set time limits and bounty * parameters and change vaults' info, and to set the other registry roles - * fee setter and arbitrator. * The arbitrator can challenge submitted claims for bounty payouts made by * vaults' committees, approve them with a different bounty percentage or * dismiss them. * The fee setter can set the fee on withdrawals on all vaults. * * This project is open-source and can be found at: * https://github.com/hats-finance/hats-contracts * * @dev New hats.finance vaults should be created through a call to {createVault} * so that they are linked to the registry */ interface IHATVaultsRegistry { // a struct with parameters for all vaults struct GeneralParameters { // vesting duration for the part of the bounty given to the hacker in HAT tokens uint32 hatVestingDuration; // vesting periods for the part of the bounty given to the hacker in HAT tokens uint32 hatVestingPeriods; // withdraw enable period. safetyPeriod starts when finished. uint32 withdrawPeriod; // withdraw disable period - time for the committee to gather and decide on actions, // withdrawals are not possible in this time. withdrawPeriod starts when finished. uint32 safetyPeriod; // period of time after withdrawRequestPendingPeriod where it is possible to withdraw // (after which withdrawals are not possible) uint32 withdrawRequestEnablePeriod; // period of time that has to pass after withdraw request until withdraw is possible uint32 withdrawRequestPendingPeriod; // period of time that has to pass after setting a pending max // bounty before it can be set as the new max bounty uint32 setMaxBountyDelay; // fee in ETH to be transferred with every logging of a claim uint256 claimFee; } /** * @notice Raised on {setWithdrawSafetyPeriod} if the withdraw period to * be set is shorter than 1 hour */ error WithdrawPeriodTooShort(); /** * @notice Raised on {setWithdrawSafetyPeriod} if the safety period to * be set is longer than 6 hours */ error SafetyPeriodTooLong(); /** * @notice Raised on {setWithdrawRequestParams} if the withdraw request * pending period to be set is shorter than 3 months */ error WithdrawRequestPendingPeriodTooLong(); /** * @notice Raised on {setWithdrawRequestParams} if the withdraw request * enabled period to be set is shorter than 6 hours */ error WithdrawRequestEnabledPeriodTooShort(); /** * @notice Raised on {setWithdrawRequestParams} if the withdraw request * enabled period to be set is longer than 100 days */ error WithdrawRequestEnabledPeriodTooLong(); /** * @notice Raised on {setHatVestingParams} if the vesting duration to be * set is longer than 180 days */ error HatVestingDurationTooLong(); /** * @notice Raised on {setHatVestingParams} if the vesting periods to be * set is 0 */ error HatVestingPeriodsCannotBeZero(); /** * @notice Raised on {setHatVestingParams} if the vesting duration is * smaller than the vesting periods */ error HatVestingDurationSmallerThanPeriods(); /** * @notice Raised on {setMaxBountyDelay} if the max bounty to be set is * shorter than 2 days */ error DelayTooShort(); /** * @notice Raised on {swapAndSend} if the amount to swap is zero */ error AmountToSwapIsZero(); /** * @notice Raised on {swapAndSend} if the swap was not successful */ error SwapFailed(); // Wrong amount received /** * @notice Raised on {swapAndSend} if the amount that was recieved in * the swap was less than the minimum amount specified */ error AmountSwappedLessThanMinimum(); /** * @notice Raised on {setDefaultHATBountySplit} if the split to be set is * greater than 20% (defined as 2000) */ error TotalHatsSplitPercentageShouldBeUpToMaxHATSplit(); /** * @notice Raised on {setDefaultChallengePeriod} if the challenge period * to be set is shorter than 1 day */ error ChallengePeriodTooShort(); /** * @notice Raised on {setDefaultChallengePeriod} if the challenge period * to be set is longer than 5 days */ error ChallengePeriodTooLong(); /** * @notice Raised on {setDefaultChallengeTimeOutPeriod} if the challenge * timeout period to be set is shorter than 1 day */ error ChallengeTimeOutPeriodTooShort(); /** * @notice Raised on {setDefaultChallengeTimeOutPeriod} if the challenge * timeout period to be set is longer than 85 days */ error ChallengeTimeOutPeriodTooLong(); /** * @notice Raised on {LogClaim} if the transaction was not sent with the * amount of ETH specified as {generalParameters.claimFee} */ error NotEnoughFeePaid(); /** * @notice Raised on {LogClaim} if the transfer of the claim fee failed */ error ClaimFeeTransferFailed(); /** * @notice Emitted on deployment of the registry * @param _hatVaultImplementation The HATVault implementation address * @param _HAT The HAT token address * @param _tokenLockFactory The token lock factory address * @param _generalParameters The registry's general parameters * @param _bountyGovernanceHAT The HAT bounty for governance * @param _bountyHackerHATVested The HAT bounty vested for the hacker * @param _hatGovernance The registry's governance * @param _defaultChallengePeriod The new default challenge period * @param _defaultChallengeTimeOutPeriod The new default challenge timeout * @param _defaultArbitratorCanChangeBounty Whether the arbitrator can change bounty percentage of claims */ event RegistryCreated( address _hatVaultImplementation, address _HAT, address _tokenLockFactory, GeneralParameters _generalParameters, uint256 _bountyGovernanceHAT, uint256 _bountyHackerHATVested, address _hatGovernance, address _defaultArbitrator, uint256 _defaultChallengePeriod, uint256 _defaultChallengeTimeOutPeriod, bool _defaultArbitratorCanChangeBounty ); /** * @notice Emitted when a claim is logged * @param _claimer The address of the claimer * @param _descriptionHash - a hash of an ipfs encrypted file which * describes the claim. */ event LogClaim(address indexed _claimer, string _descriptionHash); /** * @notice Emitted when a new fee setter is set * @param _feeSetter The address of the new fee setter */ event SetFeeSetter(address indexed _feeSetter); /** * @notice Emitted when new withdraw request time limits are set * @param _withdrawRequestPendingPeriod Time period where the withdraw * request is pending * @param _withdrawRequestEnablePeriod Time period after the peding period * has ended during which withdrawal is enabled */ event SetWithdrawRequestParams( uint256 _withdrawRequestPendingPeriod, uint256 _withdrawRequestEnablePeriod ); /** * @notice Emitted when a new fee for logging a claim for a bounty is set * @param _fee Claim fee in ETH to be transferred on any call of {logClaim} */ event SetClaimFee(uint256 _fee); /** * @notice Emitted when new durations are set for withdraw period and * safety period * @param _withdrawPeriod Amount of time during which withdrawals are * enabled, and the bounty split can be changed by the governance * @param _safetyPeriod Amount of time during which claims for bounties * can be submitted and withdrawals are disabled */ event SetWithdrawSafetyPeriod( uint256 _withdrawPeriod, uint256 _safetyPeriod ); /** * @notice Emitted when new HAT vesting parameters are set * @param _duration The duration of the vesting period * @param _periods The number of vesting periods */ event SetHatVestingParams(uint256 _duration, uint256 _periods); /** * @notice Emitted when a new timelock delay for setting the * max bounty is set * @param _delay The time period for the delay */ event SetMaxBountyDelay(uint256 _delay); /** * @notice Emitted when the UI visibility of a vault is changed * @param _vault The address of the vault to update * @param _visible Is this vault visible in the UI */ event SetVaultVisibility(address indexed _vault, bool indexed _visible); /** @dev Emitted when a new vault is created * @param _vault The address of the vault to add to the registry * @param _params The vault initialization parameters */ event VaultCreated(address indexed _vault, IHATVault.VaultInitParams _params); /** @notice Emitted when a swap of vault tokens to HAT tokens is done and * the HATS tokens are sent to beneficiary through vesting contract * @param _beneficiary Address of beneficiary * @param _amountSwapped Amount of vault's native tokens that was swapped * @param _amountSent Amount of HAT tokens sent to beneficiary * @param _tokenLock Address of the token lock contract that holds the HAT * tokens (address(0) if no token lock is used) */ event SwapAndSend( address indexed _beneficiary, uint256 _amountSwapped, uint256 _amountSent, address indexed _tokenLock ); /** * @notice Emitted when a new default HAT bounty split is set * @param _defaultBountyGovernanceHAT The new default HAT bounty part sent to governance * @param _defaultBountyHackerHATVested The new default HAT bounty part vseted for the hacker */ event SetDefaultHATBountySplit(uint256 _defaultBountyGovernanceHAT, uint256 _defaultBountyHackerHATVested); /** * @notice Emitted when a new default arbitrator is set * @param _defaultArbitrator The address of the new arbitrator */ event SetDefaultArbitrator(address indexed _defaultArbitrator); /** * @notice Emitted when a new default challenge period is set * @param _defaultChallengePeriod The new default challenge period */ event SetDefaultChallengePeriod(uint256 _defaultChallengePeriod); /** * @notice Emitted when a new default challenge timeout period is set * @param _defaultChallengeTimeOutPeriod The new default challenge timeout * period */ event SetDefaultChallengeTimeOutPeriod(uint256 _defaultChallengeTimeOutPeriod); /** * @notice Emitted when the default arbitrator can change bounty is set * @param _defaultArbitratorCanChangeBounty Whether the arbitrator can change bounty of claims */ event SetDefaultArbitratorCanChangeBounty(bool _defaultArbitratorCanChangeBounty); /** @notice Emitted when the system is put into emergency pause/unpause * @param _isEmergencyPaused Is the system in an emergency pause */ event SetEmergencyPaused(bool _isEmergencyPaused); /** * @notice Emitted when a new swap token is set * @param _swapToken The new swap token address */ event SetSwapToken(address indexed _swapToken); /** * @notice Called by governance to pause/unpause the system in case of an * emergency * @param _isEmergencyPaused Is the system in an emergency pause */ function setEmergencyPaused(bool _isEmergencyPaused) external; /** * @notice Called by governance to set a new swap token * @param _swapToken the new swap token address */ function setSwapToken(address _swapToken) external; /** * @notice Emit an event that includes the given _descriptionHash * This can be used by the claimer as evidence that she had access to the * information at the time of the call * if a {generalParameters.claimFee} > 0, the caller must send that amount * of ETH for the claim to succeed * @param _descriptionHash - a hash of an IPFS encrypted file which * describes the claim. */ function logClaim(string calldata _descriptionHash) external payable; /** * @notice Called by governance to set the default percentage of each claim bounty * that will be swapped for hats and sent to the governance or vested for the hacker * @param _defaultBountyGovernanceHAT The HAT bounty for governance * @param _defaultBountyHackerHATVested The HAT bounty vested for the hacker */ function setDefaultHATBountySplit( uint16 _defaultBountyGovernanceHAT, uint16 _defaultBountyHackerHATVested ) external; /** * @dev Check that a given hats bounty split is legal, meaning that: * Each entry is a number between 0 and less than `MAX_HAT_SPLIT`. * Total splits should be less than `MAX_HAT_SPLIT`. * function will revert in case the bounty split is not legal. * @param _bountyGovernanceHAT The HAT bounty for governance * @param _bountyHackerHATVested The HAT bounty vested for the hacker */ function validateHATSplit(uint16 _bountyGovernanceHAT, uint16 _bountyHackerHATVested) external pure; /** * @notice Called by governance to set the default arbitrator. * @param _defaultArbitrator The default arbitrator address */ function setDefaultArbitrator(address _defaultArbitrator) external; /** * @notice Called by governance to set the default challenge period * @param _defaultChallengePeriod The default challenge period */ function setDefaultChallengePeriod(uint32 _defaultChallengePeriod) external; /** * @notice Called by governance to set the default challenge timeout * @param _defaultChallengeTimeOutPeriod The Default challenge timeout */ function setDefaultChallengeTimeOutPeriod( uint32 _defaultChallengeTimeOutPeriod ) external; /** * @notice Called by governance to set Whether the arbitrator can change bounty of claims. * @param _defaultArbitratorCanChangeBounty The default for whether the arbitrator can change bounty of claims */ function setDefaultArbitratorCanChangeBounty(bool _defaultArbitratorCanChangeBounty) external; /** * @notice Check that the given challenge period is legal, meaning that it * is greater than 1 day and less than 5 days. * @param _challengePeriod The challenge period to check */ function validateChallengePeriod(uint32 _challengePeriod) external pure; /** * @notice Check that the given challenge timeout period is legal, meaning * that it is greater than 2 days and less than 85 days. * @param _challengeTimeOutPeriod The challenge timeout period to check */ function validateChallengeTimeOutPeriod(uint32 _challengeTimeOutPeriod) external pure; /** * @notice Called by governance to set the fee setter role * @param _feeSetter Address of new fee setter */ function setFeeSetter(address _feeSetter) external; /** * @notice Called by governance to set time limits for withdraw requests * @param _withdrawRequestPendingPeriod Time period where the withdraw * request is pending * @param _withdrawRequestEnablePeriod Time period after the peding period * has ended during which withdrawal is enabled */ function setWithdrawRequestParams( uint32 _withdrawRequestPendingPeriod, uint32 _withdrawRequestEnablePeriod ) external; /** * @notice Called by governance to set the fee for logging a claim for a * bounty in any vault. * @param _fee Claim fee in ETH to be transferred on any call of * {logClaim} */ function setClaimFee(uint256 _fee) external; /** * @notice Called by governance to set the withdraw period and safety * period, which are always interchanging. * The safety period is time that the committee can submit claims for * bounty payouts, and during which withdrawals are disabled and the * bounty split cannot be changed. * @param _withdrawPeriod Amount of time during which withdrawals are * enabled, and the bounty split can be changed by the governance. Must be * at least 1 hour. * @param _safetyPeriod Amount of time during which claims for bounties * can be submitted and withdrawals are disabled. Must be at most 6 hours. */ function setWithdrawSafetyPeriod( uint32 _withdrawPeriod, uint32 _safetyPeriod ) external; /** * @notice Called by governance to set vesting params for rewarding hackers * with rewardToken, for all vaults * @param _duration Duration of the vesting period. Must be less than 180 * days. * @param _periods The number of vesting periods. Must be more than 0 and * less then the vesting duration. */ function setHatVestingParams(uint32 _duration, uint32 _periods) external; /** * @notice Called by governance to set the timelock delay for setting the * max bounty (the time between setPendingMaxBounty and setMaxBounty) * @param _delay The time period for the delay. Must be at least 2 days. */ function setMaxBountyDelay(uint32 _delay) external; /** * @notice Create a new vault * NOTE: Vaults should not use tokens which do not guarantee that the * amount specified is the amount transferred * @param _params The vault initialization parameters * @return vault The address of the new vault */ function createVault(IHATVault.VaultInitParams calldata _params) external returns(address vault); /** * @notice Called by governance to change the UI visibility of a vault * @param _vault The address of the vault to update * @param _visible Is this vault visible in the UI * This parameter can be used by the UI to include or exclude the vault */ function setVaultVisibility(address _vault, bool _visible) external; /** * @notice Transfer the part of the bounty that is supposed to be swapped * into HAT tokens from the HATVault to the registry, and keep track of * the amounts to be swapped and sent/burnt in a later transaction * @param _asset The vault's native token * @param _hacker The address of the beneficiary of the bounty * @param _hackersHatReward The amount of the vault's native token to be * swapped to HAT tokens and sent to the hacker via a vesting contract * @param _governanceHatReward The amount of the vault's native token to * be swapped to HAT tokens and sent to governance */ function addTokensToSwap( IERC20 _asset, address _hacker, uint256 _hackersHatReward, uint256 _governanceHatReward ) external; /** * @notice Called by governance to swap the given asset to HAT tokens and * distribute the HAT tokens: Send to governance their share and send to * beneficiaries their share through a vesting contract. * @param _asset The address of the token to be swapped to HAT tokens * @param _beneficiaries Addresses of beneficiaries * @param _amountOutMinimum Minimum amount of HAT tokens at swap * @param _routingContract Routing contract to call for the swap * @param _routingPayload Payload to send to the _routingContract for the * swap */ function swapAndSend( address _asset, address[] calldata _beneficiaries, uint256 _amountOutMinimum, address _routingContract, bytes calldata _routingPayload ) external; /** * @notice Returns the withdraw enable period for all vaults. The safety * period starts when finished. * @return Withdraw enable period for all vaults */ function getWithdrawPeriod() external view returns (uint256); /** * @notice Returns the withdraw disable period - time for the committee to * gather and decide on actions, withdrawals are not possible in this * time. The withdraw period starts when finished. * @return Safety period for all vaults */ function getSafetyPeriod() external view returns (uint256); /** * @notice Returns the withdraw request enable period for all vaults - * period of time after withdrawRequestPendingPeriod where it is possible * to withdraw, and after which withdrawals are not possible. * @return Withdraw request enable period for all vaults */ function getWithdrawRequestEnablePeriod() external view returns (uint256); /** * @notice Returns the withdraw request pending period for all vaults - * period of time that has to pass after withdraw request until withdraw * is possible * @return Withdraw request pending period for all vaults */ function getWithdrawRequestPendingPeriod() external view returns (uint256); /** * @notice Returns the set max bounty delay for all vaults - period of * time that has to pass after setting a pending max bounty before it can * be set as the new max bounty * @return Set max bounty delay for all vaults */ function getSetMaxBountyDelay() external view returns (uint256); /** * @notice Returns the number of vaults that have been previously created * @return The number of vaults in the registry */ function getNumberOfVaults() external view returns(uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; interface IRewardController { error EpochLengthZero(); // Not enough rewards to transfer to user error NotEnoughRewardsToTransferToUser(); event RewardControllerCreated( address _rewardToken, address _governance, uint256 _startBlock, uint256 _epochLength, uint256[24] _epochRewardPerBlock ); event SetEpochRewardPerBlock(uint256[24] _epochRewardPerBlock); event SetAllocPoint(address indexed _vault, uint256 _prevAllocPoint, uint256 _allocPoint); event VaultUpdated(address indexed _vault, uint256 _rewardPerShare, uint256 _lastProcessedVaultUpdate); event UserBalanceCommitted(address indexed _vault, address indexed _user, uint256 _unclaimedReward, uint256 _rewardDebt); event ClaimReward(address indexed _vault, address indexed _user, uint256 _amount); /** * @notice Initializes the reward controller * @param _rewardToken The address of the ERC20 token to be distributed as rewards * @param _governance The hats governance address, to be given ownership of the reward controller * @param _startRewardingBlock The block number from which to start rewarding * @param _epochLength The length of a rewarding epoch * @param _epochRewardPerBlock The reward per block for each of the 24 epochs */ function initialize( address _rewardToken, address _governance, uint256 _startRewardingBlock, uint256 _epochLength, uint256[24] calldata _epochRewardPerBlock ) external; /** * @notice Called by the owner to set the allocation points for a vault, meaning the * vault's relative share of the total rewards * @param _vault The address of the vault * @param _allocPoint The allocation points for the vault */ function setAllocPoint(address _vault, uint256 _allocPoint) external; /** * @notice Update the vault's reward per share, not more then once per block * @param _vault The vault's address */ function updateVault(address _vault) external; /** * @notice Called by the owner to set reward per epoch * Reward can only be set for epochs which have not yet started * @param _epochRewardPerBlock reward per block for each epoch */ function setEpochRewardPerBlock(uint256[24] calldata _epochRewardPerBlock) external; /** * @notice Called by the vault to update a user claimable reward after deposit or withdraw. * This call should never revert. * @param _user The user address to updare rewards for * @param _sharesChange The user of shared the user deposited or withdrew * @param _isDeposit Whether user deposited or withdrew */ function commitUserBalance(address _user, uint256 _sharesChange, bool _isDeposit) external; /** * @notice Transfer to the specified user their pending share of rewards. * @param _vault The vault address * @param _user The user address to claim for */ function claimReward(address _vault, address _user) external; /** * @notice Calculate rewards for a vault by iterating over the history of totalAllocPoints updates, * and sum up all rewards periods from vault.lastRewardBlock until current block number. * @param _vault The vault address * @param _fromBlock The block from which to start calculation * @return reward The amount of rewards for the vault */ function getVaultReward(address _vault, uint256 _fromBlock) external view returns(uint256 reward); /** * @notice Calculate the amount of rewards a user can claim for having contributed to a specific vault * @param _vault The vault address * @param _user The user for which the reward is calculated */ function getPendingReward(address _vault, address _user) external view returns (uint256); /** * @notice Called by the owner to transfer any tokens held in this contract to the owner * @param _token The token to sweep * @param _amount The amount of token to sweep */ function sweepToken(IERC20Upgradeable _token, uint256 _amount) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; pragma experimental ABIEncoderV2; interface ITokenLock { enum Revocability { NotSet, Enabled, Disabled } // -- Value Transfer -- function release() external; function withdrawSurplus(uint256 _amount) external; function revoke() external; // -- Balances -- function currentBalance() external view returns (uint256); // -- Time & Periods -- function currentTime() external view returns (uint256); function duration() external view returns (uint256); function sinceStartTime() external view returns (uint256); function amountPerPeriod() external view returns (uint256); function periodDuration() external view returns (uint256); function currentPeriod() external view returns (uint256); function passedPeriods() external view returns (uint256); // -- Locking & Release Schedule -- function availableAmount() external view returns (uint256); function vestedAmount() external view returns (uint256); function releasableAmount() external view returns (uint256); function totalOutstandingAmount() external view returns (uint256); function surplusAmount() external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import "./ITokenLock.sol"; interface ITokenLockFactory { // -- Factory -- function setMasterCopy(address _masterCopy) external; function createTokenLock( address _token, address _owner, address _beneficiary, uint256 _managedAmount, uint256 _startTime, uint256 _endTime, uint256 _periods, uint256 _releaseStartTime, uint256 _vestingCliffTime, ITokenLock.Revocability _revocable, bool _canDelegate ) external returns(address contractAddress); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import "@openzeppelin/contracts/proxy/Clones.sol"; import "./ITokenLockFactory.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; /** * @title TokenLockFactory * a factory of TokenLock contracts. * * This contract receives funds to make the process of creating TokenLock contracts * easier by distributing them the initial tokens to be managed. */ contract TokenLockFactory is ITokenLockFactory, Ownable { // -- State -- address public masterCopy; // -- Events -- event MasterCopyUpdated(address indexed masterCopy); event TokenLockCreated( address indexed contractAddress, bytes32 indexed initHash, address indexed beneficiary, address token, uint256 managedAmount, uint256 startTime, uint256 endTime, uint256 periods, uint256 releaseStartTime, uint256 vestingCliffTime, ITokenLock.Revocability revocable, bool canDelegate ); /** * Constructor. * @param _masterCopy Address of the master copy to use to clone proxies * @param _governance Owner of the factory */ constructor(address _masterCopy, address _governance) { setMasterCopy(_masterCopy); _transferOwnership(_governance); } // -- Factory -- /** * @notice Creates and fund a new token lock wallet using a minimum proxy * @param _token token to time lock * @param _owner Address of the contract owner * @param _beneficiary Address of the beneficiary of locked tokens * @param _managedAmount Amount of tokens to be managed by the lock contract * @param _startTime Start time of the release schedule * @param _endTime End time of the release schedule * @param _periods Number of periods between start time and end time * @param _releaseStartTime Override time for when the releases start * @param _revocable Whether the contract is revocable * @param _canDelegate Whether the contract should call delegate */ function createTokenLock( address _token, address _owner, address _beneficiary, uint256 _managedAmount, uint256 _startTime, uint256 _endTime, uint256 _periods, uint256 _releaseStartTime, uint256 _vestingCliffTime, ITokenLock.Revocability _revocable, bool _canDelegate ) external override returns(address contractAddress) { // Create contract using a minimal proxy and call initializer bytes memory initializer = abi.encodeWithSignature( "initialize(address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,uint8,bool)", _owner, _beneficiary, _token, _managedAmount, _startTime, _endTime, _periods, _releaseStartTime, _vestingCliffTime, _revocable, _canDelegate ); contractAddress = deployProxyPrivate(initializer, _beneficiary, _token, _managedAmount, _startTime, _endTime, _periods, _releaseStartTime, _vestingCliffTime, _revocable, _canDelegate); } /** * @notice Sets the masterCopy bytecode to use to create clones of TokenLock contracts * @param _masterCopy Address of contract bytecode to factory clone */ function setMasterCopy(address _masterCopy) public override onlyOwner { require(_masterCopy != address(0), "MasterCopy cannot be zero"); masterCopy = _masterCopy; emit MasterCopyUpdated(_masterCopy); } //this private function is to handle stack too deep issue function deployProxyPrivate( bytes memory _initializer, address _beneficiary, address _token, uint256 _managedAmount, uint256 _startTime, uint256 _endTime, uint256 _periods, uint256 _releaseStartTime, uint256 _vestingCliffTime, ITokenLock.Revocability _revocable, bool _canDelegate ) private returns (address contractAddress) { contractAddress = Clones.clone(masterCopy); Address.functionCall(contractAddress, _initializer); emit TokenLockCreated( contractAddress, keccak256(_initializer), _beneficiary, _token, _managedAmount, _startTime, _endTime, _periods, _releaseStartTime, _vestingCliffTime, _revocable, _canDelegate ); } }
{ "evmVersion": "london", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 200 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_hatVaultImplementation","type":"address"},{"internalType":"address","name":"_hatGovernance","type":"address"},{"internalType":"address","name":"_defaultArbitrator","type":"address"},{"internalType":"address","name":"_HAT","type":"address"},{"internalType":"uint16","name":"_bountyGovernanceHAT","type":"uint16"},{"internalType":"uint16","name":"_bountyHackerHATVested","type":"uint16"},{"internalType":"contract ITokenLockFactory","name":"_tokenLockFactory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AmountSwappedLessThanMinimum","type":"error"},{"inputs":[],"name":"AmountToSwapIsZero","type":"error"},{"inputs":[],"name":"ChallengePeriodTooLong","type":"error"},{"inputs":[],"name":"ChallengePeriodTooShort","type":"error"},{"inputs":[],"name":"ChallengeTimeOutPeriodTooLong","type":"error"},{"inputs":[],"name":"ChallengeTimeOutPeriodTooShort","type":"error"},{"inputs":[],"name":"ClaimFeeTransferFailed","type":"error"},{"inputs":[],"name":"DelayTooShort","type":"error"},{"inputs":[],"name":"HatVestingDurationSmallerThanPeriods","type":"error"},{"inputs":[],"name":"HatVestingDurationTooLong","type":"error"},{"inputs":[],"name":"HatVestingPeriodsCannotBeZero","type":"error"},{"inputs":[],"name":"NotEnoughFeePaid","type":"error"},{"inputs":[],"name":"SafetyPeriodTooLong","type":"error"},{"inputs":[],"name":"SwapFailed","type":"error"},{"inputs":[],"name":"TotalHatsSplitPercentageShouldBeUpToMaxHATSplit","type":"error"},{"inputs":[],"name":"WithdrawPeriodTooShort","type":"error"},{"inputs":[],"name":"WithdrawRequestEnabledPeriodTooLong","type":"error"},{"inputs":[],"name":"WithdrawRequestEnabledPeriodTooShort","type":"error"},{"inputs":[],"name":"WithdrawRequestPendingPeriodTooLong","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_claimer","type":"address"},{"indexed":false,"internalType":"string","name":"_descriptionHash","type":"string"}],"name":"LogClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_hatVaultImplementation","type":"address"},{"indexed":false,"internalType":"address","name":"_HAT","type":"address"},{"indexed":false,"internalType":"address","name":"_tokenLockFactory","type":"address"},{"components":[{"internalType":"uint32","name":"hatVestingDuration","type":"uint32"},{"internalType":"uint32","name":"hatVestingPeriods","type":"uint32"},{"internalType":"uint32","name":"withdrawPeriod","type":"uint32"},{"internalType":"uint32","name":"safetyPeriod","type":"uint32"},{"internalType":"uint32","name":"withdrawRequestEnablePeriod","type":"uint32"},{"internalType":"uint32","name":"withdrawRequestPendingPeriod","type":"uint32"},{"internalType":"uint32","name":"setMaxBountyDelay","type":"uint32"},{"internalType":"uint256","name":"claimFee","type":"uint256"}],"indexed":false,"internalType":"struct IHATVaultsRegistry.GeneralParameters","name":"_generalParameters","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"_bountyGovernanceHAT","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_bountyHackerHATVested","type":"uint256"},{"indexed":false,"internalType":"address","name":"_hatGovernance","type":"address"},{"indexed":false,"internalType":"address","name":"_defaultArbitrator","type":"address"},{"indexed":false,"internalType":"uint256","name":"_defaultChallengePeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_defaultChallengeTimeOutPeriod","type":"uint256"},{"indexed":false,"internalType":"bool","name":"_defaultArbitratorCanChangeBounty","type":"bool"}],"name":"RegistryCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"SetClaimFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_defaultArbitrator","type":"address"}],"name":"SetDefaultArbitrator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"_defaultArbitratorCanChangeBounty","type":"bool"}],"name":"SetDefaultArbitratorCanChangeBounty","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_defaultChallengePeriod","type":"uint256"}],"name":"SetDefaultChallengePeriod","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_defaultChallengeTimeOutPeriod","type":"uint256"}],"name":"SetDefaultChallengeTimeOutPeriod","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_defaultBountyGovernanceHAT","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_defaultBountyHackerHATVested","type":"uint256"}],"name":"SetDefaultHATBountySplit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"_isEmergencyPaused","type":"bool"}],"name":"SetEmergencyPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_feeSetter","type":"address"}],"name":"SetFeeSetter","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_duration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_periods","type":"uint256"}],"name":"SetHatVestingParams","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_delay","type":"uint256"}],"name":"SetMaxBountyDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_swapToken","type":"address"}],"name":"SetSwapToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_vault","type":"address"},{"indexed":true,"internalType":"bool","name":"_visible","type":"bool"}],"name":"SetVaultVisibility","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_withdrawRequestPendingPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_withdrawRequestEnablePeriod","type":"uint256"}],"name":"SetWithdrawRequestParams","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_withdrawPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_safetyPeriod","type":"uint256"}],"name":"SetWithdrawSafetyPeriod","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amountSwapped","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amountSent","type":"uint256"},{"indexed":true,"internalType":"address","name":"_tokenLock","type":"address"}],"name":"SwapAndSend","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_vault","type":"address"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"contract IRewardController[]","name":"rewardControllers","type":"address[]"},{"internalType":"uint32","name":"vestingDuration","type":"uint32"},{"internalType":"uint32","name":"vestingPeriods","type":"uint32"},{"internalType":"uint16","name":"maxBounty","type":"uint16"},{"components":[{"internalType":"uint16","name":"hackerVested","type":"uint16"},{"internalType":"uint16","name":"hacker","type":"uint16"},{"internalType":"uint16","name":"committee","type":"uint16"}],"internalType":"struct IHATVault.BountySplit","name":"bountySplit","type":"tuple"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"committee","type":"address"},{"internalType":"bool","name":"isPaused","type":"bool"},{"internalType":"string","name":"descriptionHash","type":"string"}],"indexed":false,"internalType":"struct IHATVault.VaultInitParams","name":"_params","type":"tuple"}],"name":"VaultCreated","type":"event"},{"inputs":[],"name":"HAT","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HUNDRED_PERCENT","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_HAT_SPLIT","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_asset","type":"address"},{"internalType":"address","name":"_hacker","type":"address"},{"internalType":"uint256","name":"_hackersHatReward","type":"uint256"},{"internalType":"uint256","name":"_governanceHatReward","type":"uint256"}],"name":"addTokensToSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"contract IRewardController[]","name":"rewardControllers","type":"address[]"},{"internalType":"uint32","name":"vestingDuration","type":"uint32"},{"internalType":"uint32","name":"vestingPeriods","type":"uint32"},{"internalType":"uint16","name":"maxBounty","type":"uint16"},{"components":[{"internalType":"uint16","name":"hackerVested","type":"uint16"},{"internalType":"uint16","name":"hacker","type":"uint16"},{"internalType":"uint16","name":"committee","type":"uint16"}],"internalType":"struct IHATVault.BountySplit","name":"bountySplit","type":"tuple"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"committee","type":"address"},{"internalType":"bool","name":"isPaused","type":"bool"},{"internalType":"string","name":"descriptionHash","type":"string"}],"internalType":"struct IHATVault.VaultInitParams","name":"_params","type":"tuple"}],"name":"createVault","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultArbitrator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultArbitratorCanChangeBounty","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultBountyGovernanceHAT","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultBountyHackerHATVested","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultChallengePeriod","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultChallengeTimeOutPeriod","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeSetter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"generalParameters","outputs":[{"internalType":"uint32","name":"hatVestingDuration","type":"uint32"},{"internalType":"uint32","name":"hatVestingPeriods","type":"uint32"},{"internalType":"uint32","name":"withdrawPeriod","type":"uint32"},{"internalType":"uint32","name":"safetyPeriod","type":"uint32"},{"internalType":"uint32","name":"withdrawRequestEnablePeriod","type":"uint32"},{"internalType":"uint32","name":"withdrawRequestPendingPeriod","type":"uint32"},{"internalType":"uint32","name":"setMaxBountyDelay","type":"uint32"},{"internalType":"uint256","name":"claimFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumberOfVaults","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSafetyPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSetMaxBountyDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawRequestEnablePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawRequestPendingPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"governanceHatReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"hackersHatReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hatVaultImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"hatVaults","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isEmergencyPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isVaultVisible","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_descriptionHash","type":"string"}],"name":"logClaim","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setClaimFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_defaultArbitrator","type":"address"}],"name":"setDefaultArbitrator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_defaultArbitratorCanChangeBounty","type":"bool"}],"name":"setDefaultArbitratorCanChangeBounty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_defaultChallengePeriod","type":"uint32"}],"name":"setDefaultChallengePeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_defaultChallengeTimeOutPeriod","type":"uint32"}],"name":"setDefaultChallengeTimeOutPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_defaultBountyGovernanceHAT","type":"uint16"},{"internalType":"uint16","name":"_defaultBountyHackerHATVested","type":"uint16"}],"name":"setDefaultHATBountySplit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isEmergencyPaused","type":"bool"}],"name":"setEmergencyPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeSetter","type":"address"}],"name":"setFeeSetter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_duration","type":"uint32"},{"internalType":"uint32","name":"_periods","type":"uint32"}],"name":"setHatVestingParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_delay","type":"uint32"}],"name":"setMaxBountyDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_swapToken","type":"address"}],"name":"setSwapToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"bool","name":"_visible","type":"bool"}],"name":"setVaultVisibility","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_withdrawRequestPendingPeriod","type":"uint32"},{"internalType":"uint32","name":"_withdrawRequestEnablePeriod","type":"uint32"}],"name":"setWithdrawRequestParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_withdrawPeriod","type":"uint32"},{"internalType":"uint32","name":"_safetyPeriod","type":"uint32"}],"name":"setWithdrawSafetyPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address[]","name":"_beneficiaries","type":"address[]"},{"internalType":"uint256","name":"_amountOutMinimum","type":"uint256"},{"internalType":"address","name":"_routingContract","type":"address"},{"internalType":"bytes","name":"_routingPayload","type":"bytes"}],"name":"swapAndSend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenLockFactory","outputs":[{"internalType":"contract ITokenLockFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_challengePeriod","type":"uint32"}],"name":"validateChallengePeriod","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint32","name":"_challengeTimeOutPeriod","type":"uint32"}],"name":"validateChallengeTimeOutPeriod","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint16","name":"_bountyGovernanceHAT","type":"uint16"},{"internalType":"uint16","name":"_bountyHackerHATVested","type":"uint16"}],"name":"validateHATSplit","outputs":[],"stateMutability":"pure","type":"function"}]
Contract Creation Code
60c06040523480156200001157600080fd5b506040516200328738038062003287833981016040819052620000349162000435565b6200003f336200037d565b6200004a866200037d565b6001600160a01b03878116608052600780546001600160a01b0319169186169190911790556200007b8383620003cd565b806001600160a01b031660a0816001600160a01b0316815250506040518061010001604052806276a70063ffffffff168152602001605a63ffffffff168152602001619ab063ffffffff168152602001610e1063ffffffff16815260200162093a8063ffffffff16815260200162093a8063ffffffff1681526020016202a30063ffffffff1681526020016000815250600560008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160000160186101000a81548163ffffffff021916908363ffffffff16021790555060e0820151816001015590505082600860146101000a81548161ffff021916908361ffff16021790555081600860166101000a81548161ffff021916908361ffff16021790555084600960006101000a8154816001600160a01b0302191690836001600160a01b031602179055506203f480600960166101000a81548163ffffffff021916908363ffffffff160217905550622e24806009601a6101000a81548163ffffffff021916908363ffffffff1602179055506001600960146101000a81548160ff0219169083151502179055507f77d457972e962930e8a217de64210a70cd59348e32d95e7f6c7513deb5d71f92878583600587878c8c600960169054906101000a900463ffffffff166009601a9054906101000a900463ffffffff16600960149054906101000a900460ff16604051620003689b9a99989796959493929190620004d9565b60405180910390a1505050505050506200062a565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6107d0620003dc8284620005f9565b61ffff16111562000400576040516307af556960e21b815260040160405180910390fd5b5050565b6001600160a01b03811681146200041a57600080fd5b50565b805161ffff811681146200043057600080fd5b919050565b600080600080600080600060e0888a0312156200045157600080fd5b87516200045e8162000404565b6020890151909750620004718162000404565b6040890151909650620004848162000404565b6060890151909550620004978162000404565b9350620004a7608089016200041d565b9250620004b760a089016200041d565b915060c0880151620004c98162000404565b8091505092959891949750929550565b60006102408201905060018060a01b03808e168352808d166020840152808c16604084015250895463ffffffff8082166060850152808260201c1660808501526200053160a08501828460401c1663ffffffff169052565b6200054960c08501828460601c1663ffffffff169052565b6200056160e08501828460801c1663ffffffff169052565b6200057a6101008501828460a01c1663ffffffff169052565b620005936101208501828460c01c1663ffffffff169052565b50506001999099015461014082015261ffff978816610160820152959096166101808601526001600160a01b039384166101a0860152919092166101c084015263ffffffff9182166101e084015216610200820152901515610220909101529392505050565b61ffff8181168382160190808211156200062357634e487b7160e01b600052601160045260246000fd5b5092915050565b60805160a051612c296200065e6000396000818161035101526116f501526000818161041c0152610d270152612c296000f3fe6080604052600436106102935760003560e01c806377c9cd8c1161015a578063d3e0bc56116100c1578063ea55f18e1161007a578063ea55f18e14610907578063eeb338871461091d578063f2fde38b1461093f578063f4bde0971461095f578063f51a90e414610981578063fb9a8740146109a557600080fd5b8063d3e0bc56146107bf578063db0f267b146107d4578063db399053146107f4578063df1b1ebe14610824578063e2b001bf146108d4578063e367497d146108f457600080fd5b8063a3fe95b211610113578063a3fe95b2146106f2578063a8acd94614610712578063aec1d10814610732578063b19805af14610752578063b851b7ca14610772578063bcfdfc581461079257600080fd5b806377c9cd8c1461063257806387cf3ef414610654578063891ce467146106745780638da5cb5b1461069457806392b2fd34146106b25780639d0ab89f146106d257600080fd5b80632e75ab50116101fe5780634f9627b0116101b75780634f9627b01461058557806354492078146105a55780635dd11415146105c75780636c0d189a146105e75780636ed93dd014610607578063715018a61461061d57600080fd5b80632e75ab501461049f5780632ea7f250146104bf5780633449a865146104eb578063354d75b91461050b5780633bd495ce14610543578063403661fb1461056557600080fd5b80631a95cf06116102505780631a95cf06146103ca5780631b2cae6c146103ea57806321c0437a1461040a5780632350e92d1461043e578063250c2cd91461045e578063290d10c41461047e57600080fd5b806306c6e3b81461029857806311566d74146102d5578063116dbc931461030e57806311c2aae31461033f578063120c1a7e14610373578063165db9a9146103a8575b600080fd5b3480156102a457600080fd5b506102b86102b3366004612399565b6109c5565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102e157600080fd5b506009546102f990600160b01b900463ffffffff1681565b60405163ffffffff90911681526020016102cc565b34801561031a57600080fd5b5060095461032f90600160a01b900460ff1681565b60405190151581526020016102cc565b34801561034b57600080fd5b506102b87f000000000000000000000000000000000000000000000000000000000000000081565b34801561037f57600080fd5b5060085461039590600160b01b900461ffff1681565b60405161ffff90911681526020016102cc565b3480156103b457600080fd5b506103c86103c33660046123c6565b6109ef565b005b3480156103d657600080fd5b506103c86103e53660046123e1565b610a46565b3480156103f657600080fd5b506103c861040536600461242d565b610b23565b34801561041657600080fd5b506102b87f000000000000000000000000000000000000000000000000000000000000000081565b34801561044a57600080fd5b506103c86104593660046123e1565b610b83565b34801561046a57600080fd5b506103c86104793660046123c6565b610c7e565b34801561048a57600080fd5b5060095461032f90600160a81b900460ff1681565b3480156104ab57600080fd5b506103c86104ba366004612399565b610ce3565b3480156104cb57600080fd5b50600554600160401b900463ffffffff165b6040519081526020016102cc565b3480156104f757600080fd5b506007546102b8906001600160a01b031681565b34801561051757600080fd5b506104dd61052636600461246a565b600360209081526000928352604080842090915290825290205481565b34801561054f57600080fd5b50600554600160a01b900463ffffffff166104dd565b34801561057157600080fd5b506102b86105803660046124a3565b610d20565b34801561059157600080fd5b506103c86105a03660046123e1565b610e38565b3480156105b157600080fd5b5060085461039590600160a01b900461ffff1681565b3480156105d357600080fd5b506103c86105e23660046124df565b610f1f565b3480156105f357600080fd5b506103c86106023660046123c6565b610fb0565b34801561061357600080fd5b5061039561271081565b34801561062957600080fd5b506103c8611036565b34801561063e57600080fd5b50600554600160c01b900463ffffffff166104dd565b34801561066057600080fd5b506008546102b8906001600160a01b031681565b34801561068057600080fd5b506103c861068f3660046123c6565b61104a565b3480156106a057600080fd5b506000546001600160a01b03166102b8565b3480156106be57600080fd5b506103c86106cd366004612537565b61109e565b3480156106de57600080fd5b506103c86106ed36600461242d565b61111e565b3480156106fe57600080fd5b506103c861070d3660046123c6565b611173565b34801561071e57600080fd5b506103c861072d366004612561565b6111d8565b34801561073e57600080fd5b506103c861074d36600461257e565b61122a565b34801561075e57600080fd5b506103c861076d366004612561565b611286565b34801561077e57600080fd5b506103c861078d366004612561565b6112d8565b34801561079e57600080fd5b506104dd6107ad366004612561565b60046020526000908152604090205481565b3480156107cb57600080fd5b506001546104dd565b3480156107e057600080fd5b506009546102b8906001600160a01b031681565b34801561080057600080fd5b5061032f61080f366004612561565b60026020526000908152604090205460ff1681565b34801561083057600080fd5b506005546006546108849163ffffffff808216926401000000008304821692600160401b8104831692600160601b8204811692600160801b8304821692600160a01b8104831692600160c01b909104169088565b6040805163ffffffff998a16815297891660208901529588169587019590955292861660608601529085166080850152841660a084015290921660c082015260e0810191909152610100016102cc565b3480156108e057600080fd5b506103c86108ef3660046125f5565b61132a565b6103c86109023660046126c1565b61191e565b34801561091357600080fd5b506103956107d081565b34801561092957600080fd5b50600554600160601b900463ffffffff166104dd565b34801561094b57600080fd5b506103c861095a366004612561565b611a06565b34801561096b57600080fd5b50600554600160801b900463ffffffff166104dd565b34801561098d57600080fd5b506009546102f990600160d01b900463ffffffff1681565b3480156109b157600080fd5b506103c86109c0366004612537565b611a81565b600181815481106109d557600080fd5b6000918252602090912001546001600160a01b0316905081565b620151808163ffffffff161015610a1957604051633a50e6a160e01b815260040160405180910390fd5b620697808163ffffffff161115610a43576040516317b7efeb60e11b815260040160405180910390fd5b50565b610a4e611ab5565b610e108263ffffffff161015610a7757604051639a4e9a8d60e01b815260040160405180910390fd5b6154608163ffffffff161115610aa0576040516310c4878160e11b815260040160405180910390fd5b600580546fffffffffffffffff00000000000000001916600160401b63ffffffff85811691820263ffffffff60601b191692909217600160601b928516928302179092556040805192835260208301919091527f47c8a5b15f6172a5053bfac488642484dd38e9c0f3073c23c5d822c4cbab530991015b60405180910390a15050565b610b2b611ab5565b60098054821515600160a01b0260ff60a01b199091161790556040517f8dd94cb9d51a52430f03387ae2b623450f5bbb1201ce3d08f9dc3561f258cf4190610b7890831515815260200190565b60405180910390a150565b610b8b611ab5565b6276a7008263ffffffff161115610bb55760405163766cee2b60e01b815260040160405180910390fd5b6154608163ffffffff161015610bde57604051638750566960e01b815260040160405180910390fd5b6283d6008163ffffffff161115610c08576040516319979c0960e11b815260040160405180910390fd5b6005805467ffffffffffffffff60801b1916600160a01b63ffffffff85811691820263ffffffff60801b191692909217600160801b928516928302179092556040805192835260208301919091527f7b8aa35646b8fddc3ccaae8e1069d8c6c365e2ba2e11bb1f0018f8d01992f25b9101610b17565b610c86611ab5565b610c8f816109ef565b6009805463ffffffff60b01b1916600160b01b63ffffffff8416908102919091179091556040519081527fc14f60dbf7139b2e92ad845e95c05208c6070962e410202d3b8ae7a1378cde3590602001610b78565b610ceb611ab5565b60068190556040518181527f13fa675fefcae94b0250d92c1fec53cd08f7031592b28bf9429f840b7d25509790602001610b78565b6000610d4b7f0000000000000000000000000000000000000000000000000000000000000000611b0f565b60405163be9efac960e01b81529091506001600160a01b0382169063be9efac990610d7a90859060040161283f565b600060405180830381600087803b158015610d9457600080fd5b505af1158015610da8573d6000803e3d6000fd5b50506001805480820182556000919091527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b0319166001600160a01b0385169081179091556040519092507f87c42456973803b7e30e88a3d384868c760496c823f4eb51223d3bc094b8aa1d9150610e2b90859061283f565b60405180910390a2919050565b610e40611ab5565b62ed4e008263ffffffff1610610e695760405163181b6a8d60e01b815260040160405180910390fd5b8063ffffffff16600003610e905760405163497a0fc360e01b815260040160405180910390fd5b8063ffffffff168263ffffffff161015610ebd576040516301a127dd60e51b815260040160405180910390fd5b6005805463ffffffff84811667ffffffffffffffff199092168217640100000000918516918202179092556040805191825260208201929092527fa3d5527033c65a7e5eda0ffec2fe75b8bfc358a419914452e5e29993f531136d9101610b17565b6001600160a01b03808516600090815260036020908152604080832093871683529290529081208054849290610f569084906129e4565b90915550506001600160a01b03841660009081526004602052604081208054839290610f839084906129e4565b90915550610faa90503330610f9884866129e4565b6001600160a01b038816929190611ba9565b50505050565b610fb8611ab5565b6202a3008163ffffffff161015610fe25760405163514e00f160e01b815260040160405180910390fd5b6005805463ffffffff60c01b1916600160c01b63ffffffff8416908102919091179091556040519081527fc2f118f047950efbfb94865ef4fc99eedc6b5e992e4fb970552deba4fda0d8e490602001610b78565b61103e611ab5565b6110486000611c14565b565b6202a3008163ffffffff16101561107457604051630fe180cd60e01b815260040160405180910390fd5b62700f808163ffffffff161115610a435760405163599dfd5d60e11b815260040160405180910390fd5b6110a6611ab5565b6110b08282611a81565b6008805463ffffffff60a01b1916600160a01b61ffff85811691820261ffff60b01b191692909217600160b01b928516928302179092556040805192835260208301919091527f9b9cfb21b737a43af5e89fc41ea51449648ce863399879a0625210588b164e5a9101610b17565b611126611ab5565b60098054821515600160a81b0260ff60a81b199091161790556040517fa18d588b4da0466ca9a3ade6753c1cf94f4ccc599b9134045aeb55aef53293c890610b7890831515815260200190565b61117b611ab5565b6111848161104a565b6009805463ffffffff60d01b1916600160d01b63ffffffff8416908102919091179091556040519081527fe6f3ddadc73ca32beb7d9755d5a7d82ab53101c097e743fd05412e6a1ce9deb990602001610b78565b6111e0611ab5565b600980546001600160a01b0319166001600160a01b0383169081179091556040517f4664bc54da0879a6626395d3154ebb4adef21b4ced228635ce9583e86148a9a790600090a250565b611232611ab5565b6001600160a01b038216600081815260026020526040808220805460ff191685151590811790915590519092917f0f8de79a0a8e021d06491203f918550c01da39c26f2e03c5f5571c75edb7d93791a35050565b61128e611ab5565b600880546001600160a01b0319166001600160a01b0383169081179091556040517f9993507f53024702e2de1be66f6c48c8957ac708927b86b3bdf4e335f586947090600090a250565b6112e0611ab5565b600780546001600160a01b0319166001600160a01b0383169081179091556040517f611a318453985b405b2f5e92971f8c383619cf48b7bf4acf39e83ed1e111180590600090a250565b611332611ab5565b61137a60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016060815260200160008152602001600081525090565b8567ffffffffffffffff811115611393576113936129fd565b6040519080825280602002602001820160405280156113bc578160200160208202803683370190505b5060a08201526001600160a01b03881660009081526004602052604081205460c0830181905282525b86811015611508576001600160a01b03891660009081526003602052604081209089898481811061141857611418612a13565b905060200201602081019061142d9190612561565b6001600160a01b03166001600160a01b03168152602001908152602001600020548260a00151828151811061146457611464612a13565b6020908102919091018101919091526001600160a01b038a166000908152600390915260408120818a8a8581811061149e5761149e612a13565b90506020020160208101906114b39190612561565b6001600160a01b0316815260208101919091526040016000205560a08201518051829081106114e4576114e4612a13565b6020026020010151826000018181516114fd91906129e4565b9052506001016113e5565b50805160000361152b5760405163dbe66a0f60e01b815260040160405180910390fd5b60075481516001600160a01b039091169061154b908a9088888888611c64565b60208401819052604084019190915282516115669190612a29565b60e0830181905260c0830151835161157f929190611f38565b608083015260c08201518251602084015161159b929091611f38565b6001600160a01b038a166000908152600460205260408120919091555b878110156118895760006115fc8460a0015183815181106115db576115db612a13565b602002602001015185600001518660400151611f389092919063ffffffff16565b9050600061163a8560a00151848151811061161957611619612a13565b602002602001015186600001518760e00151611f389092919063ffffffff16565b9050818560600181815161164e91906129e4565b90525060a0850151805161168e91908590811061166d5761166d612a13565b602002602001015186600001518760200151611f389092919063ffffffff16565b6001600160a01b038d166000908152600360205260408120908d8d878181106116b9576116b9612a13565b90506020020160208101906116ce9190612561565b6001600160a01b03168152602081019190915260400160009081209190915582156117ff577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e95cd0518660008f8f8981811061173757611737612a13565b905060200201602081019061174c9190612561565b600554889042906117639063ffffffff16826129e4565b60055460405160e089901b6001600160e01b03191681526117a697969594939291640100000000900463ffffffff16906000908190600290600190600401612a3c565b6020604051808303816000875af11580156117c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e99190612ad1565b90506117ff6001600160a01b0386168285611fed565b806001600160a01b03168c8c8681811061181b5761181b612a13565b90506020020160208101906118309190612561565b6001600160a01b03167f4f8abed31d725d1e727a30b06defad85513b99ee0d373925f63d71e099edaa308486604051611873929190918252602082015260400190565b60405180910390a38360010193505050506115b8565b50600080546001600160a01b031690506000836060015184604001516118af9190612a29565b90506118c56001600160a01b0384168383611fed565b608084015160408051918252602082018390526000916001600160a01b038516917f4f8abed31d725d1e727a30b06defad85513b99ee0d373925f63d71e099edaa30910160405180910390a35050505050505050505050565b60065480156119be578034101561194857604051633244470d60e01b815260040160405180910390fd5b600080546040516001600160a01b039091169034908381818185875af1925050503d8060008114611995576040519150601f19603f3d011682016040523d82523d6000602084013e61199a565b606091505b50509050806119bc5760405163684fb74f60e11b815260040160405180910390fd5b505b336001600160a01b03167f9fcc410c642f895d8e83453cc710a30c7f00e42070fb7fd399c29b24781615e884846040516119f9929190612aee565b60405180910390a2505050565b611a0e611ab5565b6001600160a01b038116611a785760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b610a4381611c14565b6107d0611a8e8284612b02565b61ffff161115611ab1576040516307af556960e21b815260040160405180910390fd5b5050565b6000546001600160a01b031633146110485760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611a6f565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008260601b60e81c176000526e5af43d82803e903d91602b57fd5bf38260781b17602052603760096000f090506001600160a01b038116611ba45760405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b6044820152606401611a6f565b919050565b6040516001600160a01b0380851660248301528316604482015260648101829052610faa9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612022565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60075460009081906001600160a01b03908116908916819003611c8e578760009250925050611f2d565b611ca26001600160a01b038a16878a6120f4565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015611ce9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0d9190612b24565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038c16906370a0823190602401602060405180830381865afa158015611d57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7b9190612b24565b90506000886001600160a01b03168888604051611d99929190612b3d565b6000604051808303816000865af19150503d8060008114611dd6576040519150601f19603f3d011682016040523d82523d6000602084013e611ddb565b606091505b5050905080611dfd5760405163081ceff360e41b815260040160405180910390fd5b6040516370a0823160e01b815230600482015283906001600160a01b038616906370a0823190602401602060405180830381865afa158015611e43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e679190612b24565b611e719190612a29565b6040516370a0823160e01b81523060048201529096506001600160a01b038d16906370a0823190602401602060405180830381865afa158015611eb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611edc9190612b24565b611ee69083612a29565b611ef0908c612a29565b945089861015611f1357604051638a866e2560e01b815260040160405180910390fd5b611f286001600160a01b038d168a60006120f4565b505050505b965096945050505050565b6000808060001985870985870292508281108382030391505080600003611f7257838281611f6857611f68612b4d565b0492505050611fe6565b808411611f7e57600080fd5b600084868809851960019081018716968790049682860381900495909211909303600082900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b6040516001600160a01b03831660248201526044810182905261201d90849063a9059cbb60e01b90606401611bdd565b505050565b6000612077826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166122099092919063ffffffff16565b80519091501561201d57808060200190518101906120959190612b63565b61201d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611a6f565b80158061216e5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015612148573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216c9190612b24565b155b6121d95760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401611a6f565b6040516001600160a01b03831660248201526044810182905261201d90849063095ea7b360e01b90606401611bdd565b60606122188484600085612220565b949350505050565b6060824710156122815760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611a6f565b600080866001600160a01b0316858760405161229d9190612ba4565b60006040518083038185875af1925050503d80600081146122da576040519150601f19603f3d011682016040523d82523d6000602084013e6122df565b606091505b50915091506122f0878383876122fb565b979650505050505050565b6060831561236a578251600003612363576001600160a01b0385163b6123635760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611a6f565b5081612218565b612218838381511561237f5781518083602001fd5b8060405162461bcd60e51b8152600401611a6f9190612bc0565b6000602082840312156123ab57600080fd5b5035919050565b803563ffffffff81168114611ba457600080fd5b6000602082840312156123d857600080fd5b611fe6826123b2565b600080604083850312156123f457600080fd5b6123fd836123b2565b915061240b602084016123b2565b90509250929050565b8015158114610a4357600080fd5b8035611ba481612414565b60006020828403121561243f57600080fd5b8135611fe681612414565b6001600160a01b0381168114610a4357600080fd5b8035611ba48161244a565b6000806040838503121561247d57600080fd5b82356124888161244a565b915060208301356124988161244a565b809150509250929050565b6000602082840312156124b557600080fd5b813567ffffffffffffffff8111156124cc57600080fd5b82016101c08185031215611fe657600080fd5b600080600080608085870312156124f557600080fd5b84356125008161244a565b935060208501356125108161244a565b93969395505050506040820135916060013590565b803561ffff81168114611ba457600080fd5b6000806040838503121561254a57600080fd5b61255383612525565b915061240b60208401612525565b60006020828403121561257357600080fd5b8135611fe68161244a565b6000806040838503121561259157600080fd5b823561259c8161244a565b9150602083013561249881612414565b60008083601f8401126125be57600080fd5b50813567ffffffffffffffff8111156125d657600080fd5b6020830191508360208285010111156125ee57600080fd5b9250929050565b600080600080600080600060a0888a03121561261057600080fd5b873561261b8161244a565b9650602088013567ffffffffffffffff8082111561263857600080fd5b818a0191508a601f83011261264c57600080fd5b81358181111561265b57600080fd5b8b60208260051b850101111561267057600080fd5b602083019850965060408a0135955061268b60608b0161245f565b945060808a01359150808211156126a157600080fd5b506126ae8a828b016125ac565b989b979a50959850939692959293505050565b600080602083850312156126d457600080fd5b823567ffffffffffffffff8111156126eb57600080fd5b6126f7858286016125ac565b90969095509350505050565b6000808335601e1984360301811261271a57600080fd5b830160208101925035905067ffffffffffffffff81111561273a57600080fd5b8036038213156125ee57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000808335601e1984360301811261278957600080fd5b830160208101925035905067ffffffffffffffff8111156127a957600080fd5b8060051b36038213156125ee57600080fd5b8183526000602080850194508260005b858110156127f95781356127de8161244a565b6001600160a01b0316875295820195908201906001016127cb565b509495945050505050565b61ffff8061281183612525565b1683528061282160208401612525565b1660208401528061283460408401612525565b166040840152505050565b60208152600061284f8384612703565b6101c08060208601526128676101e086018385612749565b92506128766020870187612703565b9250601f1980878603016040880152612890858584612749565b945061289f6040890189612772565b94509150808786030160608801526128b88585846127bb565b94506128c6606089016123b2565b63ffffffff8116608089015293506128e0608089016123b2565b63ffffffff811660a089015293506128fa60a08901612525565b61ffff811660c0890152935061291660e0880160c08a01612804565b612923610120890161245f565b9350610140915061293e828801856001600160a01b03169052565b61294982890161245f565b93506101609150612964828801856001600160a01b03169052565b61296f82890161245f565b9350610180915061298a828801856001600160a01b03169052565b612995828901612422565b93506101a091506129a98288018515159052565b6129b582890189612703565b94509150808786030183880152506122f0848483612749565b634e487b7160e01b600052601160045260246000fd5b808201808211156129f7576129f76129ce565b92915050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b818103818111156129f7576129f76129ce565b6001600160a01b038c811682528b811660208301528a166040820152606081018990526080810188905260a0810187905263ffffffff861660c082015260e081018590526101008101849052610160810160038410612aab57634e487b7160e01b600052602160045260246000fd5b83610120830152612ac161014083018415159052565b9c9b505050505050505050505050565b600060208284031215612ae357600080fd5b8151611fe68161244a565b602081526000612218602083018486612749565b61ffff818116838216019080821115612b1d57612b1d6129ce565b5092915050565b600060208284031215612b3657600080fd5b5051919050565b8183823760009101908152919050565b634e487b7160e01b600052601260045260246000fd5b600060208284031215612b7557600080fd5b8151611fe681612414565b60005b83811015612b9b578181015183820152602001612b83565b50506000910152565b60008251612bb6818460208701612b80565b9190910192915050565b6020815260008251806020840152612bdf816040850160208701612b80565b601f01601f1916919091016040019291505056fea264697066735822122008e20e885bcbd634116756388a3314073f7d027fb51e915cb131d91c5a80dd8c64736f6c63430008100033000000000000000000000000028a7c6873dfa8357c9dcf9c9d76ef2abb66256e00000000000000000000000007368f6a959ef3096230a258dd0af692699c3a4c000000000000000000000000cbe0b90bfe99f827b8bcb5c5ac4b17107caea814000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e198cbb727758b9ad38a12e1ad475a843e5e730f
Deployed Bytecode
0x6080604052600436106102935760003560e01c806377c9cd8c1161015a578063d3e0bc56116100c1578063ea55f18e1161007a578063ea55f18e14610907578063eeb338871461091d578063f2fde38b1461093f578063f4bde0971461095f578063f51a90e414610981578063fb9a8740146109a557600080fd5b8063d3e0bc56146107bf578063db0f267b146107d4578063db399053146107f4578063df1b1ebe14610824578063e2b001bf146108d4578063e367497d146108f457600080fd5b8063a3fe95b211610113578063a3fe95b2146106f2578063a8acd94614610712578063aec1d10814610732578063b19805af14610752578063b851b7ca14610772578063bcfdfc581461079257600080fd5b806377c9cd8c1461063257806387cf3ef414610654578063891ce467146106745780638da5cb5b1461069457806392b2fd34146106b25780639d0ab89f146106d257600080fd5b80632e75ab50116101fe5780634f9627b0116101b75780634f9627b01461058557806354492078146105a55780635dd11415146105c75780636c0d189a146105e75780636ed93dd014610607578063715018a61461061d57600080fd5b80632e75ab501461049f5780632ea7f250146104bf5780633449a865146104eb578063354d75b91461050b5780633bd495ce14610543578063403661fb1461056557600080fd5b80631a95cf06116102505780631a95cf06146103ca5780631b2cae6c146103ea57806321c0437a1461040a5780632350e92d1461043e578063250c2cd91461045e578063290d10c41461047e57600080fd5b806306c6e3b81461029857806311566d74146102d5578063116dbc931461030e57806311c2aae31461033f578063120c1a7e14610373578063165db9a9146103a8575b600080fd5b3480156102a457600080fd5b506102b86102b3366004612399565b6109c5565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102e157600080fd5b506009546102f990600160b01b900463ffffffff1681565b60405163ffffffff90911681526020016102cc565b34801561031a57600080fd5b5060095461032f90600160a01b900460ff1681565b60405190151581526020016102cc565b34801561034b57600080fd5b506102b87f000000000000000000000000e198cbb727758b9ad38a12e1ad475a843e5e730f81565b34801561037f57600080fd5b5060085461039590600160b01b900461ffff1681565b60405161ffff90911681526020016102cc565b3480156103b457600080fd5b506103c86103c33660046123c6565b6109ef565b005b3480156103d657600080fd5b506103c86103e53660046123e1565b610a46565b3480156103f657600080fd5b506103c861040536600461242d565b610b23565b34801561041657600080fd5b506102b87f000000000000000000000000028a7c6873dfa8357c9dcf9c9d76ef2abb66256e81565b34801561044a57600080fd5b506103c86104593660046123e1565b610b83565b34801561046a57600080fd5b506103c86104793660046123c6565b610c7e565b34801561048a57600080fd5b5060095461032f90600160a81b900460ff1681565b3480156104ab57600080fd5b506103c86104ba366004612399565b610ce3565b3480156104cb57600080fd5b50600554600160401b900463ffffffff165b6040519081526020016102cc565b3480156104f757600080fd5b506007546102b8906001600160a01b031681565b34801561051757600080fd5b506104dd61052636600461246a565b600360209081526000928352604080842090915290825290205481565b34801561054f57600080fd5b50600554600160a01b900463ffffffff166104dd565b34801561057157600080fd5b506102b86105803660046124a3565b610d20565b34801561059157600080fd5b506103c86105a03660046123e1565b610e38565b3480156105b157600080fd5b5060085461039590600160a01b900461ffff1681565b3480156105d357600080fd5b506103c86105e23660046124df565b610f1f565b3480156105f357600080fd5b506103c86106023660046123c6565b610fb0565b34801561061357600080fd5b5061039561271081565b34801561062957600080fd5b506103c8611036565b34801561063e57600080fd5b50600554600160c01b900463ffffffff166104dd565b34801561066057600080fd5b506008546102b8906001600160a01b031681565b34801561068057600080fd5b506103c861068f3660046123c6565b61104a565b3480156106a057600080fd5b506000546001600160a01b03166102b8565b3480156106be57600080fd5b506103c86106cd366004612537565b61109e565b3480156106de57600080fd5b506103c86106ed36600461242d565b61111e565b3480156106fe57600080fd5b506103c861070d3660046123c6565b611173565b34801561071e57600080fd5b506103c861072d366004612561565b6111d8565b34801561073e57600080fd5b506103c861074d36600461257e565b61122a565b34801561075e57600080fd5b506103c861076d366004612561565b611286565b34801561077e57600080fd5b506103c861078d366004612561565b6112d8565b34801561079e57600080fd5b506104dd6107ad366004612561565b60046020526000908152604090205481565b3480156107cb57600080fd5b506001546104dd565b3480156107e057600080fd5b506009546102b8906001600160a01b031681565b34801561080057600080fd5b5061032f61080f366004612561565b60026020526000908152604090205460ff1681565b34801561083057600080fd5b506005546006546108849163ffffffff808216926401000000008304821692600160401b8104831692600160601b8204811692600160801b8304821692600160a01b8104831692600160c01b909104169088565b6040805163ffffffff998a16815297891660208901529588169587019590955292861660608601529085166080850152841660a084015290921660c082015260e0810191909152610100016102cc565b3480156108e057600080fd5b506103c86108ef3660046125f5565b61132a565b6103c86109023660046126c1565b61191e565b34801561091357600080fd5b506103956107d081565b34801561092957600080fd5b50600554600160601b900463ffffffff166104dd565b34801561094b57600080fd5b506103c861095a366004612561565b611a06565b34801561096b57600080fd5b50600554600160801b900463ffffffff166104dd565b34801561098d57600080fd5b506009546102f990600160d01b900463ffffffff1681565b3480156109b157600080fd5b506103c86109c0366004612537565b611a81565b600181815481106109d557600080fd5b6000918252602090912001546001600160a01b0316905081565b620151808163ffffffff161015610a1957604051633a50e6a160e01b815260040160405180910390fd5b620697808163ffffffff161115610a43576040516317b7efeb60e11b815260040160405180910390fd5b50565b610a4e611ab5565b610e108263ffffffff161015610a7757604051639a4e9a8d60e01b815260040160405180910390fd5b6154608163ffffffff161115610aa0576040516310c4878160e11b815260040160405180910390fd5b600580546fffffffffffffffff00000000000000001916600160401b63ffffffff85811691820263ffffffff60601b191692909217600160601b928516928302179092556040805192835260208301919091527f47c8a5b15f6172a5053bfac488642484dd38e9c0f3073c23c5d822c4cbab530991015b60405180910390a15050565b610b2b611ab5565b60098054821515600160a01b0260ff60a01b199091161790556040517f8dd94cb9d51a52430f03387ae2b623450f5bbb1201ce3d08f9dc3561f258cf4190610b7890831515815260200190565b60405180910390a150565b610b8b611ab5565b6276a7008263ffffffff161115610bb55760405163766cee2b60e01b815260040160405180910390fd5b6154608163ffffffff161015610bde57604051638750566960e01b815260040160405180910390fd5b6283d6008163ffffffff161115610c08576040516319979c0960e11b815260040160405180910390fd5b6005805467ffffffffffffffff60801b1916600160a01b63ffffffff85811691820263ffffffff60801b191692909217600160801b928516928302179092556040805192835260208301919091527f7b8aa35646b8fddc3ccaae8e1069d8c6c365e2ba2e11bb1f0018f8d01992f25b9101610b17565b610c86611ab5565b610c8f816109ef565b6009805463ffffffff60b01b1916600160b01b63ffffffff8416908102919091179091556040519081527fc14f60dbf7139b2e92ad845e95c05208c6070962e410202d3b8ae7a1378cde3590602001610b78565b610ceb611ab5565b60068190556040518181527f13fa675fefcae94b0250d92c1fec53cd08f7031592b28bf9429f840b7d25509790602001610b78565b6000610d4b7f000000000000000000000000028a7c6873dfa8357c9dcf9c9d76ef2abb66256e611b0f565b60405163be9efac960e01b81529091506001600160a01b0382169063be9efac990610d7a90859060040161283f565b600060405180830381600087803b158015610d9457600080fd5b505af1158015610da8573d6000803e3d6000fd5b50506001805480820182556000919091527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b0319166001600160a01b0385169081179091556040519092507f87c42456973803b7e30e88a3d384868c760496c823f4eb51223d3bc094b8aa1d9150610e2b90859061283f565b60405180910390a2919050565b610e40611ab5565b62ed4e008263ffffffff1610610e695760405163181b6a8d60e01b815260040160405180910390fd5b8063ffffffff16600003610e905760405163497a0fc360e01b815260040160405180910390fd5b8063ffffffff168263ffffffff161015610ebd576040516301a127dd60e51b815260040160405180910390fd5b6005805463ffffffff84811667ffffffffffffffff199092168217640100000000918516918202179092556040805191825260208201929092527fa3d5527033c65a7e5eda0ffec2fe75b8bfc358a419914452e5e29993f531136d9101610b17565b6001600160a01b03808516600090815260036020908152604080832093871683529290529081208054849290610f569084906129e4565b90915550506001600160a01b03841660009081526004602052604081208054839290610f839084906129e4565b90915550610faa90503330610f9884866129e4565b6001600160a01b038816929190611ba9565b50505050565b610fb8611ab5565b6202a3008163ffffffff161015610fe25760405163514e00f160e01b815260040160405180910390fd5b6005805463ffffffff60c01b1916600160c01b63ffffffff8416908102919091179091556040519081527fc2f118f047950efbfb94865ef4fc99eedc6b5e992e4fb970552deba4fda0d8e490602001610b78565b61103e611ab5565b6110486000611c14565b565b6202a3008163ffffffff16101561107457604051630fe180cd60e01b815260040160405180910390fd5b62700f808163ffffffff161115610a435760405163599dfd5d60e11b815260040160405180910390fd5b6110a6611ab5565b6110b08282611a81565b6008805463ffffffff60a01b1916600160a01b61ffff85811691820261ffff60b01b191692909217600160b01b928516928302179092556040805192835260208301919091527f9b9cfb21b737a43af5e89fc41ea51449648ce863399879a0625210588b164e5a9101610b17565b611126611ab5565b60098054821515600160a81b0260ff60a81b199091161790556040517fa18d588b4da0466ca9a3ade6753c1cf94f4ccc599b9134045aeb55aef53293c890610b7890831515815260200190565b61117b611ab5565b6111848161104a565b6009805463ffffffff60d01b1916600160d01b63ffffffff8416908102919091179091556040519081527fe6f3ddadc73ca32beb7d9755d5a7d82ab53101c097e743fd05412e6a1ce9deb990602001610b78565b6111e0611ab5565b600980546001600160a01b0319166001600160a01b0383169081179091556040517f4664bc54da0879a6626395d3154ebb4adef21b4ced228635ce9583e86148a9a790600090a250565b611232611ab5565b6001600160a01b038216600081815260026020526040808220805460ff191685151590811790915590519092917f0f8de79a0a8e021d06491203f918550c01da39c26f2e03c5f5571c75edb7d93791a35050565b61128e611ab5565b600880546001600160a01b0319166001600160a01b0383169081179091556040517f9993507f53024702e2de1be66f6c48c8957ac708927b86b3bdf4e335f586947090600090a250565b6112e0611ab5565b600780546001600160a01b0319166001600160a01b0383169081179091556040517f611a318453985b405b2f5e92971f8c383619cf48b7bf4acf39e83ed1e111180590600090a250565b611332611ab5565b61137a60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016060815260200160008152602001600081525090565b8567ffffffffffffffff811115611393576113936129fd565b6040519080825280602002602001820160405280156113bc578160200160208202803683370190505b5060a08201526001600160a01b03881660009081526004602052604081205460c0830181905282525b86811015611508576001600160a01b03891660009081526003602052604081209089898481811061141857611418612a13565b905060200201602081019061142d9190612561565b6001600160a01b03166001600160a01b03168152602001908152602001600020548260a00151828151811061146457611464612a13565b6020908102919091018101919091526001600160a01b038a166000908152600390915260408120818a8a8581811061149e5761149e612a13565b90506020020160208101906114b39190612561565b6001600160a01b0316815260208101919091526040016000205560a08201518051829081106114e4576114e4612a13565b6020026020010151826000018181516114fd91906129e4565b9052506001016113e5565b50805160000361152b5760405163dbe66a0f60e01b815260040160405180910390fd5b60075481516001600160a01b039091169061154b908a9088888888611c64565b60208401819052604084019190915282516115669190612a29565b60e0830181905260c0830151835161157f929190611f38565b608083015260c08201518251602084015161159b929091611f38565b6001600160a01b038a166000908152600460205260408120919091555b878110156118895760006115fc8460a0015183815181106115db576115db612a13565b602002602001015185600001518660400151611f389092919063ffffffff16565b9050600061163a8560a00151848151811061161957611619612a13565b602002602001015186600001518760e00151611f389092919063ffffffff16565b9050818560600181815161164e91906129e4565b90525060a0850151805161168e91908590811061166d5761166d612a13565b602002602001015186600001518760200151611f389092919063ffffffff16565b6001600160a01b038d166000908152600360205260408120908d8d878181106116b9576116b9612a13565b90506020020160208101906116ce9190612561565b6001600160a01b03168152602081019190915260400160009081209190915582156117ff577f000000000000000000000000e198cbb727758b9ad38a12e1ad475a843e5e730f6001600160a01b031663e95cd0518660008f8f8981811061173757611737612a13565b905060200201602081019061174c9190612561565b600554889042906117639063ffffffff16826129e4565b60055460405160e089901b6001600160e01b03191681526117a697969594939291640100000000900463ffffffff16906000908190600290600190600401612a3c565b6020604051808303816000875af11580156117c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e99190612ad1565b90506117ff6001600160a01b0386168285611fed565b806001600160a01b03168c8c8681811061181b5761181b612a13565b90506020020160208101906118309190612561565b6001600160a01b03167f4f8abed31d725d1e727a30b06defad85513b99ee0d373925f63d71e099edaa308486604051611873929190918252602082015260400190565b60405180910390a38360010193505050506115b8565b50600080546001600160a01b031690506000836060015184604001516118af9190612a29565b90506118c56001600160a01b0384168383611fed565b608084015160408051918252602082018390526000916001600160a01b038516917f4f8abed31d725d1e727a30b06defad85513b99ee0d373925f63d71e099edaa30910160405180910390a35050505050505050505050565b60065480156119be578034101561194857604051633244470d60e01b815260040160405180910390fd5b600080546040516001600160a01b039091169034908381818185875af1925050503d8060008114611995576040519150601f19603f3d011682016040523d82523d6000602084013e61199a565b606091505b50509050806119bc5760405163684fb74f60e11b815260040160405180910390fd5b505b336001600160a01b03167f9fcc410c642f895d8e83453cc710a30c7f00e42070fb7fd399c29b24781615e884846040516119f9929190612aee565b60405180910390a2505050565b611a0e611ab5565b6001600160a01b038116611a785760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b610a4381611c14565b6107d0611a8e8284612b02565b61ffff161115611ab1576040516307af556960e21b815260040160405180910390fd5b5050565b6000546001600160a01b031633146110485760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611a6f565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008260601b60e81c176000526e5af43d82803e903d91602b57fd5bf38260781b17602052603760096000f090506001600160a01b038116611ba45760405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b6044820152606401611a6f565b919050565b6040516001600160a01b0380851660248301528316604482015260648101829052610faa9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612022565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60075460009081906001600160a01b03908116908916819003611c8e578760009250925050611f2d565b611ca26001600160a01b038a16878a6120f4565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015611ce9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0d9190612b24565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038c16906370a0823190602401602060405180830381865afa158015611d57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7b9190612b24565b90506000886001600160a01b03168888604051611d99929190612b3d565b6000604051808303816000865af19150503d8060008114611dd6576040519150601f19603f3d011682016040523d82523d6000602084013e611ddb565b606091505b5050905080611dfd5760405163081ceff360e41b815260040160405180910390fd5b6040516370a0823160e01b815230600482015283906001600160a01b038616906370a0823190602401602060405180830381865afa158015611e43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e679190612b24565b611e719190612a29565b6040516370a0823160e01b81523060048201529096506001600160a01b038d16906370a0823190602401602060405180830381865afa158015611eb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611edc9190612b24565b611ee69083612a29565b611ef0908c612a29565b945089861015611f1357604051638a866e2560e01b815260040160405180910390fd5b611f286001600160a01b038d168a60006120f4565b505050505b965096945050505050565b6000808060001985870985870292508281108382030391505080600003611f7257838281611f6857611f68612b4d565b0492505050611fe6565b808411611f7e57600080fd5b600084868809851960019081018716968790049682860381900495909211909303600082900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b6040516001600160a01b03831660248201526044810182905261201d90849063a9059cbb60e01b90606401611bdd565b505050565b6000612077826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166122099092919063ffffffff16565b80519091501561201d57808060200190518101906120959190612b63565b61201d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611a6f565b80158061216e5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015612148573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216c9190612b24565b155b6121d95760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401611a6f565b6040516001600160a01b03831660248201526044810182905261201d90849063095ea7b360e01b90606401611bdd565b60606122188484600085612220565b949350505050565b6060824710156122815760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611a6f565b600080866001600160a01b0316858760405161229d9190612ba4565b60006040518083038185875af1925050503d80600081146122da576040519150601f19603f3d011682016040523d82523d6000602084013e6122df565b606091505b50915091506122f0878383876122fb565b979650505050505050565b6060831561236a578251600003612363576001600160a01b0385163b6123635760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611a6f565b5081612218565b612218838381511561237f5781518083602001fd5b8060405162461bcd60e51b8152600401611a6f9190612bc0565b6000602082840312156123ab57600080fd5b5035919050565b803563ffffffff81168114611ba457600080fd5b6000602082840312156123d857600080fd5b611fe6826123b2565b600080604083850312156123f457600080fd5b6123fd836123b2565b915061240b602084016123b2565b90509250929050565b8015158114610a4357600080fd5b8035611ba481612414565b60006020828403121561243f57600080fd5b8135611fe681612414565b6001600160a01b0381168114610a4357600080fd5b8035611ba48161244a565b6000806040838503121561247d57600080fd5b82356124888161244a565b915060208301356124988161244a565b809150509250929050565b6000602082840312156124b557600080fd5b813567ffffffffffffffff8111156124cc57600080fd5b82016101c08185031215611fe657600080fd5b600080600080608085870312156124f557600080fd5b84356125008161244a565b935060208501356125108161244a565b93969395505050506040820135916060013590565b803561ffff81168114611ba457600080fd5b6000806040838503121561254a57600080fd5b61255383612525565b915061240b60208401612525565b60006020828403121561257357600080fd5b8135611fe68161244a565b6000806040838503121561259157600080fd5b823561259c8161244a565b9150602083013561249881612414565b60008083601f8401126125be57600080fd5b50813567ffffffffffffffff8111156125d657600080fd5b6020830191508360208285010111156125ee57600080fd5b9250929050565b600080600080600080600060a0888a03121561261057600080fd5b873561261b8161244a565b9650602088013567ffffffffffffffff8082111561263857600080fd5b818a0191508a601f83011261264c57600080fd5b81358181111561265b57600080fd5b8b60208260051b850101111561267057600080fd5b602083019850965060408a0135955061268b60608b0161245f565b945060808a01359150808211156126a157600080fd5b506126ae8a828b016125ac565b989b979a50959850939692959293505050565b600080602083850312156126d457600080fd5b823567ffffffffffffffff8111156126eb57600080fd5b6126f7858286016125ac565b90969095509350505050565b6000808335601e1984360301811261271a57600080fd5b830160208101925035905067ffffffffffffffff81111561273a57600080fd5b8036038213156125ee57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000808335601e1984360301811261278957600080fd5b830160208101925035905067ffffffffffffffff8111156127a957600080fd5b8060051b36038213156125ee57600080fd5b8183526000602080850194508260005b858110156127f95781356127de8161244a565b6001600160a01b0316875295820195908201906001016127cb565b509495945050505050565b61ffff8061281183612525565b1683528061282160208401612525565b1660208401528061283460408401612525565b166040840152505050565b60208152600061284f8384612703565b6101c08060208601526128676101e086018385612749565b92506128766020870187612703565b9250601f1980878603016040880152612890858584612749565b945061289f6040890189612772565b94509150808786030160608801526128b88585846127bb565b94506128c6606089016123b2565b63ffffffff8116608089015293506128e0608089016123b2565b63ffffffff811660a089015293506128fa60a08901612525565b61ffff811660c0890152935061291660e0880160c08a01612804565b612923610120890161245f565b9350610140915061293e828801856001600160a01b03169052565b61294982890161245f565b93506101609150612964828801856001600160a01b03169052565b61296f82890161245f565b9350610180915061298a828801856001600160a01b03169052565b612995828901612422565b93506101a091506129a98288018515159052565b6129b582890189612703565b94509150808786030183880152506122f0848483612749565b634e487b7160e01b600052601160045260246000fd5b808201808211156129f7576129f76129ce565b92915050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b818103818111156129f7576129f76129ce565b6001600160a01b038c811682528b811660208301528a166040820152606081018990526080810188905260a0810187905263ffffffff861660c082015260e081018590526101008101849052610160810160038410612aab57634e487b7160e01b600052602160045260246000fd5b83610120830152612ac161014083018415159052565b9c9b505050505050505050505050565b600060208284031215612ae357600080fd5b8151611fe68161244a565b602081526000612218602083018486612749565b61ffff818116838216019080821115612b1d57612b1d6129ce565b5092915050565b600060208284031215612b3657600080fd5b5051919050565b8183823760009101908152919050565b634e487b7160e01b600052601260045260246000fd5b600060208284031215612b7557600080fd5b8151611fe681612414565b60005b83811015612b9b578181015183820152602001612b83565b50506000910152565b60008251612bb6818460208701612b80565b9190910192915050565b6020815260008251806020840152612bdf816040850160208701612b80565b601f01601f1916919091016040019291505056fea264697066735822122008e20e885bcbd634116756388a3314073f7d027fb51e915cb131d91c5a80dd8c64736f6c63430008100033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000028a7c6873dfa8357c9dcf9c9d76ef2abb66256e00000000000000000000000007368f6a959ef3096230a258dd0af692699c3a4c000000000000000000000000cbe0b90bfe99f827b8bcb5c5ac4b17107caea814000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e198cbb727758b9ad38a12e1ad475a843e5e730f
-----Decoded View---------------
Arg [0] : _hatVaultImplementation (address): 0x028A7C6873dFA8357c9dcF9C9d76EF2abb66256E
Arg [1] : _hatGovernance (address): 0x07368F6a959Ef3096230a258dd0af692699c3a4c
Arg [2] : _defaultArbitrator (address): 0xcBe0b90bfe99f827B8BCB5C5Ac4b17107caEA814
Arg [3] : _HAT (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [4] : _bountyGovernanceHAT (uint16): 1000
Arg [5] : _bountyHackerHATVested (uint16): 0
Arg [6] : _tokenLockFactory (address): 0xe198CBb727758b9Ad38a12E1ad475a843e5e730F
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 000000000000000000000000028a7c6873dfa8357c9dcf9c9d76ef2abb66256e
Arg [1] : 00000000000000000000000007368f6a959ef3096230a258dd0af692699c3a4c
Arg [2] : 000000000000000000000000cbe0b90bfe99f827b8bcb5c5ac4b17107caea814
Arg [3] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [4] : 00000000000000000000000000000000000000000000000000000000000003e8
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [6] : 000000000000000000000000e198cbb727758b9ad38a12e1ad475a843e5e730f
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.