Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Loading...
Loading
Contract Name:
OverdropRewards
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 100 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "../utils/proxy/ProxyOwned.sol";
import "../utils/proxy/ProxyPausable.sol";
import "../utils/proxy/ProxyReentrancyGuard.sol";
contract OverdropRewards is Initializable, ProxyOwned, ProxyPausable, ProxyReentrancyGuard {
using SafeERC20 for IERC20;
error InvalidMerkleRoot();
error InvalidAmount();
error AlreadyClaimed();
error ClaimsDisabled();
error InvalidRecipient();
error InvalidMerkleProof();
error InvalidSeason();
// The reward token being distributed
IERC20 public collateral;
// Current merkle root for reward distribution
bytes32 public merkleRoot;
// Total amount of rewards that have been claimed
mapping(uint256 => uint256) public totalClaimed;
// Mapping to track if an address has claimed their rewards per season
mapping(address => mapping(uint256 => bool)) public hasClaimed;
// Flag to enable/disable claims
bool public claimsEnabled;
// Distribution round/epoch for tracking updates
uint256 public currentSeason;
/**
* @notice Initialize the contract
* @param _owner The contract owner
* @param _collateral The ERC20 token to distribute as collateral
* @param _merkleRoot Initial merkle root
*/
function initialize(address _owner, address _collateral, bytes32 _merkleRoot) external initializer {
setOwner(_owner);
initNonReentrant();
collateral = IERC20(_collateral);
merkleRoot = _merkleRoot;
currentSeason = 1;
emit MerkleRootUpdated(bytes32(0), _merkleRoot, currentSeason);
}
/* ========== VIEW FUNCTIONS ========== */
/**
* @notice Check if an address has claimed their rewards in the current season
* @param account The address to check
* @return Whether the address has claimed
*/
function hasClaimedCurrentSeason(address account) external view returns (bool) {
return hasClaimed[account][currentSeason];
}
/**
* @notice Verify a merkle proof without claiming
* @param account The account address
* @param amount The reward amount
* @param merkleProof The proof to verify
* @return Whether the proof is valid
*/
function verifyProof(address account, uint256 amount, bytes32[] calldata merkleProof) external view returns (bool) {
bytes32 leaf = keccak256(abi.encodePacked(account, amount));
return MerkleProof.verify(merkleProof, merkleRoot, leaf);
}
/* ========== EXTERNAL FUNCTIONS ========== */
/**
* @notice Claim rewards using merkle proof
* @param amount The amount of rewards to claim
* @param merkleProof The merkle proof for the claim
*/
function claimRewards(uint256 amount, bytes32[] calldata merkleProof) external nonReentrant notPaused {
if (!claimsEnabled) revert ClaimsDisabled();
if (hasClaimed[msg.sender][currentSeason]) revert AlreadyClaimed();
if (amount == 0) revert InvalidAmount();
// Verify the merkle proof
bytes32 leaf = keccak256(abi.encodePacked(msg.sender, amount));
if (!MerkleProof.verify(merkleProof, merkleRoot, leaf)) revert InvalidMerkleProof();
// Mark as claimed
hasClaimed[msg.sender][currentSeason] = true;
totalClaimed[currentSeason] += amount;
// Transfer rewards
collateral.safeTransfer(msg.sender, amount);
emit RewardsClaimed(msg.sender, amount, currentSeason);
}
/**
* @notice Toggle claims on/off
* @param enabled Whether claims should be enabled
*/
function setClaimsEnabled(bool enabled) external onlyOwner {
claimsEnabled = enabled;
emit ClaimsEnabled(enabled);
}
/**
* @notice Update the merkle root (upgradeable functionality)
* @param newMerkleRoot The new merkle root
* @param resetClaims Whether to reset all claim states
*/
function updateMerkleRoot(bytes32 newMerkleRoot, bool resetClaims, uint256 newSeason) external onlyOwner {
if (newMerkleRoot == bytes32(0)) revert InvalidMerkleRoot();
if (newSeason == 0) revert InvalidSeason();
bytes32 oldRoot = merkleRoot;
merkleRoot = newMerkleRoot;
currentSeason = newSeason;
if (resetClaims) {
totalClaimed[newSeason] = 0;
}
emit MerkleRootUpdated(oldRoot, newMerkleRoot, newSeason);
}
/**
* @notice Set the collateral token
* @param _collateral The new collateral token
*/
function setCollateral(address _collateral) external onlyOwner {
collateral = IERC20(_collateral);
emit RewardsCollateralUpdated(_collateral);
}
/**
* @notice Emergency withdraw function for owner
* @param amount Amount to withdraw (0 = all)
* @param recipient Address to send tokens to
*/
function withdrawCollateral(uint256 amount, address recipient) external onlyOwner {
if (recipient == address(0)) revert InvalidRecipient();
uint256 balance = collateral.balanceOf(address(this));
uint256 withdrawAmount = amount > balance ? balance : amount;
collateral.safeTransfer(recipient, withdrawAmount);
emit CollateralWithdrawn(withdrawAmount, recipient);
}
/* ========== EVENTS ========== */
event RewardsClaimed(address indexed account, uint256 amount, uint256 round);
event MerkleRootUpdated(bytes32 oldRoot, bytes32 newRoot, uint256 newRound);
event ClaimsEnabled(bool enabled);
event RewardsCollateralUpdated(address indexed collateral);
event CollateralWithdrawn(uint256 amount, address indexed recipient);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MerkleProof.sol)
pragma solidity ^0.8.20;
/**
* @dev These functions deal with verification of Merkle Tree proofs.
*
* The tree and the proofs can be generated using our
* https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
* You will find a quickstart guide in the readme.
*
* WARNING: You should avoid using leaf values that are 64 bytes long prior to
* hashing, or use a hash function other than keccak256 for hashing leaves.
* This is because the concatenation of a sorted pair of internal nodes in
* the Merkle tree could be reinterpreted as a leaf value.
* OpenZeppelin's JavaScript library generates Merkle trees that are safe
* against this attack out of the box.
*/
library MerkleProof {
/**
*@dev The multiproof provided is not valid.
*/
error MerkleProofInvalidMultiproof();
/**
* @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
* defined by `root`. For this, a `proof` must be provided, containing
* sibling hashes on the branch from the leaf to the root of the tree. Each
* pair of leaves and each pair of pre-images are assumed to be sorted.
*/
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
/**
* @dev Calldata version of {verify}
*/
function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProofCalldata(proof, leaf) == root;
}
/**
* @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
* hash matches the root of the tree. When processing the proof, the pairs
* of leafs & pre-images are assumed to be sorted.
*/
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Calldata version of {processProof}
*/
function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
* `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
*
* CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
*/
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
/**
* @dev Calldata version of {multiProofVerify}
*
* CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
*/
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
/**
* @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
* proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
* leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
* respectively.
*
* CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
* is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
* tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
*/
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the Merkle tree.
uint256 leavesLen = leaves.length;
uint256 proofLen = proof.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
if (leavesLen + proofLen != totalHashes + 1) {
revert MerkleProofInvalidMultiproof();
}
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
// `proof` array.
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
if (proofPos != proofLen) {
revert MerkleProofInvalidMultiproof();
}
unchecked {
return hashes[totalHashes - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
/**
* @dev Calldata version of {processMultiProof}.
*
* CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
*/
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the Merkle tree.
uint256 leavesLen = leaves.length;
uint256 proofLen = proof.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
if (leavesLen + proofLen != totalHashes + 1) {
revert MerkleProofInvalidMultiproof();
}
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
// `proof` array.
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
if (proofPos != proofLen) {
revert MerkleProofInvalidMultiproof();
}
unchecked {
return hashes[totalHashes - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
/**
* @dev Sorts the pair (a, b) and hashes the result.
*/
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
}
/**
* @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.
*/
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// Clone of syntetix contract without constructor
contract ProxyOwned {
address public owner;
address public nominatedOwner;
bool private _initialized;
bool private _transferredAtInit;
function setOwner(address _owner) public {
require(_owner != address(0), "Owner address cannot be 0");
require(!_initialized, "Already initialized, use nominateNewOwner");
_initialized = true;
owner = _owner;
emit OwnerChanged(address(0), _owner);
}
function nominateNewOwner(address _owner) external onlyOwner {
nominatedOwner = _owner;
emit OwnerNominated(_owner);
}
function acceptOwnership() external {
require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership");
emit OwnerChanged(owner, nominatedOwner);
owner = nominatedOwner;
nominatedOwner = address(0);
}
function transferOwnershipAtInit(address proxyAddress) external onlyOwner {
require(proxyAddress != address(0), "Invalid address");
require(!_transferredAtInit, "Already transferred");
owner = proxyAddress;
_transferredAtInit = true;
emit OwnerChanged(owner, proxyAddress);
}
modifier onlyOwner() {
_onlyOwner();
_;
}
function _onlyOwner() private view {
require(msg.sender == owner, "Only the contract owner may perform this action");
}
event OwnerNominated(address newOwner);
event OwnerChanged(address oldOwner, address newOwner);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// Inheritance
import "./ProxyOwned.sol";
// Clone of syntetix contract without constructor
contract ProxyPausable is ProxyOwned {
uint public lastPauseTime;
bool public paused;
/**
* @notice Change the paused state of the contract
* @dev Only the contract owner may call this.
*/
function setPaused(bool _paused) external onlyOwner {
// Ensure we're actually changing the state before we do anything
if (_paused == paused) {
return;
}
// Set our paused state.
paused = _paused;
// If applicable, set the last pause time.
if (paused) {
lastPauseTime = block.timestamp;
}
// Let everyone know that our pause state has changed.
emit PauseChanged(paused);
}
event PauseChanged(bool isPaused);
modifier notPaused() {
require(!paused, "This action cannot be performed while the contract is paused");
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the `nonReentrant` modifier
* available, which can be aplied 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.
*/
contract ProxyReentrancyGuard {
/// @dev counter to allow mutex lock with only one SSTORE operation
uint256 private _guardCounter;
bool private _initialized;
function initNonReentrant() public {
require(!_initialized, "Already initialized");
_initialized = true;
_guardCounter = 1;
}
/**
* @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 make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_guardCounter += 1;
uint256 localCounter = _guardCounter;
_;
require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call");
}
}{
"optimizer": {
"enabled": true,
"runs": 100
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract ABI
API[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AlreadyClaimed","type":"error"},{"inputs":[],"name":"ClaimsDisabled","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidMerkleProof","type":"error"},{"inputs":[],"name":"InvalidMerkleRoot","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidSeason","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"ClaimsEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"CollateralWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"oldRoot","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"newRoot","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"newRound","type":"uint256"}],"name":"MerkleRootUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"PauseChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"RewardsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collateral","type":"address"}],"name":"RewardsCollateralUpdated","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimsEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateral","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentSeason","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"hasClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"hasClaimedCurrentSeason","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initNonReentrant","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_collateral","type":"address"},{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastPauseTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setClaimsEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_collateral","type":"address"}],"name":"setCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalClaimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"proxyAddress","type":"address"}],"name":"transferOwnershipAtInit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"newMerkleRoot","type":"bytes32"},{"internalType":"bool","name":"resetClaims","type":"bool"},{"internalType":"uint256","name":"newSeason","type":"uint256"}],"name":"updateMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"name":"verifyProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"withdrawCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b506114f6806100206000396000f3fe608060405234801561001057600080fd5b50600436106101585760003560e01c8063886abef5116100c3578063c3b83f5f1161007c578063c3b83f5f146102cb578063d7d76b0f146102de578063d8dfeb4514610317578063eaab2c3f1461032f578063ebc797721461034f578063f616ec851461035757600080fd5b8063886abef5146102525780638da5cb5b1461026557806391b4ded914610278578063abd40e1e14610281578063b293109614610294578063bcb39621146102c257600080fd5b80632eb4a7ab116101155780632eb4a7ab146101e057806353a47bb7146101f75780635c975abb146102175780636133f985146102245780637564a48b1461023757806379ba50971461024a57600080fd5b80630406aa611461015d5780630af504cc1461017f57806313af4035146101945780631627540c146101a757806316c38b3c146101ba57806321e39729146101cd575b600080fd5b60095461016a9060ff1681565b60405190151581526020015b60405180910390f35b61019261018d366004611178565b61036a565b005b6101926101a23660046111a4565b61048b565b6101926101b53660046111a4565b6105a7565b6101926101c83660046111cd565b6105fa565b6101926101db3660046111ea565b61066c565b6101e960065481565b604051908152602001610176565b60015461020a906001600160a01b031681565b6040516101769190611222565b60035461016a9060ff1681565b610192610232366004611236565b61071d565b6101926102453660046111cd565b6108a6565b6101926108ef565b6101926102603660046111a4565b6109c7565b60005461020a906001600160a01b031681565b6101e960025481565b61019261028f3660046112be565b610a21565b61016a6102a236600461130a565b600860209081526000928352604080842090915290825290205460ff1681565b6101e9600a5481565b6101926102d93660046111a4565b610cc2565b61016a6102ec3660046111a4565b6001600160a01b03166000908152600860209081526040808320600a54845290915290205460ff1690565b60055461020a9061010090046001600160a01b031681565b6101e961033d366004611334565b60076020526000908152604090205481565b610192610db2565b61016a61036536600461134d565b610e10565b610372610e89565b6001600160a01b03811661039957604051634e46966960e11b815260040160405180910390fd5b6005546040516370a0823160e01b815260009161010090046001600160a01b0316906370a08231906103cf903090600401611222565b602060405180830381865afa1580156103ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041091906113a7565b905060008184116104215783610423565b815b6005549091506104429061010090046001600160a01b03168483610efd565b826001600160a01b03167f2d428178e65c47bfb7d75b43e57e93851220995d8887d6826253c18d9b9fc99f8260405161047d91815260200190565b60405180910390a250505050565b6001600160a01b0381166104e25760405162461bcd60e51b815260206004820152601960248201527804f776e657220616464726573732063616e6e6f74206265203603c1b60448201526064015b60405180910390fd5b600154600160a01b900460ff161561054e5760405162461bcd60e51b815260206004820152602960248201527f416c726561647920696e697469616c697a65642c20757365206e6f6d696e617460448201526832a732bba7bbb732b960b91b60648201526084016104d9565b6001805460ff60a01b1916600160a01b179055600080546001600160a01b0383166001600160a01b03199091161781556040516000805160206114a18339815191529161059c9184906113c0565b60405180910390a150565b6105af610e89565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229061059c908390611222565b610602610e89565b60035460ff16151581151514610669576003805460ff191682151590811790915560ff161561063057426002555b60035460405160ff909116151581527f8fb6c181ee25a520cf3dd6565006ef91229fcfe5a989566c2a3b8c115570cec59060200161059c565b50565b610674610e89565b8261069257604051639dd854d360e01b815260040160405180910390fd5b806000036106b35760405163d40820c360e01b815260040160405180910390fd5b6006805490849055600a82905582156106d6576000828152600760205260408120555b60408051828152602081018690529081018390527f4245c4fc9e349a90fcc3b21a800990dd8bbc22ca78480f3a9354e024d627a5e89060600160405180910390a150505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156107635750825b905060008267ffffffffffffffff1660011480156107805750303b155b90508115801561078e575080155b156107ac5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156107d657845460ff60401b1916600160401b1785555b6107df8861048b565b6107e7610db2565b60058054610100600160a81b0319166101006001600160a01b038a160217905560068690556001600a819055604080516000815260208101899052908101919091527f4245c4fc9e349a90fcc3b21a800990dd8bbc22ca78480f3a9354e024d627a5e89060600160405180910390a1831561089c57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b6108ae610e89565b6009805460ff19168215159081179091556040519081527f3a869d9664493bfe0738e60e82e556b36b71fe12c90258fc7960f8f236de8c449060200161059c565b6001546001600160a01b031633146109675760405162461bcd60e51b815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527402063616e20616363657074206f776e65727368697605c1b60648201526084016104d9565b6000546001546040516000805160206114a183398151915292610998926001600160a01b03918216929116906113c0565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6109cf610e89565b60058054610100600160a81b0319166101006001600160a01b038416908102919091179091556040517fcbf7a97486a086d9a64b3c92cafb67161a05f39b24d342a7836518a14556938e90600090a250565b600160046000828254610a3491906113f0565b909155505060045460035460ff1615610ab55760405162461bcd60e51b815260206004820152603c60248201527f5468697320616374696f6e2063616e6e6f7420626520706572666f726d65642060448201527f7768696c652074686520636f6e7472616374206973207061757365640000000060648201526084016104d9565b60095460ff16610ad857604051632e372e6560e01b815260040160405180910390fd5b336000908152600860209081526040808320600a54845290915290205460ff1615610b1657604051630c8d9eab60e31b815260040160405180910390fd5b83600003610b375760405163162908e360e11b815260040160405180910390fd5b60003385604051602001610b4c929190611403565b604051602081830303815290604052805190602001209050610ba5848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506006549150849050610f54565b610bc25760405163582f497d60e11b815260040160405180910390fd5b336000908152600860209081526040808320600a80548552908352818420805460ff19166001179055548352600790915281208054879290610c059084906113f0565b9091555050600554610c269061010090046001600160a01b03163387610efd565b600a5460405133917fdacbdde355ba930696a362ea6738feb9f8bd52dfb3d81947558fd3217e23e32591610c6291898252602082015260400190565b60405180910390a2506004548114610cbc5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016104d9565b50505050565b610cca610e89565b6001600160a01b038116610d125760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064016104d9565b600154600160a81b900460ff1615610d625760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481d1c985b9cd9995c9c9959606a1b60448201526064016104d9565b600080546001600160a01b0383166001600160a01b031990911681179091556001805460ff60a81b1916600160a81b1790556040516000805160206114a18339815191529161059c9184906113c0565b60055460ff1615610dfb5760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b60448201526064016104d9565b6005805460ff19166001908117909155600455565b6000808585604051602001610e26929190611403565b604051602081830303815290604052805190602001209050610e7f848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506006549150849050610f54565b9695505050505050565b6000546001600160a01b03163314610efb5760405162461bcd60e51b815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201526e37b936903a3434b99030b1ba34b7b760891b60648201526084016104d9565b565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610f4f908490610f6c565b505050565b600082610f618584610fc6565b1490505b9392505050565b6000610f816001600160a01b03841683611015565b90508051600014158015610fa6575080806020019051810190610fa49190611425565b155b15610f4f5782604051635274afe760e01b81526004016104d99190611222565b600081815b845181101561100b57610ff782868381518110610fea57610fea611442565b6020026020010151611023565b91508061100381611458565b915050610fcb565b5090505b92915050565b6060610f6583836000611052565b600081831061103f576000828152602084905260409020610f65565b6000838152602083905260409020610f65565b606081471015611077573060405163cd78605960e01b81526004016104d99190611222565b600080856001600160a01b031684866040516110939190611471565b60006040518083038185875af1925050503d80600081146110d0576040519150601f19603f3d011682016040523d82523d6000602084013e6110d5565b606091505b5091509150610e7f8683836060826110f5576110f082611133565b610f65565b815115801561110c57506001600160a01b0384163b155b1561112c5783604051639996b31560e01b81526004016104d99190611222565b5080610f65565b8051156111435780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b80356001600160a01b038116811461117357600080fd5b919050565b6000806040838503121561118b57600080fd5b8235915061119b6020840161115c565b90509250929050565b6000602082840312156111b657600080fd5b610f658261115c565b801515811461066957600080fd5b6000602082840312156111df57600080fd5b8135610f65816111bf565b6000806000606084860312156111ff57600080fd5b833592506020840135611211816111bf565b929592945050506040919091013590565b6001600160a01b0391909116815260200190565b60008060006060848603121561124b57600080fd5b6112548461115c565b92506112626020850161115c565b9150604084013590509250925092565b60008083601f84011261128457600080fd5b50813567ffffffffffffffff81111561129c57600080fd5b6020830191508360208260051b85010111156112b757600080fd5b9250929050565b6000806000604084860312156112d357600080fd5b83359250602084013567ffffffffffffffff8111156112f157600080fd5b6112fd86828701611272565b9497909650939450505050565b6000806040838503121561131d57600080fd5b6113268361115c565b946020939093013593505050565b60006020828403121561134657600080fd5b5035919050565b6000806000806060858703121561136357600080fd5b61136c8561115c565b935060208501359250604085013567ffffffffffffffff81111561138f57600080fd5b61139b87828801611272565b95989497509550505050565b6000602082840312156113b957600080fd5b5051919050565b6001600160a01b0392831681529116602082015260400190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561100f5761100f6113da565b60609290921b6bffffffffffffffffffffffff19168252601482015260340190565b60006020828403121561143757600080fd5b8151610f65816111bf565b634e487b7160e01b600052603260045260246000fd5b60006001820161146a5761146a6113da565b5060010190565b6000825160005b818110156114925760208186018101518583015201611478565b50600092019182525091905056feb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159ca2646970667358221220197b6b6629ed38afd6298d288add02f85750d8a59b6ec375f684a1b9dbe1404864736f6c63430008140033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101585760003560e01c8063886abef5116100c3578063c3b83f5f1161007c578063c3b83f5f146102cb578063d7d76b0f146102de578063d8dfeb4514610317578063eaab2c3f1461032f578063ebc797721461034f578063f616ec851461035757600080fd5b8063886abef5146102525780638da5cb5b1461026557806391b4ded914610278578063abd40e1e14610281578063b293109614610294578063bcb39621146102c257600080fd5b80632eb4a7ab116101155780632eb4a7ab146101e057806353a47bb7146101f75780635c975abb146102175780636133f985146102245780637564a48b1461023757806379ba50971461024a57600080fd5b80630406aa611461015d5780630af504cc1461017f57806313af4035146101945780631627540c146101a757806316c38b3c146101ba57806321e39729146101cd575b600080fd5b60095461016a9060ff1681565b60405190151581526020015b60405180910390f35b61019261018d366004611178565b61036a565b005b6101926101a23660046111a4565b61048b565b6101926101b53660046111a4565b6105a7565b6101926101c83660046111cd565b6105fa565b6101926101db3660046111ea565b61066c565b6101e960065481565b604051908152602001610176565b60015461020a906001600160a01b031681565b6040516101769190611222565b60035461016a9060ff1681565b610192610232366004611236565b61071d565b6101926102453660046111cd565b6108a6565b6101926108ef565b6101926102603660046111a4565b6109c7565b60005461020a906001600160a01b031681565b6101e960025481565b61019261028f3660046112be565b610a21565b61016a6102a236600461130a565b600860209081526000928352604080842090915290825290205460ff1681565b6101e9600a5481565b6101926102d93660046111a4565b610cc2565b61016a6102ec3660046111a4565b6001600160a01b03166000908152600860209081526040808320600a54845290915290205460ff1690565b60055461020a9061010090046001600160a01b031681565b6101e961033d366004611334565b60076020526000908152604090205481565b610192610db2565b61016a61036536600461134d565b610e10565b610372610e89565b6001600160a01b03811661039957604051634e46966960e11b815260040160405180910390fd5b6005546040516370a0823160e01b815260009161010090046001600160a01b0316906370a08231906103cf903090600401611222565b602060405180830381865afa1580156103ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041091906113a7565b905060008184116104215783610423565b815b6005549091506104429061010090046001600160a01b03168483610efd565b826001600160a01b03167f2d428178e65c47bfb7d75b43e57e93851220995d8887d6826253c18d9b9fc99f8260405161047d91815260200190565b60405180910390a250505050565b6001600160a01b0381166104e25760405162461bcd60e51b815260206004820152601960248201527804f776e657220616464726573732063616e6e6f74206265203603c1b60448201526064015b60405180910390fd5b600154600160a01b900460ff161561054e5760405162461bcd60e51b815260206004820152602960248201527f416c726561647920696e697469616c697a65642c20757365206e6f6d696e617460448201526832a732bba7bbb732b960b91b60648201526084016104d9565b6001805460ff60a01b1916600160a01b179055600080546001600160a01b0383166001600160a01b03199091161781556040516000805160206114a18339815191529161059c9184906113c0565b60405180910390a150565b6105af610e89565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229061059c908390611222565b610602610e89565b60035460ff16151581151514610669576003805460ff191682151590811790915560ff161561063057426002555b60035460405160ff909116151581527f8fb6c181ee25a520cf3dd6565006ef91229fcfe5a989566c2a3b8c115570cec59060200161059c565b50565b610674610e89565b8261069257604051639dd854d360e01b815260040160405180910390fd5b806000036106b35760405163d40820c360e01b815260040160405180910390fd5b6006805490849055600a82905582156106d6576000828152600760205260408120555b60408051828152602081018690529081018390527f4245c4fc9e349a90fcc3b21a800990dd8bbc22ca78480f3a9354e024d627a5e89060600160405180910390a150505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156107635750825b905060008267ffffffffffffffff1660011480156107805750303b155b90508115801561078e575080155b156107ac5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156107d657845460ff60401b1916600160401b1785555b6107df8861048b565b6107e7610db2565b60058054610100600160a81b0319166101006001600160a01b038a160217905560068690556001600a819055604080516000815260208101899052908101919091527f4245c4fc9e349a90fcc3b21a800990dd8bbc22ca78480f3a9354e024d627a5e89060600160405180910390a1831561089c57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b6108ae610e89565b6009805460ff19168215159081179091556040519081527f3a869d9664493bfe0738e60e82e556b36b71fe12c90258fc7960f8f236de8c449060200161059c565b6001546001600160a01b031633146109675760405162461bcd60e51b815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527402063616e20616363657074206f776e65727368697605c1b60648201526084016104d9565b6000546001546040516000805160206114a183398151915292610998926001600160a01b03918216929116906113c0565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6109cf610e89565b60058054610100600160a81b0319166101006001600160a01b038416908102919091179091556040517fcbf7a97486a086d9a64b3c92cafb67161a05f39b24d342a7836518a14556938e90600090a250565b600160046000828254610a3491906113f0565b909155505060045460035460ff1615610ab55760405162461bcd60e51b815260206004820152603c60248201527f5468697320616374696f6e2063616e6e6f7420626520706572666f726d65642060448201527f7768696c652074686520636f6e7472616374206973207061757365640000000060648201526084016104d9565b60095460ff16610ad857604051632e372e6560e01b815260040160405180910390fd5b336000908152600860209081526040808320600a54845290915290205460ff1615610b1657604051630c8d9eab60e31b815260040160405180910390fd5b83600003610b375760405163162908e360e11b815260040160405180910390fd5b60003385604051602001610b4c929190611403565b604051602081830303815290604052805190602001209050610ba5848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506006549150849050610f54565b610bc25760405163582f497d60e11b815260040160405180910390fd5b336000908152600860209081526040808320600a80548552908352818420805460ff19166001179055548352600790915281208054879290610c059084906113f0565b9091555050600554610c269061010090046001600160a01b03163387610efd565b600a5460405133917fdacbdde355ba930696a362ea6738feb9f8bd52dfb3d81947558fd3217e23e32591610c6291898252602082015260400190565b60405180910390a2506004548114610cbc5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016104d9565b50505050565b610cca610e89565b6001600160a01b038116610d125760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064016104d9565b600154600160a81b900460ff1615610d625760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481d1c985b9cd9995c9c9959606a1b60448201526064016104d9565b600080546001600160a01b0383166001600160a01b031990911681179091556001805460ff60a81b1916600160a81b1790556040516000805160206114a18339815191529161059c9184906113c0565b60055460ff1615610dfb5760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b60448201526064016104d9565b6005805460ff19166001908117909155600455565b6000808585604051602001610e26929190611403565b604051602081830303815290604052805190602001209050610e7f848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506006549150849050610f54565b9695505050505050565b6000546001600160a01b03163314610efb5760405162461bcd60e51b815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201526e37b936903a3434b99030b1ba34b7b760891b60648201526084016104d9565b565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610f4f908490610f6c565b505050565b600082610f618584610fc6565b1490505b9392505050565b6000610f816001600160a01b03841683611015565b90508051600014158015610fa6575080806020019051810190610fa49190611425565b155b15610f4f5782604051635274afe760e01b81526004016104d99190611222565b600081815b845181101561100b57610ff782868381518110610fea57610fea611442565b6020026020010151611023565b91508061100381611458565b915050610fcb565b5090505b92915050565b6060610f6583836000611052565b600081831061103f576000828152602084905260409020610f65565b6000838152602083905260409020610f65565b606081471015611077573060405163cd78605960e01b81526004016104d99190611222565b600080856001600160a01b031684866040516110939190611471565b60006040518083038185875af1925050503d80600081146110d0576040519150601f19603f3d011682016040523d82523d6000602084013e6110d5565b606091505b5091509150610e7f8683836060826110f5576110f082611133565b610f65565b815115801561110c57506001600160a01b0384163b155b1561112c5783604051639996b31560e01b81526004016104d99190611222565b5080610f65565b8051156111435780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b80356001600160a01b038116811461117357600080fd5b919050565b6000806040838503121561118b57600080fd5b8235915061119b6020840161115c565b90509250929050565b6000602082840312156111b657600080fd5b610f658261115c565b801515811461066957600080fd5b6000602082840312156111df57600080fd5b8135610f65816111bf565b6000806000606084860312156111ff57600080fd5b833592506020840135611211816111bf565b929592945050506040919091013590565b6001600160a01b0391909116815260200190565b60008060006060848603121561124b57600080fd5b6112548461115c565b92506112626020850161115c565b9150604084013590509250925092565b60008083601f84011261128457600080fd5b50813567ffffffffffffffff81111561129c57600080fd5b6020830191508360208260051b85010111156112b757600080fd5b9250929050565b6000806000604084860312156112d357600080fd5b83359250602084013567ffffffffffffffff8111156112f157600080fd5b6112fd86828701611272565b9497909650939450505050565b6000806040838503121561131d57600080fd5b6113268361115c565b946020939093013593505050565b60006020828403121561134657600080fd5b5035919050565b6000806000806060858703121561136357600080fd5b61136c8561115c565b935060208501359250604085013567ffffffffffffffff81111561138f57600080fd5b61139b87828801611272565b95989497509550505050565b6000602082840312156113b957600080fd5b5051919050565b6001600160a01b0392831681529116602082015260400190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561100f5761100f6113da565b60609290921b6bffffffffffffffffffffffff19168252601482015260340190565b60006020828403121561143757600080fd5b8151610f65816111bf565b634e487b7160e01b600052603260045260246000fd5b60006001820161146a5761146a6113da565b5060010190565b6000825160005b818110156114925760208186018101518583015201611478565b50600092019182525091905056feb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159ca2646970667358221220197b6b6629ed38afd6298d288add02f85750d8a59b6ec375f684a1b9dbe1404864736f6c63430008140033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.