Source Code
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Cross-Chain Transactions
Loading...
Loading
Contract Name:
ERC20DAO
Compiler Version
v0.8.16+commit.07a7930e
Optimization Enabled:
Yes with 5 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./factory.sol";
import "./emitter.sol";
import "./helper.sol";
interface IERC20Extented is IERC20 {
function decimals() external view returns (uint8);
}
/// @title StationX Governance Token Contract
/// @dev Base Contract as a reference for DAO Governance Token contract proxies
contract ERC20DAO is
ERC20Upgradeable,
AccessControl,
IERC721Receiver,
ReentrancyGuard,
Helper
{
using SafeERC20 for IERC20;
///@dev address of the emitter contract
address public emitterContractAddress;
address public factoryAddress;
ERC20DAOdetails public erc20DaoDetails;
bytes32 constant RefundModule = keccak256("RefundModule");
constructor() {
_disableInitializers();
}
/// @dev initialize Function to initialize Token contract
function initializeERC20(
address _factory,
address _emitter,
string memory _DaoName,
string memory _DaoSymbol,
uint256 _quorum,
uint256 _threshold,
bool _isGovernanceActive,
bool _isTransferable,
bool _onlyAllowWhitelist,
address _owner
) external initializer {
factoryAddress = _factory;
emitterContractAddress = _emitter;
ERC20DAOdetails memory _erc20DaoDetails = ERC20DAOdetails(
_DaoName,
_DaoSymbol,
_quorum,
_threshold,
_isGovernanceActive,
_isTransferable,
_onlyAllowWhitelist,
_owner
);
erc20DaoDetails = _erc20DaoDetails;
__ERC20_init(_DaoName, _DaoSymbol);
}
/// @dev This function returns details of a particular dao
function getERC20DAOdetails()
external
view
returns (ERC20DAOdetails memory)
{
return erc20DaoDetails;
}
/// @dev Function execute proposals called by gnosis safe
/// @param _data function signature data encoded along with parameters
function updateProposalAndExecution(
address _contract,
bytes memory _data
) external onlyGnosis(factoryAddress, address(this)) nonReentrant {
if (_contract == address(0))
revert AddressInvalid("_contract", _contract);
(bool success, ) = _contract.call(_data);
require(success);
}
/// @dev Function to transfer NFT from this contract
/// @param _nft address of nft to transfer
/// @param _to address of receiver
/// @param _tokenId tokenId of nft to transfer
function transferNft(
address _nft,
address _to,
uint256 _tokenId
) external onlyCurrentContract {
if (_nft == address(0)) revert AddressInvalid("_nft", _nft);
if (_to == address(0)) revert AddressInvalid("_to", _to);
IERC721(_nft).safeTransferFrom(address(this), _to, _tokenId);
}
/// @dev function to mint GT token to a addresses
/// @param _amountArray array of amount to be transferred
/// @param _userAddress array of address where the amount should be transferred
function mintGTToAddress(
uint256[] memory _amountArray,
address[] memory _userAddress
) external onlyCurrentContract {
if (_amountArray.length != _userAddress.length)
revert ArrayLengthMismatch(
_amountArray.length,
_userAddress.length
);
uint256 leng = _amountArray.length;
for (uint256 i; i < leng; ) {
_mint(_userAddress[i], _amountArray[i]);
Emitter(emitterContractAddress).newUser(
address(this),
_userAddress[i],
Factory(factoryAddress)
.getDAOdetails(address(this))
.depositTokenAddress,
0,
block.timestamp,
_amountArray[i],
Safe(
Factory(factoryAddress)
.getDAOdetails(address(this))
.gnosisAddress
).isOwner(_userAddress[i])
);
unchecked {
++i;
}
}
Emitter(emitterContractAddress).mintGTToAddress(
address(this),
_amountArray,
_userAddress
);
}
/// @dev function to update governance settings
/// @param _quorum update quorum into the contract
/// @param _threshold update threshold into the contract
function updateGovernanceSettings(
uint256 _quorum,
uint256 _threshold
) external onlyCurrentContract {
if (_quorum == 0) revert AmountInvalid("_quorum", _quorum);
if (_threshold == 0) revert AmountInvalid("_threshold", _threshold);
if (!(_quorum <= FLOAT_HANDLER_TEN_4))
revert AmountInvalid("_quorum", _quorum);
if (!(_threshold <= FLOAT_HANDLER_TEN_4))
revert AmountInvalid("_threshold", _threshold);
erc20DaoDetails.quorum = _quorum;
erc20DaoDetails.threshold = _threshold;
Emitter(emitterContractAddress).updateGovernanceSettings(
address(this),
_quorum,
_threshold
);
}
/// @dev Function to change governance active
/// @param _isGovernanceActive New governance active status
function updateGovernanceActive(
bool _isGovernanceActive
) external payable onlyCurrentContract {
erc20DaoDetails.isGovernanceActive = _isGovernanceActive;
}
/// @dev Function to update token transferability for a particular token contract
/// @param _isTokenTransferable New token transferability
function updateTokenTransferability(
bool _isTokenTransferable
) external payable onlyCurrentContract {
erc20DaoDetails.isTransferable = _isTokenTransferable;
Emitter(emitterContractAddress).updateTokenTransferability(
address(this),
_isTokenTransferable
);
}
/// @dev Function to set whitelist to true for a particular token contract
function toggleOnlyAllowWhitelist() external payable onlyCurrentContract {
erc20DaoDetails.onlyAllowWhitelist = !erc20DaoDetails
.onlyAllowWhitelist;
}
/// @dev Function to override transfer to restrict token transfers
function transfer(
address to,
uint256 amount
) public virtual override(ERC20Upgradeable) returns (bool) {
require(erc20DaoDetails.isTransferable, "Token Non Transferable");
address owner = _msgSender();
_transfer(owner, to, amount);
Emitter(emitterContractAddress).transferGT(
address(this),
owner,
to,
amount
);
return true;
}
/// @dev Function to override transferFrom to restrict token transfers
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override(ERC20Upgradeable) returns (bool) {
require(erc20DaoDetails.isTransferable, "Token Non Transferable");
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
Emitter(emitterContractAddress).transferGT(
address(this),
from,
to,
amount
);
return true;
}
/// @dev Function to mint Governance Token and assign delegate
/// @param to Address to which tokens will be minted
/// @param amount Value of tokens to be minted based on deposit by DAO member
function mintToken(address to, uint256 amount) public {
require(msg.sender == factoryAddress || msg.sender == address(this));
_mint(to, amount);
}
// -- Who will have access control for burning tokens?
/// @dev Function to burn Governance Token
/// @param account Address from where token will be burned
/// @param amount Value of tokens to be burned
function burn(
address account,
uint256 amount
) external onlyRole(RefundModule) {
_burn(account, amount);
}
function grantRefundModule(
address _refundModule
) external payable onlyCurrentContract {
_grantRole(RefundModule, _refundModule);
}
/// @dev Internal function that needs to be override
function _msgSender()
internal
view
virtual
override(Context, ContextUpgradeable)
returns (address)
{
return msg.sender;
}
function _msgData()
internal
view
virtual
override(Context, ContextUpgradeable)
returns (bytes calldata)
{
return msg.data;
}
function onERC721Received(
address,
address,
uint256,
bytes calldata
) external pure override returns (bytes4) {
return IERC721Receiver.onERC721Received.selector;
}
receive() external payable {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* 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 Internal function that returns the initialized version. Returns `_initialized`
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Internal function that returns the initialized version. Returns `_initializing`
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// 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 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 (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.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) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @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 ReentrancyGuard {
// 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;
constructor() {
_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;
}
}// 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.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 (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) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// 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/cryptography/MerkleProof.sol)
pragma solidity ^0.8.0;
/**
* @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 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}
*
* _Available since v4.7._
*/
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.
*
* _Available since v4.4._
*/
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}
*
* _Available since v4.7._
*/
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.
*
* _Available since v4.7._
*/
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.
*
* _Available since v4.7._
*/
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).
*
* _Available since v4.7._
*/
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuild 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 totalHashes = proofFlags.length;
// Check proof validity.
require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
// 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 for 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) {
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.
*
* _Available since v4.7._
*/
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuild 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 totalHashes = proofFlags.length;
// Check proof validity.
require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
// 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 for 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) {
return hashes[totalHashes - 1];
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
}
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
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated 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
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
/// @title StationXFactory Emitter Contract
/// @dev Contract Emits events for Factory and Proxy
contract Emitter is Initializable, AccessControl {
bytes32 constant ADMIN = keccak256("ADMIN");
bytes32 public constant EMITTER = keccak256("EMITTER");
bytes32 public constant FACTORY = keccak256("FACTORY");
//FACTORY EVENTS
event DefineContracts(
address indexed factory,
address ERC20ImplementationAddress,
address ERC721ImplementationAddress,
address emitterImplementationAddress
);
event ChangeMerkleRoot(
address indexed factory,
address indexed daoAddress,
bytes32 newMerkleRoot
);
event CreateDaoErc20(
address indexed deployerAddress,
address indexed proxy,
string name,
string symbol,
uint256 distributionAmount,
uint256 pricePerToken,
uint256 minDeposit,
uint256 maxDeposit,
uint256 ownerFee,
uint256 _days,
uint256 quorum,
uint256 threshold,
address depositTokenAddress,
address emitter,
address gnosisAddress,
bool isGovernanceActive,
bool isTransferable,
bool assetsStoredOnGnosis
);
event CreateDaoErc721(
address indexed deployerAddress,
address indexed proxy,
string name,
string symbol,
string tokenURI,
uint256 pricePerToken,
uint256 distributionAmount,
uint256 maxTokensPerUser,
uint256 ownerFee,
uint256 _days,
uint256 quorum,
uint256 threshold,
address depositTokenAddress,
address emitter,
address gnosisAddress,
bool isGovernanceActive,
bool isTransferable,
bool assetsStoredOnGnosis
);
event FactoryCreated(
address indexed _ERC20Implementation,
address indexed _ERC721Implementation,
address indexed _factory,
address _emitter
);
//PROXY EVENTS
event Deposited(
address indexed _daoAddress,
address indexed _depositor,
address indexed _depositTokenAddress,
uint256 _amount,
uint256 _timeStamp,
uint256 _ownerFee,
uint256 _adminShare
);
event StartDeposit(
address indexed _proxy,
uint256 startTime,
uint256 closeTime
);
event CloseDeposit(address indexed _proxy, uint256 closeTime);
event UpdateMinMaxDeposit(
address indexed _proxy,
uint256 _minDeposit,
uint256 _maxDeposit
);
event UpdateOwnerFee(address indexed _proxy, uint256 _ownerFee);
event AirDropToken(
address indexed _daoAddress,
address _token,
address _to,
uint256 _amount
);
event MintGTToAddress(
address indexed _daoAddress,
uint256[] _amount,
address[] _userAddress
);
event UpdateGovernanceSettings(
address indexed _daoAddress,
uint256 _quorum,
uint256 _threshold
);
event UpdateDistributionAmount(
address indexed _daoAddress,
uint256 _amount
);
event UpdatePricePerToken(address indexed _daoAddress, uint256 _amount);
event SendCustomToken(
address indexed _daoAddress,
address _token,
uint256[] _amount,
address[] _addresses
);
event NewUser(
address indexed _daoAddress,
address indexed _depositor,
address indexed _depositTokenAddress,
uint256 _depositTokenAmount,
uint256 _timeStamp,
uint256 _gtToken,
bool _isAdmin
);
event NewUserCC(
address indexed _daoAddress,
address indexed _depositor,
address indexed _depositTokenAddress,
uint256 _depositTokenAmount,
uint256 _timeStamp,
uint256 _gtToken,
bool _isAdmin
);
//nft events
event MintNft(
address indexed _to,
address indexed _daoAddress,
string _tokenURI,
uint256 _tokenId
);
event UpdateMaxTokensPerUser(
address indexed _daoAddress,
uint256 _maxTokensPerUser
);
event UpdateTotalSupplyOfToken(
address indexed _daoAddress,
uint256 _totalSupplyOfToken
);
event UpdateTokenTransferability(
address indexed _daoAddress,
bool _isTokenTransferable
);
event WhitelistAddress(
address indexed _daoAddress,
address indexed _address
);
event RemoveWhitelistAddress(
address indexed _daoAddress,
address indexed _address
);
event DeployRefundModule(
address _refundModule,
address _safe,
address _daoAddress,
bytes32 _merkleRoot
);
event RefundERC20DAO(
address _user,
address _daoAddress,
address _refundModule,
address _transferToken,
uint256 _burnAmount,
uint256 _transferAmount
);
event RefundERC721DAO(
address _user,
address _daoAddress,
address _refundModule,
address _transferToken,
uint256 _tokenId,
uint256 _transferAmount
);
event ChangeRefundModuleMerkleRoot(
address indexed _refundModule,
address indexed _daoAddress,
bytes32 _newMerkleRoot
);
event CreateCCDAO(address _daoAddress, uint256[] _chainIds);
event TransferGT(
address indexed _daoAddress,
address indexed _from,
address indexed _to,
uint256 _value
);
event ChangedSigners(
address indexed _daoAddress,
address indexed _signer,
bool indexed _isAdded
);
address public factoryAddress;
function initialize(
address _ERC20Implementation,
address _ERC721Implementation,
address _factory
) external initializer {
_grantRole(ADMIN, msg.sender);
_grantRole(FACTORY, _factory);
_grantRole(EMITTER, _factory);
factoryAddress = _factory;
emit FactoryCreated(
_ERC20Implementation,
_ERC721Implementation,
_factory,
address(this)
);
}
function changeFactory(address _newFactory) external onlyRole(ADMIN) {
_revokeRole(FACTORY, factoryAddress);
_grantRole(FACTORY, _newFactory);
_revokeRole(EMITTER, factoryAddress);
_grantRole(EMITTER, _newFactory);
factoryAddress = _newFactory;
}
function allowActionContract(
address _actionContract
) external onlyRole(ADMIN) {
_grantRole(EMITTER, _actionContract);
}
function defineContracts(
address ERC20ImplementationAddress,
address ERC721ImplementationAddress,
address emitterImplementationAddress
) external payable onlyRole(FACTORY) {
emit DefineContracts(
msg.sender,
ERC20ImplementationAddress,
ERC721ImplementationAddress,
emitterImplementationAddress
);
}
function changeMerkleRoot(
address factory,
address daoAddress,
bytes32 newMerkleRoot
) external payable onlyRole(FACTORY) {
emit ChangeMerkleRoot(factory, daoAddress, newMerkleRoot);
}
function createDaoErc20(
address _deployerAddress,
address _proxy,
string memory _name,
string memory _symbol,
uint256 _distributionAmount,
uint256 _pricePerToken,
uint256 _minDeposit,
uint256 _maxDeposit,
uint256 _ownerFee,
uint256 _totalDays,
uint256 _quorum,
uint256 _threshold,
address _depositTokenAddress,
address _emitter,
address _gnosisAddress,
bool _isGovernanceActive,
bool isTransferable,
bool assetsStoredOnGnosis
) external payable onlyRole(FACTORY) {
_grantRole(EMITTER, _proxy);
_grantRole(EMITTER, msg.sender);
emit CreateDaoErc20(
_deployerAddress,
_proxy,
_name,
_symbol,
_distributionAmount,
_pricePerToken,
_minDeposit,
_maxDeposit,
_ownerFee,
_totalDays,
_quorum,
_threshold,
_depositTokenAddress,
_emitter,
_gnosisAddress,
_isGovernanceActive,
isTransferable,
assetsStoredOnGnosis
);
}
function createDaoErc721(
address _deployerAddress,
address _proxy,
string memory _name,
string memory _symbol,
string memory _tokenURI,
uint256 _pricePerToken,
uint256 _distributionAmount,
uint256 _maxTokensPerUser,
uint256 _ownerFee,
uint256 _totalDays,
uint256 _quorum,
uint256 _threshold,
address _depositTokenAddress,
address _emitter,
address _gnosisAddress,
bool _isGovernanceActive,
bool isTransferable,
bool assetsStoredOnGnosis
) external payable onlyRole(FACTORY) {
_grantRole(EMITTER, _proxy);
_grantRole(EMITTER, msg.sender);
emit CreateDaoErc721(
_deployerAddress,
_proxy,
_name,
_symbol,
_tokenURI,
_pricePerToken,
_distributionAmount,
_maxTokensPerUser,
_ownerFee,
_totalDays,
_quorum,
_threshold,
_depositTokenAddress,
_emitter,
_gnosisAddress,
_isGovernanceActive,
isTransferable,
assetsStoredOnGnosis
);
}
function deposited(
address _daoAddress,
address _depositor,
address _depositTokenAddress,
uint256 _amount,
uint256 _timestamp,
uint256 _ownerFee,
uint256 _adminShare
) external onlyRole(EMITTER) {
emit Deposited(
_daoAddress,
_depositor,
_depositTokenAddress,
_amount,
_timestamp,
_ownerFee,
_adminShare
);
}
function newUser(
address _daoAddress,
address _depositor,
address _depositTokenAddress,
uint256 _depositTokenAmount,
uint256 _timeStamp,
uint256 _gtToken,
bool _isAdmin
) external onlyRole(EMITTER) {
emit NewUser(
_daoAddress,
_depositor,
_depositTokenAddress,
_depositTokenAmount,
_timeStamp,
_gtToken,
_isAdmin
);
}
function newUserCC(
address _daoAddress,
address _depositor,
address _depositTokenAddress,
uint256 _depositTokenAmount,
uint256 _timeStamp,
uint256 _gtToken,
bool _isAdmin
) external onlyRole(EMITTER) {
emit NewUserCC(
_daoAddress,
_depositor,
_depositTokenAddress,
_depositTokenAmount,
_timeStamp,
_gtToken,
_isAdmin
);
}
function startDeposit(
address _proxy,
uint256 _startTime,
uint256 _closeTime
) external onlyRole(EMITTER) {
emit StartDeposit(_proxy, _startTime, _closeTime);
}
function closeDeposit(
address _proxy,
uint256 _closeTime
) external onlyRole(EMITTER) {
emit CloseDeposit(_proxy, _closeTime);
}
function updateMinMaxDeposit(
address _proxy,
uint256 _minDeposit,
uint256 _maxDeposit
) external onlyRole(EMITTER) {
emit UpdateMinMaxDeposit(_proxy, _minDeposit, _maxDeposit);
}
function updateOwnerFee(
address _proxy,
uint256 _ownerFee
) external onlyRole(EMITTER) {
emit UpdateOwnerFee(_proxy, _ownerFee);
}
function airDropToken(
address _proxy,
address _token,
address _to,
uint256 _amount
) external onlyRole(EMITTER) {
emit AirDropToken(_proxy, _token, _to, _amount);
}
function mintGTToAddress(
address _proxy,
uint256[] memory _amount,
address[] memory _userAddress
) external onlyRole(EMITTER) {
emit MintGTToAddress(_proxy, _amount, _userAddress);
}
function updateGovernanceSettings(
address _proxy,
uint256 _quorum,
uint256 _threshold
) external onlyRole(EMITTER) {
emit UpdateGovernanceSettings(_proxy, _quorum, _threshold);
}
function updateDistributionAmount(
address _daoAddress,
uint256 _distributionAmount
) external onlyRole(EMITTER) {
emit UpdateDistributionAmount(_daoAddress, _distributionAmount);
}
function updatePricePerToken(
address _daoAddress,
uint256 _pricePerToken
) external onlyRole(EMITTER) {
emit UpdatePricePerToken(_daoAddress, _pricePerToken);
}
function sendCustomToken(
address _daoAddress,
address _token,
uint256[] memory _amount,
address[] memory _addresses
) external onlyRole(EMITTER) {
emit SendCustomToken(_daoAddress, _token, _amount, _addresses);
}
function mintNft(
address _to,
address _implementation,
string memory _tokenURI,
uint256 _tokenId
) external onlyRole(EMITTER) {
emit MintNft(_to, _implementation, _tokenURI, _tokenId);
}
function updateMaxTokensPerUser(
address _nftAddress,
uint256 _maxTokensPerUser
) external onlyRole(EMITTER) {
emit UpdateMaxTokensPerUser(_nftAddress, _maxTokensPerUser);
}
function updateTotalSupplyOfToken(
address _nftAddress,
uint256 _totalSupplyOfToken
) external onlyRole(EMITTER) {
emit UpdateTotalSupplyOfToken(_nftAddress, _totalSupplyOfToken);
}
function updateTokenTransferability(
address _nftAddress,
bool _isTokenTransferable
) external onlyRole(EMITTER) {
emit UpdateTokenTransferability(_nftAddress, _isTokenTransferable);
}
function whitelistAddress(
address _nftAddress,
address _address
) external onlyRole(EMITTER) {
emit WhitelistAddress(_nftAddress, _address);
}
function removeWhitelistAddress(
address _nftAddress,
address _address
) external onlyRole(EMITTER) {
emit RemoveWhitelistAddress(_nftAddress, _address);
}
function deployRefundModule(
address _refundModule,
address _safe,
address _dao,
bytes32 _merkleRoot
) external onlyRole(EMITTER) {
_grantRole(EMITTER, _refundModule);
emit DeployRefundModule(_refundModule, _safe, _dao, _merkleRoot);
}
function refundERC20DAO(
address _user,
address _dao,
address _refundModule,
address _transferToken,
uint256 _burnAmount,
uint256 _transferAmount
) external onlyRole(EMITTER) {
emit RefundERC20DAO(
_user,
_dao,
_refundModule,
_transferToken,
_burnAmount,
_transferAmount
);
}
function refundERC721DAO(
address _user,
address _dao,
address _refundModule,
address _transferToken,
uint256 _tokenId,
uint256 _transferAmount
) external onlyRole(EMITTER) {
emit RefundERC721DAO(
_user,
_dao,
_refundModule,
_transferToken,
_tokenId,
_transferAmount
);
}
function changeRefundModuleMerkleRoot(
address _refundModule,
address _daoAddress,
bytes32 newMerkleRoot
) external onlyRole(EMITTER) {}
function createCCDao(
address _dao,
uint256[] memory _chainIds
) external onlyRole(EMITTER) {
emit CreateCCDAO(_dao, _chainIds);
}
function transferGT(
address _dao,
address _from,
address _to,
uint256 _value
) external onlyRole(EMITTER) {
emit TransferGT(_dao, _from, _to, _value);
}
function changedSigners(
address _dao,
address _signer,
bool _isAdded
) external onlyRole(EMITTER) {
emit ChangedSigners(_dao, _signer, _isAdded);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "./interfaces/IERC20DAO.sol";
import "./interfaces/IERC721DAO.sol";
import "./interfaces/IDeployer.sol";
import "./helper.sol";
import "./interfaces/IEmitter.sol";
import "./interfaces/ICommLayer.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
interface IWrappedToken {
function deposit() external payable;
}
/// @title StationXFactory Cloning Contract
/// @dev Contract create proxies of DAO Token and Governor contract
contract Factory is Helper {
using SafeERC20 for IERC20;
address private ERC20Implementation;
address private ERC721Implementation;
address private emitterAddress;
address private constant wrappedTokenAddress =
0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270;
address private safe;
address private singleton;
address private _owner;
//Mapping to get details of a particular dao
mapping(address => DAODetails) private daoDetails;
//Mapping to store total deposit by a user in a particular dao
mapping(address => mapping(address => uint256)) private totalDeposit;
//Mapping to get details of token gating for a particular dao
mapping(address => TokenGatingCondition[]) private tokenGatingDetails;
bool private _initialized;
address private constant NATIVE_TOKEN_ADDRESS =
address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
bool public _isPaused;
address private deployer;
mapping(address => address) private dstCommLayer;
//Mapping to store total deposit by a user in a particular dao
mapping(address => mapping(address => uint256)) private ownerShares;
//Mapping to get details of token gating for a particular dao
mapping(address => TokenGatingCondition) private tokenGatingDetailsNew;
address private commLayer;
mapping(address => CrossChainDetails) private ccDetails;
uint256 public createFees;
uint256 public depositFees;
uint256 public platformFeeMultiplier;
mapping(address => bool) private isKycEnabled;
function _onlyOwners() private view {
require(msg.sender == _owner, "caller is not the owner");
}
function _onlyIsNotPaused() private view {
require(!_isPaused, "deposits paused");
}
function initialize() external {
require(!_initialized);
_owner = msg.sender;
_initialized = true;
createFees = 1e14;
depositFees = 1e14;
platformFeeMultiplier = 125;
_isPaused = false;
}
function changeOwner(address _newOwner) external {
_onlyOwners();
_owner = _newOwner;
}
function togglePaused() external {
_onlyOwners();
_isPaused = !_isPaused;
}
function defineTokenContracts(
address _emitter,
address _deployer,
address _commLayer
) external {
_onlyOwners();
emitterAddress = _emitter;
deployer = _deployer;
commLayer = _commLayer;
}
/// @dev This function returns details of a particular dao
/// @param _daoAddress address of token contract
function getDAOdetails(
address _daoAddress
) public view returns (DAODetails memory) {
return daoDetails[_daoAddress];
}
/// @dev This function returns token gating details of a particular dao
/// @param _daoAddress address of token contract
function getTokenGatingDetails(
address _daoAddress
) external view returns (TokenGatingCondition memory) {
return tokenGatingDetailsNew[_daoAddress];
}
/// @dev Function to change merkle root of particular token contract
/// @param _daoAddress address token contract
function changeMerkleRoot(
address _daoAddress,
bytes32 _newMerkleRoot
) external payable onlyGnosisOrDao(address(this), _daoAddress) {
validateDaoAddress(_daoAddress);
daoDetails[_daoAddress].merkleRoot = _newMerkleRoot;
IEmitter(emitterAddress).changeMerkleRoot(
address(this),
_daoAddress,
_newMerkleRoot
);
}
/// @dev Function to create proxies and initialization of Token and Governor contract
function createERC20DAO(
string calldata _DaoName,
string calldata _DaoSymbol,
uint16 _commLayerId,
uint256 _distributionAmount,
uint256 _pricePerToken,
uint256 _minDepositPerUser,
uint256 _maxDepositPerUser,
uint256 _ownerFeePerDepositPercent,
uint256 _depositTime,
uint256 _quorumPercent,
uint256 _thresholdPercent,
uint256 _safeThreshold,
uint256[] calldata _depositChainIds,
address _gnosisAddress,
address[] calldata _depositTokenAddress,
address[] memory _admins,
bool _isGovernanceActive,
bool _isTransferable,
bool _onlyAllowWhitelist,
bool _assetsStoredOnGnosis,
bytes32 _merkleRoot
) external payable {
uint256 fees = checkCreateFeesSent(_depositChainIds);
bytes memory data = abi.encodeWithSignature(
"initializeERC20(address,address,string,string,uint256,uint256,bool,bool,bool,address)",
address(this),
emitterAddress,
_DaoName,
_DaoSymbol,
_quorumPercent,
_thresholdPercent,
_isGovernanceActive,
_isTransferable,
_onlyAllowWhitelist,
msg.sender
);
address _daoAddress = IDeployer(deployer).deployERC20DAO(_owner, data);
address _safe = IDeployer(deployer).deploySAFE(
_admins,
_safeThreshold,
_daoAddress
);
_createERC20DAO(
_distributionAmount,
_pricePerToken,
_minDepositPerUser,
_maxDepositPerUser,
_ownerFeePerDepositPercent,
_depositTime,
_quorumPercent,
_thresholdPercent,
_daoAddress,
_depositTokenAddress[0],
_safe,
_assetsStoredOnGnosis,
_merkleRoot
);
IEmitter(emitterAddress).createDaoErc20(
msg.sender,
_daoAddress,
_DaoName,
_DaoSymbol,
_distributionAmount,
_pricePerToken,
_minDepositPerUser,
_maxDepositPerUser,
_ownerFeePerDepositPercent,
_depositTime,
_quorumPercent,
_thresholdPercent,
_depositTokenAddress[0],
emitterAddress,
_safe,
_isGovernanceActive,
_isTransferable,
_assetsStoredOnGnosis
);
for (uint256 i; i < _admins.length; ) {
IEmitter(emitterAddress).newUser(
_daoAddress,
_admins[i],
_depositTokenAddress[0],
0,
block.timestamp,
0,
true
);
unchecked {
++i;
}
}
if (_depositChainIds.length != 0) {
for (uint256 i; i < _depositChainIds.length - 1; ) {
bytes memory _payload = abi.encode(
_commLayerId,
_distributionAmount,
amountToSD(_depositTokenAddress[0], _pricePerToken),
amountToSD(_depositTokenAddress[0], _minDepositPerUser),
amountToSD(_depositTokenAddress[0], _maxDepositPerUser),
_ownerFeePerDepositPercent,
_depositTime,
_quorumPercent,
_thresholdPercent,
_safeThreshold,
_depositChainIds,
_daoAddress,
_depositTokenAddress[i + 1],
_admins,
_onlyAllowWhitelist,
_merkleRoot,
0
);
ICommLayer(commLayer).sendMsg{
value: (msg.value - fees) / _depositChainIds.length
}(
commLayer,
_payload,
abi.encode(_depositChainIds[i + 1], msg.sender)
);
unchecked {
++i;
}
}
IEmitter(emitterAddress).createCCDao(_daoAddress, _depositChainIds);
}
}
function createCrossChainERC20DAO(
uint16 _commLayerId,
uint256 _distributionAmount,
uint256 _pricePerToken,
uint256 _minDepositPerUser,
uint256 _maxDepositPerUser,
uint256 _ownerFeePerDepositPercent,
uint256 _depositTime,
uint256 _quorumPercent,
uint256 _thresholdPercent,
uint256 _safeThreshold,
uint256[] calldata _depositChainIds,
address _daoAddress,
address _depositTokenAddress,
address[] memory _admins,
bool _onlyAllowWhitelist,
bytes32 _merkleRoot
) external {
require(msg.sender == commLayer, "Caller not LZ Deployer");
address _safe = IDeployer(deployer).deploySAFE(
_admins,
_safeThreshold,
_daoAddress
);
_createERC20DAO(
_distributionAmount,
amountToLD(_depositTokenAddress, _pricePerToken),
amountToLD(_depositTokenAddress, _minDepositPerUser),
amountToLD(_depositTokenAddress, _maxDepositPerUser),
_ownerFeePerDepositPercent,
_depositTime,
_quorumPercent,
_thresholdPercent,
_daoAddress,
_depositTokenAddress,
_safe,
true,
_merkleRoot
);
ccDetails[_daoAddress] = CrossChainDetails(
_commLayerId,
_depositChainIds,
false,
msg.sender,
_onlyAllowWhitelist
);
for (uint256 i; i < _admins.length; ) {
IEmitter(emitterAddress).newUserCC(
_daoAddress,
_admins[i],
_depositTokenAddress,
0,
block.timestamp,
0,
true
);
unchecked {
++i;
}
}
}
/// @dev Function to create proxies and initialization of Token and Governor contract
function _createERC20DAO(
uint256 _distributionAmount,
uint256 _pricePerToken,
uint256 _minDepositPerUser,
uint256 _maxDepositPerUser,
uint256 _ownerFeePerDepositPercent,
uint256 _depositTime,
uint256 _quorumPercent,
uint256 _thresholdPercent,
address _daoAddress,
address _depositTokenAddress,
address _gnosisAddress,
bool _assetsStoredOnGnosis,
bytes32 _merkleRoot
) private {
if (_quorumPercent == 0 || _quorumPercent > FLOAT_HANDLER_TEN_4) {
revert AmountInvalid("_quorumPercent", _quorumPercent);
}
if (_thresholdPercent == 0 || _thresholdPercent > FLOAT_HANDLER_TEN_4) {
revert AmountInvalid("_thresholdPercent", _thresholdPercent);
}
if (_depositTime == 0) {
revert AmountInvalid("_depositFunctioningDays", _depositTime);
}
if (!(_ownerFeePerDepositPercent < FLOAT_HANDLER_TEN_4)) {
revert AmountInvalid(
"_ownerFeePerDeposit",
_ownerFeePerDepositPercent
);
}
if (_maxDepositPerUser == 0) {
revert AmountInvalid("_maxDepositPerUser", _maxDepositPerUser);
}
if (_maxDepositPerUser <= _minDepositPerUser) {
revert DepositAmountInvalid(_maxDepositPerUser, _minDepositPerUser);
}
if (
((_distributionAmount * _pricePerToken) / 1e18) < _maxDepositPerUser
) {
revert RaiseAmountInvalid(
((_distributionAmount * _pricePerToken) / 1e18),
_maxDepositPerUser
);
}
daoDetails[_daoAddress] = DAODetails(
_pricePerToken,
_distributionAmount,
_minDepositPerUser,
_maxDepositPerUser,
_ownerFeePerDepositPercent,
_depositTime,
_depositTokenAddress,
_gnosisAddress,
_merkleRoot,
true,
false,
_assetsStoredOnGnosis
);
}
/// @dev Function to create proxies and initialization of Token and Governor contract
function createERC721DAO(
string calldata _DaoName,
string calldata _DaoSymbol,
string calldata _tokenURI,
uint16 _commLayerId,
uint256 _ownerFeePerDepositPercent,
uint256 _depositTime,
uint256 _quorumPercent,
uint256 _thresholdPercent,
uint256 _safeThreshold,
uint256[] calldata _depositChainIds,
address _gnosisAddress,
address[] memory _depositTokenAddress,
address[] memory _admins,
uint256 _maxTokensPerUser,
uint256 _distributionAmount,
uint256 _pricePerToken,
bool _isNftTransferable,
bool _isNftTotalSupplyUnlimited,
bool _isGovernanceActive,
bool _onlyAllowWhitelist,
bool _assetsStoredOnGnosis,
bytes32 _merkleRoot
) external payable {
uint256 fees = checkCreateFeesSent(_depositChainIds);
bytes memory data = abi.encodeWithSignature(
"initializeERC721(string,string,address,address,uint256,uint256,uint256,bool,bool,bool,bool,address)",
_DaoName,
_DaoSymbol,
address(this),
emitterAddress,
_quorumPercent,
_thresholdPercent,
_maxTokensPerUser,
_isNftTransferable,
_isNftTotalSupplyUnlimited,
_isGovernanceActive,
_onlyAllowWhitelist,
msg.sender
);
address _daoAddress = IDeployer(deployer).deployERC721DAO(_owner, data);
address _safe = IDeployer(deployer).deploySAFE(
_admins,
_safeThreshold,
_daoAddress
);
_createERC721DAO(
_ownerFeePerDepositPercent,
_depositTime,
_quorumPercent,
_thresholdPercent,
_daoAddress,
_depositTokenAddress[0],
_safe,
_maxTokensPerUser,
_distributionAmount,
_pricePerToken,
_assetsStoredOnGnosis,
_merkleRoot
);
IEmitter(emitterAddress).createDaoErc721(
msg.sender,
_daoAddress,
_DaoName,
_DaoSymbol,
_tokenURI,
_pricePerToken,
_distributionAmount,
_maxTokensPerUser,
_ownerFeePerDepositPercent,
_depositTime,
_quorumPercent,
_thresholdPercent,
_depositTokenAddress[0],
emitterAddress,
_safe,
_isGovernanceActive,
_isNftTransferable,
_assetsStoredOnGnosis
);
for (uint256 i; i < _admins.length; ) {
IEmitter(emitterAddress).newUser(
_daoAddress,
_admins[i],
_depositTokenAddress[0],
0,
block.timestamp,
0,
true
);
unchecked {
++i;
}
}
if (_depositChainIds.length != 0) {
for (uint256 i; i < _depositChainIds.length - 1; ) {
bytes memory _payload = abi.encode(
_commLayerId,
_distributionAmount,
amountToSD(_depositTokenAddress[0], _pricePerToken),
0,
0,
_ownerFeePerDepositPercent,
_depositTime,
_quorumPercent,
_thresholdPercent,
_safeThreshold,
_depositChainIds,
_daoAddress,
_depositTokenAddress[i + 1],
_admins,
_onlyAllowWhitelist,
_merkleRoot,
_maxTokensPerUser
);
ICommLayer(commLayer).sendMsg{
value: (msg.value - fees) / _depositChainIds.length
}(
commLayer,
_payload,
abi.encode(_depositChainIds[i + 1], msg.sender)
);
unchecked {
++i;
}
}
IEmitter(emitterAddress).createCCDao(_daoAddress, _depositChainIds);
}
}
/// @dev Function to create proxies and initialization of Token and Governor contract
function createCrossChainERC721DAO(
uint16 _commLayerId,
uint256 _ownerFeePerDepositPercent,
uint256 _depositTime,
uint256 _quorumPercent,
uint256 _thresholdPercent,
uint256 _safeThreshold,
uint256[] memory _depoitChainIds,
address _daoAddress,
address _depositTokenAddress,
address[] memory _admins,
uint256 _maxTokensPerUser,
uint256 _distributionAmount,
uint256 _pricePerToken,
bool _onlyAllowWhitelist,
bytes32 _merkleRoot
) external {
require(msg.sender == commLayer, "Caller not LZ Deployer");
address _safe = IDeployer(deployer).deploySAFE(
_admins,
_safeThreshold,
_daoAddress
);
_createERC721DAO(
_ownerFeePerDepositPercent,
_depositTime,
_quorumPercent,
_thresholdPercent,
_daoAddress,
_depositTokenAddress,
_safe,
_maxTokensPerUser,
_distributionAmount,
amountToLD(_depositTokenAddress, _pricePerToken),
true,
_merkleRoot
);
ccDetails[_daoAddress] = CrossChainDetails(
_commLayerId,
_depoitChainIds,
false,
msg.sender,
_onlyAllowWhitelist
);
for (uint256 i; i < _admins.length; ) {
IEmitter(emitterAddress).newUserCC(
_daoAddress,
_admins[i],
_depositTokenAddress,
0,
block.timestamp,
0,
true
);
unchecked {
++i;
}
}
}
/// @dev Function to create proxies and initialization of Token and Governor contract
function _createERC721DAO(
uint256 _ownerFeePerDepositPercent,
uint256 _depositTime,
uint256 _quorumPercent,
uint256 _thresholdPercent,
address _daoAddress,
address _depositTokenAddress,
address _gnosisAddress,
uint256 _maxTokensPerUser,
uint256 _distributionAmount,
uint256 _pricePerToken,
bool _assetsStoredOnGnosis,
bytes32 _merkleRoot
) private {
if (_quorumPercent == 0 || _quorumPercent > FLOAT_HANDLER_TEN_4) {
revert AmountInvalid("_quorumPercent", _quorumPercent);
}
if (_thresholdPercent == 0 || _thresholdPercent > FLOAT_HANDLER_TEN_4) {
revert AmountInvalid("_thresholdPercent", _thresholdPercent);
}
if (_depositTime == 0) {
revert AmountInvalid("_depositFunctioningDays", _depositTime);
}
if (!(_ownerFeePerDepositPercent < FLOAT_HANDLER_TEN_4)) {
revert AmountInvalid(
"_ownerFeePerDeposit",
_ownerFeePerDepositPercent
);
}
if (_maxTokensPerUser == 0) {
revert AmountInvalid("_maxTokensPerUser", _maxTokensPerUser);
}
daoDetails[_daoAddress] = DAODetails(
_pricePerToken,
_distributionAmount,
0,
0,
_ownerFeePerDepositPercent,
_depositTime,
_depositTokenAddress,
_gnosisAddress,
_merkleRoot,
true,
false,
_assetsStoredOnGnosis
);
}
function crossChainMint(
address _user,
address payable _daoAddress,
uint256 _numOfTokensToBuy,
string calldata _tokenURI,
bytes32[] calldata _merkleProof
) external {
require(msg.sender == IDeployer(deployer).lzImpl());
DAODetails memory _daoDetails = daoDetails[_daoAddress];
uint256 _daoBalance = IERC20(_daoDetails.depositTokenAddress).balanceOf(
_daoAddress
);
uint256 _totalAmount = _daoDetails.pricePerToken * (_numOfTokensToBuy);
if (_daoDetails.isTokenGatingApplied) {
ifTokenGatingApplied(_daoAddress);
}
if (bytes(_tokenURI).length != 0) {
checkAmountValidity(
_daoBalance,
_totalAmount,
_daoDetails.pricePerToken,
_daoDetails.distributionAmount
);
if (
IERC721DAO(_daoAddress).getERC721DAOdetails().onlyAllowWhitelist
) {
if (
!MerkleProof.verify(
_merkleProof,
_daoDetails.merkleRoot,
keccak256(abi.encodePacked(_user))
)
) {
revert IncorrectProof();
}
}
IERC721DAO(_daoAddress).mintToken(
_user,
_tokenURI,
_numOfTokensToBuy
);
} else {
_totalAmount = _totalAmount / 1e18;
uint256 _totalDeposit = totalDeposit[_user][_daoAddress];
if (_totalDeposit == 0) {
if (_totalAmount < _daoDetails.minDepositPerUser) {
revert AmountInvalid(
"_numOfTokensToBuy",
_numOfTokensToBuy
);
}
if (_totalAmount > _daoDetails.maxDepositPerUser) {
revert AmountInvalid(
"_numOfTokensToBuy",
_numOfTokensToBuy
);
}
} else {
if (
_totalDeposit + _totalAmount > _daoDetails.maxDepositPerUser
) {
revert AmountInvalid(
"_numOfTokensToBuy",
_numOfTokensToBuy
);
}
}
totalDeposit[_user][_daoAddress] += _totalAmount;
if (
IERC20DAO(_daoAddress).getERC20DAOdetails().onlyAllowWhitelist
) {
if (
!MerkleProof.verify(
_merkleProof,
_daoDetails.merkleRoot,
keccak256(abi.encodePacked(_user))
)
) {
revert IncorrectProof();
}
}
if (
_daoBalance + _totalAmount >
(_daoDetails.pricePerToken * _daoDetails.distributionAmount) /
1e18
) {
revert AmountInvalid("daoBalance", _daoBalance + _totalAmount);
}
IERC20DAO(_daoAddress).mintToken(_user, _numOfTokensToBuy);
}
IEmitter(emitterAddress).newUser(
_daoAddress,
_user,
_daoDetails.depositTokenAddress,
_totalAmount,
block.timestamp,
_numOfTokensToBuy,
false
);
}
function _buyGovernanceTokenERC20DAO(
address payable _daoAddress,
uint256 _numOfTokensToBuy
) private {
DAODetails memory _daoDetails = daoDetails[_daoAddress];
if (_numOfTokensToBuy == 0) {
revert AmountInvalid("_numOfTokensToBuy", _numOfTokensToBuy);
}
uint256 _totalAmount = (_numOfTokensToBuy * _daoDetails.pricePerToken) /
1e18;
if (_totalAmount == 0) {
revert AmountInvalid("_numOfTokensToBuy", _totalAmount);
}
uint256 ownerShare = (_totalAmount *
_daoDetails.ownerFeePerDepositPercent) / (FLOAT_HANDLER_TEN_4);
if (_daoDetails.depositTokenAddress == NATIVE_TOKEN_ADDRESS) {
checkDepositFeesSent(_daoAddress, _totalAmount + ownerShare);
payable(
_daoDetails.assetsStoredOnGnosis
? _daoDetails.gnosisAddress
: _daoAddress
).call{value: _totalAmount}("");
payable(
ccDetails[_daoAddress].ownerAddress != address(0)
? ccDetails[_daoAddress].ownerAddress
: IERC20DAO(_daoAddress).getERC20DAOdetails().ownerAddress
).call{value: ownerShare}("");
} else {
checkDepositFeesSent(_daoAddress, 0);
IERC20(_daoDetails.depositTokenAddress).safeTransferFrom(
msg.sender,
_daoDetails.assetsStoredOnGnosis
? _daoDetails.gnosisAddress
: _daoAddress,
_totalAmount
);
IERC20(_daoDetails.depositTokenAddress).safeTransferFrom(
msg.sender,
ccDetails[_daoAddress].ownerAddress != address(0)
? ccDetails[_daoAddress].ownerAddress
: IERC20DAO(_daoAddress).getERC20DAOdetails().ownerAddress,
ownerShare
);
}
IEmitter(emitterAddress).deposited(
_daoAddress,
msg.sender,
_daoDetails.depositTokenAddress,
_totalAmount,
block.timestamp,
_daoDetails.ownerFeePerDepositPercent,
ownerShare
);
}
function _buyGovernanceTokenERC721DAO(
address payable _daoAddress,
uint256 _numOfTokensToBuy
) private {
DAODetails memory _daoDetails = daoDetails[_daoAddress];
if (_numOfTokensToBuy == 0) {
revert AmountInvalid("_numOfTokensToBuy", _numOfTokensToBuy);
}
uint256 _totalAmount = _daoDetails.pricePerToken * (_numOfTokensToBuy);
uint256 ownerShare = (_totalAmount *
_daoDetails.ownerFeePerDepositPercent) / (FLOAT_HANDLER_TEN_4);
if (_daoDetails.depositTokenAddress == NATIVE_TOKEN_ADDRESS) {
checkDepositFeesSent(_daoAddress, _totalAmount + ownerShare);
payable(
_daoDetails.assetsStoredOnGnosis
? _daoDetails.gnosisAddress
: _daoAddress
).call{value: _totalAmount}("");
payable(
ccDetails[_daoAddress].ownerAddress != address(0)
? ccDetails[_daoAddress].ownerAddress
: IERC721DAO(_daoAddress).getERC721DAOdetails().ownerAddress
).call{value: ownerShare}("");
} else {
checkDepositFeesSent(_daoAddress, 0);
IERC20(_daoDetails.depositTokenAddress).safeTransferFrom(
msg.sender,
_daoDetails.assetsStoredOnGnosis
? _daoDetails.gnosisAddress
: _daoAddress,
_totalAmount
);
IERC20(_daoDetails.depositTokenAddress).safeTransferFrom(
msg.sender,
ccDetails[_daoAddress].ownerAddress != address(0)
? ccDetails[_daoAddress].ownerAddress
: IERC721DAO(_daoAddress)
.getERC721DAOdetails()
.ownerAddress,
ownerShare
);
}
IEmitter(emitterAddress).deposited(
_daoAddress,
msg.sender,
_daoDetails.depositTokenAddress,
_totalAmount,
block.timestamp,
_daoDetails.ownerFeePerDepositPercent,
ownerShare
);
}
/// @dev Function to update Minimum and Maximum deposits allowed by DAO members
/// @param _minDepositPerUser New minimum deposit requirement amount in wei
/// @param _maxDepositPerUser New maximum deposit limit amount in wei
/// @param _daoAddress address of the token contract
function updateMinMaxDeposit(
uint256 _minDepositPerUser,
uint256 _maxDepositPerUser,
address _daoAddress
) external payable onlyGnosisOrDao(address(this), _daoAddress) {
validateDaoAddress(_daoAddress);
validateDepositAmounts(_minDepositPerUser, _maxDepositPerUser);
daoDetails[_daoAddress].minDepositPerUser = _minDepositPerUser;
daoDetails[_daoAddress].maxDepositPerUser = _maxDepositPerUser;
IEmitter(emitterAddress).updateMinMaxDeposit(
_daoAddress,
_minDepositPerUser,
_maxDepositPerUser
);
}
/// @dev Function to update DAO Owner Fee
/// @param _ownerFeePerDeposit New Owner fee
/// @param _daoAddress address of the token contract
function updateOwnerFee(
uint256 _ownerFeePerDeposit,
address _daoAddress
) external payable onlyAdmins(daoDetails[_daoAddress].gnosisAddress) {
validateDaoAddress(_daoAddress);
if (!(_ownerFeePerDeposit < FLOAT_HANDLER_TEN_4)) {
revert AmountInvalid("_ownerFeePerDeposit", _ownerFeePerDeposit);
}
daoDetails[_daoAddress].ownerFeePerDepositPercent = _ownerFeePerDeposit;
IEmitter(emitterAddress).updateOwnerFee(
_daoAddress,
_ownerFeePerDeposit
);
}
/// @dev Function to update total raise amount
/// @param _newDistributionAmount New distribution amount
/// @param _newPricePerToken New price per token
/// @param _daoAddress address of the token contract
function updateTotalRaiseAmount(
uint256 _newDistributionAmount,
uint256 _newPricePerToken,
address _daoAddress
) external payable onlyGnosisOrDao(address(this), _daoAddress) {
validateDaoAddress(_daoAddress);
uint256 _distributionAmount = daoDetails[_daoAddress]
.distributionAmount;
if (_distributionAmount != _newDistributionAmount) {
if (_distributionAmount > _newDistributionAmount) {
revert AmountInvalid(
"_newDistributionAmount",
_newDistributionAmount
);
}
daoDetails[_daoAddress].distributionAmount = _newDistributionAmount;
IEmitter(emitterAddress).updateDistributionAmount(
_daoAddress,
_newDistributionAmount
);
}
if (daoDetails[_daoAddress].pricePerToken != _newPricePerToken) {
daoDetails[_daoAddress].pricePerToken = _newPricePerToken;
IEmitter(emitterAddress).updatePricePerToken(
_daoAddress,
_newPricePerToken
);
}
}
/// @dev Function to update deposit time
/// @param _depositTime New start time
/// @param _daoAddress address of the token contract
function updateDepositTime(
uint256 _depositTime,
address _daoAddress
) external payable onlyAdmins(daoDetails[_daoAddress].gnosisAddress) {
validateDaoAddress(_daoAddress);
if (_depositTime == 0) revert AmountInvalid("_days", _depositTime);
daoDetails[_daoAddress].depositCloseTime = _depositTime;
IEmitter(emitterAddress).startDeposit(
_daoAddress,
block.timestamp,
daoDetails[_daoAddress].depositCloseTime
);
}
/// @dev Function to setup multiple token checks to gate community
/// @param _tokens Address of tokens
/// @param _operator Operator for token checks (0 for AND and 1 for OR)
/// @param _value Minimum user balance amount
/// @param _daoAddress Address to DAO
function setupTokenGating(
address[] calldata _tokens,
Operator _operator,
uint256[] calldata _value,
address payable _daoAddress
) external payable onlyAdmins(daoDetails[_daoAddress].gnosisAddress) {
require(_value.length == _tokens.length, "Length mismatch");
tokenGatingDetailsNew[_daoAddress] = TokenGatingCondition(
_tokens,
_operator,
_value
);
daoDetails[_daoAddress].isTokenGatingApplied = true;
}
// @dev Function to disable token gating
/// @param _daoAddress address of the token contract
function disableTokenGating(
address _daoAddress
) external payable onlyAdmins(daoDetails[_daoAddress].gnosisAddress) {
delete tokenGatingDetailsNew[_daoAddress];
daoDetails[_daoAddress].isTokenGatingApplied = false;
}
/// @dev function to deposit tokens and receive dao tokens in return
/// @param _daoAddress address of the token contract
/// @param _numOfTokensToBuy amount of tokens to buy
function buyGovernanceTokenERC20DAO(
address payable _daoAddress,
uint256 _numOfTokensToBuy,
bytes32[] calldata _merkleProof
) public payable {
_onlyIsNotPaused();
DAODetails memory _daoDetails = daoDetails[_daoAddress];
uint256 daoBalance;
if (
daoDetails[_daoAddress].depositTokenAddress == NATIVE_TOKEN_ADDRESS
) {
daoBalance = _daoAddress.balance;
} else {
daoBalance = IERC20(daoDetails[_daoAddress].depositTokenAddress)
.balanceOf(_daoAddress);
}
uint256 _totalAmount = (_numOfTokensToBuy * _daoDetails.pricePerToken) /
1e18;
uint256 _totalDeposit = totalDeposit[msg.sender][_daoAddress];
if (_totalDeposit == 0) {
if (_totalAmount < _daoDetails.minDepositPerUser) {
revert AmountInvalid("_numOfTokensToBuy", _numOfTokensToBuy);
}
if (_totalAmount > _daoDetails.maxDepositPerUser) {
revert AmountInvalid("_numOfTokensToBuy", _numOfTokensToBuy);
}
} else {
if (_totalDeposit + _totalAmount > _daoDetails.maxDepositPerUser) {
revert AmountInvalid("_numOfTokensToBuy", _numOfTokensToBuy);
}
}
if (_daoDetails.isTokenGatingApplied) {
ifTokenGatingApplied(_daoAddress);
}
if (IERC20DAO(_daoAddress).getERC20DAOdetails().onlyAllowWhitelist) {
if (
!MerkleProof.verify(
_merkleProof,
_daoDetails.merkleRoot,
keccak256(abi.encodePacked(msg.sender))
)
) {
revert IncorrectProof();
}
}
totalDeposit[msg.sender][_daoAddress] += _totalAmount;
if (
daoBalance + _totalAmount >
(_daoDetails.pricePerToken * _daoDetails.distributionAmount) / 1e18
) {
revert AmountInvalid("daoBalance", daoBalance + _totalAmount);
}
if (_daoDetails.depositCloseTime < block.timestamp) {
revert DepositClosed();
}
_buyGovernanceTokenERC20DAO(_daoAddress, _numOfTokensToBuy);
IERC20DAO(_daoAddress).mintToken(msg.sender, _numOfTokensToBuy);
IEmitter(emitterAddress).newUser(
_daoAddress,
msg.sender,
_daoDetails.depositTokenAddress,
_totalAmount,
block.timestamp,
_numOfTokensToBuy,
false
);
}
/// @dev This internal function performs required operations if token gating is applied
function ifTokenGatingApplied(address _daoAddress) private view {
TokenGatingCondition memory condition = tokenGatingDetailsNew[
_daoAddress
];
bool isValid;
bool isNewValid;
for (uint256 i = 0; i < condition.tokens.length; ++i) {
uint256 balance = IERC20(condition.tokens[i]).balanceOf(msg.sender);
if (i == 0) {
isValid = balance >= condition.value[i];
isNewValid = balance >= condition.value[i];
} else {
isNewValid = balance >= condition.value[i];
}
if (condition.operator == Operator.AND) {
isValid = isValid && isNewValid;
} else {
isValid = isValid || isNewValid;
if (isValid) {
return;
}
}
}
if (!isValid) {
revert InsufficientBalance();
}
}
/// @dev function to deposit tokens and receive dao tokens in return
/// @param _daoAddress address of the token contract
/// @param _numOfTokensToBuy amount of nfts to mint
function buyGovernanceTokenERC721DAO(
address payable _daoAddress,
string calldata _tokenURI,
uint256 _numOfTokensToBuy,
bytes32[] calldata _merkleProof
) public payable {
_onlyIsNotPaused();
DAODetails memory _daoDetails = daoDetails[_daoAddress];
uint256 daoBalance;
if (
daoDetails[_daoAddress].depositTokenAddress == NATIVE_TOKEN_ADDRESS
) {
daoBalance = _daoAddress.balance;
} else {
daoBalance = IERC20(daoDetails[_daoAddress].depositTokenAddress)
.balanceOf(_daoAddress);
}
uint256 _totalAmount = _daoDetails.pricePerToken * (_numOfTokensToBuy);
if (_daoDetails.isTokenGatingApplied) {
ifTokenGatingApplied(_daoAddress);
}
if (IERC721DAO(_daoAddress).getERC721DAOdetails().onlyAllowWhitelist) {
if (
!MerkleProof.verify(
_merkleProof,
_daoDetails.merkleRoot,
keccak256(abi.encodePacked(msg.sender))
)
) {
revert IncorrectProof();
}
}
checkAmountValidity(
daoBalance,
_totalAmount,
_daoDetails.pricePerToken,
_daoDetails.distributionAmount
);
if (_daoDetails.depositCloseTime < block.timestamp) {
revert DepositClosed();
}
_buyGovernanceTokenERC721DAO(_daoAddress, _numOfTokensToBuy);
IERC721DAO(_daoAddress).mintToken(
msg.sender,
_tokenURI,
_numOfTokensToBuy
);
IEmitter(emitterAddress).newUser(
_daoAddress,
msg.sender,
_daoDetails.depositTokenAddress,
_totalAmount,
block.timestamp,
_numOfTokensToBuy,
false
);
}
function crossChainBuy(
address payable _daoAddress,
string calldata _tokenURI,
uint16 _commLayerId,
uint256 _numOfTokensToBuy,
bytes calldata _extraParams,
bytes32[] calldata _merkleProof
) external payable {
_onlyIsNotPaused();
if (bytes(_tokenURI).length != 0) {
_buyGovernanceTokenERC721DAO(_daoAddress, _numOfTokensToBuy);
} else {
_buyGovernanceTokenERC20DAO(_daoAddress, _numOfTokensToBuy);
}
bytes memory _payload = abi.encode(
_daoAddress,
msg.sender,
_numOfTokensToBuy,
_tokenURI,
_merkleProof
);
address _commLayer = IDeployer(deployer).getCommunicationLayer(
_commLayerId
);
uint256 fees = depositFees;
if (
ccDetails[_daoAddress].depositChainIds.length > 1 ||
isKycEnabled[_daoAddress]
) {
fees = ((depositFees * platformFeeMultiplier) / 100);
}
ICommLayer(_commLayer).sendMsg{value: msg.value - fees}(
_commLayer,
_payload,
_extraParams
);
}
function validateDaoAddress(address _daoAddress) internal view {
if (!daoDetails[_daoAddress].isDeployedByFactory) {
revert AddressInvalid("_daoAddress", _daoAddress);
}
}
function validateDepositAmounts(uint256 _min, uint256 _max) internal pure {
if (_min == 0 || _min > _max) revert DepositAmountInvalid(_min, _max);
}
function checkAmountValidity(
uint256 _daoBalance,
uint256 _totalAmount,
uint256 _pricePerToken,
uint256 _distributionAmount
) internal pure {
if (_distributionAmount != 0) {
uint256 _maxAllowedAmount = _pricePerToken * _distributionAmount;
if (_daoBalance + _totalAmount > _maxAllowedAmount) {
revert AmountInvalid("daoBalance", _daoBalance + _totalAmount);
}
}
}
function rescueFunds(address tokenAddr) external {
_onlyOwners();
if (tokenAddr == NATIVE_TOKEN_ADDRESS) {
uint256 balance = address(this).balance;
payable(_owner).call{value: balance}("");
} else {
uint256 balance = IERC20(tokenAddr).balanceOf(address(this));
IERC20(tokenAddr).transfer(_owner, balance);
}
}
function updateFees(
uint256 _createFees,
uint256 _depositFees,
uint256 _val
) external {
_onlyOwners();
depositFees = _depositFees;
createFees = _createFees;
platformFeeMultiplier = _val;
}
function toggleKYC(
address _daoAddress
) external payable onlyAdmins(daoDetails[_daoAddress].gnosisAddress) {
isKycEnabled[_daoAddress] = !isKycEnabled[_daoAddress];
}
function checkCreateFeesSent(
uint256[] calldata _depositChainIds
) internal returns (uint256) {
uint256 fees = createFees * _depositChainIds.length;
require(msg.value >= fees, "Insufficient fees");
return fees;
}
function checkDepositFeesSent(
address _daoAddress,
uint256 _totalAmount
) internal {
if (
ccDetails[_daoAddress].depositChainIds.length > 1 ||
isKycEnabled[_daoAddress]
) {
require(
msg.value >=
_totalAmount +
((depositFees * platformFeeMultiplier) / 100),
"Insufficient fees"
);
} else {
require(
msg.value >= _totalAmount + depositFees,
"Insufficient fees"
);
}
}
function emitSignerChanged(
address _dao,
address _signer,
bool _isAdded
) external onlyGnosisOrDao(address(this), _dao) {
IEmitter(emitterAddress).changedSigners(_dao, _signer, _isAdded);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "./interfaces/IFactory.sol";
import "@openzeppelin/contracts/access/IAccessControl.sol";
interface IERC20Extended {
function decimals() external view returns (uint8);
}
interface Safe {
function isOwner(address owner) external view returns (bool);
}
contract Helper {
///@dev Admin role
bytes32 constant ADMIN = keccak256("ADMIN");
uint8 constant UNIFORM_DECIMALS = 18;
bytes32 constant operationNameAND = keccak256(abi.encodePacked(("AND")));
bytes32 constant operationNameOR = keccak256(abi.encodePacked(("OR")));
uint256 constant EIGHTEEN_DECIMALS = 1e18;
uint256 constant FLOAT_HANDLER_TEN_4 = 10000;
struct DAODetails {
uint256 pricePerToken;
uint256 distributionAmount;
uint256 minDepositPerUser;
uint256 maxDepositPerUser;
uint256 ownerFeePerDepositPercent;
uint256 depositCloseTime;
address depositTokenAddress;
address gnosisAddress;
bytes32 merkleRoot;
bool isDeployedByFactory;
bool isTokenGatingApplied;
bool assetsStoredOnGnosis;
}
struct CrossChainDetails {
uint16 commLayerId;
uint256[] depositChainIds;
bool isDefaultChain;
address ownerAddress;
bool onlyAllowWhitelist;
}
struct ERC20DAOdetails {
string DaoName;
string DaoSymbol;
uint256 quorum;
uint256 threshold;
bool isGovernanceActive;
bool isTransferable;
bool onlyAllowWhitelist;
address ownerAddress;
}
struct ERC721DAOdetails {
string DaoName;
string DaoSymbol;
uint256 quorum;
uint256 threshold;
uint256 maxTokensPerUser;
bool isTransferable;
bool isNftTotalSupplyUnlimited;
bool isGovernanceActive;
bool onlyAllowWhitelist;
address ownerAddress;
}
enum Operator {
AND,
OR
}
enum Comparator {
GREATER,
BELOW,
EQUAL
}
struct TokenGatingCondition {
address[] tokens;
Operator operator;
uint256[] value;
}
//implementation contract errors
error AmountInvalid(string _param, uint256 _amount);
error NotERC20Template();
error DepositAmountInvalid(
uint256 _maxDepositPerUser,
uint256 _minDepositPerUser
);
error DepositClosed();
error DepositStarted();
error Max4TokensAllowed(uint256 _length);
error ArrayLengthMismatch(uint256 _length1, uint256 _length2);
error AddressInvalid(string _param, address _address);
error InsufficientFunds();
error InvalidData();
error InsufficientAllowance(uint256 required, uint256 current);
error SafeProxyCreationFailed(string _reason);
//nft contract errors
error NotWhitelisted();
error MaxTokensMinted();
error NoAccess(address _user);
error MintingNotOpen();
error MaxTokensMintedForUser(address _user);
error RaiseAmountInvalid(
uint256 _totalRaiseAmount,
uint256 _maxDepositPerUser
);
error InsufficientBalance();
error InsufficientFees();
error NotDefaultChain();
error IncorrectProof();
/// @dev onlyOwner modifier to allow only Owner access to functions
modifier onlyGnosis(address _factory, address _daoAddress) {
require(
IFactory(_factory).getDAOdetails(_daoAddress).gnosisAddress ==
msg.sender,
"Only Gnosis"
);
_;
}
function _onlyGnosisOrDao(address _factory, address _daoAddress) private {
require(
IFactory(_factory).getDAOdetails(_daoAddress).gnosisAddress ==
msg.sender ||
_daoAddress == msg.sender,
"Only Gnosis or Dao"
);
}
modifier onlyGnosisOrDao(address _factory, address _daoAddress) {
_onlyGnosisOrDao(_factory, _daoAddress);
_;
}
modifier onlyFactory(address _factory) {
require(msg.sender == _factory);
_;
}
modifier onlyCurrentContract() {
require(msg.sender == address(this));
_;
}
modifier onlyAdmins(address _safe) {
require(Safe(_safe).isOwner(msg.sender), "Only owner access");
_;
}
function amountToSD(
address token,
uint256 amount
) public view returns (uint256) {
uint8 decimals;
if (token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
decimals = 18;
} else {
decimals = IERC20Extended(token).decimals();
}
if (decimals == 18) {
return amount;
} else {
uint256 convertRate = 10 ** (18 - decimals);
return amount * convertRate;
}
}
function amountToLD(
address token,
uint256 amount
) public view returns (uint256) {
uint8 decimals;
if (token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
decimals = 18;
} else {
decimals = IERC20Extended(token).decimals();
}
if (decimals == 18) {
return amount;
} else {
uint256 convertRate = 10 ** (18 - decimals);
return amount / convertRate;
}
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
interface ICommLayer {
function sendMsg(address, bytes memory, bytes memory) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
interface IDeployer {
function lzImpl() external view returns (address);
function deployERC20DAO(address, bytes calldata) external returns (address);
function deployERC721DAO(
address,
bytes calldata
) external returns (address);
function deploySAFE(
address[] calldata,
uint256,
address
) external returns (address);
function getCommunicationLayer(uint16) external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
interface IEmitter {
function initialize(address, address, address, address) external;
function changeFactory(address) external;
function allowActionContract(address) external;
function defineContracts(address, address, address) external;
function changeMerkleRoot(address, address, bytes32) external;
function createDaoErc20(
address,
address,
string calldata,
string calldata,
uint256,
uint256,
uint256,
uint256,
uint256,
uint256,
uint256,
uint256,
address,
address,
address,
bool,
bool,
bool
) external;
function createDaoErc721(
address,
address,
string calldata,
string calldata,
string calldata,
uint256,
uint256,
uint256,
uint256,
uint256,
uint256,
uint256,
address,
address,
address,
bool,
bool,
bool
) external;
function deposited(
address,
address,
address,
uint256,
uint256,
uint256,
uint256
) external;
function newUser(
address,
address,
address,
uint256,
uint256,
uint256,
bool
) external;
function newUserCC(
address,
address,
address,
uint256,
uint256,
uint256,
bool
) external;
function startDeposit(address, uint256, uint256) external;
function closeDeposit(address, uint256) external;
function updateMinMaxDeposit(address, uint256, uint256) external;
function updateOwnerFee(address, uint256) external;
function airDropToken(address, address, address, uint256) external;
function mintGTToAddress(
address,
uint256[] memory,
address[] memory
) external;
function updateGovernanceSettings(address, uint256, uint256) external;
function updateDistributionAmount(address, uint256) external;
function updatePricePerToken(address, uint256) external;
function sendCustomToken(
address,
address,
uint256[] memory,
address[] memory
) external;
function mintNft(address, address, string memory, uint256) external;
function updateMaxTokensPerUser(address, uint256) external;
function updateTotalSupplyOfToken(address, uint256) external;
function updateTokenTransferability(address, bool) external;
function whitelistAddress(address, address) external;
function removeWhitelistAddress(address, address) external;
function createCCDao(address, uint256[] memory) external;
function transferGT(address, address, address, uint256) external;
function changedSigners(address, address, bool) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "../helper.sol";
interface IERC20DAO {
function getERC20DAOdetails()
external
returns (Helper.ERC20DAOdetails memory);
function mintToken(address to, uint256 amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
interface IERC721DAO {
struct ERC721DAOdetails {
string DaoName;
string DaoSymbol;
uint256 quorum;
uint256 threshold;
uint256 maxTokensPerUser;
bool isTransferable;
bool isNftTotalSupplyUnlimited;
bool isGovernanceActive;
bool onlyAllowWhitelist;
address ownerAddress;
}
function getERC721DAOdetails() external returns (ERC721DAOdetails memory);
function mintToken(
address _to,
string calldata _tokenURI,
uint256 _numOfTokensToBuy
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "../helper.sol";
interface IFactory {
function getDAOdetails(address) external returns (Helper.DAODetails memory);
function crossChainMint(
address,
address,
uint256,
string calldata,
bytes32[] calldata
) external;
function createCrossChainERC20DAO(
uint16,
uint256,
uint256,
uint256,
uint256,
uint256,
uint256,
uint256,
uint256,
uint256,
uint256[] calldata,
address,
address,
address[] memory,
bool,
bytes32
) external;
function createCrossChainERC721DAO(
uint16,
uint256,
uint256,
uint256,
uint256,
uint256,
uint256[] memory,
address,
address,
address[] memory,
uint256,
uint256,
uint256,
bool,
bytes32
) external;
}{
"viaIR": true,
"optimizer": {
"enabled": true,
"runs": 5
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"string","name":"_param","type":"string"},{"internalType":"address","name":"_address","type":"address"}],"name":"AddressInvalid","type":"error"},{"inputs":[{"internalType":"string","name":"_param","type":"string"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"AmountInvalid","type":"error"},{"inputs":[{"internalType":"uint256","name":"_length1","type":"uint256"},{"internalType":"uint256","name":"_length2","type":"uint256"}],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"_maxDepositPerUser","type":"uint256"},{"internalType":"uint256","name":"_minDepositPerUser","type":"uint256"}],"name":"DepositAmountInvalid","type":"error"},{"inputs":[],"name":"DepositClosed","type":"error"},{"inputs":[],"name":"DepositStarted","type":"error"},{"inputs":[],"name":"IncorrectProof","type":"error"},{"inputs":[{"internalType":"uint256","name":"required","type":"uint256"},{"internalType":"uint256","name":"current","type":"uint256"}],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InsufficientFees","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InvalidData","type":"error"},{"inputs":[{"internalType":"uint256","name":"_length","type":"uint256"}],"name":"Max4TokensAllowed","type":"error"},{"inputs":[],"name":"MaxTokensMinted","type":"error"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"MaxTokensMintedForUser","type":"error"},{"inputs":[],"name":"MintingNotOpen","type":"error"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"NoAccess","type":"error"},{"inputs":[],"name":"NotDefaultChain","type":"error"},{"inputs":[],"name":"NotERC20Template","type":"error"},{"inputs":[],"name":"NotWhitelisted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_totalRaiseAmount","type":"uint256"},{"internalType":"uint256","name":"_maxDepositPerUser","type":"uint256"}],"name":"RaiseAmountInvalid","type":"error"},{"inputs":[{"internalType":"string","name":"_reason","type":"string"}],"name":"SafeProxyCreationFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"amountToLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"amountToSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emitterContractAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc20DaoDetails","outputs":[{"internalType":"string","name":"DaoName","type":"string"},{"internalType":"string","name":"DaoSymbol","type":"string"},{"internalType":"uint256","name":"quorum","type":"uint256"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"bool","name":"isGovernanceActive","type":"bool"},{"internalType":"bool","name":"isTransferable","type":"bool"},{"internalType":"bool","name":"onlyAllowWhitelist","type":"bool"},{"internalType":"address","name":"ownerAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factoryAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getERC20DAOdetails","outputs":[{"components":[{"internalType":"string","name":"DaoName","type":"string"},{"internalType":"string","name":"DaoSymbol","type":"string"},{"internalType":"uint256","name":"quorum","type":"uint256"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"bool","name":"isGovernanceActive","type":"bool"},{"internalType":"bool","name":"isTransferable","type":"bool"},{"internalType":"bool","name":"onlyAllowWhitelist","type":"bool"},{"internalType":"address","name":"ownerAddress","type":"address"}],"internalType":"struct Helper.ERC20DAOdetails","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_refundModule","type":"address"}],"name":"grantRefundModule","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_emitter","type":"address"},{"internalType":"string","name":"_DaoName","type":"string"},{"internalType":"string","name":"_DaoSymbol","type":"string"},{"internalType":"uint256","name":"_quorum","type":"uint256"},{"internalType":"uint256","name":"_threshold","type":"uint256"},{"internalType":"bool","name":"_isGovernanceActive","type":"bool"},{"internalType":"bool","name":"_isTransferable","type":"bool"},{"internalType":"bool","name":"_onlyAllowWhitelist","type":"bool"},{"internalType":"address","name":"_owner","type":"address"}],"name":"initializeERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amountArray","type":"uint256[]"},{"internalType":"address[]","name":"_userAddress","type":"address[]"}],"name":"mintGTToAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mintToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleOnlyAllowWhitelist","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_nft","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferNft","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isGovernanceActive","type":"bool"}],"name":"updateGovernanceActive","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_quorum","type":"uint256"},{"internalType":"uint256","name":"_threshold","type":"uint256"}],"name":"updateGovernanceSettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"updateProposalAndExecution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isTokenTransferable","type":"bool"}],"name":"updateTokenTransferability","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
608080604052346100c75760016066556000549060ff8260081c16610075575060ff8082161061003a575b604051612ef39081620000cd8239f35b60ff90811916176000557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160ff8152a13861002a565b62461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608490fd5b600080fdfe60e080604052600436101561001d575b50361561001b57600080fd5b005b60008060c052803560e01c91826301ffc9a7146121575750816306fdde03146120a4578163095ea7b31461207e578163150b7a021461201557816318160ddd14611ff557816323b872dd14611eda578163248a9ca314611ea95781632f2ff15d14611e38578163313ce56714611e1a57816336568abe14611d885781633950935114611d335781634c1ff9ab14611c78578163515f0c1414611aa6578163667ab70314611972578163668132c9146118575781636ffc166f1461142557816370a08231146113e957816379c65068146113a05781638728c87d1461136d57816391d148541461132057816395d89b4114611239578163966dae0e1461120e5781639dc29fac14610f06578163a0619e3714610edb578163a217fddf14610ebd578163a457c2d714610e18578163a9059cbb14610d73578163b3cda50d14610b90578163b8cd71f914610b16578163d02ea86514610aef578163d11eccd6146109f6578163d3cff1ba146109c7578163d547741f14610986578163da2e9c721461024c578163dd62ed3e146101f7575063e6f002a8146101bc573861000f565b60c051806003193601126101f4573033036101f457606d5462ff000060ff8260101c161560101b169062ff0000191617606d55604051f35b80fd5b346102465760403660031901126102465760406020916102156121f2565b61021d61220d565b60c080516001600160a01b03938416905260348652518490209116825283522054604051908152f35b60c05180fd5b3461024657610140366003190112610246576102666121f2565b9061026f61220d565b6044356001600160401b0381116102465761028e90369060040161244a565b926064356001600160401b038111610246576102ae90369060040161244a565b9260c4359182151583036109825760e435801515810361097e576101043591821515830361097a5761012435936001600160a01b03851685036101f4575060c051549560ff8760081c16159687809861096d575b8015610956575b156108fa5760c05160ff198216600117815590886108e8575b5050606880546001600160a01b039384166001600160a01b031991821617909155606780549290931691161790556040519361035d856122bb565b87855260208501879052608435604086015260a435606086015215156080850152151560a0840152151560c08301526001600160a01b031660e082015283516001600160401b038111610687576103b5606954612258565b601f81116108a0575b508060c051602090601f8311600114610837575060c0519161082c575b508160011b916000199060031b1c1916176069555b60208101518051906001600160401b038211610687578190610413606a54612258565b601f81116107d7575b5060c05190602091601f8411600114610769575060c0519261075e575b50508160011b916000199060031b1c191617606a555b6040810151606b556060810151606c556080810151151590606d5461ff0060a0830151151560081b169060ff62ff000060c0850151151560101b169360e06301000000600160b81b0391015160181b1694169060018060b81b03191617171717606d556104cd60ff60c0515460081c166104c8816128ca565b6128ca565b82516001600160401b038111610687576104e8603654612258565b601f8111610712575b5060c051602090601f83116001146106aa57508192939460c0519261069f575b50508160011b916000199060031b1c1916176036555b81516001600160401b03811161068757610542603754612258565b601f811161063b575b5060c05192602090601f83116001146105d5578293945060c051926105ca575b50508160011b916000199060031b1c1916176037555b61058e575b60c051604051f35b60c05161ff001981541690557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160018152a1610586565b01519050838061056b565b906037601f198416955260c0519160208320925b868110610623575083600195961061060a575b505050811b01603755610581565b015160001960f88460031b161c191690558380806105fc565b919260206001819286850151815501940192016105e9565b603760c0515260c05160208120601f840160051c8101926020851061067d575b601f0160051c01915b82811061067257505061054b565b818155600101610664565b909250829061065b565b634e487b7160e01b60c051526041600452602460c051fd5b015190508480610511565b6036905260c051602081209190601f198416905b8181106106fa575095836001959697106106e1575b505050811b01603655610527565b015160001960f88460031b161c191690558480806106d3565b9192602060018192868b0151815501940192016106be565b603660c0515260c05160208120601f840160051c81019260208510610754575b601f0160051c01915b8281106107495750506104f1565b81815560010161073b565b9092508290610732565b015190508680610439565b606a9194505260c051906020822091935b601f19841685106107bc576001945083601f198116106107a3575b505050811b01606a5561044f565b015160001960f88460031b161c19169055868080610795565b8181015183556020948501946001909301929091019061077a565b909150606a60c0515260c05160208120601f850160051c810160208610610825575b9085949392915b601f840160051c820181106108175750505061041c565b828155869550600101610800565b50806107f9565b9050850151866103db565b60699193505260c0516020812090925b601f1983168410610888576001935082601f1981161061086f575b5050811b016069556103f0565b87015160001960f88460031b161c191690558680610862565b87810151825560209384019360019092019101610847565b606960c0515260c05160208120601f840160051c8101602085106108e1575b601f840160051c820181106108d6575050506103be565b8281556001016108bf565b50806108bf565b61ffff19166101011790558980610322565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b50303b1580156103095750600160ff821614610309565b50600160ff821610610302565b8380fd5b8280fd5b5080fd5b34610246576040366003190112610246576105866004356109a561220d565b908060c0515260656020526109c26001604060c05120015461258d565b61272f565b346102465760403660031901126102465760206109ee6109e56121f2565b60243590612ce7565b604051908152f35b3461024657610a0436612223565b91303303610246576001600160a01b03908116918215610abc5716918215610a8a57813b156102465760405192632142170760e11b8452306004850152602484015260448301528160648160c05180945af18015610a7d57610a685760c051604051f35b610a7190612292565b60c05180156105865780fd5b6040513d60c051823e3d90fd5b6084836040519063045a4b3160e01b82526040600483015260036044830152625f746f60e81b60648301526024820152fd5b6084836040519063045a4b3160e01b825260406004830152600460448301526317db999d60e21b60648301526024820152fd5b346102465760403660031901126102465760206109ee610b0d6121f2565b60243590612dac565b602036600319011261024657610b2a6123e9565b303303610246571515606d5461ff008260081b169061ff00191617606d5560018060a01b0360675416803b15610246576040519163089a084f60e21b835230600484015260248301528160448160c05180945af18015610a7d57610a685760c051604051f35b3461024657604036600319011261024657610ba96121f2565b60249081356001600160401b038111610246573660238201121561024657610bda9036908481600401359101612413565b606854604051633b188ab560e01b815230600482015260c0519294926001600160a01b03926101809182918491879183919088165af18015610a7d57839260e09260c05192610d46575b50500151163303610d1457600260665414610cd057600260665582168015610c9957505060c05191829182602083519301915af13d15610c94573d610c68816123f8565b90610c7660405192836122f2565b815260c0513d916020013e5b1561024657600160665560c051604051f35b610c82565b608492506040519163045a4b3160e01b835260406004840152600960448401526817d8dbdb9d1c9858dd60ba1b6064840152820152fd5b60405162461bcd60e51b815260206004820152601f818401527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b60405162461bcd60e51b815260206004820152600b818401526a4f6e6c7920476e6f73697360a81b6044820152606490fd5b610d659250803d10610d6c575b610d5d81836122f2565b81019061294b565b8780610c24565b503d610d53565b3461024657604036600319011261024657610d8c6121f2565b60243590610da160ff606d5460081c16612ade565b610dac828233612b4e565b6067546001600160a01b031691823b1561024657610de592604051808095819463debfa06360e01b835260c05196333060048601612b23565b039160c051905af18015610a7d57610e03575b602060405160018152f35b610e0c90612292565b60c0518015610df85780fd5b3461024657604036600319011261024657610e316121f2565b6040602435923360c0515260346020528160c0512060018060a01b0384168252602052205491808310610e6a57610df89203903361248b565b60405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608490fd5b346102465760c051806003193601126101f457602090604051908152f35b346102465760c051806003193601126101f4576067546040516001600160a01b039091168152602090f35b3461024657604036600319011261024657610f1f6121f2565b6024803591600080516020612e9e8339815191528085526020946065865260408120338252865260ff604082205416156110555750506001600160a01b0316908115611008578160c0515260338452604060c051205490838210610fba575082908260c051526033855203604060c05120558160355403603555604051918252600080516020612e7e83398151915260c051938493a3604051f35b8460226084926040519262461bcd60e51b845260048401528201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152fd5b8360216084926040519262461bcd60e51b845260048401528201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152fd5b859250611061336127ce565b916040519061106f826122d7565b604282528482019260603685378251156111fb57603084538251906001918210156111e85790607860218501536041915b81831161117c5750505061114c5760486111489361111d9361112c9360405195869376020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b8a8601526110f4815180928c6037890191016121aa565b8401917001034b99036b4b9b9b4b733903937b6329607d1b6037840152518093868401906121aa565b010360288101845201826122f2565b60405193849362461bcd60e51b855260048501528301906121cd565b0390fd5b606485856040519162461bcd60e51b8352816004840152820152600080516020612e5e8339815191526044820152fd5b909192600f811660108110156111d5576f181899199a1a9b1b9c1cb0b131b232b360811b901a6111ac85876127a7565b5360041c9280156111c2576000190191906110a0565b634e487b7160e01b825260116004528882fd5b634e487b7160e01b835260326004528983fd5b634e487b7160e01b815260326004528790fd5b634e487b7160e01b815260326004528690fd5b346102465760c051806003193601126101f4576068546040516001600160a01b039091168152602090f35b346102465760c051806003193601126101f457506040518160375461125d81612258565b808452906001908181169081156112f8575060011461129f575b61129b84611287818803826122f2565b6040519182916020835260208301906121cd565b0390f35b60378352602094507f42a7b7dd785cd69714a189dffb3fd7d7174edc9ece837694ce50f7078f7c31ae5b8284106112e5575050508161129b936112879282010193611277565b80548585018701529285019281016112c9565b61129b96506112879450602092508593915060ff191682840152151560051b82010193611277565b346102465760403660031901126102465760ff604060209261134061220d565b60c08051600435905260658652518390206001600160a01b03909116825284522054604051911615158152f35b6020366003190112610246576113816123e9565b3033036102465760ff8019606d54169115151617606d5560c051604051f35b34610246576040366003190112610246576113b96121f2565b6068546001600160a01b0316331480156113e0575b15610246576105869060243590612a24565b503033146113ce565b34610246576020366003190112610246576001600160a01b0361140a6121f2565b1660c0515260336020526020604060c0512054604051908152f35b34610246576040366003190112610246576001600160401b039060043590828211610246573660238301121561024657816004013591602460a05261147861146c846123d2565b604051806080526122f2565b8260805152602060805101809360a051809160051b840101923684116102465701905b8282106118475750505060a051359283116102465736602384011215610246578260040135906114ca826123d2565b936114d860405195866122f2565b8285526020850191829360a051809160051b840101923684116102465701925b8284106118275750505050303303610246576080515183518082036118085750506080515160c0515b8181106115fd5750506067546001600160a01b039081169290833b15610246576040949291945194859363b9d3970560e01b855260648501306004870152606060a0518701526080515180915260848601929060c0515b8181106115e457505050602090600319868403016044870152519182815201929160c051905b8282106115c55760c05186908180880381838c5af18015610a7d57610a685760c051604051f35b835181168552879550602094850194909301926001919091019061159e565b8251855289975060209485019490920191600101611578565b6116276001600160a01b036116128388612a10565b511661162083608051612a10565b5190612a24565b6067546001600160a01b03908116906116408388612a10565b51169060018060a01b0360685416604051633b188ab560e01b81523060048201526101808160a05181855afa908115610a7d5760c051916117e7575b5060c060018060a01b03910151169061169785608051612a10565b51906101806040518092633b188ab560e01b82523060048301528160a051915afa908115610a7d5760c051916117c6575b5060e001516001600160a01b0390811692906020906116e7888d612a10565b51166040519485916317aa5fb760e11b835260048301528160a051915afa928315610a7d5760c0519361178a575b50833b156102465760405194637c28875f60e01b865230600487015260a051860152604485015260c051606485015242608485015260a4840152151560c48301528160e48160c05180945af18015610a7d57611775575b50600101611521565b61177e90612292565b60c051801561176c5780fd5b9092506020813d6020116117be575b816117a6602093836122f2565b81010312610246576117b79061293e565b918a611715565b3d9150611799565b6117e191506101803d61018011610d6c57610d5d81836122f2565b8a6116c8565b61180291506101803d61018011610d6c57610d5d81836122f2565b8961167c565b6044925060405191631f4bb7c160e31b8352600483015260a051820152fd5b83356001600160a01b038116810361097e578152602093840193016114f8565b813581526020918201910161149b565b34610246576040366003190112610246576004356024353033036102465781156119575780156118f95761271080831161193c5781116118f957606b829055606c8190556067546001600160a01b031690813b156102465760405192630dff04f760e31b8452306004850152602484015260448301528160648160c05180945af18015610a7d576118ea5760c051604051f35b6118f390612292565b80610586565b604051631aac77f760e31b81529081906111489060048301919060408352600a60408401526917dd1a1c995cda1bdb1960b21b6060840152602060808401930152565b604051631aac77f760e31b8152806111488560048301612ab6565b604051631aac77f760e31b8152806111488460048301612ab6565b346102465760c051806003193601126101f45760405160695461199481612258565b808352600191808316908115611a7e5750600114611a3e575b6119e7836119bd818703826122f2565b6119c5612315565b606b5490606c546119f5606d54926040519687966101008089528801906121cd565b9086820360208801526121cd565b6040850193909352606084015260ff81811615156080850152600882901c8116151560a0850152601082901c16151560c084015260181c6001600160a01b031660e08301520390f35b909250606960c0515260c051906020938483205b828410611a6b575050508101909101906119bd816119ad565b8054858501870152928501928101611a52565b6119e795506119bd93506020915091849260ff191682840152151560051b82010193506119ad565b346102465760c051806003193601126101f457604051611ac5816122bb565b6060815260209060608282015260c051604082015260c051606082015260c051608082015260c05160a082015260c05160c082015260e060c051910152604051611b0e816122bb565b60405160c051606954611b2081612258565b80845290600190818116908115611c5a5750600114611c1a575b611bd8858786611b4c818803826122f2565b8252611b56612315565b90808301918252606b549160408401928352606c549060608501918252606d54916080860160ff84161515815260a087019060ff8560081c161515825260c088019260ff8660101c1615158452611beb60e08a019560018060a01b03809860181c1687526040519b8c9b8a8d52518c6101009b8c9101526101208d01906121cd565b90518b8203601f190160408d01526121cd565b975160608a015251608089015251151560a088015251151560c087015251151560e08601525116908301520390f35b94929150606960c0515260c051948386205b828710611c47575092949192505081018301611b4c82611b3a565b8054848801860152958401958101611c2c565b60ff1916878601525050151560051b820184019050611b4c82611b3a565b602036600319011261024657611c8c6121f2565b30330361024657600080516020612e9e833981519152908160c05152606560205260c05190604082209060018060a01b031680925260205260c05160ff60408220541615611cdc5760c051604051f35b829052606560205260c0518160408220915260205260c0519160408320600160ff198254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d3393604051a4808080610586565b3461024657604036600319011261024657610df8611d4f6121f2565b3360c05152603460205260c051604081209060018060a01b0383169052602052611d81602435604060c0512054612468565b903361248b565b3461024657604036600319011261024657611da161220d565b336001600160a01b03821603611dbd576105869060043561272f565b60405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608490fd5b346102465760c051806003193601126101f457602060405160128152f35b3461024657604036600319011261024657600435611e5461220d565b8160c051526065602052611e706001604060c05120015461258d565b8160c05152606560205260c05190604082209060018060a01b031680925260205260c05160ff60408220541615611cdc5760c051604051f35b346102465760203660031901126102465760043560c05152606560205260206001604060c051200154604051908152f35b3461024657611ee836612223565b611efc60ff606d9493945460081c16612ade565b60018060a01b0380831660c05152603460205260c0516040812090339052602052604060c05120546000198103611f96575b50611f3a828585612b4e565b60675416803b1561024657611f6a9360405180958194829363debfa06360e01b845260c051973060048601612b23565b039160c051905af18015610a7d57611f8757602060405160018152f35b611f9090612292565b80610df8565b828110611fb05782611faa9103338561248b565b84611f2e565b60405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606490fd5b346102465760c051806003193601126101f4576020603554604051908152f35b346102465760803660031901126102465761202e6121f2565b5061203761220d565b506064356001600160401b038082116102465736602383011215610246578160040135908111610246573691016024011161024657604051630a85bd0160e11b8152602090f35b3461024657604036600319011261024657610df861209a6121f2565b602435903361248b565b346102465760c051806003193601126101f4576040516036546120c681612258565b80835260019180831690811561212f57506001146120ef575b61129b83611287818703826122f2565b909250603660c0515260c051906020938483205b82841061211c57505050810190910190611287816120df565b8054858501870152928501928101612103565b61129b955061128793506020915091849260ff191682840152151560051b82010193506120df565b346109825760203660031901126109825760043563ffffffff60e01b811680910361097e5760209250637965db0b60e01b8114908115612199575b5015158152f35b6301ffc9a760e01b14905083612192565b60005b8381106121bd5750506000910152565b81810151838201526020016121ad565b906020916121e6815180928185528580860191016121aa565b601f01601f1916010190565b600435906001600160a01b038216820361220857565b600080fd5b602435906001600160a01b038216820361220857565b6060906003190112612208576001600160a01b0390600435828116810361220857916024359081168103612208579060443590565b90600182811c92168015612288575b602083101461227257565b634e487b7160e01b600052602260045260246000fd5b91607f1691612267565b6001600160401b0381116122a557604052565b634e487b7160e01b600052604160045260246000fd5b61010081019081106001600160401b038211176122a557604052565b608081019081106001600160401b038211176122a557604052565b601f909101601f19168101906001600160401b038211908210176122a557604052565b60405190600082606a549161232983612258565b8083526001938085169081156123b15750600114612351575b5061234f925003836122f2565b565b606a60009081527f116fea137db6e131133e7f2bab296045d8f41cc5607279db17b218cab0929a5194602093509091905b81831061239957505061234f935082010138612342565b85548884018501529485019487945091830191612382565b905061234f94506020925060ff191682840152151560051b82010138612342565b6001600160401b0381116122a55760051b60200190565b60043590811515820361220857565b6001600160401b0381116122a557601f01601f191660200190565b92919261241f826123f8565b9161242d60405193846122f2565b829481845281830111612208578281602093846000960137010152565b9080601f830112156122085781602061246593359101612413565b90565b9190820180921161247557565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b0390811691821561253c57169182156124ec5760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925918360005260348252604060002085600052825280604060002055604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608490fd5b60405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b60009080825260209060658252604092838120338252835260ff8482205416156125b75750505050565b6125c0336127ce565b918451906125cd826122d7565b6042825284820192606036853782511561271b576030845382519060019182101561271b5790607860218501536041915b8183116126ad5750505061267d57604861114893869361266193612652985198899376020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b8a8601526110f4815180928c6037890191016121aa565b010360288101875201856122f2565b5192839262461bcd60e51b8452600484015260248301906121cd565b60648486519062461bcd60e51b82528060048301526024820152600080516020612e5e8339815191526044820152fd5b909192600f81166010811015612707576f181899199a1a9b1b9c1cb0b131b232b360811b901a6126dd85876127a7565b5360041c9280156126f3576000190191906125fe565b634e487b7160e01b82526011600452602482fd5b634e487b7160e01b83526032600452602483fd5b634e487b7160e01b81526032600452602490fd5b906000918083526065602052604083209160018060a01b03169182845260205260ff60408420541661276057505050565b8083526065602052604083208284526020526040832060ff1981541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b3393604051a4565b9081518110156127b8570160200190565b634e487b7160e01b600052603260045260246000fd5b60405190606082016001600160401b038111838210176122a557604052602a82526020820160403682378251156127b8576030905381516001908110156127b857607860218401536029905b80821161285c57505061282a5790565b606460405162461bcd60e51b81526020600482015260206024820152600080516020612e5e8339815191526044820152fd5b9091600f811660108110156128b5576f181899199a1a9b1b9c1cb0b131b232b360811b901a61288b84866127a7565b5360041c9180156128a057600019019061281a565b60246000634e487b7160e01b81526011600452fd5b60246000634e487b7160e01b81526032600452fd5b156128d157565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b51906001600160a01b038216820361220857565b5190811515820361220857565b80916101809283910312612208576040519182016001600160401b038111838210176122a557604052805182526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a08301526129b660c0820161292a565b60c08301526129c760e0820161292a565b60e083015261010080820151908301526101206129e581830161293e565b908301526101406129f781830161293e565b90830152612a0961016080920161293e565b9082015290565b80518210156127b85760209160051b010190565b6001600160a01b0316908115612a7157600080516020612e7e833981519152602082612a54600094603554612468565b6035558484526033825260408420818154019055604051908152a3565b60405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606490fd5b91906040835260076040840152665f71756f72756d60c81b6060840152602060808401930152565b15612ae557565b60405162461bcd60e51b8152602060048201526016602482015275546f6b656e204e6f6e205472616e7366657261626c6560501b6044820152606490fd5b6001600160a01b03918216815291811660208301529091166040820152606081019190915260800190565b6001600160a01b03908116918215612c595716918215612c085760008281526033602052604081205491808310612bb45760408282600080516020612e7e83398151915295876020965260338652038282205586815220818154019055604051908152a3565b60405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b60405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608490fd5b90816020910312612208575160ff811681036122085790565b60ff166012039060ff821161247557565b60ff16604d811161247557600a0a90565b6000906001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8103612d4757505060125b60ff8116601203612d22575090565b612d2e612d3391612cc5565b612cd6565b908060001904821181151516612475570290565b60206004916040519283809263313ce56760e01b82525afa918215612da05791612d72575b50612d13565b612d93915060203d8111612d99575b612d8b81836122f2565b810190612cac565b38612d6c565b503d612d81565b604051903d90823e3d90fd5b6000906001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8103612e1457505060125b60ff8116601203612de7575090565b612d2e612df391612cc5565b908115612dfe570490565b634e487b7160e01b600052601260045260246000fd5b60206004916040519283809263313ce56760e01b82525afa918215612da05791612e3f575b50612dd8565b612e57915060203d8111612d9957612d8b81836122f2565b38612e3956fe537472696e67733a20686578206c656e67746820696e73756666696369656e74ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60dabe9ef7b41f3c1cc359b009558ac4700a6bef8c5a11b51767e4980ed66341a2646970667358221220a90e785d0f600c83c302860d40b186f5d3fa4db79cb47890aa98a17d5bce6b6664736f6c63430008100033
Deployed Bytecode
0x60e080604052600436101561001d575b50361561001b57600080fd5b005b60008060c052803560e01c91826301ffc9a7146121575750816306fdde03146120a4578163095ea7b31461207e578163150b7a021461201557816318160ddd14611ff557816323b872dd14611eda578163248a9ca314611ea95781632f2ff15d14611e38578163313ce56714611e1a57816336568abe14611d885781633950935114611d335781634c1ff9ab14611c78578163515f0c1414611aa6578163667ab70314611972578163668132c9146118575781636ffc166f1461142557816370a08231146113e957816379c65068146113a05781638728c87d1461136d57816391d148541461132057816395d89b4114611239578163966dae0e1461120e5781639dc29fac14610f06578163a0619e3714610edb578163a217fddf14610ebd578163a457c2d714610e18578163a9059cbb14610d73578163b3cda50d14610b90578163b8cd71f914610b16578163d02ea86514610aef578163d11eccd6146109f6578163d3cff1ba146109c7578163d547741f14610986578163da2e9c721461024c578163dd62ed3e146101f7575063e6f002a8146101bc573861000f565b60c051806003193601126101f4573033036101f457606d5462ff000060ff8260101c161560101b169062ff0000191617606d55604051f35b80fd5b346102465760403660031901126102465760406020916102156121f2565b61021d61220d565b60c080516001600160a01b03938416905260348652518490209116825283522054604051908152f35b60c05180fd5b3461024657610140366003190112610246576102666121f2565b9061026f61220d565b6044356001600160401b0381116102465761028e90369060040161244a565b926064356001600160401b038111610246576102ae90369060040161244a565b9260c4359182151583036109825760e435801515810361097e576101043591821515830361097a5761012435936001600160a01b03851685036101f4575060c051549560ff8760081c16159687809861096d575b8015610956575b156108fa5760c05160ff198216600117815590886108e8575b5050606880546001600160a01b039384166001600160a01b031991821617909155606780549290931691161790556040519361035d856122bb565b87855260208501879052608435604086015260a435606086015215156080850152151560a0840152151560c08301526001600160a01b031660e082015283516001600160401b038111610687576103b5606954612258565b601f81116108a0575b508060c051602090601f8311600114610837575060c0519161082c575b508160011b916000199060031b1c1916176069555b60208101518051906001600160401b038211610687578190610413606a54612258565b601f81116107d7575b5060c05190602091601f8411600114610769575060c0519261075e575b50508160011b916000199060031b1c191617606a555b6040810151606b556060810151606c556080810151151590606d5461ff0060a0830151151560081b169060ff62ff000060c0850151151560101b169360e06301000000600160b81b0391015160181b1694169060018060b81b03191617171717606d556104cd60ff60c0515460081c166104c8816128ca565b6128ca565b82516001600160401b038111610687576104e8603654612258565b601f8111610712575b5060c051602090601f83116001146106aa57508192939460c0519261069f575b50508160011b916000199060031b1c1916176036555b81516001600160401b03811161068757610542603754612258565b601f811161063b575b5060c05192602090601f83116001146105d5578293945060c051926105ca575b50508160011b916000199060031b1c1916176037555b61058e575b60c051604051f35b60c05161ff001981541690557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160018152a1610586565b01519050838061056b565b906037601f198416955260c0519160208320925b868110610623575083600195961061060a575b505050811b01603755610581565b015160001960f88460031b161c191690558380806105fc565b919260206001819286850151815501940192016105e9565b603760c0515260c05160208120601f840160051c8101926020851061067d575b601f0160051c01915b82811061067257505061054b565b818155600101610664565b909250829061065b565b634e487b7160e01b60c051526041600452602460c051fd5b015190508480610511565b6036905260c051602081209190601f198416905b8181106106fa575095836001959697106106e1575b505050811b01603655610527565b015160001960f88460031b161c191690558480806106d3565b9192602060018192868b0151815501940192016106be565b603660c0515260c05160208120601f840160051c81019260208510610754575b601f0160051c01915b8281106107495750506104f1565b81815560010161073b565b9092508290610732565b015190508680610439565b606a9194505260c051906020822091935b601f19841685106107bc576001945083601f198116106107a3575b505050811b01606a5561044f565b015160001960f88460031b161c19169055868080610795565b8181015183556020948501946001909301929091019061077a565b909150606a60c0515260c05160208120601f850160051c810160208610610825575b9085949392915b601f840160051c820181106108175750505061041c565b828155869550600101610800565b50806107f9565b9050850151866103db565b60699193505260c0516020812090925b601f1983168410610888576001935082601f1981161061086f575b5050811b016069556103f0565b87015160001960f88460031b161c191690558680610862565b87810151825560209384019360019092019101610847565b606960c0515260c05160208120601f840160051c8101602085106108e1575b601f840160051c820181106108d6575050506103be565b8281556001016108bf565b50806108bf565b61ffff19166101011790558980610322565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b50303b1580156103095750600160ff821614610309565b50600160ff821610610302565b8380fd5b8280fd5b5080fd5b34610246576040366003190112610246576105866004356109a561220d565b908060c0515260656020526109c26001604060c05120015461258d565b61272f565b346102465760403660031901126102465760206109ee6109e56121f2565b60243590612ce7565b604051908152f35b3461024657610a0436612223565b91303303610246576001600160a01b03908116918215610abc5716918215610a8a57813b156102465760405192632142170760e11b8452306004850152602484015260448301528160648160c05180945af18015610a7d57610a685760c051604051f35b610a7190612292565b60c05180156105865780fd5b6040513d60c051823e3d90fd5b6084836040519063045a4b3160e01b82526040600483015260036044830152625f746f60e81b60648301526024820152fd5b6084836040519063045a4b3160e01b825260406004830152600460448301526317db999d60e21b60648301526024820152fd5b346102465760403660031901126102465760206109ee610b0d6121f2565b60243590612dac565b602036600319011261024657610b2a6123e9565b303303610246571515606d5461ff008260081b169061ff00191617606d5560018060a01b0360675416803b15610246576040519163089a084f60e21b835230600484015260248301528160448160c05180945af18015610a7d57610a685760c051604051f35b3461024657604036600319011261024657610ba96121f2565b60249081356001600160401b038111610246573660238201121561024657610bda9036908481600401359101612413565b606854604051633b188ab560e01b815230600482015260c0519294926001600160a01b03926101809182918491879183919088165af18015610a7d57839260e09260c05192610d46575b50500151163303610d1457600260665414610cd057600260665582168015610c9957505060c05191829182602083519301915af13d15610c94573d610c68816123f8565b90610c7660405192836122f2565b815260c0513d916020013e5b1561024657600160665560c051604051f35b610c82565b608492506040519163045a4b3160e01b835260406004840152600960448401526817d8dbdb9d1c9858dd60ba1b6064840152820152fd5b60405162461bcd60e51b815260206004820152601f818401527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b60405162461bcd60e51b815260206004820152600b818401526a4f6e6c7920476e6f73697360a81b6044820152606490fd5b610d659250803d10610d6c575b610d5d81836122f2565b81019061294b565b8780610c24565b503d610d53565b3461024657604036600319011261024657610d8c6121f2565b60243590610da160ff606d5460081c16612ade565b610dac828233612b4e565b6067546001600160a01b031691823b1561024657610de592604051808095819463debfa06360e01b835260c05196333060048601612b23565b039160c051905af18015610a7d57610e03575b602060405160018152f35b610e0c90612292565b60c0518015610df85780fd5b3461024657604036600319011261024657610e316121f2565b6040602435923360c0515260346020528160c0512060018060a01b0384168252602052205491808310610e6a57610df89203903361248b565b60405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608490fd5b346102465760c051806003193601126101f457602090604051908152f35b346102465760c051806003193601126101f4576067546040516001600160a01b039091168152602090f35b3461024657604036600319011261024657610f1f6121f2565b6024803591600080516020612e9e8339815191528085526020946065865260408120338252865260ff604082205416156110555750506001600160a01b0316908115611008578160c0515260338452604060c051205490838210610fba575082908260c051526033855203604060c05120558160355403603555604051918252600080516020612e7e83398151915260c051938493a3604051f35b8460226084926040519262461bcd60e51b845260048401528201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152fd5b8360216084926040519262461bcd60e51b845260048401528201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152fd5b859250611061336127ce565b916040519061106f826122d7565b604282528482019260603685378251156111fb57603084538251906001918210156111e85790607860218501536041915b81831161117c5750505061114c5760486111489361111d9361112c9360405195869376020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b8a8601526110f4815180928c6037890191016121aa565b8401917001034b99036b4b9b9b4b733903937b6329607d1b6037840152518093868401906121aa565b010360288101845201826122f2565b60405193849362461bcd60e51b855260048501528301906121cd565b0390fd5b606485856040519162461bcd60e51b8352816004840152820152600080516020612e5e8339815191526044820152fd5b909192600f811660108110156111d5576f181899199a1a9b1b9c1cb0b131b232b360811b901a6111ac85876127a7565b5360041c9280156111c2576000190191906110a0565b634e487b7160e01b825260116004528882fd5b634e487b7160e01b835260326004528983fd5b634e487b7160e01b815260326004528790fd5b634e487b7160e01b815260326004528690fd5b346102465760c051806003193601126101f4576068546040516001600160a01b039091168152602090f35b346102465760c051806003193601126101f457506040518160375461125d81612258565b808452906001908181169081156112f8575060011461129f575b61129b84611287818803826122f2565b6040519182916020835260208301906121cd565b0390f35b60378352602094507f42a7b7dd785cd69714a189dffb3fd7d7174edc9ece837694ce50f7078f7c31ae5b8284106112e5575050508161129b936112879282010193611277565b80548585018701529285019281016112c9565b61129b96506112879450602092508593915060ff191682840152151560051b82010193611277565b346102465760403660031901126102465760ff604060209261134061220d565b60c08051600435905260658652518390206001600160a01b03909116825284522054604051911615158152f35b6020366003190112610246576113816123e9565b3033036102465760ff8019606d54169115151617606d5560c051604051f35b34610246576040366003190112610246576113b96121f2565b6068546001600160a01b0316331480156113e0575b15610246576105869060243590612a24565b503033146113ce565b34610246576020366003190112610246576001600160a01b0361140a6121f2565b1660c0515260336020526020604060c0512054604051908152f35b34610246576040366003190112610246576001600160401b039060043590828211610246573660238301121561024657816004013591602460a05261147861146c846123d2565b604051806080526122f2565b8260805152602060805101809360a051809160051b840101923684116102465701905b8282106118475750505060a051359283116102465736602384011215610246578260040135906114ca826123d2565b936114d860405195866122f2565b8285526020850191829360a051809160051b840101923684116102465701925b8284106118275750505050303303610246576080515183518082036118085750506080515160c0515b8181106115fd5750506067546001600160a01b039081169290833b15610246576040949291945194859363b9d3970560e01b855260648501306004870152606060a0518701526080515180915260848601929060c0515b8181106115e457505050602090600319868403016044870152519182815201929160c051905b8282106115c55760c05186908180880381838c5af18015610a7d57610a685760c051604051f35b835181168552879550602094850194909301926001919091019061159e565b8251855289975060209485019490920191600101611578565b6116276001600160a01b036116128388612a10565b511661162083608051612a10565b5190612a24565b6067546001600160a01b03908116906116408388612a10565b51169060018060a01b0360685416604051633b188ab560e01b81523060048201526101808160a05181855afa908115610a7d5760c051916117e7575b5060c060018060a01b03910151169061169785608051612a10565b51906101806040518092633b188ab560e01b82523060048301528160a051915afa908115610a7d5760c051916117c6575b5060e001516001600160a01b0390811692906020906116e7888d612a10565b51166040519485916317aa5fb760e11b835260048301528160a051915afa928315610a7d5760c0519361178a575b50833b156102465760405194637c28875f60e01b865230600487015260a051860152604485015260c051606485015242608485015260a4840152151560c48301528160e48160c05180945af18015610a7d57611775575b50600101611521565b61177e90612292565b60c051801561176c5780fd5b9092506020813d6020116117be575b816117a6602093836122f2565b81010312610246576117b79061293e565b918a611715565b3d9150611799565b6117e191506101803d61018011610d6c57610d5d81836122f2565b8a6116c8565b61180291506101803d61018011610d6c57610d5d81836122f2565b8961167c565b6044925060405191631f4bb7c160e31b8352600483015260a051820152fd5b83356001600160a01b038116810361097e578152602093840193016114f8565b813581526020918201910161149b565b34610246576040366003190112610246576004356024353033036102465781156119575780156118f95761271080831161193c5781116118f957606b829055606c8190556067546001600160a01b031690813b156102465760405192630dff04f760e31b8452306004850152602484015260448301528160648160c05180945af18015610a7d576118ea5760c051604051f35b6118f390612292565b80610586565b604051631aac77f760e31b81529081906111489060048301919060408352600a60408401526917dd1a1c995cda1bdb1960b21b6060840152602060808401930152565b604051631aac77f760e31b8152806111488560048301612ab6565b604051631aac77f760e31b8152806111488460048301612ab6565b346102465760c051806003193601126101f45760405160695461199481612258565b808352600191808316908115611a7e5750600114611a3e575b6119e7836119bd818703826122f2565b6119c5612315565b606b5490606c546119f5606d54926040519687966101008089528801906121cd565b9086820360208801526121cd565b6040850193909352606084015260ff81811615156080850152600882901c8116151560a0850152601082901c16151560c084015260181c6001600160a01b031660e08301520390f35b909250606960c0515260c051906020938483205b828410611a6b575050508101909101906119bd816119ad565b8054858501870152928501928101611a52565b6119e795506119bd93506020915091849260ff191682840152151560051b82010193506119ad565b346102465760c051806003193601126101f457604051611ac5816122bb565b6060815260209060608282015260c051604082015260c051606082015260c051608082015260c05160a082015260c05160c082015260e060c051910152604051611b0e816122bb565b60405160c051606954611b2081612258565b80845290600190818116908115611c5a5750600114611c1a575b611bd8858786611b4c818803826122f2565b8252611b56612315565b90808301918252606b549160408401928352606c549060608501918252606d54916080860160ff84161515815260a087019060ff8560081c161515825260c088019260ff8660101c1615158452611beb60e08a019560018060a01b03809860181c1687526040519b8c9b8a8d52518c6101009b8c9101526101208d01906121cd565b90518b8203601f190160408d01526121cd565b975160608a015251608089015251151560a088015251151560c087015251151560e08601525116908301520390f35b94929150606960c0515260c051948386205b828710611c47575092949192505081018301611b4c82611b3a565b8054848801860152958401958101611c2c565b60ff1916878601525050151560051b820184019050611b4c82611b3a565b602036600319011261024657611c8c6121f2565b30330361024657600080516020612e9e833981519152908160c05152606560205260c05190604082209060018060a01b031680925260205260c05160ff60408220541615611cdc5760c051604051f35b829052606560205260c0518160408220915260205260c0519160408320600160ff198254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d3393604051a4808080610586565b3461024657604036600319011261024657610df8611d4f6121f2565b3360c05152603460205260c051604081209060018060a01b0383169052602052611d81602435604060c0512054612468565b903361248b565b3461024657604036600319011261024657611da161220d565b336001600160a01b03821603611dbd576105869060043561272f565b60405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608490fd5b346102465760c051806003193601126101f457602060405160128152f35b3461024657604036600319011261024657600435611e5461220d565b8160c051526065602052611e706001604060c05120015461258d565b8160c05152606560205260c05190604082209060018060a01b031680925260205260c05160ff60408220541615611cdc5760c051604051f35b346102465760203660031901126102465760043560c05152606560205260206001604060c051200154604051908152f35b3461024657611ee836612223565b611efc60ff606d9493945460081c16612ade565b60018060a01b0380831660c05152603460205260c0516040812090339052602052604060c05120546000198103611f96575b50611f3a828585612b4e565b60675416803b1561024657611f6a9360405180958194829363debfa06360e01b845260c051973060048601612b23565b039160c051905af18015610a7d57611f8757602060405160018152f35b611f9090612292565b80610df8565b828110611fb05782611faa9103338561248b565b84611f2e565b60405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606490fd5b346102465760c051806003193601126101f4576020603554604051908152f35b346102465760803660031901126102465761202e6121f2565b5061203761220d565b506064356001600160401b038082116102465736602383011215610246578160040135908111610246573691016024011161024657604051630a85bd0160e11b8152602090f35b3461024657604036600319011261024657610df861209a6121f2565b602435903361248b565b346102465760c051806003193601126101f4576040516036546120c681612258565b80835260019180831690811561212f57506001146120ef575b61129b83611287818703826122f2565b909250603660c0515260c051906020938483205b82841061211c57505050810190910190611287816120df565b8054858501870152928501928101612103565b61129b955061128793506020915091849260ff191682840152151560051b82010193506120df565b346109825760203660031901126109825760043563ffffffff60e01b811680910361097e5760209250637965db0b60e01b8114908115612199575b5015158152f35b6301ffc9a760e01b14905083612192565b60005b8381106121bd5750506000910152565b81810151838201526020016121ad565b906020916121e6815180928185528580860191016121aa565b601f01601f1916010190565b600435906001600160a01b038216820361220857565b600080fd5b602435906001600160a01b038216820361220857565b6060906003190112612208576001600160a01b0390600435828116810361220857916024359081168103612208579060443590565b90600182811c92168015612288575b602083101461227257565b634e487b7160e01b600052602260045260246000fd5b91607f1691612267565b6001600160401b0381116122a557604052565b634e487b7160e01b600052604160045260246000fd5b61010081019081106001600160401b038211176122a557604052565b608081019081106001600160401b038211176122a557604052565b601f909101601f19168101906001600160401b038211908210176122a557604052565b60405190600082606a549161232983612258565b8083526001938085169081156123b15750600114612351575b5061234f925003836122f2565b565b606a60009081527f116fea137db6e131133e7f2bab296045d8f41cc5607279db17b218cab0929a5194602093509091905b81831061239957505061234f935082010138612342565b85548884018501529485019487945091830191612382565b905061234f94506020925060ff191682840152151560051b82010138612342565b6001600160401b0381116122a55760051b60200190565b60043590811515820361220857565b6001600160401b0381116122a557601f01601f191660200190565b92919261241f826123f8565b9161242d60405193846122f2565b829481845281830111612208578281602093846000960137010152565b9080601f830112156122085781602061246593359101612413565b90565b9190820180921161247557565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b0390811691821561253c57169182156124ec5760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925918360005260348252604060002085600052825280604060002055604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608490fd5b60405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b60009080825260209060658252604092838120338252835260ff8482205416156125b75750505050565b6125c0336127ce565b918451906125cd826122d7565b6042825284820192606036853782511561271b576030845382519060019182101561271b5790607860218501536041915b8183116126ad5750505061267d57604861114893869361266193612652985198899376020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b8a8601526110f4815180928c6037890191016121aa565b010360288101875201856122f2565b5192839262461bcd60e51b8452600484015260248301906121cd565b60648486519062461bcd60e51b82528060048301526024820152600080516020612e5e8339815191526044820152fd5b909192600f81166010811015612707576f181899199a1a9b1b9c1cb0b131b232b360811b901a6126dd85876127a7565b5360041c9280156126f3576000190191906125fe565b634e487b7160e01b82526011600452602482fd5b634e487b7160e01b83526032600452602483fd5b634e487b7160e01b81526032600452602490fd5b906000918083526065602052604083209160018060a01b03169182845260205260ff60408420541661276057505050565b8083526065602052604083208284526020526040832060ff1981541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b3393604051a4565b9081518110156127b8570160200190565b634e487b7160e01b600052603260045260246000fd5b60405190606082016001600160401b038111838210176122a557604052602a82526020820160403682378251156127b8576030905381516001908110156127b857607860218401536029905b80821161285c57505061282a5790565b606460405162461bcd60e51b81526020600482015260206024820152600080516020612e5e8339815191526044820152fd5b9091600f811660108110156128b5576f181899199a1a9b1b9c1cb0b131b232b360811b901a61288b84866127a7565b5360041c9180156128a057600019019061281a565b60246000634e487b7160e01b81526011600452fd5b60246000634e487b7160e01b81526032600452fd5b156128d157565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b51906001600160a01b038216820361220857565b5190811515820361220857565b80916101809283910312612208576040519182016001600160401b038111838210176122a557604052805182526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a08301526129b660c0820161292a565b60c08301526129c760e0820161292a565b60e083015261010080820151908301526101206129e581830161293e565b908301526101406129f781830161293e565b90830152612a0961016080920161293e565b9082015290565b80518210156127b85760209160051b010190565b6001600160a01b0316908115612a7157600080516020612e7e833981519152602082612a54600094603554612468565b6035558484526033825260408420818154019055604051908152a3565b60405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606490fd5b91906040835260076040840152665f71756f72756d60c81b6060840152602060808401930152565b15612ae557565b60405162461bcd60e51b8152602060048201526016602482015275546f6b656e204e6f6e205472616e7366657261626c6560501b6044820152606490fd5b6001600160a01b03918216815291811660208301529091166040820152606081019190915260800190565b6001600160a01b03908116918215612c595716918215612c085760008281526033602052604081205491808310612bb45760408282600080516020612e7e83398151915295876020965260338652038282205586815220818154019055604051908152a3565b60405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b60405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608490fd5b90816020910312612208575160ff811681036122085790565b60ff166012039060ff821161247557565b60ff16604d811161247557600a0a90565b6000906001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8103612d4757505060125b60ff8116601203612d22575090565b612d2e612d3391612cc5565b612cd6565b908060001904821181151516612475570290565b60206004916040519283809263313ce56760e01b82525afa918215612da05791612d72575b50612d13565b612d93915060203d8111612d99575b612d8b81836122f2565b810190612cac565b38612d6c565b503d612d81565b604051903d90823e3d90fd5b6000906001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8103612e1457505060125b60ff8116601203612de7575090565b612d2e612df391612cc5565b908115612dfe570490565b634e487b7160e01b600052601260045260246000fd5b60206004916040519283809263313ce56760e01b82525afa918215612da05791612e3f575b50612dd8565b612e57915060203d8111612d9957612d8b81836122f2565b38612e3956fe537472696e67733a20686578206c656e67746820696e73756666696369656e74ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60dabe9ef7b41f3c1cc359b009558ac4700a6bef8c5a11b51767e4980ed66341a2646970667358221220a90e785d0f600c83c302860d40b186f5d3fa4db79cb47890aa98a17d5bce6b6664736f6c63430008100033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in FRAX
0
Token Allocations
FRAX
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| FRAXTAL | 100.00% | $0.821031 | 0.000000013407 | <$0.000001 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.